1
0
Fork 0

Rewritten entity-on-fire management ("forever on fire" bugs)

Fixes FS #297 and part of FS #403.
Added sizes to all entities.
Moved all damage-related functions from cPawn to cEntity
API change: renamed cPawn:TeleportTo() to cEntity:TeleportToCoords()

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1635 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-07-01 10:39:56 +00:00
parent 3cfe865df3
commit 37276a4430
72 changed files with 2640 additions and 2446 deletions

View File

@ -1,7 +1,7 @@
function HandleSpawnCommand( Split, Player )
function HandleSpawnCommand(Split, Player)
World = Player:GetWorld()
SetBackCoordinates( Player )
Player:TeleportTo( World:GetSpawnX(), World:GetSpawnY(), World:GetSpawnZ() )
LOGINFO( Player:GetName() .. " returned to spawn." )
SetBackCoordinates(Player)
Player:TeleportToCoords(World:GetSpawnX(), World:GetSpawnY(), World:GetSpawnZ())
LOGINFO(Player:GetName() .. " returned to spawn.")
return true
end

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 06/29/13 17:21:36.
** Generated automatically by tolua++-1.0.92 on 07/01/13 09:49:29.
*/
/* Exported function */

View File

@ -510,16 +510,16 @@ void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, c
void cChunkMap::BroadcastMetadata(const cPawn & a_Pawn, const cClientHandle * a_Exclude)
void cChunkMap::BroadcastMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_Pawn.GetChunkX(), ZERO_CHUNK_Y, a_Pawn.GetChunkZ());
cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ());
if (Chunk == NULL)
{
return;
}
// It's perfectly legal to broadcast packets even to invalid chunks!
Chunk->BroadcastMetadata(a_Pawn, a_Exclude);
Chunk->BroadcastMetadata(a_Entity, a_Exclude);
}

View File

@ -79,7 +79,7 @@ public:
void BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
void BroadcastMetadata(const cPawn & a_Pawn, const cClientHandle * a_Exclude = NULL);
void BroadcastMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastSpawn(cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);

View File

@ -12,6 +12,7 @@
#include "Tracer.h"
#include "Chunk.h"
#include "Simulator/FluidSimulator.h"
#include "PluginManager.h"
@ -24,8 +25,10 @@ cCriticalSection cEntity::m_CSCount;
cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z)
cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height)
: m_UniqueID(0)
, m_Health(1)
, m_MaxHealth(1)
, m_AttachedTo(NULL)
, m_Attachee(NULL)
, m_Referencers(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCERS))
@ -49,9 +52,13 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z)
, m_TimeLastSpeedPacket(0)
, m_EntityType(a_EntityType)
, m_World(NULL)
, m_FireDamageInterval(0.f)
, m_BurnPeriod(0.f)
, m_WaterSpeed( 0.0 , 0.0 , 0.0 )
, m_TicksSinceLastBurnDamage(0)
, m_TicksSinceLastLavaDamage(0)
, m_TicksSinceLastFireDamage(0)
, m_TicksLeftBurning(0)
, m_WaterSpeed(0, 0, 0)
, m_Width(a_Width)
, m_Height(a_Height)
{
cCSLock Lock(m_CSCount);
m_EntityCount++;
@ -194,6 +201,236 @@ void cEntity::Destroy(bool a_ShouldBroadcast)
void cEntity::TakeDamage(cEntity & a_Attacker)
{
int RawDamage = a_Attacker.GetRawDamageAgainst(*this);
TakeDamage(dtAttack, &a_Attacker, RawDamage, a_Attacker.GetKnockbackAmountAgainst(*this));
}
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount)
{
int FinalDamage = a_RawDamage - GetArmorCoverAgainst(a_Attacker, a_DamageType, a_RawDamage);
cEntity::TakeDamage(a_DamageType, a_Attacker, a_RawDamage, FinalDamage, a_KnockbackAmount);
}
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount)
{
TakeDamageInfo TDI;
TDI.DamageType = a_DamageType;
TDI.Attacker = a_Attacker;
TDI.RawDamage = a_RawDamage;
TDI.FinalDamage = a_FinalDamage;
Vector3d Heading;
Heading.x = sin(GetRotation());
Heading.y = 0.4; // TODO: adjust the amount of "up" knockback when testing
Heading.z = cos(GetRotation());
TDI.Knockback = Heading * a_KnockbackAmount;
DoTakeDamage(TDI);
}
void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI))
{
return;
}
if (m_Health <= 0)
{
// Can't take damage if already dead
return;
}
m_Health -= (short)a_TDI.FinalDamage;
// TODO: Apply damage to armor
if (m_Health < 0)
{
m_Health = 0;
}
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
if (m_Health <= 0)
{
KilledBy(a_TDI.Attacker);
}
}
int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver)
{
// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
// Ref: http://www.minecraftwiki.net/wiki/Damage#Dealing_damage as of 2012_12_20
switch (this->GetEquippedWeapon().m_ItemType)
{
case E_ITEM_WOODEN_SWORD: return 4;
case E_ITEM_GOLD_SWORD: return 4;
case E_ITEM_STONE_SWORD: return 5;
case E_ITEM_IRON_SWORD: return 6;
case E_ITEM_DIAMOND_SWORD: return 7;
case E_ITEM_WOODEN_AXE: return 3;
case E_ITEM_GOLD_AXE: return 3;
case E_ITEM_STONE_AXE: return 4;
case E_ITEM_IRON_AXE: return 5;
case E_ITEM_DIAMOND_AXE: return 6;
case E_ITEM_WOODEN_PICKAXE: return 2;
case E_ITEM_GOLD_PICKAXE: return 2;
case E_ITEM_STONE_PICKAXE: return 3;
case E_ITEM_IRON_PICKAXE: return 4;
case E_ITEM_DIAMOND_PICKAXE: return 5;
case E_ITEM_WOODEN_SHOVEL: return 1;
case E_ITEM_GOLD_SHOVEL: return 1;
case E_ITEM_STONE_SHOVEL: return 2;
case E_ITEM_IRON_SHOVEL: return 3;
case E_ITEM_DIAMOND_SHOVEL: return 4;
}
// All other equipped items give a damage of 1:
return 1;
}
int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
{
// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
// Filter out damage types that are not protected by armor:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20
switch (a_DamageType)
{
case dtOnFire:
case dtSuffocating:
case dtDrowning: // TODO: This one could be a special case - in various MC versions (PC vs XBox) it is and isn't armor-protected
case dtStarving:
case dtInVoid:
case dtPoisoning:
case dtPotionOfHarming:
case dtFalling:
case dtLightning:
{
return 0;
}
}
// Add up all armor points:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20
int ArmorValue = 0;
switch (GetEquippedHelmet().m_ItemType)
{
case E_ITEM_LEATHER_CAP: ArmorValue += 1; break;
case E_ITEM_GOLD_HELMET: ArmorValue += 2; break;
case E_ITEM_CHAIN_HELMET: ArmorValue += 2; break;
case E_ITEM_IRON_HELMET: ArmorValue += 2; break;
case E_ITEM_DIAMOND_HELMET: ArmorValue += 3; break;
}
switch (GetEquippedChestplate().m_ItemType)
{
case E_ITEM_LEATHER_TUNIC: ArmorValue += 3; break;
case E_ITEM_GOLD_CHESTPLATE: ArmorValue += 5; break;
case E_ITEM_CHAIN_CHESTPLATE: ArmorValue += 5; break;
case E_ITEM_IRON_CHESTPLATE: ArmorValue += 6; break;
case E_ITEM_DIAMOND_CHESTPLATE: ArmorValue += 8; break;
}
switch (GetEquippedLeggings().m_ItemType)
{
case E_ITEM_LEATHER_PANTS: ArmorValue += 2; break;
case E_ITEM_GOLD_LEGGINGS: ArmorValue += 3; break;
case E_ITEM_CHAIN_LEGGINGS: ArmorValue += 4; break;
case E_ITEM_IRON_LEGGINGS: ArmorValue += 5; break;
case E_ITEM_DIAMOND_LEGGINGS: ArmorValue += 6; break;
}
switch (GetEquippedBoots().m_ItemType)
{
case E_ITEM_LEATHER_BOOTS: ArmorValue += 1; break;
case E_ITEM_GOLD_BOOTS: ArmorValue += 1; break;
case E_ITEM_CHAIN_BOOTS: ArmorValue += 1; break;
case E_ITEM_IRON_BOOTS: ArmorValue += 2; break;
case E_ITEM_DIAMOND_BOOTS: ArmorValue += 3; break;
}
// TODO: Special armor cases, such as wool, saddles, dog's collar
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Mob_armor as of 2012_12_20
// Now ArmorValue is in [0, 20] range, which corresponds to [0, 80%] protection. Calculate the hitpoints from that:
return a_Damage * (ArmorValue * 4) / 100;
}
double cEntity::GetKnockbackAmountAgainst(const cEntity & a_Receiver)
{
// Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit
// TODO: Enchantments
return 1;
}
void cEntity::KilledBy(cEntity * a_Killer)
{
m_Health = 0;
cRoot::Get()->GetPluginManager()->CallHookKilling(*this, a_Killer);
if (m_Health > 0)
{
// Plugin wants to 'unkill' the pawn. Abort
return;
}
// Drop loot:
cItems Drops;
GetDrops(Drops, a_Killer);
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD);
}
void cEntity::Heal(int a_HitPoints)
{
m_Health += a_HitPoints;
if (m_Health > m_MaxHealth)
{
m_Health = m_MaxHealth;
}
}
void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_AttachedTo != NULL)
@ -207,6 +444,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
HandlePhysics(a_Dt, a_Chunk);
}
TickBurning(a_Chunk);
}
@ -391,6 +629,226 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
void cEntity::TickBurning(cChunk & a_Chunk)
{
// Do the burning damage:
if (m_TicksLeftBurning > 0)
{
m_TicksSinceLastBurnDamage++;
if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE)
{
TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0, 0);
m_TicksSinceLastFireDamage = 0;
}
m_TicksLeftBurning--;
if (m_TicksLeftBurning == 0)
{
OnFinishedBurning();
}
}
// Remember the current burning state:
bool HasBeenBurning = (m_TicksLeftBurning > 0);
// Update the burning times, based on surroundings:
int MinRelX = (int)floor(GetPosX() - m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
int MaxRelX = (int)floor(GetPosX() + m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
int MinRelZ = (int)floor(GetPosZ() - m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
int MaxRelZ = (int)floor(GetPosZ() + m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
int MinY = std::max(0, std::min(cChunkDef::Height - 1, (int)floor(GetPosY())));
int MaxY = std::max(0, std::min(cChunkDef::Height - 1, (int)ceil (GetPosY() + m_Height)));
bool HasWater = false;
bool HasLava = false;
bool HasFire = false;
for (int x = MinRelX; x <= MaxRelX; x++)
{
for (int z = MinRelZ; z <= MaxRelZ; z++)
{
int RelX = x;
int RelZ = z;
cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ);
if (CurChunk == NULL)
{
continue;
}
for (int y = MinY; y <= MaxY; y++)
{
switch (CurChunk->GetBlock(RelX, y, RelZ))
{
case E_BLOCK_FIRE:
{
HasFire = true;
break;
}
case E_BLOCK_LAVA:
case E_BLOCK_STATIONARY_LAVA:
{
HasLava = true;
break;
}
case E_BLOCK_STATIONARY_WATER:
case E_BLOCK_WATER:
{
HasWater = true;
break;
}
} // switch (BlockType)
} // for y
} // for z
} // for x
if (HasWater)
{
// Extinguish the fire
m_TicksLeftBurning = 0;
}
if (HasLava)
{
// Burn:
m_TicksLeftBurning = BURN_TICKS;
// Periodically damage:
m_TicksSinceLastLavaDamage++;
if (m_TicksSinceLastLavaDamage >= 10)
{
TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
m_TicksSinceLastLavaDamage = 0;
}
}
else
{
m_TicksSinceLastLavaDamage = 0;
}
if (HasFire)
{
// Burn:
m_TicksLeftBurning = BURN_TICKS;
// Periodically damage:
m_TicksSinceLastFireDamage++;
if (m_TicksSinceLastFireDamage >= FIRE_TICKS_PER_DAMAGE)
{
TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
}
}
else
{
m_TicksSinceLastFireDamage = 0;
}
// If just started / finished burning, notify descendants:
if ((m_TicksLeftBurning > 0) && !HasBeenBurning)
{
OnStartedBurning();
}
else if ((m_TicksLeftBurning <= 0) && HasBeenBurning)
{
OnFinishedBurning();
}
}
/// Called when the entity starts burning
void cEntity::OnStartedBurning(void)
{
// Broadcast the change:
m_World->BroadcastMetadata(*this);
}
/// Called when the entity finishes burning
void cEntity::OnFinishedBurning(void)
{
// Broadcast the change:
m_World->BroadcastMetadata(*this);
}
/// Sets the maximum value for the health
void cEntity::SetMaxHealth(int a_MaxHealth)
{
m_MaxHealth = a_MaxHealth;
// Reset health, if too high:
if (m_Health > a_MaxHealth)
{
m_Health = a_MaxHealth;
}
}
/// Puts the entity on fire for the specified amount of ticks
void cEntity::StartBurning(int a_TicksLeftBurning)
{
if (m_TicksLeftBurning > 0)
{
// Already burning, top up the ticks left burning and bail out:
m_TicksLeftBurning = std::max(m_TicksLeftBurning, a_TicksLeftBurning);
return;
}
m_TicksLeftBurning = a_TicksLeftBurning;
OnStartedBurning();
}
/// Stops the entity from burning, resets all burning timers
void cEntity::StopBurning(void)
{
bool HasBeenBurning = (m_TicksLeftBurning > 0);
m_TicksLeftBurning = 0;
m_TicksSinceLastBurnDamage = 0;
m_TicksSinceLastFireDamage = 0;
m_TicksSinceLastLavaDamage = 0;
// Notify if the entity has stopped burning
if (HasBeenBurning)
{
OnFinishedBurning();
}
}
void cEntity::TeleportToEntity(cEntity & a_Entity)
{
TeleportToCoords(a_Entity.GetPosX(), a_Entity.GetPosY(), a_Entity.GetPosZ());
}
void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
{
SetPosition(a_PosX, a_PosY, a_PosZ);
m_World->BroadcastTeleportEntity(*this);
}
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
//We need to keep updating the clients when there is movement or if there was a change in speed and after 2 ticks

View File

@ -1,9 +1,7 @@
#pragma once
#include "Item.h"
#include "Vector3d.h"
#include "Vector3f.h"
@ -43,6 +41,65 @@ class cChunk;
// tolua_begin
enum eDamageType
{
// Canonical names for the types (as documented in the plugin wiki):
dtAttack, // Being attacked by a mob
dtLightning, // Hit by a lightning strike
dtFalling, // Falling down; dealt when hitting the ground
dtDrowning, // Drowning in water / lava
dtSuffocating, // Suffocating inside a block
dtStarving, // Hunger
dtCactusContact, // Contact with a cactus block
dtLavaContact, // Contact with a lava block
dtPoisoning, // Having the poison effect
dtOnFire, // Being on fire
dtFireContact, // Standing inside a fire block
dtInVoid, // Falling into the Void (Y < 0)
dtPotionOfHarming,
dtAdmin, // Damage applied by an admin command
// Some common synonyms:
dtPawnAttack = dtAttack,
dtEntityAttack = dtAttack,
dtMob = dtAttack,
dtMobAttack = dtAttack,
dtFall = dtFalling,
dtDrown = dtDrowning,
dtSuffocation = dtSuffocating,
dtStarvation = dtStarving,
dtHunger = dtStarving,
dtCactus = dtCactusContact,
dtCactuses = dtCactusContact,
dtCacti = dtCactusContact,
dtLava = dtLavaContact,
dtPoison = dtPoisoning,
dtBurning = dtOnFire,
dtInFire = dtFireContact,
dtPlugin = dtAdmin,
} ;
struct TakeDamageInfo
{
eDamageType DamageType; // Where does the damage come from? Being hit / on fire / contact with cactus / ...
cEntity * Attacker; // The attacking entity; valid only for dtAttack
int RawDamage; // What damage would the receiver get without any armor. Usually: attacker mob type + weapons
int FinalDamage; // What actual damage will be received. Usually: m_RawDamage minus armor
Vector3d Knockback; // The amount and direction of knockback received from the damage
// TODO: Effects - list of effects that the hit is causing. Unknown representation yet
} ;
// tolua_end
// tolua_begin
class cEntity
{
@ -58,6 +115,17 @@ public:
ENTITY_STATUS_SHEEP_EATING = 10,
} ;
enum
{
FIRE_TICKS_PER_DAMAGE = 10, ///< How many ticks to wait between damaging an entity when it stands in fire
FIRE_DAMAGE = 1, ///< How much damage to deal when standing in fire
LAVA_TICKS_PER_DAMAGE = 10, ///< How many ticks to wait between damaging an entity when it stands in lava
LAVA_DAMAGE = 5, ///< How much damage to deal when standing in lava
BURN_TICKS_PER_DAMAGE = 20, ///< How many ticks to wait between damaging an entity when it is burning
BURN_DAMAGE = 1, ///< How much damage to deal when the entity is burning
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
} ;
enum eEntityType
{
etEntity, // For all other types
@ -78,7 +146,7 @@ public:
// tolua_end
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z);
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
virtual ~cEntity();
virtual void Initialize(cWorld * a_World);
@ -164,10 +232,85 @@ public:
/// Schedules the entity for destroying; if a_ShouldBroadcast is set to true, broadcasts the DestroyEntity packet
void Destroy(bool a_ShouldBroadcast = true);
/// Makes this pawn take damage from an attack by a_Attacker. Damage values are calculated automatically and DoTakeDamage() called
void TakeDamage(cEntity & a_Attacker);
/// Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount);
/// 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);
// tolua_end
/// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied
virtual void DoTakeDamage(TakeDamageInfo & a_TDI);
// tolua_begin
/// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
virtual int GetRawDamageAgainst(const cEntity & a_Receiver);
/// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage);
/// Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit
virtual double GetKnockbackAmountAgainst(const cEntity & a_Receiver);
/// Returns the curently equipped weapon; empty item if none
virtual cItem GetEquippedWeapon(void) const { return cItem(); }
/// Returns the currently equipped helmet; empty item if nonte
virtual cItem GetEquippedHelmet(void) const { return cItem(); }
/// Returns the currently equipped chestplate; empty item if nonte
virtual cItem GetEquippedChestplate(void) const { return cItem(); }
/// Returns the currently equipped leggings; empty item if nonte
virtual cItem GetEquippedLeggings(void) const { return cItem(); }
/// Returns the currently equipped boots; empty item if nonte
virtual cItem GetEquippedBoots(void) const { return cItem(); }
/// Called when the health drops below zero. a_Killer may be NULL (environmental damage)
virtual void KilledBy(cEntity * a_Killer);
/// Heals the specified amount of HPs
void Heal(int a_HitPoints);
/// Returns the health of this pawn
int GetHealth(void) const { return m_Health; }
// tolua_end
virtual void Tick(float a_Dt, cChunk & a_Chunk);
/// Handles the physics of the entity - updates position based on speed, updates speed based on environment
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk);
/// Updates the state related to this entity being on fire
virtual void TickBurning(cChunk & a_Chunk);
/// Called when the entity starts burning
virtual void OnStartedBurning(void);
/// Called when the entity finishes burning
virtual void OnFinishedBurning(void);
// tolua_begin
/// Sets the maximum value for the health
void SetMaxHealth(int a_MaxHealth);
int GetMaxHealth(void) const { return m_MaxHealth; }
/// Puts the entity on fire for the specified amount of ticks
void StartBurning(int a_TicksLeftBurning);
/// Stops the entity from burning, resets all burning timers
void StopBurning(void);
// tolua_end
/** Descendants override this function to send a command to the specified client to spawn the entity on the client.
To spawn on all eligible clients, use cChunkMap::BroadcastSpawnEntity()
@ -175,6 +318,16 @@ public:
*/
virtual void SpawnOn(cClientHandle & a_Client) {ASSERT(!"SpawnOn() unimplemented!"); }
// tolua_begin
/// Teleports to the entity specified
virtual void TeleportToEntity(cEntity & a_Entity);
/// Teleports to the coordinates specified
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ);
// tolua_end
/// Updates clients of changes in the entity.
virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = NULL);
@ -196,7 +349,7 @@ public:
// tolua_begin
// Metadata flags; descendants may override the defaults:
virtual bool IsOnFire (void) const {return (m_BurnPeriod > 0); }
virtual bool IsOnFire (void) const {return (m_TicksLeftBurning > 0); }
virtual bool IsCrouched (void) const {return false; }
virtual bool IsRiding (void) const {return false; }
virtual bool IsSprinting(void) const {return false; }
@ -207,12 +360,18 @@ public:
/// Called when the specified player right-clicks this entity
virtual void OnRightClicked(cPlayer & a_Player) {};
/// Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy().
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) {}
protected:
static cCriticalSection m_CSCount;
static int m_EntityCount;
int m_UniqueID;
int m_Health;
int m_MaxHealth;
/// The entity to which this entity is attached (vehicle), NULL if none
cEntity * m_AttachedTo;
@ -243,8 +402,17 @@ protected:
cWorld * m_World;
float m_FireDamageInterval;
float m_BurnPeriod;
/// Time, in ticks, since the last damage dealt by being on fire. Valid only if on fire (IsOnFire())
int m_TicksSinceLastBurnDamage;
/// Time, in ticks, since the last damage dealt by standing in lava. Reset to zero when moving out of lava.
int m_TicksSinceLastLavaDamage;
/// Time, in ticks, since the last damage dealt by standing in fire. Reset to zero when moving out of fire.
int m_TicksSinceLastFireDamage;
/// Time, in ticks, until the entity extinguishes its fire
int m_TicksLeftBurning;
virtual void Destroyed(void) {} // Called after the entity has been destroyed
@ -254,22 +422,28 @@ protected:
void AddReference( cEntity*& a_EntityPtr );
void ReferencedBy( cEntity*& a_EntityPtr );
void Dereference( cEntity*& a_EntityPtr );
private:
//Measured in degrees (MAX 360°)
// Measured in degrees (MAX 360°)
double m_HeadYaw;
//Measured in meter/second (m/s)
// Measured in meter/second (m/s)
Vector3d m_Speed;
//Measured in degrees (MAX 360°)
// Measured in degrees (MAX 360°)
Vector3d m_Rot;
//Measured in meters (1 meter = 1 block) (m)
/// Position of the entity's XZ center and Y bottom
Vector3d m_Pos;
//Measured in meter/second
// Measured in meter / second
Vector3d m_WaterSpeed;
//Measured in Kilograms (Kg)
// Measured in Kilograms (Kg)
double m_Mass;
//It's Width.
/// Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter.
double m_Width;
//It's height
/// Height of the entity (Y axis)
double m_Height;
} ; // tolua_export

View File

@ -11,7 +11,7 @@
cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
super(etFallingBlock, a_BlockPosition.x + 0.5f, a_BlockPosition.y + 0.5f, a_BlockPosition.z + 0.5f),
super(etFallingBlock, a_BlockPosition.x + 0.5f, a_BlockPosition.y + 0.5f, a_BlockPosition.z + 0.5f, 0.98, 0.98),
m_BlockType(a_BlockType),
m_BlockMeta(a_BlockMeta),
m_OriginalPosition(a_BlockPosition)

View File

@ -14,7 +14,7 @@
cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
super(etMinecart, a_X, a_Y, a_Z),
super(etMinecart, a_X, a_Y, a_Z, 0.98, 0.7),
m_Payload(a_Payload)
{
}

View File

@ -11,8 +11,8 @@
cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath) :
super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath),
cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height),
m_ChaseTime(999999)
{
m_EMPersonality = AGGRESSIVE;

View File

@ -13,7 +13,7 @@ class cAggressiveMonster :
typedef cMonster super;
public:
cAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath);
cAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
virtual void InStateChasing(float a_Dt) override;

View File

@ -14,7 +14,8 @@ class cBat :
public:
cBat(void) :
super("Bat", 65, "mob.bat.hurt", "mob.bat.death")
// TODO: The size is only a guesstimate, measure in vanilla and fix the size values here
super("Bat", 65, "mob.bat.hurt", "mob.bat.death", 0.7, 0.7)
{
}

View File

@ -8,7 +8,8 @@
cBlaze::cBlaze(void) :
super("Blaze", 61, "mob.blaze.hit", "mob.blaze.death")
// TODO: The size is only a guesstimate, measure in vanilla and fix the size values here
super("Blaze", 61, "mob.blaze.hit", "mob.blaze.death", 0.7, 1.8)
{
}
@ -16,7 +17,7 @@ cBlaze::cBlaze(void) :
void cBlaze::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cBlaze::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_BLAZE_ROD);
}

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cBlaze);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -8,7 +8,8 @@
cCavespider::cCavespider(void) :
super("Cavespider", 59, "mob.spider.say", "mob.spider.death")
// TODO: The size is only a guesstimate, measure in vanilla and fix the size values here
super("Cavespider", 59, "mob.spider.say", "mob.spider.death", 0.9, 0.6)
{
}
@ -28,7 +29,7 @@ void cCavespider::Tick(float a_Dt, cChunk & a_Chunk)
void cCavespider::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cCavespider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_STRING);
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_SPIDER_EYE);

View File

@ -18,7 +18,7 @@ public:
CLASS_PROTODEF(cCaveSpider);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -14,7 +14,7 @@
cChicken::cChicken(void) :
super("Chicken", 93, "mob.chicken.hurt", "mob.chicken.hurt")
super("Chicken", 93, "mob.chicken.hurt", "mob.chicken.hurt", 0.3, 0.4)
{
}
@ -22,10 +22,10 @@ cChicken::cChicken(void) :
void cChicken::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cChicken::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_FEATHER);
a_Drops.push_back(cItem((GetMetaData() == BURNING) ? E_ITEM_COOKED_CHICKEN : E_ITEM_RAW_CHICKEN, 1));
a_Drops.push_back(cItem(IsOnFire() ? E_ITEM_COOKED_CHICKEN : E_ITEM_RAW_CHICKEN, 1));
}

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cChicken);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -14,7 +14,7 @@
cCow::cCow(void) :
super("Cow", 92, "mob.cow.hurt", "mob.cow.hurt")
super("Cow", 92, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3)
{
}
@ -22,10 +22,10 @@ cCow::cCow(void) :
void cCow::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cCow::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_LEATHER);
AddRandomDropItem(a_Drops, 1, 3, (GetMetaData() == BURNING) ? E_ITEM_STEAK : E_ITEM_RAW_BEEF);
AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_STEAK : E_ITEM_RAW_BEEF);
}

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cCow);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -8,7 +8,7 @@
cCreeper::cCreeper(void) :
super("Creeper", 50, "mob.creeper.say", "mob.creeper.say")
super("Creeper", 50, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8)
{
}
@ -16,7 +16,7 @@ cCreeper::cCreeper(void) :
void cCreeper::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_GUNPOWDER);

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cCreeper);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -8,7 +8,8 @@
cEnderman::cEnderman(void) :
super("Enderman", 58, "mob.endermen.hit", "mob.endermen.death")
// TODO: The size is only a guesstimate, measure in vanilla and fix the size values here
super("Enderman", 58, "mob.endermen.hit", "mob.endermen.death", 0.5, 2.5)
{
}
@ -16,7 +17,7 @@ cEnderman::cEnderman(void) :
void cEnderman::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_ENDER_PEARL);
}

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cEnderman);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -8,7 +8,7 @@
cGhast::cGhast(void) :
super("Ghast", 56, "mob.ghast.scream", "mob.ghast.death")
super("Ghast", 56, "mob.ghast.scream", "mob.ghast.death", 4, 4)
{
}
@ -16,7 +16,7 @@ cGhast::cGhast(void) :
void cGhast::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cGhast::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_GUNPOWDER);
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_GHAST_TEAR);

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cGhast);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -7,8 +7,9 @@
cMagmacube::cMagmacube(void) :
super("Magmacube", 62, "mob.magmacube.big", "mob.magmacube.big")
cMagmacube::cMagmacube(int a_Size) :
super("Magmacube", 62, "mob.magmacube.big", "mob.magmacube.big", 0.6 * a_Size, 0.6 * a_Size),
m_Size(a_Size)
{
}
@ -16,7 +17,7 @@ cMagmacube::cMagmacube(void) :
void cMagmacube::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cMagmacube::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_MAGMA_CREAM);
}

View File

@ -13,11 +13,17 @@ class cMagmacube :
typedef cAggressiveMonster super;
public:
cMagmacube();
/// Creates a magmacube of the specified size; size is 1 .. 3, with 1 being the smallest
cMagmacube(int a_Size);
CLASS_PROTODEF(cMagmacube);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
protected:
/// Size of the magmacube, 1 .. 3, with 1 being the smallest
int m_Size;
} ;

View File

@ -22,8 +22,8 @@
cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath)
: super(etMob)
cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height)
: super(etMob, a_Width, a_Height)
, m_Target(NULL)
, m_bMovingToDestination(false)
, m_DestinationTime( 0 )
@ -204,10 +204,13 @@ void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
void cMonster::KilledBy(cPawn * a_Killer)
void cMonster::KilledBy(cEntity * a_Killer)
{
super::KilledBy(a_Killer);
if(m_SoundHurt != "") m_World->BroadcastSoundEffect(m_SoundDeath, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
if (m_SoundHurt != "")
{
m_World->BroadcastSoundEffect(m_SoundDeath, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
}
m_DestroyTimer = 0;
}

View File

@ -31,7 +31,7 @@ public:
* a_ProtocolMobType is the ID of the mob used in the protocol ( http://wiki.vg/Entities#Mobs , 2012_12_22)
* a_SoundHurt and a_SoundDeath are assigned into m_SoundHurt and m_SoundDeath, respectively
*/
cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath);
cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
CLASS_PROTODEF(cMonster);
@ -41,7 +41,7 @@ public:
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void KilledBy(cPawn * a_Killer) override;
virtual void KilledBy(cEntity * a_Killer) override;
virtual void MoveToPosition(const Vector3f & a_Position);
virtual bool ReachedDestination(void);

View File

@ -14,7 +14,7 @@
cMooshroom::cMooshroom(void) :
super("Mooshroom", 96, "mob.cow.hurt", "mob.cow.hurt")
super("Mooshroom", 96, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3)
{
}
@ -22,10 +22,10 @@ cMooshroom::cMooshroom(void) :
void cMooshroom::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cMooshroom::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_LEATHER);
AddRandomDropItem(a_Drops, 1, 3, (GetMetaData() == BURNING) ? E_ITEM_STEAK : E_ITEM_RAW_BEEF);
AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_STEAK : E_ITEM_RAW_BEEF);
}

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cMooshroom);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -14,7 +14,8 @@ class cOcelot :
public:
cOcelot(void) :
super("Ocelot", 98, "mob.cat.hitt", "mob.cat.hitt")
// TODO: The size is only a guesstimate, measure in vanilla and fix the size values here
super("Ocelot", 98, "mob.cat.hitt", "mob.cat.hitt", 0.9, 0.5)
{
}

View File

@ -9,8 +9,8 @@
cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath) :
super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath)
cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
{
m_EMPersonality = PASSIVE;
}

View File

@ -13,7 +13,7 @@ class cPassiveAggressiveMonster :
typedef cAggressiveMonster super;
public:
cPassiveAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath);
cPassiveAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
} ;

View File

@ -8,8 +8,8 @@
cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath) :
super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath)
cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
{
m_EMPersonality = PASSIVE;
}

View File

@ -13,7 +13,7 @@ class cPassiveMonster :
typedef cMonster super;
public:
cPassiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath);
cPassiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;

View File

@ -8,7 +8,7 @@
cPig::cPig(void) :
super("Pig", 90, "mob.pig.say", "mob.pig.death")
super("Pig", 90, "mob.pig.say", "mob.pig.death", 0.9, 0.9)
{
}
@ -16,9 +16,9 @@ cPig::cPig(void) :
void cPig::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cPig::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 1, 3, (GetMetaData() == BURNING) ? E_ITEM_COOKED_PORKCHOP : E_ITEM_RAW_PORKCHOP);
AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_COOKED_PORKCHOP : E_ITEM_RAW_PORKCHOP);
}

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cPig);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -9,7 +9,7 @@
cSheep::cSheep(void) :
super("Sheep", 91, "mob.sheep.say", "mob.sheep.say"),
super("Sheep", 91, "mob.sheep.say", "mob.sheep.say", 0.6, 1.3),
m_IsSheared(false),
m_WoolColor(E_META_WOOL_WHITE)
{
@ -19,7 +19,7 @@ cSheep::cSheep(void) :
void cSheep::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
if (!m_IsSheared)
{

View File

@ -20,7 +20,7 @@ public:
CLASS_PROTODEF(cSheep);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -14,7 +14,8 @@ class cSilverfish :
public:
cSilverfish(void) :
super("Silverfish", 60, "mob.silverfish.hit", "mob.silverfish.kill")
// TODO: The size is only a guesstimate, measure in vanilla and fix the size values here
super("Silverfish", 60, "mob.silverfish.hit", "mob.silverfish.kill", 0.9, 0.3)
{
}

View File

@ -8,7 +8,7 @@
cSkeleton::cSkeleton(void) :
super("Skeleton", 51, "mob.skeleton.hurt", "mob.skeleton.death")
super("Skeleton", 51, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8)
{
}
@ -22,9 +22,10 @@ void cSkeleton::Tick(float a_Dt, cChunk & a_Chunk)
// TODO Outsource
// TODO should do SkyLight check, mobs in the dark don´t burn
if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsBurning())
if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsOnFire())
{
SetMetaData(BURNING); // BURN, BABY, BURN! >:D
// Burn for 10 ticks, then decide again
StartBurning(10);
}
}
@ -32,7 +33,7 @@ void cSkeleton::Tick(float a_Dt, cChunk & a_Chunk)
void cSkeleton::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_ARROW);
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_BONE);

View File

@ -18,7 +18,7 @@ public:
CLASS_PROTODEF(cSkeleton);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -9,8 +9,10 @@
cSlime::cSlime(void) :
super("Slime", 55, "mob.slime.attack", "mob.slime.attack")
/// Creates a slime of the specified size; size is 1 .. 3, with 1 being the smallest
cSlime::cSlime(int a_Size) :
super("Slime", 55, "mob.slime.attack", "mob.slime.attack", 0.6 * a_Size, 0.6 * a_Size),
m_Size(a_Size)
{
}
@ -18,7 +20,7 @@ cSlime::cSlime(void) :
void cSlime::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cSlime::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
// TODO: only when tiny
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_SLIMEBALL);

View File

@ -13,11 +13,17 @@ class cSlime :
typedef cAggressiveMonster super;
public:
cSlime(void);
/// Creates a slime of the specified size; size is 1 .. 3, with 1 being the smallest
cSlime(int a_Size);
CLASS_PROTODEF(cSlime);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
protected:
/// Size of the slime, 1 .. 3, with 1 being the smallest
int m_Size;
} ;

View File

@ -8,7 +8,7 @@
cSpider::cSpider(void) :
super("Spider", 52, "mob.spider.say", "mob.spider.death")
super("Spider", 52, "mob.spider.say", "mob.spider.death", 1.4, 0.9)
{
}
@ -16,7 +16,7 @@ cSpider::cSpider(void) :
void cSpider::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_STRING);
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_SPIDER_EYE);

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cSpider);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -3,13 +3,14 @@
#include "Squid.h"
#include "../Vector3d.h"
#include "../Chunk.h"
cSquid::cSquid(void) :
super("Squid", 94, "", "")
super("Squid", 94, "", "", 0.95, 0.95)
{
}
@ -17,7 +18,7 @@ cSquid::cSquid(void) :
void cSquid::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cSquid::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
// Drops 0-3 Ink Sacs
AddRandomDropItem(a_Drops, 0, 3, E_ITEM_DYE, E_META_DYE_BLACK);
@ -29,15 +30,17 @@ void cSquid::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cSquid::Tick(float a_Dt, cChunk & a_Chunk)
{
// TODO: Rewrite this function to use a_Chunk instead of m_World
super::Tick(a_Dt, a_Chunk);
Vector3d Pos = GetPosition();
// TODO: Not a real behavior, but cool :D
if (!IsBlockWater(GetWorld()->GetBlock((int) Pos.x, (int) Pos.y, (int) Pos.z)) && !IsBurning())
int RelX = (int)floor(Pos.x + 0.5) - a_Chunk.GetPosX() * cChunkDef::Width;
int RelZ = (int)floor(Pos.z + 0.5) - a_Chunk.GetPosZ() * cChunkDef::Width;
if (!IsBlockWater(a_Chunk.GetBlock(RelX, (int)Pos.y, RelZ)) && !IsOnFire())
{
SetMetaData(BURNING);
// Burn for 10 ticks, then decide again
StartBurning(10);
}
}

View File

@ -19,7 +19,7 @@ public:
CLASS_PROTODEF(cSquid);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -8,7 +8,7 @@
cVillager::cVillager(void) :
super("Villager", 120, "", "")
super("Villager", 120, "", "", 0.6, 1.8)
{
}

View File

@ -8,7 +8,7 @@
cWitch::cWitch(void) :
super("Witch", 66, "", "")
super("Witch", 66, "", "", 0.6, 1.8)
{
}
@ -16,7 +16,7 @@ cWitch::cWitch(void) :
void cWitch::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cWitch::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 6, E_ITEM_GLASS_BOTTLE);
AddRandomDropItem(a_Drops, 0, 6, E_ITEM_GLOWSTONE_DUST);

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cWitch);
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -14,7 +14,8 @@ class cWolf :
public:
cWolf(void) :
super("Wolf", 95, "mob.wolf.hurt", "mob.wolf.death")
// TODO: The size is only a guesstimate, measure in vanilla and fix the size values here (wiki.vg values are suspicious)
super("Wolf", 95, "mob.wolf.hurt", "mob.wolf.death", 0.9, 0.9)
{
}

View File

@ -8,7 +8,7 @@
cZombie::cZombie(void) :
super("Zombie", 54, "mob.zombie.hurt", "mob.zombie.death")
super("Zombie", 54, "mob.zombie.hurt", "mob.zombie.death", 0.6, 1.8)
{
}
@ -21,9 +21,10 @@ void cZombie::Tick(float a_Dt, cChunk & a_Chunk)
super::Tick(a_Dt, a_Chunk);
// TODO Same as in cSkeleton :D
if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsBurning())
if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsOnFire())
{
SetMetaData(BURNING); // BURN, BABY, BURN! >:D
// Burn for 10 ticks, then decide again
StartBurning(10);
}
}
@ -31,7 +32,7 @@ void cZombie::Tick(float a_Dt, cChunk & a_Chunk)
void cZombie::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_ROTTEN_FLESH);

View File

@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cZombie);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;

View File

@ -8,7 +8,7 @@
cZombiepigman::cZombiepigman(void) :
super("Zombiepigman", 57, "mob.zombiepig.zpighurt", "mob.zombiepig.zpigdeath")
super("Zombiepigman", 57, "mob.zombiepig.zpighurt", "mob.zombiepig.zpigdeath", 0.6, 1.8)
{
}
@ -21,9 +21,10 @@ void cZombiepigman::Tick(float a_Dt, cChunk & a_Chunk)
super::Tick(a_Dt, a_Chunk);
// TODO Same as noticed in cSkeleton AND Do they really burn by sun?? :D In the neather is no sun :D
if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsBurning())
if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsOnFire())
{
SetMetaData(BURNING); // BURN, BABY, BURN! >:D
// Burn for 10 ticks, then decide again
StartBurning(10);
}
}
@ -31,7 +32,7 @@ void cZombiepigman::Tick(float a_Dt, cChunk & a_Chunk)
void cZombiepigman::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cZombiepigman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_ROTTEN_FLESH);
AddRandomDropItem(a_Drops, 0, 1, E_ITEM_GOLD_NUGGET);
@ -43,7 +44,7 @@ void cZombiepigman::GetDrops(cItems & a_Drops, cPawn * a_Killer)
void cZombiepigman::KilledBy(cPawn * a_Killer)
void cZombiepigman::KilledBy(cEntity * a_Killer)
{
super::KilledBy(a_Killer);

View File

@ -18,8 +18,8 @@ public:
CLASS_PROTODEF(cZombiepigman);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override;
virtual void KilledBy(cPawn * a_Killer) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void KilledBy(cEntity * a_Killer) override;
} ;

View File

@ -15,12 +15,9 @@
cPawn::cPawn(eEntityType a_EntityType)
: cEntity(a_EntityType, 0, 0, 0)
, m_Health(1)
, m_MaxHealth(1)
cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height)
: cEntity(a_EntityType, 0, 0, 0, a_Width, a_Height)
, m_bBurnable(true)
, m_MetaData(NORMAL)
{
}
@ -28,374 +25,3 @@ cPawn::cPawn(eEntityType a_EntityType)
void cPawn::Heal(int a_HitPoints)
{
m_Health += a_HitPoints;
if (m_Health > m_MaxHealth)
{
m_Health = m_MaxHealth;
}
}
void cPawn::TakeDamage(cPawn & a_Attacker)
{
int RawDamage = a_Attacker.GetRawDamageAgainst(*this);
TakeDamage(dtAttack, &a_Attacker, RawDamage, a_Attacker.GetKnockbackAmountAgainst(*this));
}
void cPawn::TakeDamage(eDamageType a_DamageType, cPawn * a_Attacker, int a_RawDamage, double a_KnockbackAmount)
{
int FinalDamage = a_RawDamage - GetArmorCoverAgainst(a_Attacker, a_DamageType, a_RawDamage);
TakeDamage(a_DamageType, a_Attacker, a_RawDamage, FinalDamage, a_KnockbackAmount);
}
void cPawn::TakeDamage(eDamageType a_DamageType, cPawn * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount)
{
TakeDamageInfo TDI;
TDI.DamageType = a_DamageType;
TDI.Attacker = a_Attacker;
TDI.RawDamage = a_RawDamage;
TDI.FinalDamage = a_FinalDamage;
Vector3d Heading;
Heading.x = sin(GetRotation());
Heading.y = 0.4; // TODO: adjust the amount of "up" knockback when testing
Heading.z = cos(GetRotation());
TDI.Knockback = Heading * a_KnockbackAmount;
DoTakeDamage(TDI);
}
void cPawn::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI))
{
return;
}
if (m_Health <= 0)
{
// Can't take damage if already dead
return;
}
m_Health -= (short)a_TDI.FinalDamage;
// TODO: Apply damage to armor
if (m_Health < 0)
{
m_Health = 0;
}
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
if (m_Health <= 0)
{
KilledBy(a_TDI.Attacker);
}
}
void cPawn::KilledBy(cPawn * a_Killer)
{
m_Health = 0;
cRoot::Get()->GetPluginManager()->CallHookKilling(*this, a_Killer);
if (m_Health > 0)
{
// Plugin wants to 'unkill' the pawn. Abort
return;
}
// Drop loot:
cItems Drops;
GetDrops(Drops, a_Killer);
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD);
}
int cPawn::GetRawDamageAgainst(const cPawn & a_Receiver)
{
// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
// Ref: http://www.minecraftwiki.net/wiki/Damage#Dealing_damage as of 2012_12_20
switch (this->GetEquippedWeapon().m_ItemType)
{
case E_ITEM_WOODEN_SWORD: return 4;
case E_ITEM_GOLD_SWORD: return 4;
case E_ITEM_STONE_SWORD: return 5;
case E_ITEM_IRON_SWORD: return 6;
case E_ITEM_DIAMOND_SWORD: return 7;
case E_ITEM_WOODEN_AXE: return 3;
case E_ITEM_GOLD_AXE: return 3;
case E_ITEM_STONE_AXE: return 4;
case E_ITEM_IRON_AXE: return 5;
case E_ITEM_DIAMOND_AXE: return 6;
case E_ITEM_WOODEN_PICKAXE: return 2;
case E_ITEM_GOLD_PICKAXE: return 2;
case E_ITEM_STONE_PICKAXE: return 3;
case E_ITEM_IRON_PICKAXE: return 4;
case E_ITEM_DIAMOND_PICKAXE: return 5;
case E_ITEM_WOODEN_SHOVEL: return 1;
case E_ITEM_GOLD_SHOVEL: return 1;
case E_ITEM_STONE_SHOVEL: return 2;
case E_ITEM_IRON_SHOVEL: return 3;
case E_ITEM_DIAMOND_SHOVEL: return 4;
}
// All other equipped items give a damage of 1:
return 1;
}
int cPawn::GetArmorCoverAgainst(const cPawn * a_Attacker, eDamageType a_DamageType, int a_Damage)
{
// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
// Filter out damage types that are not protected by armor:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20
switch (a_DamageType)
{
case dtOnFire:
case dtSuffocating:
case dtDrowning: // TODO: This one could be a special case - in various MC versions (PC vs XBox) it is and isn't armor-protected
case dtStarving:
case dtInVoid:
case dtPoisoning:
case dtPotionOfHarming:
case dtFalling:
case dtLightning:
{
return 0;
}
}
// Add up all armor points:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20
int ArmorValue = 0;
switch (GetEquippedHelmet().m_ItemType)
{
case E_ITEM_LEATHER_CAP: ArmorValue += 1; break;
case E_ITEM_GOLD_HELMET: ArmorValue += 2; break;
case E_ITEM_CHAIN_HELMET: ArmorValue += 2; break;
case E_ITEM_IRON_HELMET: ArmorValue += 2; break;
case E_ITEM_DIAMOND_HELMET: ArmorValue += 3; break;
}
switch (GetEquippedChestplate().m_ItemType)
{
case E_ITEM_LEATHER_TUNIC: ArmorValue += 3; break;
case E_ITEM_GOLD_CHESTPLATE: ArmorValue += 5; break;
case E_ITEM_CHAIN_CHESTPLATE: ArmorValue += 5; break;
case E_ITEM_IRON_CHESTPLATE: ArmorValue += 6; break;
case E_ITEM_DIAMOND_CHESTPLATE: ArmorValue += 8; break;
}
switch (GetEquippedLeggings().m_ItemType)
{
case E_ITEM_LEATHER_PANTS: ArmorValue += 2; break;
case E_ITEM_GOLD_LEGGINGS: ArmorValue += 3; break;
case E_ITEM_CHAIN_LEGGINGS: ArmorValue += 4; break;
case E_ITEM_IRON_LEGGINGS: ArmorValue += 5; break;
case E_ITEM_DIAMOND_LEGGINGS: ArmorValue += 6; break;
}
switch (GetEquippedBoots().m_ItemType)
{
case E_ITEM_LEATHER_BOOTS: ArmorValue += 1; break;
case E_ITEM_GOLD_BOOTS: ArmorValue += 1; break;
case E_ITEM_CHAIN_BOOTS: ArmorValue += 1; break;
case E_ITEM_IRON_BOOTS: ArmorValue += 2; break;
case E_ITEM_DIAMOND_BOOTS: ArmorValue += 3; break;
}
// TODO: Special armor cases, such as wool, saddles, dog's collar
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Mob_armor as of 2012_12_20
// Now ArmorValue is in [0, 20] range, which corresponds to [0, 80%] protection. Calculate the hitpoints from that:
return a_Damage * (ArmorValue * 4) / 100;
}
double cPawn::GetKnockbackAmountAgainst(const cPawn & a_Receiver)
{
// Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit
// TODO: Enchantments
return 1;
}
void cPawn::GetDrops(cItems & a_Drops, cPawn * a_Killer)
{
UNUSED(a_Drops);
UNUSED(a_Killer);
}
void cPawn::TeleportToEntity(cEntity & a_Entity)
{
TeleportTo(a_Entity.GetPosX(), a_Entity.GetPosY(), a_Entity.GetPosZ());
}
void cPawn::TeleportTo(double a_PosX, double a_PosY, double a_PosZ)
{
SetPosition(a_PosX, a_PosY, a_PosZ);
GetWorld()->BroadcastTeleportEntity(*this);
}
void cPawn::Tick(float a_Dt, cChunk & a_Chunk)
{
CheckMetaDataBurn(a_Chunk); // Check to see if pawn should burn based on block they are on
if (IsBurning())
{
InStateBurning(a_Dt);
}
}
void cPawn::SetMetaData(MetaData a_MetaData)
{
//Broadcast new status to clients in the chunk
m_MetaData = a_MetaData;
m_World->BroadcastMetadata(*this);
}
//----Change Entity MetaData
void cPawn::CheckMetaDataBurn(cChunk & a_Chunk)
{
// TODO: Rewrite this function to use a_Chunk instead of m_World
if ((GetPosY() < 1) || (GetPosY() >= 254))
{
// Y coord out of range
return;
}
BLOCKTYPE Block = GetWorld()->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ());
BLOCKTYPE BlockAbove = GetWorld()->GetBlock((int) GetPosX(), (int) GetPosY() + 1, (int) GetPosZ());
BLOCKTYPE BlockBelow = GetWorld()->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ());
if (
(GetMetaData() == BURNING) &&
(IsBlockWater(Block) || IsBlockWater(BlockAbove) || IsBlockWater(BlockBelow))
)
{
SetMetaData(NORMAL);
}
else if (
m_bBurnable &&
(GetMetaData() != BURNING) &&
(
IsBlockLava(Block) || (Block == E_BLOCK_FIRE) ||
IsBlockLava(BlockAbove) || (BlockAbove == E_BLOCK_FIRE) ||
IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE)
)
)
{
SetMetaData(BURNING);
}
}
// What to do if On fire
void cPawn::InStateBurning(float a_Dt)
{
m_FireDamageInterval += a_Dt;
if (m_FireDamageInterval < 800)
{
return;
}
BLOCKTYPE Block = GetWorld()->GetBlock((int)GetPosX(), (int)GetPosY(), (int)GetPosZ());
BLOCKTYPE BlockAbove = GetWorld()->GetBlock((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ());
m_FireDamageInterval = 0;
TakeDamage(dtOnFire, NULL, 1, 0);
m_BurnPeriod++;
if (
IsBlockLava(Block) ||
(Block == E_BLOCK_FIRE) ||
IsBlockLava(BlockAbove) ||
(BlockAbove == E_BLOCK_FIRE)
)
{
m_BurnPeriod = 0;
TakeDamage(dtLavaContact, NULL, 6, 0);
}
if (m_BurnPeriod > 7)
{
SetMetaData(NORMAL);
m_BurnPeriod = 0;
}
}
void cPawn::SetMaxHealth(short a_MaxHealth)
{
this->m_MaxHealth = a_MaxHealth;
// Reset health
m_Health = a_MaxHealth;
}

View File

@ -8,71 +8,6 @@
// fwd:
class cPawn;
// tolua_begin
enum eDamageType
{
// Canonical names for the types (as documented in the plugin wiki):
dtAttack, // Being attacked by a mob
dtLightning, // Hit by a lightning strike
dtFalling, // Falling down; dealt when hitting the ground
dtDrowning, // Drowning in water / lava
dtSuffocating, // Suffocating inside a block
dtStarving, // Hunger
dtCactusContact, // Contact with a cactus block
dtLavaContact, // Contact with a lava block
dtPoisoning, // Having the poison effect
dtOnFire, // Being on fire
dtFireContact, // Standing inside a fire block
dtInVoid, // Falling into the Void (Y < 0)
dtPotionOfHarming,
dtAdmin, // Damage applied by an admin command
// Some common synonyms:
dtPawnAttack = dtAttack,
dtEntityAttack = dtAttack,
dtMob = dtAttack,
dtMobAttack = dtAttack,
dtFall = dtFalling,
dtDrown = dtDrowning,
dtSuffocation = dtSuffocating,
dtStarvation = dtStarving,
dtHunger = dtStarving,
dtCactus = dtCactusContact,
dtCactuses = dtCactusContact,
dtCacti = dtCactusContact,
dtLava = dtLavaContact,
dtPoison = dtPoisoning,
dtBurning = dtOnFire,
dtInFire = dtFireContact,
dtPlugin = dtAdmin,
} ;
struct TakeDamageInfo
{
eDamageType DamageType; // Where does the damage come from? Being hit / on fire / contact with cactus / ...
cPawn * Attacker; // The attacking pawn; valid only for dtAttack
int RawDamage; // What damage would the receiver get without any armor. Usually: attacker mob type + weapons
int FinalDamage; // What actual damage will be received. Usually: m_RawDamage minus armor
Vector3d Knockback; // The amount and direction of knockback received from the damage
// TODO: Effects - list of effects that the hit is causing. Unknown representation yet
} ;
// tolua_end
// tolua_begin
class cPawn :
public cEntity
@ -83,91 +18,11 @@ class cPawn :
public:
CLASS_PROTODEF(cPawn);
cPawn(eEntityType a_EntityType);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
// tolua_begin
/// Teleports to the entity specified
virtual void TeleportToEntity(cEntity & a_Entity);
/// Teleports to the coordinates specified
virtual void TeleportTo(double a_PosX, double a_PosY, double a_PosZ);
/// Heals the specified amount of HPs
void Heal(int a_HitPoints);
/// Returns the health of this pawn
int GetHealth(void) const { return m_Health; }
/// Makes this pawn take damage from an attack by a_Attacker. Damage values are calculated automatically and DoTakeDamage() called
void TakeDamage(cPawn & a_Attacker);
/// Makes this pawn take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called
void TakeDamage(eDamageType a_DamageType, cPawn * a_Attacker, int a_RawDamage, double a_KnockbackAmount);
/// Makes this pawn take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage()
void TakeDamage(eDamageType a_DamageType, cPawn * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount);
/// Makes this pawn take damage specified in the a_TDI. The TDI is sent through plugins first, then applied
virtual void DoTakeDamage(TakeDamageInfo & a_TDI);
/// Called when the health drops below zero. a_Killer may be NULL (environmental damage)
virtual void KilledBy(cPawn * a_Killer);
/// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
virtual int GetRawDamageAgainst(const cPawn & a_Receiver);
/// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
virtual int GetArmorCoverAgainst(const cPawn * a_Attacker, eDamageType a_DamageType, int a_RawDamage);
/// Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit
virtual double GetKnockbackAmountAgainst(const cPawn & a_Receiver);
/// Returns the curently equipped weapon; empty item if none
virtual cItem GetEquippedWeapon(void) const { return cItem(); }
/// Returns the currently equipped helmet; empty item if nonte
virtual cItem GetEquippedHelmet(void) const { return cItem(); }
/// Returns the currently equipped chestplate; empty item if nonte
virtual cItem GetEquippedChestplate(void) const { return cItem(); }
/// Returns the currently equipped leggings; empty item if nonte
virtual cItem GetEquippedLeggings(void) const { return cItem(); }
/// Returns the currently equipped boots; empty item if nonte
virtual cItem GetEquippedBoots(void) const { return cItem(); }
// tolua_end
/// Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy().
virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL);
enum MetaData {NORMAL, BURNING, CROUCHED, RIDING, SPRINTING, EATING, BLOCKING};
virtual void SetMetaData(MetaData a_MetaData);
virtual MetaData GetMetaData(void) const { return m_MetaData; }
virtual void InStateBurning(float a_Dt);
virtual void CheckMetaDataBurn(cChunk & a_Chunk);
virtual void SetMaxHealth(short a_MaxHealth);
virtual short GetMaxHealth() { return m_MaxHealth; }
bool IsBurning(void) const { return (m_MetaData == BURNING); }
cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
protected:
short m_Health;
short m_MaxHealth;
bool m_bBurnable;
MetaData m_MetaData;
}; // tolua_export
} ; // tolua_export

View File

@ -26,7 +26,7 @@
cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem & a_Item, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */)
: cEntity(etPickup, ((double)(a_MicroPosX)) / 32, ((double)(a_MicroPosY)) / 32, ((double)(a_MicroPosZ)) / 32)
: cEntity(etPickup, ((double)(a_MicroPosX)) / 32, ((double)(a_MicroPosY)) / 32, ((double)(a_MicroPosZ)) / 32, 0.2, 0.2)
, m_Health(5)
, m_Timer( 0.f )
, m_Item(a_Item)

View File

@ -33,7 +33,7 @@
cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
: super(etPlayer)
: super(etPlayer, 0.6, 1.8)
, m_GameMode(eGameMode_NotSet)
, m_IP("")
, m_LastBlockActionTime( 0 )
@ -197,7 +197,7 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
}
else if (m_FoodLevel == 0)
{
super::TakeDamage(dtStarving, NULL, 1, 1, 0);
TakeDamage(dtStarving, NULL, 1, 1, 0);
}
}
@ -272,7 +272,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
m_LastJumpHeight = (float)GetPosY();
if (Damage > 0)
{
super::TakeDamage(dtFalling, NULL, Damage, Damage, 0);
TakeDamage(dtFalling, NULL, Damage, Damage, 0);
}
m_LastGroundHeight = (float)GetPosY();
@ -396,9 +396,9 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
void cPlayer::KilledBy(cPawn * a_Killer)
void cPlayer::KilledBy(cEntity * a_Killer)
{
cPawn::KilledBy(a_Killer);
super::KilledBy(a_Killer);
if (m_Health > 0)
{
@ -425,10 +425,10 @@ void cPlayer::Respawn(void)
m_ClientHandle->SendRespawn();
// Set non Burning
SetMetaData(NORMAL);
// Extinguish the fire:
StopBurning();
TeleportTo(GetWorld()->GetSpawnX(), GetWorld()->GetSpawnY(), GetWorld()->GetSpawnZ());
TeleportToCoords(GetWorld()->GetSpawnX(), GetWorld()->GetSpawnY(), GetWorld()->GetSpawnZ());
SetVisible(true);
}
@ -437,12 +437,15 @@ void cPlayer::Respawn(void)
double cPlayer::GetEyeHeight()
double cPlayer::GetEyeHeight(void) const
{
return m_Stance;
}
Vector3d cPlayer::GetEyePosition()
Vector3d cPlayer::GetEyePosition(void) const
{
return Vector3d( GetPosX(), m_Stance, GetPosZ() );
}
@ -574,7 +577,7 @@ void cPlayer::SendMessage(const AString & a_Message)
void cPlayer::TeleportTo(double a_PosX, double a_PosY, double a_PosZ)
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
{
SetPosition( a_PosX, a_PosY, a_PosZ );

View File

@ -61,8 +61,8 @@ public:
void SetTouchGround( bool a_bTouchGround );
inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
double GetEyeHeight(); // tolua_export
Vector3d GetEyePosition(); // tolua_export
double GetEyeHeight(void) const; // tolua_export
Vector3d GetEyePosition(void) const; // tolua_export
inline bool IsOnGround(void) const {return m_bTouchGround; } // tolua_export
inline const double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
@ -70,7 +70,7 @@ public:
inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export
virtual void TeleportTo(double a_PosX, double a_PosY, double a_PosZ) override;
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
eGameMode GetGameMode(void) const { return m_GameMode; } // tolua_export
std::string GetIP() { return m_IP; } // tolua_export
@ -138,7 +138,7 @@ public:
void AddFoodExhaustion(float a_Exhaustion) { m_FoodExhaustionLevel += a_Exhaustion; } // tolua_export
virtual void KilledBy(cPawn * a_Killer) override;
virtual void KilledBy(cEntity * a_Killer) override;
void Respawn(void); // tolua_export

View File

@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Plugin.h"
#include "Pawn.h"
// #include "Pawn.h"
#include "Player.h"
#include "World.h"
#include "CommandOutput.h"
@ -187,7 +187,7 @@ bool cPlugin::OnHandshake(cClientHandle * a_Client, const AString & a_Username)
bool cPlugin::OnKilling(cPawn & a_Victim, cEntity * a_Killer)
bool cPlugin::OnKilling(cEntity & a_Victim, cEntity * a_Killer)
{
UNUSED(a_Victim);
UNUSED(a_Killer);
@ -468,9 +468,9 @@ bool cPlugin::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Gr
bool cPlugin::OnTakeDamage(cPawn & a_Pawn, TakeDamageInfo & a_TakeDamageInfo)
bool cPlugin::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo)
{
UNUSED(a_Pawn);
UNUSED(a_Receiver);
UNUSED(a_TakeDamageInfo);
return false;
}

View File

@ -13,7 +13,6 @@ class cPlayer;
class cPickup;
class cItem;
class cEntity;
class cPawn;
class cWorld;
class cChunkDesc;
struct TakeDamageInfo;
@ -60,7 +59,7 @@ public:
virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason);
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split);
virtual bool OnHandshake (cClientHandle * a_Client, const AString & a_Username);
virtual bool OnKilling (cPawn & a_Victim, cEntity * a_Killer);
virtual bool OnKilling (cEntity & a_Victim, cEntity * a_Killer);
virtual bool OnLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username);
virtual bool OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
virtual bool OnPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
@ -80,7 +79,7 @@ public:
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
virtual bool OnTakeDamage (cPawn & a_Receiver, TakeDamageInfo & a_TakeDamageInfo);
virtual bool OnTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo);
virtual bool OnUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player);
virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player);
virtual bool OnWeatherChanged (cWorld & a_World);

View File

@ -447,7 +447,7 @@ bool cPluginManager::CallHookHandshake(cClientHandle * a_ClientHandle, const ASt
bool cPluginManager::CallHookKilling(cPawn & a_Victim, cEntity * a_Killer)
bool cPluginManager::CallHookKilling(cEntity & a_Victim, cEntity * a_Killer)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_KILLING);
if (Plugins == m_Hooks.end())
@ -867,7 +867,7 @@ bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCrafti
bool cPluginManager::CallHookTakeDamage(cPawn & a_Receiver, TakeDamageInfo & a_TDI)
bool cPluginManager::CallHookTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_TAKE_DAMAGE);
if (Plugins == m_Hooks.end())

View File

@ -126,7 +126,7 @@ public: // tolua_export
bool CallHookDisconnect (cPlayer * a_Player, const AString & a_Reason);
bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd
bool CallHookHandshake (cClientHandle * a_ClientHandle, const AString & a_Username);
bool CallHookKilling (cPawn & a_Victim, cEntity * a_Killer);
bool CallHookKilling (cEntity & a_Victim, cEntity * a_Killer);
bool CallHookLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username);
bool CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
bool CallHookPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
@ -146,7 +146,7 @@ public: // tolua_export
bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
bool CallHookTakeDamage (cPawn & a_Receiver, TakeDamageInfo & a_TDI);
bool CallHookTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TDI);
bool CallHookUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player);
bool CallHookUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player);
bool CallHookWeatherChanged (cWorld & a_World);

View File

@ -549,7 +549,7 @@ bool cPlugin_NewLua::OnHandshake(cClientHandle * a_Client, const AString & a_Use
bool cPlugin_NewLua::OnKilling(cPawn & a_Victim, cEntity * a_Killer)
bool cPlugin_NewLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer)
{
cCSLock Lock(m_CriticalSection);
const char * FnName = GetHookFnName(cPluginManager::HOOK_KILLING);
@ -559,7 +559,7 @@ bool cPlugin_NewLua::OnKilling(cPawn & a_Victim, cEntity * a_Killer)
return false;
}
tolua_pushusertype(m_LuaState, &a_Victim, "cPawn");
tolua_pushusertype(m_LuaState, &a_Victim, "cEntity");
tolua_pushusertype(m_LuaState, a_Killer, "cEntity");
if (!CallFunction(2, 1, FnName))
@ -1150,7 +1150,7 @@ bool cPlugin_NewLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid
bool cPlugin_NewLua::OnTakeDamage(cPawn & a_Receiver, TakeDamageInfo & a_TDI)
bool cPlugin_NewLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI)
{
cCSLock Lock(m_CriticalSection);
const char * FnName = GetHookFnName(cPluginManager::HOOK_TAKE_DAMAGE);
@ -1160,7 +1160,7 @@ bool cPlugin_NewLua::OnTakeDamage(cPawn & a_Receiver, TakeDamageInfo & a_TDI)
return false;
}
tolua_pushusertype(m_LuaState, &a_Receiver, "cPawn");
tolua_pushusertype(m_LuaState, &a_Receiver, "cEntity");
tolua_pushusertype(m_LuaState, &a_TDI, "TakeDamageInfo");
if (!CallFunction(2, 1, FnName))

View File

@ -49,7 +49,7 @@ public:
virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) override;
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override;
virtual bool OnHandshake (cClientHandle * a_Client, const AString & a_Username) override;
virtual bool OnKilling (cPawn & a_Victim, cEntity * a_Killer) override;
virtual bool OnKilling (cEntity & a_Victim, cEntity * a_Killer) override;
virtual bool OnLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username) override;
virtual bool OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual bool OnPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
@ -69,7 +69,7 @@ public:
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
virtual bool OnTakeDamage (cPawn & a_Receiver, TakeDamageInfo & a_TakeDamageInfo) override;
virtual bool OnTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo) override;
virtual bool OnUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) override;
virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) override;
virtual bool OnWeatherChanged (cWorld & a_World) override;

View File

@ -9,7 +9,7 @@
cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, float a_FuseTimeInSec) :
super(etTNT, a_X, a_Y, a_Z),
super(etTNT, a_X, a_Y, a_Z, 0.98, 0.98),
m_Counter(0),
m_MaxFuseTime(a_FuseTimeInSec)
{
@ -20,7 +20,7 @@ cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, float a_FuseTimeInSec
cTNTEntity::cTNTEntity(const Vector3d & a_Pos, float a_FuseTimeInSec) :
super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z),
super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
m_Counter(0),
m_MaxFuseTime(a_FuseTimeInSec)
{

View File

@ -1523,9 +1523,9 @@ void cWorld::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, cons
void cWorld::BroadcastMetadata(const cPawn & a_Pawn, const cClientHandle * a_Exclude)
void cWorld::BroadcastMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude)
{
m_ChunkMap->BroadcastMetadata(a_Pawn, a_Exclude);
m_ChunkMap->BroadcastMetadata(a_Entity, a_Exclude);
}
@ -2317,31 +2317,33 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, int a_EntityTy
{
cMonster * Monster = NULL;
int Size = GetTickRandomNumber(2) + 1; // 1 .. 3
switch (a_EntityType)
{
case E_ENTITY_TYPE_BAT: Monster = new cBat(); break;
case E_ENTITY_TYPE_BLAZE: Monster = new cBlaze(); break;
case E_ENTITY_TYPE_CAVE_SPIDER: Monster = new cCavespider(); break;
case E_ENTITY_TYPE_CHICKEN: Monster = new cChicken(); break;
case E_ENTITY_TYPE_COW: Monster = new cCow(); break;
case E_ENTITY_TYPE_CREEPER: Monster = new cCreeper(); break;
case E_ENTITY_TYPE_ENDERMAN: Monster = new cEnderman(); break;
case E_ENTITY_TYPE_GHAST: Monster = new cGhast(); break;
case E_ENTITY_TYPE_MAGMA_CUBE: Monster = new cMagmacube(); break;
case E_ENTITY_TYPE_MOOSHROOM: Monster = new cMooshroom(); break;
case E_ENTITY_TYPE_OCELOT: Monster = new cOcelot(); break;
case E_ENTITY_TYPE_PIG: Monster = new cPig(); break;
case E_ENTITY_TYPE_SHEEP: Monster = new cSheep(); break;
case E_ENTITY_TYPE_SILVERFISH: Monster = new cSilverfish(); break;
case E_ENTITY_TYPE_SKELETON: Monster = new cSkeleton(); break;
case E_ENTITY_TYPE_SLIME: Monster = new cSlime(); break;
case E_ENTITY_TYPE_SPIDER: Monster = new cSpider(); break;
case E_ENTITY_TYPE_SQUID: Monster = new cSquid(); break;
case E_ENTITY_TYPE_VILLAGER: Monster = new cVillager(); break;
case E_ENTITY_TYPE_WITCH: Monster = new cWitch(); break;
case E_ENTITY_TYPE_WOLF: Monster = new cWolf(); break;
case E_ENTITY_TYPE_ZOMBIE: Monster = new cZombie(); break;
case E_ENTITY_TYPE_ZOMBIE_PIGMAN: Monster = new cZombiepigman(); break;
case E_ENTITY_TYPE_BAT: Monster = new cBat(); break;
case E_ENTITY_TYPE_BLAZE: Monster = new cBlaze(); break;
case E_ENTITY_TYPE_CAVE_SPIDER: Monster = new cCavespider(); break;
case E_ENTITY_TYPE_CHICKEN: Monster = new cChicken(); break;
case E_ENTITY_TYPE_COW: Monster = new cCow(); break;
case E_ENTITY_TYPE_CREEPER: Monster = new cCreeper(); break;
case E_ENTITY_TYPE_ENDERMAN: Monster = new cEnderman(); break;
case E_ENTITY_TYPE_GHAST: Monster = new cGhast(); break;
case E_ENTITY_TYPE_MAGMA_CUBE: Monster = new cMagmacube(Size); break;
case E_ENTITY_TYPE_MOOSHROOM: Monster = new cMooshroom(); break;
case E_ENTITY_TYPE_OCELOT: Monster = new cOcelot(); break;
case E_ENTITY_TYPE_PIG: Monster = new cPig(); break;
case E_ENTITY_TYPE_SHEEP: Monster = new cSheep(); break;
case E_ENTITY_TYPE_SILVERFISH: Monster = new cSilverfish(); break;
case E_ENTITY_TYPE_SKELETON: Monster = new cSkeleton(); break;
case E_ENTITY_TYPE_SLIME: Monster = new cSlime(Size); break;
case E_ENTITY_TYPE_SPIDER: Monster = new cSpider(); break;
case E_ENTITY_TYPE_SQUID: Monster = new cSquid(); break;
case E_ENTITY_TYPE_VILLAGER: Monster = new cVillager(); break;
case E_ENTITY_TYPE_WITCH: Monster = new cWitch(); break;
case E_ENTITY_TYPE_WOLF: Monster = new cWolf(); break;
case E_ENTITY_TYPE_ZOMBIE: Monster = new cZombie(); break;
case E_ENTITY_TYPE_ZOMBIE_PIGMAN: Monster = new cZombiepigman(); break;
default:
{

View File

@ -133,7 +133,7 @@ public:
void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
void BroadcastMetadata (const cPawn & a_Pawn, const cClientHandle * a_Exclude = NULL);
void BroadcastMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastSpawn (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);