From 42ea85786a44b519eb79f08a350020ed693d2e0e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 30 Aug 2013 23:48:03 +0200 Subject: Thrown ender pearls now teleport and hurt. --- source/Entities/ProjectileEntity.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 91b2c97a8..8f9f3b480 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -316,7 +316,13 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X void cThrownEnderPearlEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) { - // TODO: Teleport the creator here, make them take 5 damage + // Teleport the creator here, make them take 5 damage: + if (m_Creator != NULL) + { + // TODO: The coords might need some tweaking based on the block face + m_Creator->TeleportToCoords(a_BlockX + 0.5, a_BlockY + 1.7, a_BlockZ + 0.5); + m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); + } Destroy(); } -- cgit v1.2.3 From a884fbb91937d3243c15477428a31cc764d03a84 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 1 Sep 2013 22:40:35 +0200 Subject: Arrows deal damage. Still needs some tweaks, they hit the shooter most of the time. --- source/Entities/ProjectileEntity.cpp | 127 +++++++++++++++++++++++++++++++++-- source/Entities/ProjectileEntity.h | 4 ++ 2 files changed, 127 insertions(+), 4 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 8f9f3b480..ed7803410 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -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)) + { + // 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()) { - // Nothing in the way, update the position - SetPosition(NextPos); + // 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: diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 95dc00abc..da82c82ea 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -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 } ; -- cgit v1.2.3 From 7433b3723ca06575e986ea48fd4a2a2af4047189 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 2 Sep 2013 21:40:56 +0200 Subject: Projectiles don't collide with their creators. --- source/Entities/ProjectileEntity.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index ed7803410..8bc9abdb0 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -85,9 +85,13 @@ public: virtual bool Item(cEntity * a_Entity) override { - if (a_Entity == m_Projectile) + if ( + (a_Entity == m_Projectile) || // Do not check collisions with self + (a_Entity == m_Projectile->GetCreator()) // Do not check whoever shot the projectile + ) { - // Self-colision + // TODO: Don't check creator only for the first 5 ticks + // so that arrows stuck in ground and dug up can hurt the player return false; } -- cgit v1.2.3 From e8b77ea2f5a9245f9ed3b28a7a637cf584037914 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 2 Sep 2013 21:56:55 +0200 Subject: Projectiles slow down in water and lava. --- source/Entities/ProjectileEntity.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 8bc9abdb0..bef411559 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -24,13 +24,18 @@ class cProjectileTracerCallback : { public: cProjectileTracerCallback(cProjectileEntity * a_Projectile) : - m_Projectile(a_Projectile) + m_Projectile(a_Projectile), + m_SlowdownCoeff(0.99) // Default slowdown when not in water { } + double GetSlowdownCoeff(void) const { return m_SlowdownCoeff; } + protected: cProjectileEntity * m_Projectile; + double m_SlowdownCoeff; + // cCallbacks overrides: virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { if (g_BlockIsSolid[a_BlockType]) @@ -47,12 +52,14 @@ protected: case E_BLOCK_STATIONARY_LAVA: { m_Projectile->StartBurning(30); + m_SlowdownCoeff = std::min(m_SlowdownCoeff, 0.9); // Slow down to 0.9* the speed each tick when moving through lava break; } case E_BLOCK_WATER: case E_BLOCK_STATIONARY_WATER: { m_Projectile->StopBurning(); + m_SlowdownCoeff = std::min(m_SlowdownCoeff, 0.8); // Slow down to 0.8* the speed each tick when moving through water break; } } // switch (a_BlockType) @@ -280,6 +287,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) // 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 // Test for entity collisions: cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos); @@ -303,8 +311,11 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) // Update the position: SetPosition(NextPos); - // Add gravity effect to the vertical speed component: - SetSpeedY(GetSpeedY() + m_Gravity / 20); + // Add slowdown and gravity effect to the speed: + Vector3d NewSpeed(GetSpeed()); + NewSpeed.y += m_Gravity / 20; + NewSpeed *= TracerCallback.GetSlowdownCoeff(); + SetSpeed(NewSpeed); // DEBUG: LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}", -- cgit v1.2.3 From 3a921955d94851b4f0148f69f3f0c35a227aa8f5 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 3 Sep 2013 08:37:15 +0200 Subject: Arrows deal damage based on their speed. --- source/Entities/ProjectileEntity.cpp | 14 ++++++++++---- source/Entities/ProjectileEntity.h | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index bef411559..c259cb52f 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -345,7 +345,8 @@ void cProjectileEntity::SpawnOn(cClientHandle & a_Client) cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), m_PickupState(psNoPickup), - m_DamageCoeff(2) + m_DamageCoeff(2), + m_IsCritical(false) { SetSpeed(a_Speed); SetMass(0.1); @@ -361,7 +362,8 @@ 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, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), m_PickupState(psInSurvivalOrCreative), - m_DamageCoeff(2) + m_DamageCoeff(2), + m_IsCritical((a_Force >= 1)) { } @@ -401,8 +403,12 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit) 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); + int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); + if (m_IsCritical) + { + Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); + } + a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); Destroy(); } diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index da82c82ea..bd282d7e7 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -140,6 +140,9 @@ protected: /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow double m_DamageCoeff; + + /// If true, the arrow deals more damage + bool m_IsCritical; // cProjectileEntity overrides: virtual void SpawnOn(cClientHandle & a_Client) override; -- cgit v1.2.3 From f7d58944273be0390c9e583eaa5bad0bcfcbfa5d Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 3 Sep 2013 08:39:35 +0200 Subject: Added cArrowEntity's criticalness to the API. --- source/Entities/ProjectileEntity.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index bd282d7e7..415b64e90 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -131,6 +131,12 @@ public: /// Returns true if the specified player can pick the arrow up bool CanPickup(const cPlayer & a_Player) const; + /// Returns true if the arrow is set as critical + bool IsCritical(void) const { return m_IsCritical; } + + /// Sets the IsCritical flag + void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } + // tolua_end protected: -- cgit v1.2.3 From 2c5e566fe7de5399fac5588671b2b6f611e6bda6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 3 Sep 2013 09:41:31 +0200 Subject: Implemented exact block hit position. Arrows now stick out of blocks at the exact position where they hit. --- source/Entities/ProjectileEntity.cpp | 47 ++++++++++++++++++++---------------- source/Entities/ProjectileEntity.h | 10 ++++---- 2 files changed, 31 insertions(+), 26 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index c259cb52f..b97f72884 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -41,8 +41,22 @@ protected: if (g_BlockIsSolid[a_BlockType]) { // The projectile hit a solid block - m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace); - return true; + // 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; + char Face; + if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face)) + { + Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff; + m_Projectile->OnHitSolidBlock(Intersection, Face); + return true; + } + else + { + LOGD("WEIRD! block tracer reports a hit, but BBox tracer doesn't. Ignoring the hit."); + } } // Convey some special effects from special blocks: @@ -206,26 +220,17 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, -void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - // TODO: Set proper position based on what face was hit - switch (a_BlockFace) - { - case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; - case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break; - case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break; - case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; - } + // Set the position based on what face was hit: + SetPosition(a_HitPos); SetSpeed(0, 0, 0); // DEBUG: LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d", m_UniqueID, - GetPosX(), GetPosY(), GetPosZ(), - a_BlockFace + a_HitPos.x, a_HitPos.y, a_HitPos.z, + a_HitFace ); m_IsInGround = true; @@ -287,7 +292,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) // 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 + // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff // Test for entity collisions: cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos); @@ -430,7 +435,7 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, -void cThrownEggEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { // TODO: Random-spawn a chicken or four @@ -454,13 +459,13 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X -void cThrownEnderPearlEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { // Teleport the creator here, make them take 5 damage: if (m_Creator != NULL) { // TODO: The coords might need some tweaking based on the block face - m_Creator->TeleportToCoords(a_BlockX + 0.5, a_BlockY + 1.7, a_BlockZ + 0.5); + m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); } @@ -484,7 +489,7 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do -void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 415b64e90..5863b4f10 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -47,8 +47,8 @@ public: static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL); - /// 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 a solid block, the hit position and the face hit (BLOCK_FACE_) is given + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace); /// Called by the physics blocktracer when the entity hits another entity virtual void OnHitEntity(cEntity & a_EntityHit) {} @@ -179,7 +179,7 @@ protected: // tolua_end // cProjectileEntity overrides: - virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; // tolua_begin @@ -207,7 +207,7 @@ protected: // tolua_end // cProjectileEntity overrides: - virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; // tolua_begin @@ -235,7 +235,7 @@ protected: // tolua_end // cProjectileEntity overrides: - virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; // tolua_begin -- cgit v1.2.3 From 4c24781a621b3c572a43f24235dbab696dff0b35 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 3 Sep 2013 10:20:56 +0200 Subject: Added cEntity's gravity to the Lua API. --- source/Entities/Entity.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source/Entities') diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h index f407cd2c1..aa5d8fbd2 100644 --- a/source/Entities/Entity.h +++ b/source/Entities/Entity.h @@ -201,6 +201,10 @@ public: /// Makes this entity take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage() void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount); + float GetGravity(void) const { return m_Gravity; } + + void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; } + // tolua_end /// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied -- cgit v1.2.3 From 3f4718154bcce6fd06939fcc0f0b20ea7181be1e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 7 Sep 2013 17:14:37 +0200 Subject: Arrows have proper yaw and pitch when shot, and stop when they hit a block. --- source/Entities/Entity.cpp | 33 ++++++++++++++++++++++++++++++++ source/Entities/Entity.h | 6 ++++++ source/Entities/ProjectileEntity.cpp | 37 +++++++++++++++++++++++++++++------- source/Entities/ProjectileEntity.h | 2 +- 4 files changed, 70 insertions(+), 8 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp index b936d8d73..a07811a96 100644 --- a/source/Entities/Entity.cpp +++ b/source/Entities/Entity.cpp @@ -253,6 +253,39 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R +void cEntity::SetRotationFromSpeed(void) +{ + const double EPS = 0.0000001; + if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS)) + { + // atan2() may overflow or is undefined, pick any number + SetRotation(0); + return; + } + SetRotation(atan2(m_Speed.x, m_Speed.z) * 180 / PI); +} + + + + + +void cEntity::SetPitchFromSpeed(void) +{ + const double EPS = 0.0000001; + double xz = sqrt(m_Speed.x * m_Speed.x + m_Speed.z * m_Speed.z); // Speed XZ-plane component + if ((abs(xz) < EPS) && (abs(m_Speed.y) < EPS)) + { + // atan2() may overflow or is undefined, pick any number + SetPitch(0); + return; + } + SetPitch(atan2(m_Speed.y, xz) * 180 / PI); +} + + + + + void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) { if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI)) diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h index aa5d8fbd2..0e30f230c 100644 --- a/source/Entities/Entity.h +++ b/source/Entities/Entity.h @@ -205,6 +205,12 @@ public: void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; } + /// Sets the rotation to match the speed vector (entity goes "face-forward") + void SetRotationFromSpeed(void); + + /// Sets the pitch to match the speed vector (entity gies "face-forward") + void SetPitchFromSpeed(void); + // tolua_end /// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index b97f72884..81ac336f0 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -16,6 +16,13 @@ +/// Converts an angle in radians into a byte representation used by the network protocol +#define ANGLE_TO_PROTO(X) (Byte)(X * 255 / 360) + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cProjectileTracerCallback: @@ -189,6 +196,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve m_IsInGround(false) { SetSpeed(a_Speed); + SetRotationFromSpeed(); + SetPitchFromSpeed(); } @@ -321,12 +330,15 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) NewSpeed.y += m_Gravity / 20; NewSpeed *= TracerCallback.GetSlowdownCoeff(); SetSpeed(NewSpeed); + SetRotationFromSpeed(); + SetPitchFromSpeed(); // DEBUG: - LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}", + LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}", m_UniqueID, GetPosX(), GetPosY(), GetPosZ(), - GetSpeedX(), GetSpeedY(), GetSpeedZ() + GetSpeedX(), GetSpeedY(), GetSpeedZ(), + GetRotation(), GetPitch() ); } @@ -337,7 +349,8 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cProjectileEntity::SpawnOn(cClientHandle & a_Client) { // Default spawning - use the projectile kind to spawn an object: - a_Client.SendSpawnObject(*this, m_ProjectileKind, 0, 0, 0); + a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch())); + a_Client.SendEntityMetadata(*this); } @@ -355,8 +368,11 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a { SetSpeed(a_Speed); SetMass(0.1); - LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f}", - m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ() + SetRotationFromSpeed(); + SetPitchFromSpeed(); + LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", + m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), + GetRotation(), GetPitch() ); } @@ -392,14 +408,21 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const -void cArrowEntity::SpawnOn(cClientHandle & a_Client) +void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0); + super::OnHitSolidBlock(a_HitPos, a_HitFace); + + // Broadcast the position and speed packets before teleporting: + BroadcastMovementUpdate(); + + // Teleport the entity to the exact hit coords: + m_World->BroadcastTeleportEntity(*this); } + void cArrowEntity::OnHitEntity(cEntity & a_EntityHit) { if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer()) diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 5863b4f10..43aecac0e 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -151,7 +151,7 @@ protected: bool m_IsCritical; // cProjectileEntity overrides: - virtual void SpawnOn(cClientHandle & a_Client) override; + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; virtual void OnHitEntity(cEntity & a_EntityHit) override; // tolua_begin -- cgit v1.2.3 From 3b1c83acf8a0592f3c09a6bd530f8b695272b1ab Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 7 Sep 2013 18:12:22 +0200 Subject: Renamed cWorld::DoExplosiontAt() to cWorld::DoExplosionAt() --- source/Entities/TNTEntity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/Entities') diff --git a/source/Entities/TNTEntity.cpp b/source/Entities/TNTEntity.cpp index ad3d9ae0c..339107b2e 100644 --- a/source/Entities/TNTEntity.cpp +++ b/source/Entities/TNTEntity.cpp @@ -52,7 +52,7 @@ void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk) { Destroy(true); LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ()); - m_World->DoExplosiontAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this); + m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this); return; } } -- cgit v1.2.3 From 06b01af017d373377a58604fa36a1607323fa6dc Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 7 Sep 2013 18:53:14 +0200 Subject: Implemented ghast fireball and firecharge projectiles --- source/Entities/ProjectileEntity.cpp | 109 ++++++++++++++++++++++++++++++++--- source/Entities/ProjectileEntity.h | 61 +++++++++++++++++++- 2 files changed, 161 insertions(+), 9 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 81ac336f0..81a708f9a 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -214,10 +214,12 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, switch (a_Kind) { - case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); - case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); + case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); // TODO: the rest } @@ -309,8 +311,9 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) if (EntityCollisionCallback.HasHit()) { // An entity was hit: - // DEBUG: Vector3d HitPos = Pos + (NextPos - Pos) * EntityCollisionCallback.GetMinCoeff(); + + // DEBUG: LOGD("Projectile %d has hit an entity %d (%s) at {%.02f, %.02f, %.02f} (coeff %.03f)", m_UniqueID, EntityCollisionCallback.GetHitEntity()->GetUniqueID(), @@ -318,7 +321,8 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) HitPos.x, HitPos.y, HitPos.z, EntityCollisionCallback.GetMinCoeff() ); - OnHitEntity(*(EntityCollisionCallback.GetHitEntity())); + + OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos); } // TODO: Test the entities in the neighboring chunks, too @@ -423,7 +427,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) -void cArrowEntity::OnHitEntity(cEntity & a_EntityHit) +void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer()) { @@ -523,3 +527,94 @@ void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_Hi +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cGhastFireballEntity : + +cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this); +} + + + + + +void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFireChargeEntity : + +cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1); + } +} + + + + + +void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); + + // TODO: Some entities are immune to hits + a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning +} + + + + diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 43aecac0e..3e87f5a2c 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -51,7 +51,7 @@ public: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace); /// Called by the physics blocktracer when the entity hits another entity - virtual void OnHitEntity(cEntity & a_EntityHit) {} + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) {} // tolua_begin @@ -152,7 +152,7 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; - virtual void OnHitEntity(cEntity & a_EntityHit) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; // tolua_begin } ; @@ -231,12 +231,41 @@ public: cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + + // tolua_begin + +} ; + + + + + +class cGhastFireballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: // tolua_end + CLASS_PROTODEF(cGhastFireballEntity); + + cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + // TODO: Deflecting the fireballs by arrow- or sword- hits + // tolua_begin } ; @@ -245,6 +274,34 @@ protected: +class cFireChargeEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireChargeEntity); + + cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // tolua_begin + +} ; + + + + // tolua_end -- cgit v1.2.3 From 7938f18c57c4ef3909d93b7c13f9e24b2b4c81f5 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 7 Sep 2013 21:26:17 +0200 Subject: Implemented loading more projectiles from MCA. --- source/Entities/ProjectileEntity.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 3e87f5a2c..547aa174e 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -67,6 +67,11 @@ public: /// Returns true if the projectile has hit the ground and is stuck there bool IsInGround(void) const { return m_IsInGround; } + // tolua_end + + /// Sets the internal InGround flag. To be used by MCA loader only! + void SetIsInGround(bool a_IsInGround) { m_IsInGround = a_IsInGround; } + protected: eKind m_ProjectileKind; @@ -76,8 +81,6 @@ protected: /// True if the projectile has hit the ground and is stuck there bool m_IsInGround; - // tolua_end - // cEntity overrides: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; -- cgit v1.2.3 From d1b68f61500e975d01c4328c01da8ed52657a64d Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 7 Sep 2013 21:56:22 +0200 Subject: Added a (disabled) block logging to projectile path-tracing. --- source/Entities/ProjectileEntity.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source/Entities') diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 81a708f9a..4c8e680d0 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -45,6 +45,16 @@ protected: // cCallbacks overrides: virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { + /* + // DEBUG: + LOGD("Hit block %d:%d at {%d, %d, %d} face %d, %s (%s)", + a_BlockType, a_BlockMeta, + a_BlockX, a_BlockY, a_BlockZ, a_EntryFace, + g_BlockIsSolid[a_BlockType] ? "solid" : "non-solid", + ItemToString(cItem(a_BlockType, 1, a_BlockMeta)).c_str() + ); + */ + if (g_BlockIsSolid[a_BlockType]) { // The projectile hit a solid block -- cgit v1.2.3