1
0

Merge pull request #954 from mc-server/projectiles-split

Totally refactored ProjectileEntity.h, splitting up into several files.
This commit is contained in:
Mattes D 2014-04-28 12:32:02 +02:00
commit c063051645
27 changed files with 932 additions and 857 deletions

View File

@ -57,6 +57,14 @@ if (NOT MSVC)
Entities/Pickup.h
Entities/Player.h
Entities/ProjectileEntity.h
Entities/ArrowEntity.h
Entities/ThrownEggEntity.h
Entities/ThrownEnderPearlEntity.h
Entities/ExpBottleEntity.h
Entities/ThrownSnowballEntity.h
Entities/FireChargeEntity.h
Entities/FireworkEntity.h
Entities/GhastFireballEntity.h
Entities/TNTEntity.h
Entities/ExpOrb.h
Entities/HangingEntity.h

View File

@ -0,0 +1,193 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Player.h"
#include "ArrowEntity.h"
#include "../Chunk.h"
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_IsCritical(false),
m_Timer(0),
m_HitGroundTimer(0),
m_bIsCollected(false),
m_HitBlockPos(Vector3i(0, 0, 0))
{
SetSpeed(a_Speed);
SetMass(0.1);
SetYawFromSpeed();
SetPitchFromSpeed();
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
GetYaw(), GetPitch()
);
}
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_IsCritical((a_Force >= 1)),
m_Timer(0),
m_HitGroundTimer(0),
m_HasTeleported(false),
m_bIsCollected(false),
m_HitBlockPos(0, 0, 0)
{
}
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
{
switch (m_PickupState)
{
case psNoPickup: return false;
case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
case psInCreative: return a_Player.IsGameModeCreative();
}
ASSERT(!"Unhandled pickup state");
return false;
}
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);
}
m_HitBlockPos = Vector3i(a_X, a_Y, a_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));
}
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)
{
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
}
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
// Broadcast successful hit sound
m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}
void cArrowEntity::CollectedBy(cPlayer * a_Dest)
{
if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
{
int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
if (NumAdded > 0) // Only play effects if there was space in inventory
{
m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsCollected = true;
}
}
}
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
m_Timer += a_Dt;
if (m_bIsCollected)
{
if (m_Timer > 500.f) // 0.5 seconds
{
Destroy();
return;
}
}
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
{
Destroy();
return;
}
if (m_IsInGround)
{
// When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
// Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
// We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
// Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
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
{
m_World->BroadcastTeleportEntity(*this);
m_HasTeleported = true;
}
else
{
m_HitGroundTimer += a_Dt;
}
}
int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
if (Chunk == NULL)
{
// Inside an unloaded chunk, abort
return;
}
if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
{
m_IsInGround = false; // Yes, begin simulating physics again
}
}
}

View File

@ -0,0 +1,96 @@
//
// ArrowEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// tolua_begin
class cArrowEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
/// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
enum ePickupState
{
psNoPickup = 0,
psInSurvivalOrCreative = 1,
psInCreative = 2,
} ;
// tolua_end
CLASS_PROTODEF(cArrowEntity);
/// 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);
/// Creates a new arrow as shot by a player, initializes it from the player object
cArrowEntity(cPlayer & a_Player, double a_Force);
// tolua_begin
/// Returns whether the arrow can be picked up by players
ePickupState GetPickupState(void) const { return m_PickupState; }
/// Sets a new pickup state
void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
/// Returns the damage modifier coeff.
double GetDamageCoeff(void) const { return m_DamageCoeff; }
/// Sets the damage modifier coeff
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
/// 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:
/// Determines when the arrow can be picked up by players
ePickupState m_PickupState;
/// 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;
/// Timer for pickup collection animation or five minute timeout
float m_Timer;
/// Timer for client arrow position confirmation via TeleportEntity
float m_HitGroundTimer;
// Whether the arrow has already been teleported into the proper position in the ground.
bool m_HasTeleported;
/// If true, the arrow is in the process of being collected - don't go to anyone else
bool m_bIsCollected;
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
Vector3i m_HitBlockPos;
// 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 CollectedBy(cPlayer * a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
}; // tolua_export

View File

@ -0,0 +1,27 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "ExpBottleEntity.h"
#include "../World.h"
cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
{
SetSpeed(a_Speed);
}
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
// Spawn an experience orb with a reward between 3 and 11.
m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
Destroy();
}

View File

@ -0,0 +1,33 @@
//
// ExpBottleEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// tolua_begin
class cExpBottleEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cExpBottleEntity);
cExpBottleEntity(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, eBlockFace a_HitFace) override;
}; // tolua_export

View File

@ -0,0 +1,50 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "FireChargeEntity.h"
#include "../World.h"
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, eBlockFace 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
}

View File

@ -0,0 +1,36 @@
//
// FireChargeEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// tolua_begin
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, eBlockFace a_HitFace) override;
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
} ; // tolua_export

View File

@ -0,0 +1,73 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "FireworkEntity.h"
#include "../World.h"
#include "../Chunk.h"
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
m_ExplodeTimer(0),
m_FireworkItem(a_Item)
{
}
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
int PosY = POSY_TOINT;
if ((PosY < 0) || (PosY >= cChunkDef::Height))
{
goto setspeed;
}
if (m_IsInGround)
{
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
{
m_IsInGround = false;
}
else
{
return;
}
}
else
{
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
{
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
return;
}
}
setspeed:
AddSpeedY(1);
AddPosition(GetSpeed() * (a_Dt / 1000));
}
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
{
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
Destroy();
}
m_ExplodeTimer++;
}

View File

@ -0,0 +1,40 @@
//
// FireworkEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// tolua_begin
class cFireworkEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cFireworkEntity);
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
const cItem & GetItem(void) const { return m_FireworkItem; }
protected:
// cProjectileEntity overrides:
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
private:
int m_ExplodeTimer;
cItem m_FireworkItem;
}; // tolua_export

View File

@ -0,0 +1,44 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "GhastFireballEntity.h"
#include "../World.h"
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, eBlockFace 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));
}

View File

@ -0,0 +1,38 @@
//
// GhastFireballEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// 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, eBlockFace a_HitFace) override;
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// TODO: Deflecting the fireballs by arrow- or sword- hits
} ; // tolua_export

View File

@ -4,15 +4,24 @@
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
#include "Globals.h"
#include "../Bindings/PluginManager.h"
#include "ProjectileEntity.h"
#include "../ClientHandle.h"
#include "Player.h"
#include "../LineBlockTracer.h"
#include "../BoundingBox.h"
#include "../ChunkMap.h"
#include "../Chunk.h"
#include "ArrowEntity.h"
#include "ThrownEggEntity.h"
#include "ThrownEnderPearlEntity.h"
#include "ExpBottleEntity.h"
#include "ThrownSnowballEntity.h"
#include "FireChargeEntity.h"
#include "FireworkEntity.h"
#include "GhastFireballEntity.h"
@ -401,546 +410,3 @@ void cProjectileEntity::CollectedBy(cPlayer * a_Dest)
// Overriden in arrow
UNUSED(a_Dest);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cArrowEntity:
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_IsCritical(false),
m_Timer(0),
m_HitGroundTimer(0),
m_bIsCollected(false),
m_HitBlockPos(Vector3i(0, 0, 0))
{
SetSpeed(a_Speed);
SetMass(0.1);
SetYawFromSpeed();
SetPitchFromSpeed();
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
GetYaw(), GetPitch()
);
}
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_IsCritical((a_Force >= 1)),
m_Timer(0),
m_HitGroundTimer(0),
m_HasTeleported(false),
m_bIsCollected(false),
m_HitBlockPos(0, 0, 0)
{
}
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
{
switch (m_PickupState)
{
case psNoPickup: return false;
case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
case psInCreative: return a_Player.IsGameModeCreative();
}
ASSERT(!"Unhandled pickup state");
return false;
}
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);
}
m_HitBlockPos = Vector3i(a_X, a_Y, a_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));
}
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)
{
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
}
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
// Broadcast successful hit sound
m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}
void cArrowEntity::CollectedBy(cPlayer * a_Dest)
{
if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
{
int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
if (NumAdded > 0) // Only play effects if there was space in inventory
{
m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsCollected = true;
}
}
}
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
m_Timer += a_Dt;
if (m_bIsCollected)
{
if (m_Timer > 500.f) // 0.5 seconds
{
Destroy();
return;
}
}
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
{
Destroy();
return;
}
if (m_IsInGround)
{
// When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
// Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
// We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
// Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
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
{
m_World->BroadcastTeleportEntity(*this);
m_HasTeleported = true;
}
else
{
m_HitGroundTimer += a_Dt;
}
}
int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
if (Chunk == NULL)
{
// Inside an unloaded chunk, abort
return;
}
if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
{
m_IsInGround = false; // Yes, begin simulating physics again
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cThrownEggEntity:
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)
{
SetSpeed(a_Speed);
}
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
TrySpawnChicken(a_HitPos);
Destroy();
}
void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
int TotalDamage = 0;
// TODO: If entity is Ender Crystal, destroy it
TrySpawnChicken(a_HitPos);
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
Destroy(true);
}
void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
{
if (m_World->GetTickRandomNumber(7) == 1)
{
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
}
else if (m_World->GetTickRandomNumber(32) == 1)
{
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cThrownEnderPearlEntity :
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)
{
SetSpeed(a_Speed);
}
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
// TODO: Tweak a_HitPos based on block face.
TeleportCreator(a_HitPos);
Destroy();
}
void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
int TotalDamage = 0;
// TODO: If entity is Ender Crystal, destroy it
TeleportCreator(a_HitPos);
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
Destroy(true);
}
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->TakeDamage(dtEnderPearl, this, 5, 0);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cThrownSnowballEntity :
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)
{
SetSpeed(a_Speed);
}
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
Destroy();
}
void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
int TotalDamage = 0;
if (a_EntityHit.IsMob())
{
cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
if (MobType == cMonster::mtBlaze)
{
TotalDamage = 3;
}
else if (MobType == cMonster::mtEnderDragon)
{
TotalDamage = 1;
}
}
// TODO: If entity is Ender Crystal, destroy it
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
Destroy(true);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBottleOEnchantingEntity :
cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
{
SetSpeed(a_Speed);
}
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
// Spawn an experience orb with a reward between 3 and 11.
m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
Destroy();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFireworkEntity :
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
m_ExplodeTimer(0),
m_FireworkItem(a_Item)
{
}
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
int PosY = POSY_TOINT;
if ((PosY < 0) || (PosY >= cChunkDef::Height))
{
goto setspeed;
}
if (m_IsInGround)
{
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
{
m_IsInGround = false;
}
else
{
return;
}
}
else
{
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
{
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
return;
}
}
setspeed:
AddSpeedY(1);
AddPosition(GetSpeed() * (a_Dt / 1000));
}
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
{
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
Destroy();
}
m_ExplodeTimer++;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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, eBlockFace 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, eBlockFace 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
}

View File

@ -94,311 +94,4 @@ protected:
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override;
// tolua_begin
} ;
class cArrowEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
/// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
enum ePickupState
{
psNoPickup = 0,
psInSurvivalOrCreative = 1,
psInCreative = 2,
} ;
// tolua_end
CLASS_PROTODEF(cArrowEntity);
/// 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);
/// Creates a new arrow as shot by a player, initializes it from the player object
cArrowEntity(cPlayer & a_Player, double a_Force);
// tolua_begin
/// Returns whether the arrow can be picked up by players
ePickupState GetPickupState(void) const { return m_PickupState; }
/// Sets a new pickup state
void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
/// Returns the damage modifier coeff.
double GetDamageCoeff(void) const { return m_DamageCoeff; }
/// Sets the damage modifier coeff
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
/// 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:
/// Determines when the arrow can be picked up by players
ePickupState m_PickupState;
/// 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;
/// Timer for pickup collection animation or five minute timeout
float m_Timer;
/// Timer for client arrow position confirmation via TeleportEntity
float m_HitGroundTimer;
// Whether the arrow has already been teleported into the proper position in the ground.
bool m_HasTeleported;
/// If true, the arrow is in the process of being collected - don't go to anyone else
bool m_bIsCollected;
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
Vector3i m_HitBlockPos;
// 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 CollectedBy(cPlayer * a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
// tolua_begin
} ;
class cThrownEggEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cThrownEggEntity);
cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
protected:
// tolua_end
// cProjectileEntity overrides:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// Randomly decides whether to spawn a chicken where the egg lands.
void TrySpawnChicken(const Vector3d & a_HitPos);
// tolua_begin
} ;
class cThrownEnderPearlEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cThrownEnderPearlEntity);
cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
protected:
// tolua_end
// 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.
void TeleportCreator(const Vector3d & a_HitPos);
// tolua_begin
} ;
class cThrownSnowballEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cThrownSnowballEntity);
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, eBlockFace a_HitFace) override;
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// tolua_begin
} ;
class cExpBottleEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cExpBottleEntity);
cExpBottleEntity(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, eBlockFace a_HitFace) override;
// tolua_begin
};
class cFireworkEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cFireworkEntity);
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
const cItem & GetItem(void) const { return m_FireworkItem; }
protected:
// cProjectileEntity overrides:
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
private:
int m_ExplodeTimer;
cItem m_FireworkItem;
// 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, eBlockFace 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
} ;
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, eBlockFace a_HitFace) override;
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// tolua_begin
} ;
// tolua_end
} ; // tolua_export

View File

@ -0,0 +1,59 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "ThrownEggEntity.h"
#include "../World.h"
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)
{
SetSpeed(a_Speed);
}
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
TrySpawnChicken(a_HitPos);
Destroy();
}
void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
int TotalDamage = 0;
// TODO: If entity is Ender Crystal, destroy it
TrySpawnChicken(a_HitPos);
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
Destroy(true);
}
void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
{
if (m_World->GetTickRandomNumber(7) == 1)
{
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
}
else if (m_World->GetTickRandomNumber(32) == 1)
{
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
}
}

View File

@ -0,0 +1,37 @@
//
// ThrownEggEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// tolua_begin
class cThrownEggEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cThrownEggEntity);
cThrownEggEntity(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, eBlockFace a_HitFace) override;
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// Randomly decides whether to spawn a chicken where the egg lands.
void TrySpawnChicken(const Vector3d & a_HitPos);
} ; // tolua_export

View File

@ -0,0 +1,54 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "ThrownEnderPearlEntity.h"
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)
{
SetSpeed(a_Speed);
}
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
// TODO: Tweak a_HitPos based on block face.
TeleportCreator(a_HitPos);
Destroy();
}
void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
int TotalDamage = 0;
// TODO: If entity is Ender Crystal, destroy it
TeleportCreator(a_HitPos);
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
Destroy(true);
}
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->TakeDamage(dtEnderPearl, this, 5, 0);
}
}

View File

@ -0,0 +1,37 @@
//
// ThrownEnderPearlEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// tolua_begin
class cThrownEnderPearlEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cThrownEnderPearlEntity);
cThrownEnderPearlEntity(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, eBlockFace a_HitFace) override;
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// Teleports the creator where the ender pearl lands.
void TeleportCreator(const Vector3d & a_HitPos);
} ; // tolua_export

View File

@ -0,0 +1,48 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "ThrownSnowballEntity.h"
#include "../World.h"
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)
{
SetSpeed(a_Speed);
}
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
Destroy();
}
void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
int TotalDamage = 0;
if (a_EntityHit.IsMob())
{
cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
if (MobType == cMonster::mtBlaze)
{
TotalDamage = 3;
}
else if (MobType == cMonster::mtEnderDragon)
{
TotalDamage = 1;
}
}
// TODO: If entity is Ender Crystal, destroy it
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
Destroy(true);
}

View File

@ -0,0 +1,34 @@
//
// ThrownSnowballEntity.h
//
#pragma once
#include "ProjectileEntity.h"
// tolua_begin
class cThrownSnowballEntity :
public cProjectileEntity
{
typedef cProjectileEntity super;
public:
// tolua_end
CLASS_PROTODEF(cThrownSnowballEntity);
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, eBlockFace a_HitFace) override;
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
} ; // tolua_export

View File

@ -9,7 +9,7 @@
#pragma once
#include "../Entities/ProjectileEntity.h"
#include "../Entities/ArrowEntity.h"

View File

@ -3,6 +3,7 @@
#include "Blaze.h"
#include "../World.h"
#include "../Entities/FireChargeEntity.h"

View File

@ -3,6 +3,7 @@
#include "Ghast.h"
#include "../World.h"
#include "../Entities/GhastFireballEntity.h"

View File

@ -3,6 +3,7 @@
#include "Skeleton.h"
#include "../World.h"
#include "../Entities/ArrowEntity.h"

View File

@ -26,7 +26,7 @@ Documentation:
#include "../Root.h"
#include "../Server.h"
#include "../Entities/ProjectileEntity.h"
#include "../Entities/ArrowEntity.h"
#include "../Entities/Minecart.h"
#include "../Entities/FallingBlock.h"

View File

@ -31,6 +31,8 @@ Implements the 1.7.x protocol classes:
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
#include "../CompositeChat.h"
#include "../Entities/ArrowEntity.h"
#include "../Entities/FireworkEntity.h"

View File

@ -28,7 +28,7 @@
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
#include "../Entities/ArrowEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"

View File

@ -27,7 +27,6 @@
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
#include "../Mobs/Monster.h"
#include "../Mobs/IncludeAllMonsters.h"
@ -36,7 +35,12 @@
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
#include "../Entities/ArrowEntity.h"
#include "../Entities/ThrownEggEntity.h"
#include "../Entities/ThrownEnderPearlEntity.h"
#include "../Entities/ThrownSnowballEntity.h"
#include "../Entities/FireChargeEntity.h"
#include "../Entities/GhastFireballEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"