summaryrefslogtreecommitdiffstats
path: root/source/Pawn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Pawn.cpp')
-rw-r--r--source/Pawn.cpp272
1 files changed, 227 insertions, 45 deletions
diff --git a/source/Pawn.cpp b/source/Pawn.cpp
index da878bf49..8d530abb4 100644
--- a/source/Pawn.cpp
+++ b/source/Pawn.cpp
@@ -21,8 +21,10 @@ CLASS_DEFINITION( cPawn, cEntity )
-cPawn::cPawn()
+cPawn::cPawn(void)
: cEntity( 0, 0, 0 )
+ , m_Health(1)
+ , m_MaxHealth(1)
, m_LastPosX( 0.0 )
, m_LastPosY( 0.0 )
, m_LastPosZ( 0.0 )
@@ -30,7 +32,6 @@ cPawn::cPawn()
, m_bBurnable(true)
, m_MetaData(NORMAL)
{
- SetMaxHealth(20);
}
@@ -39,40 +40,83 @@ cPawn::cPawn()
cPawn::~cPawn()
{
+ // Nothing needed yet
+}
+
+
+
+
+void cPawn::Heal(int a_HitPoints)
+{
+ m_Health += a_HitPoints;
+ if (m_Health > m_MaxHealth)
+ {
+ m_Health = m_MaxHealth;
+ }
}
-void cPawn::Heal( int a_Health )
+void cPawn::TakeDamage(cPawn & a_Attacker)
{
- (void)a_Health;
+ int RawDamage = a_Attacker.GetRawDamageAgainst(*this);
+
+ TakeDamage(dtAttack, &a_Attacker, RawDamage, a_Attacker.GetKnockbackAmountAgainst(*this));
}
-void cPawn::TakeDamage(int a_Damage, cEntity * a_Instigator)
+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.Damage = a_Damage;
- TDI.Instigator = a_Instigator;
- cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_TAKE_DAMAGE, 2, this, &TDI);
+ TDI.DamageType = a_DamageType;
+ TDI.Attacker = a_Attacker;
+ TDI.RawDamage = a_RawDamage;
+ TDI.FinalDamage = a_FinalDamage;
+ Vector3d Heading;
+ Heading.x = sin(m_Rot.x);
+ Heading.y = 0.4; // TODO: adjust the amount of "up" knockback when testing
+ Heading.z = cos(m_Rot.x);
+ TDI.Knockback = Heading * a_KnockbackAmount;
+ DoTakeDamage(TDI);
+}
+
- if (TDI.Damage == 0)
+
+
+
+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)TDI.Damage;
+ m_Health -= (short)a_TDI.FinalDamage;
+
+ // TODO: Apply damage to armor
+
if (m_Health < 0)
{
m_Health = 0;
@@ -82,7 +126,7 @@ void cPawn::TakeDamage(int a_Damage, cEntity * a_Instigator)
if (m_Health <= 0)
{
- KilledBy(TDI.Instigator);
+ KilledBy(a_TDI.Attacker);
}
}
@@ -90,15 +134,23 @@ void cPawn::TakeDamage(int a_Damage, cEntity * a_Instigator)
-void cPawn::KilledBy(cEntity * a_Killer)
+void cPawn::KilledBy(cPawn * a_Killer)
{
+ short OldHealth = m_Health;
m_Health = 0;
- if( cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_KILLED, 2, this, a_Killer ) )
+ if (cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_KILLED, 2, this, a_Killer))
{
- return; // Give plugins a chance to 'unkill' the pawn.
+ // Plugin wants to 'unkill' the pawn. Set health back and abort
+ m_Health = OldHealth;
+ return;
}
+ // Drop loot:
+ cItems Drops;
+ GetDrops(Drops, a_Killer);
+ m_World->SpawnItemPickups(Drops, m_Pos.x, m_Pos.y, m_Pos.z);
+
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD);
}
@@ -106,18 +158,147 @@ void cPawn::KilledBy(cEntity * a_Killer)
-void cPawn::TeleportToEntity(cEntity * a_Entity)
+int cPawn::GetRawDamageAgainst(const cPawn & a_Receiver)
{
- TeleportTo(a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ());
+ // 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;
}
-void cPawn::TeleportTo( const double & a_PosX, const double & a_PosY, const double & a_PosZ )
+int cPawn::GetArmorCoverAgainst(const cPawn * a_Attacker, eDamageType a_DamageType, int a_Damage)
{
- SetPosition( a_PosX, a_PosY, a_PosZ );
+ // 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);
}
@@ -155,9 +336,9 @@ void cPawn::SetMetaData(MetaData a_MetaData)
//----Change Entity MetaData
void cPawn::CheckMetaDataBurn()
{
- char Block = GetWorld()->GetBlock((int) m_Pos.x, (int) m_Pos.y, (int) m_Pos.z);
- char BlockAbove = GetWorld()->GetBlock((int) m_Pos.x, (int) m_Pos.y + 1, (int) m_Pos.z);
- char BlockBelow = GetWorld()->GetBlock((int) m_Pos.x, (int) m_Pos.y - 1, (int) m_Pos.z);
+ BLOCKTYPE Block = GetWorld()->GetBlock((int) m_Pos.x, (int) m_Pos.y, (int) m_Pos.z);
+ BLOCKTYPE BlockAbove = GetWorld()->GetBlock((int) m_Pos.x, (int) m_Pos.y + 1, (int) m_Pos.z);
+ BLOCKTYPE BlockBelow = GetWorld()->GetBlock((int) m_Pos.x, (int) m_Pos.y - 1, (int) m_Pos.z);
if (
(GetMetaData() == BURNING) &&
@@ -184,35 +365,36 @@ void cPawn::CheckMetaDataBurn()
-//What to do if On fire
+// What to do if On fire
void cPawn::InStateBurning(float a_Dt)
{
m_FireDamageInterval += a_Dt;
- char Block = GetWorld()->GetBlock( (int)m_Pos.x, (int)m_Pos.y, (int)m_Pos.z );
- char BlockAbove = GetWorld()->GetBlock( (int)m_Pos.x, (int)m_Pos.y + 1, (int)m_Pos.z );
- if (m_FireDamageInterval > 800)
+ if (m_FireDamageInterval < 800)
{
+ return;
+ }
- m_FireDamageInterval = 0;
- TakeDamage(1, this);
+ BLOCKTYPE Block = GetWorld()->GetBlock((int)m_Pos.x, (int)m_Pos.y, (int)m_Pos.z);
+ BLOCKTYPE BlockAbove = GetWorld()->GetBlock((int)m_Pos.x, (int)m_Pos.y + 1, (int)m_Pos.z);
+ 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(6, this);
- }
- else
- {
- TakeDamage(1, this);
- }
-
- if (m_BurnPeriod > 7)
- {
- SetMetaData(NORMAL);
- m_BurnPeriod = 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;
}
}
@@ -224,7 +406,7 @@ void cPawn::SetMaxHealth(short a_MaxHealth)
{
this->m_MaxHealth = a_MaxHealth;
- //Reset health
+ // Reset health
m_Health = a_MaxHealth;
}