summaryrefslogtreecommitdiffstats
path: root/src/Mobs/Old Mobs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs/Old Mobs')
-rw-r--r--src/Mobs/Old Mobs/AggressiveMonster.cpp124
-rw-r--r--src/Mobs/Old Mobs/AggressiveMonster.h33
-rw-r--r--src/Mobs/Old Mobs/Bat.cpp14
-rw-r--r--src/Mobs/Old Mobs/Bat.h25
-rw-r--r--src/Mobs/Old Mobs/Blaze.cpp57
-rw-r--r--src/Mobs/Old Mobs/Blaze.h22
-rw-r--r--src/Mobs/Old Mobs/CaveSpider.cpp61
-rw-r--r--src/Mobs/Old Mobs/CaveSpider.h26
-rw-r--r--src/Mobs/Old Mobs/Chicken.cpp66
-rw-r--r--src/Mobs/Old Mobs/Chicken.h30
-rw-r--r--src/Mobs/Old Mobs/Cow.cpp48
-rw-r--r--src/Mobs/Old Mobs/Cow.h29
-rw-r--r--src/Mobs/Old Mobs/Creeper.cpp152
-rw-r--r--src/Mobs/Old Mobs/Creeper.h38
-rw-r--r--src/Mobs/Old Mobs/EnderDragon.cpp27
-rw-r--r--src/Mobs/Old Mobs/EnderDragon.h25
-rw-r--r--src/Mobs/Old Mobs/Enderman.cpp183
-rw-r--r--src/Mobs/Old Mobs/Enderman.h42
-rw-r--r--src/Mobs/Old Mobs/Ghast.cpp61
-rw-r--r--src/Mobs/Old Mobs/Ghast.h28
-rw-r--r--src/Mobs/Old Mobs/Giant.cpp27
-rw-r--r--src/Mobs/Old Mobs/Giant.h25
-rw-r--r--src/Mobs/Old Mobs/Horse.cpp157
-rw-r--r--src/Mobs/Old Mobs/Horse.h44
-rw-r--r--src/Mobs/Old Mobs/IronGolem.cpp28
-rw-r--r--src/Mobs/Old Mobs/IronGolem.h29
-rw-r--r--src/Mobs/Old Mobs/MagmaCube.cpp30
-rw-r--r--src/Mobs/Old Mobs/MagmaCube.h31
-rw-r--r--src/Mobs/Old Mobs/Monster.cpp1045
-rw-r--r--src/Mobs/Old Mobs/Monster.h271
-rw-r--r--src/Mobs/Old Mobs/Mooshroom.cpp75
-rw-r--r--src/Mobs/Old Mobs/Mooshroom.h28
-rw-r--r--src/Mobs/Old Mobs/Ocelot.h26
-rw-r--r--src/Mobs/Old Mobs/PassiveAggressiveMonster.cpp41
-rw-r--r--src/Mobs/Old Mobs/PassiveAggressiveMonster.h23
-rw-r--r--src/Mobs/Old Mobs/PassiveMonster.cpp65
-rw-r--r--src/Mobs/Old Mobs/PassiveMonster.h30
-rw-r--r--src/Mobs/Old Mobs/Pig.cpp100
-rw-r--r--src/Mobs/Old Mobs/Pig.h36
-rw-r--r--src/Mobs/Old Mobs/Sheep.cpp154
-rw-r--r--src/Mobs/Old Mobs/Sheep.h50
-rw-r--r--src/Mobs/Old Mobs/Silverfish.h26
-rw-r--r--src/Mobs/Old Mobs/Skeleton.cpp107
-rw-r--r--src/Mobs/Old Mobs/Skeleton.h37
-rw-r--r--src/Mobs/Old Mobs/Slime.cpp106
-rw-r--r--src/Mobs/Old Mobs/Slime.h41
-rw-r--r--src/Mobs/Old Mobs/SnowGolem.cpp46
-rw-r--r--src/Mobs/Old Mobs/SnowGolem.h26
-rw-r--r--src/Mobs/Old Mobs/Spider.cpp35
-rw-r--r--src/Mobs/Old Mobs/Spider.h25
-rw-r--r--src/Mobs/Old Mobs/Squid.cpp62
-rw-r--r--src/Mobs/Old Mobs/Squid.h31
-rw-r--r--src/Mobs/Old Mobs/Villager.cpp197
-rw-r--r--src/Mobs/Old Mobs/Villager.h66
-rw-r--r--src/Mobs/Old Mobs/Witch.cpp47
-rw-r--r--src/Mobs/Old Mobs/Witch.h28
-rw-r--r--src/Mobs/Old Mobs/Wither.cpp136
-rw-r--r--src/Mobs/Old Mobs/Wither.h45
-rw-r--r--src/Mobs/Old Mobs/Wolf.cpp246
-rw-r--r--src/Mobs/Old Mobs/Wolf.h61
-rw-r--r--src/Mobs/Old Mobs/Zombie.cpp62
-rw-r--r--src/Mobs/Old Mobs/Zombie.h36
-rw-r--r--src/Mobs/Old Mobs/ZombiePigman.cpp53
-rw-r--r--src/Mobs/Old Mobs/ZombiePigman.h27
64 files changed, 4952 insertions, 0 deletions
diff --git a/src/Mobs/Old Mobs/AggressiveMonster.cpp b/src/Mobs/Old Mobs/AggressiveMonster.cpp
new file mode 100644
index 000000000..5f5b1853d
--- /dev/null
+++ b/src/Mobs/Old Mobs/AggressiveMonster.cpp
@@ -0,0 +1,124 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "AggressiveMonster.h"
+
+#include "../World.h"
+#include "../Entities/Player.h"
+#include "../Tracer.h"
+
+
+
+
+
+cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
+ super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
+{
+ m_EMPersonality = AGGRESSIVE;
+}
+
+
+
+
+
+// What to do if in Chasing State
+void cAggressiveMonster::InStateChasing(float a_Dt)
+{
+ super::InStateChasing(a_Dt);
+
+ if (m_Target != NULL)
+ {
+ if (m_Target->IsPlayer())
+ {
+ if (((cPlayer *)m_Target)->IsGameModeCreative())
+ {
+ m_EMState = IDLE;
+ return;
+ }
+ }
+
+ if (!IsMovingToTargetPosition())
+ {
+ MoveToPosition(m_Target->GetPosition());
+ }
+ }
+}
+
+
+
+
+
+void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity)
+{
+ if (!((cPlayer *)a_Entity)->IsGameModeCreative())
+ {
+ super::EventSeePlayer(a_Entity);
+ m_EMState = CHASING;
+ }
+}
+
+
+
+
+
+void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_EMState == CHASING)
+ {
+ CheckEventLostPlayer();
+ }
+ else
+ {
+ CheckEventSeePlayer();
+ }
+
+ if (m_Target == NULL)
+ return;
+
+ cTracer LineOfSight(GetWorld());
+ Vector3d AttackDirection(m_Target->GetPosition() - GetPosition());
+
+ if (ReachedFinalDestination() && !LineOfSight.Trace(GetPosition(), AttackDirection, (int)AttackDirection.Length()))
+ {
+ // Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls)
+ Attack(a_Dt / 1000);
+ }
+}
+
+
+
+
+
+void cAggressiveMonster::Attack(float a_Dt)
+{
+ m_AttackInterval += a_Dt * m_AttackRate;
+
+ if ((m_Target == NULL) || (m_AttackInterval < 3.0))
+ {
+ return;
+ }
+
+ // Setting this higher gives us more wiggle room for attackrate
+ m_AttackInterval = 0.0;
+ m_Target->TakeDamage(dtMobAttack, this, m_AttackDamage, 0);
+}
+
+
+
+
+bool cAggressiveMonster::IsMovingToTargetPosition()
+{
+ // Difference between destination x and target x is negligible (to 10^-12 precision)
+ if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < std::numeric_limits<float>::epsilon())
+ {
+ return false;
+ }
+ // Difference between destination z and target z is negligible (to 10^-12 precision)
+ else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > std::numeric_limits<float>::epsilon())
+ {
+ return false;
+ }
+ return true;
+}
diff --git a/src/Mobs/Old Mobs/AggressiveMonster.h b/src/Mobs/Old Mobs/AggressiveMonster.h
new file mode 100644
index 000000000..d70ff04a3
--- /dev/null
+++ b/src/Mobs/Old Mobs/AggressiveMonster.h
@@ -0,0 +1,33 @@
+
+#pragma once
+
+#include "Monster.h"
+
+
+
+
+
+class cAggressiveMonster :
+ public cMonster
+{
+ typedef cMonster super;
+
+public:
+
+ cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, 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;
+
+ virtual void EventSeePlayer(cEntity *) override;
+ virtual void Attack(float a_Dt);
+
+protected:
+ /** Whether this mob's destination is the same as its target's position. */
+ bool IsMovingToTargetPosition();
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Bat.cpp b/src/Mobs/Old Mobs/Bat.cpp
new file mode 100644
index 000000000..c072d4f48
--- /dev/null
+++ b/src/Mobs/Old Mobs/Bat.cpp
@@ -0,0 +1,14 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Bat.h"
+#include "../Vector3.h"
+#include "../Chunk.h"
+
+
+cBat::cBat(void) :
+ super("Bat", mtBat, "mob.bat.hurt", "mob.bat.death", 0.5, 0.9)
+{
+}
+
+
diff --git a/src/Mobs/Old Mobs/Bat.h b/src/Mobs/Old Mobs/Bat.h
new file mode 100644
index 000000000..6b06aeb4f
--- /dev/null
+++ b/src/Mobs/Old Mobs/Bat.h
@@ -0,0 +1,25 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cBat :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cBat(void);
+
+ CLASS_PROTODEF(cBat)
+
+ bool IsHanging(void) const {return false; }
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Blaze.cpp b/src/Mobs/Old Mobs/Blaze.cpp
new file mode 100644
index 000000000..b4104d530
--- /dev/null
+++ b/src/Mobs/Old Mobs/Blaze.cpp
@@ -0,0 +1,57 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Blaze.h"
+#include "../World.h"
+#include "../Entities/FireChargeEntity.h"
+
+
+
+
+cBlaze::cBlaze(void) :
+ super("Blaze", mtBlaze, "mob.blaze.hit", "mob.blaze.death", 0.6, 1.8)
+{
+}
+
+
+
+
+
+void cBlaze::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ if ((a_Killer != NULL) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf")))
+ {
+ int LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_BLAZE_ROD);
+ }
+}
+
+
+
+
+
+void cBlaze::Attack(float a_Dt)
+{
+ m_AttackInterval += a_Dt * m_AttackRate;
+
+ if (m_Target != NULL && m_AttackInterval > 3.0)
+ {
+ // Setting this higher gives us more wiggle room for attackrate
+ Vector3d Speed = GetLookVector() * 20;
+ Speed.y = Speed.y + 1;
+ cFireChargeEntity * FireCharge = new cFireChargeEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed);
+ if (FireCharge == NULL)
+ {
+ return;
+ }
+ if (!FireCharge->Initialize(*m_World))
+ {
+ delete FireCharge;
+ FireCharge = NULL;
+ return;
+ }
+ m_World->BroadcastSpawnEntity(*FireCharge);
+ m_AttackInterval = 0.0;
+ // ToDo: Shoot 3 fireballs instead of 1.
+ }
+}
diff --git a/src/Mobs/Old Mobs/Blaze.h b/src/Mobs/Old Mobs/Blaze.h
new file mode 100644
index 000000000..f283b1070
--- /dev/null
+++ b/src/Mobs/Old Mobs/Blaze.h
@@ -0,0 +1,22 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cBlaze :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cBlaze(void);
+
+ CLASS_PROTODEF(cBlaze)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void Attack(float a_Dt) override;
+} ;
diff --git a/src/Mobs/Old Mobs/CaveSpider.cpp b/src/Mobs/Old Mobs/CaveSpider.cpp
new file mode 100644
index 000000000..118a6e93b
--- /dev/null
+++ b/src/Mobs/Old Mobs/CaveSpider.cpp
@@ -0,0 +1,61 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "CaveSpider.h"
+#include "../World.h"
+
+
+
+
+
+cCaveSpider::cCaveSpider(void) :
+ super("CaveSpider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5)
+{
+}
+
+
+
+
+
+void cCaveSpider::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ m_EMPersonality = (GetWorld()->GetTimeOfDay() < (12000 + 1000)) ? PASSIVE : AGGRESSIVE;
+}
+
+
+
+
+
+void cCaveSpider::Attack(float a_Dt)
+{
+ super::Attack(a_Dt);
+
+ if (m_Target->IsPawn())
+ {
+ // TODO: Easy = no poison, Medium = 7 seconds, Hard = 15 seconds
+ ((cPawn *) m_Target)->AddEntityEffect(cEntityEffect::effPoison, 7 * 20, 0);
+ }
+}
+
+
+
+
+
+void cCaveSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_STRING);
+ if ((a_Killer != NULL) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf")))
+ {
+ AddRandomUncommonDropItem(a_Drops, 33.0f, E_ITEM_SPIDER_EYE);
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/CaveSpider.h b/src/Mobs/Old Mobs/CaveSpider.h
new file mode 100644
index 000000000..f9ed10e1b
--- /dev/null
+++ b/src/Mobs/Old Mobs/CaveSpider.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cCaveSpider :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cCaveSpider(void);
+
+ CLASS_PROTODEF(cCaveSpider)
+
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void Attack(float a_Dt) override;
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Chicken.cpp b/src/Mobs/Old Mobs/Chicken.cpp
new file mode 100644
index 000000000..f7e44238f
--- /dev/null
+++ b/src/Mobs/Old Mobs/Chicken.cpp
@@ -0,0 +1,66 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Chicken.h"
+#include "../World.h"
+
+
+
+
+
+
+
+cChicken::cChicken(void) :
+ super("Chicken", mtChicken, "mob.chicken.hurt", "mob.chicken.hurt", 0.3, 0.4),
+ m_EggDropTimer(0)
+{
+}
+
+
+
+
+void cChicken::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if ((m_EggDropTimer == 6000) && (m_World->GetTickRandomNumber(1) == 0))
+ {
+ cItems Drops;
+ m_EggDropTimer = 0;
+ Drops.push_back(cItem(E_ITEM_EGG, 1));
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
+ }
+ else if (m_EggDropTimer == 12000)
+ {
+ cItems Drops;
+ m_EggDropTimer = 0;
+ Drops.push_back(cItem(E_ITEM_EGG, 1));
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
+ }
+ else
+ {
+ m_EggDropTimer++;
+ }
+}
+
+
+
+
+
+void cChicken::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_FEATHER);
+ AddRandomDropItem(a_Drops, 1, 1, IsOnFire() ? E_ITEM_COOKED_CHICKEN : E_ITEM_RAW_CHICKEN);
+}
+
+
+
+
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Chicken.h b/src/Mobs/Old Mobs/Chicken.h
new file mode 100644
index 000000000..b1a50b61c
--- /dev/null
+++ b/src/Mobs/Old Mobs/Chicken.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cChicken :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cChicken(void);
+
+ CLASS_PROTODEF(cChicken)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_SEEDS); }
+
+private:
+
+ int m_EggDropTimer;
+} ;
+
+
+
diff --git a/src/Mobs/Old Mobs/Cow.cpp b/src/Mobs/Old Mobs/Cow.cpp
new file mode 100644
index 000000000..9914df6b5
--- /dev/null
+++ b/src/Mobs/Old Mobs/Cow.cpp
@@ -0,0 +1,48 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Cow.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+
+
+cCow::cCow(void) :
+ super("Cow", mtCow, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3)
+{
+}
+
+
+
+
+
+void cCow::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_LEATHER);
+ AddRandomDropItem(a_Drops, 1, 3 + LootingLevel, IsOnFire() ? E_ITEM_STEAK : E_ITEM_RAW_BEEF);
+}
+
+
+
+
+
+void cCow::OnRightClicked(cPlayer & a_Player)
+{
+ if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_BUCKET))
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ a_Player.GetInventory().AddItem(E_ITEM_MILK);
+ }
+ }
+}
+
diff --git a/src/Mobs/Old Mobs/Cow.h b/src/Mobs/Old Mobs/Cow.h
new file mode 100644
index 000000000..8814b7e09
--- /dev/null
+++ b/src/Mobs/Old Mobs/Cow.h
@@ -0,0 +1,29 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cCow :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cCow();
+
+ CLASS_PROTODEF(cCow)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+
+ virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Creeper.cpp b/src/Mobs/Old Mobs/Creeper.cpp
new file mode 100644
index 000000000..02718edf8
--- /dev/null
+++ b/src/Mobs/Old Mobs/Creeper.cpp
@@ -0,0 +1,152 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Creeper.h"
+#include "../World.h"
+#include "../Entities/ProjectileEntity.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cCreeper::cCreeper(void) :
+ super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8),
+ m_bIsBlowing(false),
+ m_bIsCharged(false),
+ m_BurnedWithFlintAndSteel(false),
+ m_ExplodingTimer(0)
+{
+}
+
+
+
+
+
+void cCreeper::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (!ReachedFinalDestination() && !m_BurnedWithFlintAndSteel)
+ {
+ m_ExplodingTimer = 0;
+ m_bIsBlowing = false;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+ else
+ {
+ if (m_bIsBlowing)
+ {
+ m_ExplodingTimer += 1;
+ }
+
+ if (m_ExplodingTimer == 30)
+ {
+ m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
+ Destroy(); // Just in case we aren't killed by the explosion
+ }
+ }
+}
+
+
+
+
+
+void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ if (m_ExplodingTimer == 30)
+ {
+ // Exploded creepers drop naught but charred flesh, which Minecraft doesn't have
+ return;
+ }
+
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);
+
+ if ((a_Killer != NULL) && a_Killer->IsProjectile() && (((cProjectileEntity *)a_Killer)->GetCreatorUniqueID() >= 0))
+ {
+ class cProjectileCreatorCallback : public cEntityCallback
+ {
+ public:
+ cProjectileCreatorCallback(void)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ if (a_Entity->IsMob() && ((cMonster *)a_Entity)->GetMobType() == mtSkeleton)
+ {
+ return true;
+ }
+ return false;
+ }
+ };
+
+ cProjectileCreatorCallback PCC;
+ if (GetWorld()->DoWithEntityByID(((cProjectileEntity *)a_Killer)->GetCreatorUniqueID(), PCC))
+ {
+ // 12 music discs. TickRand starts from 0 to 11. Disk IDs start at 2256, so add that. There.
+ AddRandomDropItem(a_Drops, 1, 1, (short)m_World->GetTickRandomNumber(11) + 2256);
+ }
+ }
+}
+
+
+
+
+
+bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+
+ if (a_TDI.DamageType == dtLightning)
+ {
+ m_bIsCharged = true;
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
+ return true;
+}
+
+
+
+
+
+void cCreeper::Attack(float a_Dt)
+{
+ UNUSED(a_Dt);
+
+ if (!m_bIsBlowing)
+ {
+ m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_bIsBlowing = true;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
+void cCreeper::OnRightClicked(cPlayer & a_Player)
+{
+ if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_FLINT_AND_STEEL))
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.UseEquippedItem();
+ }
+ m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_bIsBlowing = true;
+ m_World->BroadcastEntityMetadata(*this);
+ m_BurnedWithFlintAndSteel = true;
+ }
+}
+
diff --git a/src/Mobs/Old Mobs/Creeper.h b/src/Mobs/Old Mobs/Creeper.h
new file mode 100644
index 000000000..747daca09
--- /dev/null
+++ b/src/Mobs/Old Mobs/Creeper.h
@@ -0,0 +1,38 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cCreeper :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cCreeper(void);
+
+ CLASS_PROTODEF(cCreeper)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void Attack(float a_Dt) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+
+ bool IsBlowing(void) const {return m_bIsBlowing; }
+ bool IsCharged(void) const {return m_bIsCharged; }
+
+private:
+
+ bool m_bIsBlowing, m_bIsCharged, m_BurnedWithFlintAndSteel;
+ int m_ExplodingTimer;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/EnderDragon.cpp b/src/Mobs/Old Mobs/EnderDragon.cpp
new file mode 100644
index 000000000..acd81cde1
--- /dev/null
+++ b/src/Mobs/Old Mobs/EnderDragon.cpp
@@ -0,0 +1,27 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "EnderDragon.h"
+
+
+
+
+
+cEnderDragon::cEnderDragon(void) :
+ // TODO: Vanilla source says this, but is it right? Dragons fly, they don't stand
+ super("EnderDragon", mtEnderDragon, "mob.enderdragon.hit", "mob.enderdragon.end", 16.0, 8.0)
+{
+}
+
+
+
+
+
+void cEnderDragon::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ return;
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/EnderDragon.h b/src/Mobs/Old Mobs/EnderDragon.h
new file mode 100644
index 000000000..1d4cd657c
--- /dev/null
+++ b/src/Mobs/Old Mobs/EnderDragon.h
@@ -0,0 +1,25 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cEnderDragon :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cEnderDragon(void);
+
+ CLASS_PROTODEF(cEnderDragon)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Enderman.cpp b/src/Mobs/Old Mobs/Enderman.cpp
new file mode 100644
index 000000000..51255beb3
--- /dev/null
+++ b/src/Mobs/Old Mobs/Enderman.cpp
@@ -0,0 +1,183 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Enderman.h"
+#include "../Entities/Player.h"
+#include "../Tracer.h"
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPlayerLookCheck
+class cPlayerLookCheck :
+ public cPlayerListCallback
+{
+public:
+ cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) :
+ m_Player(NULL),
+ m_EndermanPos(a_EndermanPos),
+ m_SightDistance(a_SightDistance)
+ {
+ }
+
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ // Don't check players who are in creative gamemode
+ if (a_Player->IsGameModeCreative())
+ {
+ return false;
+ }
+
+ Vector3d Direction = m_EndermanPos - a_Player->GetPosition();
+
+ // Don't check players who are more then SightDistance (64) blocks away
+ if (Direction.Length() > m_SightDistance)
+ {
+ return false;
+ }
+
+ // Don't check if the player has a pumpkin on his head
+ if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
+ {
+ return false;
+ }
+
+
+ Vector3d LookVector = a_Player->GetLookVector();
+ double dot = Direction.Dot(LookVector);
+
+ // 0.09 rad ~ 5 degrees
+ // If the player's crosshair is within 5 degrees of the enderman, it counts as looking
+ if (dot <= cos(0.09))
+ {
+ return false;
+ }
+
+ cTracer LineOfSight(a_Player->GetWorld());
+ if (LineOfSight.Trace(m_EndermanPos, Direction, (int)Direction.Length()))
+ {
+ // No direct line of sight
+ return false;
+ }
+
+ m_Player = a_Player;
+ return true;
+ }
+
+ cPlayer * GetPlayer(void) const { return m_Player; }
+
+protected:
+ cPlayer * m_Player;
+ Vector3d m_EndermanPos;
+ int m_SightDistance;
+} ;
+
+
+
+
+
+cEnderman::cEnderman(void) :
+ super("Enderman", mtEnderman, "mob.endermen.hit", "mob.endermen.death", 0.5, 2.9),
+ m_bIsScreaming(false),
+ CarriedBlock(E_BLOCK_AIR),
+ CarriedMeta(0)
+{
+}
+
+
+
+
+
+void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_ENDER_PEARL);
+}
+
+
+
+
+void cEnderman::CheckEventSeePlayer()
+{
+ if (m_Target != NULL)
+ {
+ return;
+ }
+
+ cPlayerLookCheck Callback(GetPosition(), m_SightDistance);
+ if (m_World->ForEachPlayer(Callback))
+ {
+ return;
+ }
+
+ ASSERT(Callback.GetPlayer() != NULL);
+
+ if (!CheckLight())
+ {
+ // Insufficient light for enderman to become aggravated
+ // TODO: Teleport to a suitable location
+ return;
+ }
+
+ if (!Callback.GetPlayer()->IsGameModeCreative())
+ {
+ super::EventSeePlayer(Callback.GetPlayer());
+ m_EMState = CHASING;
+ m_bIsScreaming = true;
+ GetWorld()->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
+void cEnderman::CheckEventLostPlayer(void)
+{
+ super::CheckEventLostPlayer();
+ if (!CheckLight())
+ {
+ EventLosePlayer();
+ }
+}
+
+
+
+
+
+void cEnderman::EventLosePlayer()
+{
+ super::EventLosePlayer();
+ m_bIsScreaming = false;
+ GetWorld()->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+bool cEnderman::CheckLight()
+{
+ int ChunkX, ChunkZ;
+ cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);
+
+ // Check if the chunk the enderman is in is lit
+ if (!m_World->IsChunkLighted(ChunkX, ChunkZ))
+ {
+ m_World->QueueLightChunk(ChunkX, ChunkZ);
+ return true;
+ }
+
+ // Enderman only attack if the skylight is lower or equal to 8
+ if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) - GetWorld()->GetSkyDarkness() > 8)
+ {
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/Mobs/Old Mobs/Enderman.h b/src/Mobs/Old Mobs/Enderman.h
new file mode 100644
index 000000000..4583746e7
--- /dev/null
+++ b/src/Mobs/Old Mobs/Enderman.h
@@ -0,0 +1,42 @@
+
+#pragma once
+
+#include "PassiveAggressiveMonster.h"
+
+
+
+
+
+class cEnderman :
+ public cPassiveAggressiveMonster
+{
+ typedef cPassiveAggressiveMonster super;
+
+public:
+ cEnderman(void);
+
+ CLASS_PROTODEF(cEnderman)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void CheckEventSeePlayer(void) override;
+ virtual void CheckEventLostPlayer(void) override;
+ virtual void EventLosePlayer(void) override;
+
+ bool IsScreaming(void) const {return m_bIsScreaming; }
+ BLOCKTYPE GetCarriedBlock(void) const {return CarriedBlock; }
+ NIBBLETYPE GetCarriedMeta(void) const {return CarriedMeta; }
+
+ /** Returns if the current sky light level is sufficient for the enderman to become aggravated */
+ bool CheckLight(void);
+
+private:
+
+ bool m_bIsScreaming;
+ BLOCKTYPE CarriedBlock;
+ NIBBLETYPE CarriedMeta;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Ghast.cpp b/src/Mobs/Old Mobs/Ghast.cpp
new file mode 100644
index 000000000..6aac14779
--- /dev/null
+++ b/src/Mobs/Old Mobs/Ghast.cpp
@@ -0,0 +1,61 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Ghast.h"
+#include "../World.h"
+#include "../Entities/GhastFireballEntity.h"
+
+
+
+
+cGhast::cGhast(void) :
+ super("Ghast", mtGhast, "mob.ghast.scream", "mob.ghast.death", 4, 4)
+{
+}
+
+
+
+
+
+void cGhast::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);
+ AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_GHAST_TEAR);
+}
+
+
+
+
+
+void cGhast::Attack(float a_Dt)
+{
+ m_AttackInterval += a_Dt * m_AttackRate;
+
+ if (m_Target != NULL && m_AttackInterval > 3.0)
+ {
+ // Setting this higher gives us more wiggle room for attackrate
+ Vector3d Speed = GetLookVector() * 20;
+ Speed.y = Speed.y + 1;
+ cGhastFireballEntity * GhastBall = new cGhastFireballEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed);
+ if (GhastBall == NULL)
+ {
+ return;
+ }
+ if (!GhastBall->Initialize(*m_World))
+ {
+ delete GhastBall;
+ GhastBall = NULL;
+ return;
+ }
+ m_World->BroadcastSpawnEntity(*GhastBall);
+ m_AttackInterval = 0.0;
+ }
+}
+
+
+
diff --git a/src/Mobs/Old Mobs/Ghast.h b/src/Mobs/Old Mobs/Ghast.h
new file mode 100644
index 000000000..1d4e6b94a
--- /dev/null
+++ b/src/Mobs/Old Mobs/Ghast.h
@@ -0,0 +1,28 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cGhast :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cGhast(void);
+
+ CLASS_PROTODEF(cGhast)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void Attack(float a_Dt) override;
+
+ bool IsCharging(void) const {return false; }
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Giant.cpp b/src/Mobs/Old Mobs/Giant.cpp
new file mode 100644
index 000000000..bbcad46f0
--- /dev/null
+++ b/src/Mobs/Old Mobs/Giant.cpp
@@ -0,0 +1,27 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Giant.h"
+
+
+
+
+
+cGiant::cGiant(void) :
+ super("Giant", mtGiant, "mob.zombie.hurt", "mob.zombie.death", 3.6, 10.8)
+{
+
+}
+
+
+
+
+
+void cGiant::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ AddRandomDropItem(a_Drops, 10, 50, E_ITEM_ROTTEN_FLESH);
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Giant.h b/src/Mobs/Old Mobs/Giant.h
new file mode 100644
index 000000000..7c04c9b4f
--- /dev/null
+++ b/src/Mobs/Old Mobs/Giant.h
@@ -0,0 +1,25 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cGiant :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cGiant(void);
+
+ CLASS_PROTODEF(cGiant)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Horse.cpp b/src/Mobs/Old Mobs/Horse.cpp
new file mode 100644
index 000000000..67a09d4ab
--- /dev/null
+++ b/src/Mobs/Old Mobs/Horse.cpp
@@ -0,0 +1,157 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Horse.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cHorse::cHorse(int Type, int Color, int Style, int TameTimes) :
+ super("Horse", mtHorse, "mob.horse.hit", "mob.horse.death", 1.4, 1.6),
+ m_bHasChest(false),
+ m_bIsEating(false),
+ m_bIsRearing(false),
+ m_bIsMouthOpen(false),
+ m_bIsTame(false),
+ m_bIsSaddled(false),
+ m_Type(Type),
+ m_Color(Color),
+ m_Style(Style),
+ m_Armour(0),
+ m_TimesToTame(TameTimes),
+ m_TameAttemptTimes(0),
+ m_RearTickCount(0)
+{
+}
+
+
+
+
+
+void cHorse::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (!m_bIsMouthOpen)
+ {
+ if (m_World->GetTickRandomNumber(50) == 25)
+ {
+ m_bIsMouthOpen = true;
+ }
+ }
+ else
+ {
+ if (m_World->GetTickRandomNumber(10) == 5)
+ {
+ m_bIsMouthOpen = false;
+ }
+ }
+
+ if ((m_Attachee != NULL) && (!m_bIsTame))
+ {
+ if (m_TameAttemptTimes < m_TimesToTame)
+ {
+ if (m_World->GetTickRandomNumber(50) == 25)
+ {
+ m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 0);
+ m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 2);
+ m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 6);
+ m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 8);
+
+ m_Attachee->Detach();
+ m_bIsRearing = true;
+ }
+ }
+ else
+ {
+ m_bIsTame = true;
+ }
+ }
+
+ if (m_bIsRearing)
+ {
+ if (m_RearTickCount == 20)
+ {
+ m_bIsRearing = false;
+ m_RearTickCount = 0;
+ }
+ else
+ {
+ m_RearTickCount++;
+ }
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cHorse::OnRightClicked(cPlayer & a_Player)
+{
+ if (!m_bIsSaddled && m_bIsTame)
+ {
+ if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SADDLE)
+ {
+ // Saddle the horse:
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ m_bIsSaddled = true;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+ else if (!a_Player.GetEquippedItem().IsEmpty())
+ {
+ // The horse doesn't like being hit, make it rear:
+ m_bIsRearing = true;
+ m_RearTickCount = 0;
+ }
+ }
+ else
+ {
+ if (m_Attachee != NULL)
+ {
+ if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
+ {
+ a_Player.Detach();
+ return;
+ }
+
+ if (m_Attachee->IsPlayer())
+ {
+ return;
+ }
+
+ m_Attachee->Detach();
+ }
+
+ m_TameAttemptTimes++;
+ a_Player.AttachTo(this);
+ }
+}
+
+
+
+
+
+void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_LEATHER);
+ if (m_bIsSaddled)
+ {
+ a_Drops.push_back(cItem(E_ITEM_SADDLE, 1));
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Horse.h b/src/Mobs/Old Mobs/Horse.h
new file mode 100644
index 000000000..47189b3b0
--- /dev/null
+++ b/src/Mobs/Old Mobs/Horse.h
@@ -0,0 +1,44 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cHorse :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cHorse(int Type, int Color, int Style, int TameTimes);
+
+ CLASS_PROTODEF(cHorse)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+
+ bool IsSaddled (void) const {return m_bIsSaddled; }
+ bool IsChested (void) const {return m_bHasChest; }
+ bool IsEating (void) const {return m_bIsEating; }
+ bool IsRearing (void) const {return m_bIsRearing; }
+ bool IsMthOpen (void) const {return m_bIsMouthOpen; }
+ bool IsTame (void) const {return m_bIsTame; }
+ int GetHorseType (void) const {return m_Type; }
+ int GetHorseColor (void) const {return m_Color; }
+ int GetHorseStyle (void) const {return m_Style; }
+ int GetHorseArmour (void) const {return m_Armour;}
+
+private:
+
+ bool m_bHasChest, m_bIsEating, m_bIsRearing, m_bIsMouthOpen, m_bIsTame, m_bIsSaddled;
+ int m_Type, m_Color, m_Style, m_Armour, m_TimesToTame, m_TameAttemptTimes, m_RearTickCount;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/IronGolem.cpp b/src/Mobs/Old Mobs/IronGolem.cpp
new file mode 100644
index 000000000..dae4615e4
--- /dev/null
+++ b/src/Mobs/Old Mobs/IronGolem.cpp
@@ -0,0 +1,28 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "IronGolem.h"
+
+
+
+
+
+cIronGolem::cIronGolem(void) :
+ super("IronGolem", mtIronGolem, "mob.IronGolem.hit", "mob.IronGolem.death", 1.4, 2.9)
+{
+}
+
+
+
+
+
+void cIronGolem::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ UNUSED(a_Killer);
+ AddRandomDropItem(a_Drops, 0, 5, E_ITEM_IRON);
+ AddRandomDropItem(a_Drops, 0, 2, E_BLOCK_FLOWER);
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/IronGolem.h b/src/Mobs/Old Mobs/IronGolem.h
new file mode 100644
index 000000000..c5341ed76
--- /dev/null
+++ b/src/Mobs/Old Mobs/IronGolem.h
@@ -0,0 +1,29 @@
+
+#pragma once
+
+#include "PassiveAggressiveMonster.h"
+
+
+
+
+
+class cIronGolem :
+ public cPassiveAggressiveMonster
+{
+ typedef cPassiveAggressiveMonster super;
+
+public:
+ cIronGolem(void);
+
+ CLASS_PROTODEF(cIronGolem)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+
+ // Iron golems do not drown nor float
+ virtual void HandleAir(void) override {}
+ virtual void SetSwimState(cChunk & a_Chunk) override {}
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/MagmaCube.cpp b/src/Mobs/Old Mobs/MagmaCube.cpp
new file mode 100644
index 000000000..3e9abc108
--- /dev/null
+++ b/src/Mobs/Old Mobs/MagmaCube.cpp
@@ -0,0 +1,30 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "MagmaCube.h"
+
+
+
+
+
+cMagmaCube::cMagmaCube(int a_Size) :
+ super("MagmaCube", mtMagmaCube, "mob.MagmaCube.big", "mob.MagmaCube.big", 0.6 * a_Size, 0.6 * a_Size),
+ m_Size(a_Size)
+{
+}
+
+
+
+
+
+void cMagmaCube::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ UNUSED(a_Killer);
+ if (GetSize() > 1)
+ {
+ AddRandomUncommonDropItem(a_Drops, 25.0f, E_ITEM_MAGMA_CREAM);
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/MagmaCube.h b/src/Mobs/Old Mobs/MagmaCube.h
new file mode 100644
index 000000000..bfe63fa2e
--- /dev/null
+++ b/src/Mobs/Old Mobs/MagmaCube.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cMagmaCube :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ /// 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, cEntity * a_Killer = NULL) override;
+ int GetSize(void) const { return m_Size; }
+
+protected:
+
+ /// Size of the MagmaCube, 1 .. 3, with 1 being the smallest
+ int m_Size;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Monster.cpp b/src/Mobs/Old Mobs/Monster.cpp
new file mode 100644
index 000000000..fe8a7346f
--- /dev/null
+++ b/src/Mobs/Old Mobs/Monster.cpp
@@ -0,0 +1,1045 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "IncludeAllMonsters.h"
+#include "../Root.h"
+#include "../Server.h"
+#include "../ClientHandle.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+#include "../Entities/ExpOrb.h"
+#include "../MonsterConfig.h"
+#include "../MersenneTwister.h"
+
+#include "../Chunk.h"
+#include "../FastRandom.h"
+
+
+
+
+
+/** Map for eType <-> string
+Needs to be alpha-sorted by the strings, because binary search is used in StringToMobType()
+The strings need to be lowercase (for more efficient comparisons in StringToMobType())
+*/
+static const struct
+{
+ cMonster::eType m_Type;
+ const char * m_lcName;
+} g_MobTypeNames[] =
+{
+ {cMonster::mtBat, "bat"},
+ {cMonster::mtBlaze, "blaze"},
+ {cMonster::mtCaveSpider, "cavespider"},
+ {cMonster::mtChicken, "chicken"},
+ {cMonster::mtCow, "cow"},
+ {cMonster::mtCreeper, "creeper"},
+ {cMonster::mtEnderman, "enderman"},
+ {cMonster::mtEnderDragon, "enderdragon"},
+ {cMonster::mtGhast, "ghast"},
+ {cMonster::mtHorse, "horse"},
+ {cMonster::mtIronGolem, "irongolem"},
+ {cMonster::mtMagmaCube, "magmacube"},
+ {cMonster::mtMooshroom, "mooshroom"},
+ {cMonster::mtOcelot, "ocelot"},
+ {cMonster::mtPig, "pig"},
+ {cMonster::mtSheep, "sheep"},
+ {cMonster::mtSilverfish, "silverfish"},
+ {cMonster::mtSkeleton, "skeleton"},
+ {cMonster::mtSlime, "slime"},
+ {cMonster::mtSnowGolem, "snowgolem"},
+ {cMonster::mtSpider, "spider"},
+ {cMonster::mtSquid, "squid"},
+ {cMonster::mtVillager, "villager"},
+ {cMonster::mtWitch, "witch"},
+ {cMonster::mtWither, "wither"},
+ {cMonster::mtWolf, "wolf"},
+ {cMonster::mtZombie, "zombie"},
+ {cMonster::mtZombiePigman, "zombiepigman"},
+} ;
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cMonster:
+
+cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height)
+ : super(etMonster, a_Width, a_Height)
+ , m_EMState(IDLE)
+ , m_EMPersonality(AGGRESSIVE)
+ , m_Target(NULL)
+ , m_bMovingToDestination(false)
+ , m_LastGroundHeight(POSY_TOINT)
+ , m_IdleInterval(0)
+ , m_DestroyTimer(0)
+ , m_MobType(a_MobType)
+ , m_SoundHurt(a_SoundHurt)
+ , m_SoundDeath(a_SoundDeath)
+ , m_AttackRate(3)
+ , m_AttackDamage(1)
+ , m_AttackRange(2)
+ , m_AttackInterval(0)
+ , m_SightDistance(25)
+ , m_DropChanceWeapon(0.085f)
+ , m_DropChanceHelmet(0.085f)
+ , m_DropChanceChestplate(0.085f)
+ , m_DropChanceLeggings(0.085f)
+ , m_DropChanceBoots(0.085f)
+ , m_CanPickUpLoot(true)
+ , m_BurnsInDaylight(false)
+{
+ if (!a_ConfigName.empty())
+ {
+ GetMonsterConfig(a_ConfigName);
+ }
+}
+
+
+
+
+
+void cMonster::SpawnOn(cClientHandle & a_Client)
+{
+ a_Client.SendSpawnMob(*this);
+}
+
+
+
+
+
+void cMonster::TickPathFinding()
+{
+ const int PosX = POSX_TOINT;
+ const int PosY = POSY_TOINT;
+ const int PosZ = POSZ_TOINT;
+
+ std::vector<Vector3d> m_PotentialCoordinates;
+ m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ));
+
+ static const struct // Define which directions to try to move to
+ {
+ int x, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0},
+ {-1, 0},
+ { 0, 1},
+ { 0, -1},
+ } ;
+
+ if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */)
+ {
+ // Too low/high, can't really do anything
+ FinishPathFinding();
+ return;
+ }
+
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ {
+ if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ)))
+ {
+ continue;
+ }
+
+ BLOCKTYPE BlockAtY = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
+ int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtLowestY = m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
+
+ if (
+ (!cBlockInfo::IsSolid(BlockAtY)) &&
+ (!cBlockInfo::IsSolid(BlockAtYP)) &&
+ (!IsBlockLava(BlockAtLowestY)) &&
+ (BlockAtLowestY != E_BLOCK_CACTUS) &&
+ (PosY - LowestY < FALL_DAMAGE_HEIGHT)
+ )
+ {
+ m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ));
+ }
+ else if (
+ (cBlockInfo::IsSolid(BlockAtY)) &&
+ (BlockAtY != E_BLOCK_CACTUS) &&
+ (!cBlockInfo::IsSolid(BlockAtYP)) &&
+ (!cBlockInfo::IsSolid(BlockAtYPP)) &&
+ (BlockAtY != E_BLOCK_FENCE) &&
+ (BlockAtY != E_BLOCK_FENCE_GATE)
+ )
+ {
+ m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ));
+ }
+ }
+
+ if (!m_PotentialCoordinates.empty())
+ {
+ Vector3f ShortestCoords = m_PotentialCoordinates.front();
+ for (std::vector<Vector3d>::const_iterator itr = m_PotentialCoordinates.begin(); itr != m_PotentialCoordinates.end(); ++itr)
+ {
+ Vector3f Distance = m_FinalDestination - ShortestCoords;
+ Vector3f Distance2 = m_FinalDestination - *itr;
+ if (Distance.SqrLength() > Distance2.SqrLength())
+ {
+ ShortestCoords = *itr;
+ }
+ }
+
+ m_Destination = ShortestCoords;
+ m_Destination.z += 0.5f;
+ m_Destination.x += 0.5f;
+ }
+ else
+ {
+ FinishPathFinding();
+ }
+}
+
+
+
+
+
+void cMonster::MoveToPosition(const Vector3d & a_Position)
+{
+ FinishPathFinding();
+
+ m_FinalDestination = a_Position;
+ m_bMovingToDestination = true;
+ TickPathFinding();
+}
+
+
+
+bool cMonster::IsCoordinateInTraversedList(Vector3i a_Coords)
+{
+ return (std::find(m_TraversedCoordinates.begin(), m_TraversedCoordinates.end(), a_Coords) != m_TraversedCoordinates.end());
+}
+
+
+
+
+
+bool cMonster::ReachedDestination()
+{
+ if ((m_Destination - GetPosition()).Length() < 0.5f)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+bool cMonster::ReachedFinalDestination()
+{
+ if ((GetPosition() - m_FinalDestination).Length() <= m_AttackRange)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+
+void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_Health <= 0)
+ {
+ // The mob is dead, but we're still animating the "puff" they leave when they die
+ m_DestroyTimer += a_Dt / 1000;
+ if (m_DestroyTimer > 1)
+ {
+ Destroy(true);
+ }
+ return;
+ }
+
+ if ((m_Target != NULL) && m_Target->IsDestroyed())
+ m_Target = NULL;
+
+ // Burning in daylight
+ HandleDaylightBurning(a_Chunk);
+
+ a_Dt /= 1000;
+
+ if (m_bMovingToDestination)
+ {
+ if (m_bOnGround)
+ {
+ if (DoesPosYRequireJump((int)floor(m_Destination.y)))
+ {
+ m_bOnGround = false;
+
+ // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport
+ AddPosY(1.2); // Jump!!
+ }
+ }
+
+ Vector3f Distance = m_Destination - GetPosition();
+ if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
+ {
+ Distance.y = 0;
+ Distance.Normalize();
+
+ if (m_bOnGround)
+ {
+ Distance *= 2.5f;
+ }
+ else if (IsSwimming())
+ {
+ Distance *= 1.3f;
+ }
+ else
+ {
+ // Don't let the mob move too much if he's falling.
+ Distance *= 0.25f;
+ }
+
+ AddSpeedX(Distance.x);
+ AddSpeedZ(Distance.z);
+
+ // It's too buggy!
+ /*
+ if (m_EMState == ESCAPING)
+ {
+ // Runs Faster when escaping :D otherwise they just walk away
+ SetSpeedX (GetSpeedX() * 2.f);
+ SetSpeedZ (GetSpeedZ() * 2.f);
+ }
+ */
+ }
+ else
+ {
+ if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate
+ {
+ FinishPathFinding();
+ }
+ else
+ {
+ TickPathFinding(); // We have reached the next point in our path, calculate another point
+ }
+ }
+ }
+
+ SetPitchAndYawFromDestination();
+ HandleFalling();
+
+ switch (m_EMState)
+ {
+ case IDLE:
+ {
+ // If enemy passive we ignore checks for player visibility
+ InStateIdle(a_Dt);
+ break;
+ }
+ case CHASING:
+ {
+ // If we do not see a player anymore skip chasing action
+ InStateChasing(a_Dt);
+ break;
+ }
+ case ESCAPING:
+ {
+ InStateEscaping(a_Dt);
+ break;
+ }
+
+ case ATTACKING: break;
+ } // switch (m_EMState)
+
+ BroadcastMovementUpdate();
+}
+
+
+
+
+void cMonster::SetPitchAndYawFromDestination()
+{
+ Vector3d FinalDestination = m_FinalDestination;
+ if (m_Target != NULL)
+ {
+ if (m_Target->IsPlayer())
+ {
+ FinalDestination.y = ((cPlayer *)m_Target)->GetStance();
+ }
+ else
+ {
+ FinalDestination.y = GetHeight();
+ }
+ }
+
+ Vector3d Distance = FinalDestination - GetPosition();
+ if (Distance.SqrLength() > 0.1f)
+ {
+ {
+ double Rotation, Pitch;
+ Distance.Normalize();
+ VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch);
+ SetHeadYaw(Rotation);
+ SetPitch(-Pitch);
+ }
+
+ {
+ Vector3d BodyDistance = m_Destination - GetPosition();
+ double Rotation, Pitch;
+ Distance.Normalize();
+ VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch);
+ SetYaw(Rotation);
+ }
+ }
+}
+
+
+
+
+void cMonster::HandleFalling()
+{
+ if (m_bOnGround)
+ {
+ int Damage = (m_LastGroundHeight - POSY_TOINT) - 3;
+
+ if (Damage > 0)
+ {
+ TakeDamage(dtFalling, NULL, Damage, Damage, 0);
+
+ // Fall particles
+ GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, POSY_TOINT - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
+ }
+
+ m_LastGroundHeight = POSY_TOINT;
+ }
+}
+
+
+
+
+
+int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
+{
+ int PosY = POSY_TOINT;
+ PosY = Clamp(PosY, 0, cChunkDef::Height);
+
+ if (!cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))))
+ {
+ while (!cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY > 0))
+ {
+ PosY--;
+ }
+
+ return PosY + 1;
+ }
+ else
+ {
+ while (cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY < cChunkDef::Height))
+ {
+ PosY++;
+ }
+
+ return PosY;
+ }
+}
+
+
+
+
+
+
+bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+
+ if (!m_SoundHurt.empty() && (m_Health > 0))
+ {
+ m_World->BroadcastSoundEffect(m_SoundHurt, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
+ }
+
+ if (a_TDI.Attacker != NULL)
+ {
+ m_Target = a_TDI.Attacker;
+ }
+ return true;
+}
+
+
+
+
+
+void cMonster::KilledBy(TakeDamageInfo & a_TDI)
+{
+ super::KilledBy(a_TDI);
+ if (m_SoundHurt != "")
+ {
+ m_World->BroadcastSoundEffect(m_SoundDeath, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
+ }
+ int Reward;
+ switch (m_MobType)
+ {
+ // Animals
+ case cMonster::mtChicken:
+ case cMonster::mtCow:
+ case cMonster::mtHorse:
+ case cMonster::mtPig:
+ case cMonster::mtSheep:
+ case cMonster::mtSquid:
+ case cMonster::mtMooshroom:
+ case cMonster::mtOcelot:
+ case cMonster::mtWolf:
+ {
+ Reward = m_World->GetTickRandomNumber(2) + 1;
+ break;
+ }
+
+ // Monsters
+ case cMonster::mtCaveSpider:
+ case cMonster::mtCreeper:
+ case cMonster::mtEnderman:
+ case cMonster::mtGhast:
+ case cMonster::mtSilverfish:
+ case cMonster::mtSkeleton:
+ case cMonster::mtSpider:
+ case cMonster::mtWitch:
+ case cMonster::mtZombie:
+ case cMonster::mtZombiePigman:
+ case cMonster::mtSlime:
+ case cMonster::mtMagmaCube:
+ {
+ Reward = 6 + (m_World->GetTickRandomNumber(2));
+ break;
+ }
+ case cMonster::mtBlaze:
+ {
+ Reward = 10;
+ break;
+ }
+
+ // Bosses
+ case cMonster::mtEnderDragon:
+ {
+ Reward = 12000;
+ break;
+ }
+ case cMonster::mtWither:
+ {
+ Reward = 50;
+ break;
+ }
+
+ default:
+ {
+ Reward = 0;
+ break;
+ }
+ }
+ if ((a_TDI.Attacker != NULL) && (!IsBaby()))
+ {
+ m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
+ }
+ m_DestroyTimer = 0;
+}
+
+
+
+
+
+// Checks to see if EventSeePlayer should be fired
+// monster sez: Do I see the player
+void cMonster::CheckEventSeePlayer(void)
+{
+ // TODO: Rewrite this to use cWorld's DoWithPlayers()
+ cPlayer * Closest = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance, false);
+
+ if (Closest != NULL)
+ {
+ EventSeePlayer(Closest);
+ }
+}
+
+
+
+
+
+void cMonster::CheckEventLostPlayer(void)
+{
+ if (m_Target != NULL)
+ {
+ if ((m_Target->GetPosition() - GetPosition()).Length() > m_SightDistance)
+ {
+ EventLosePlayer();
+ }
+ }
+ else
+ {
+ EventLosePlayer();
+ }
+}
+
+
+
+
+
+// What to do if player is seen
+// default to change state to chasing
+void cMonster::EventSeePlayer(cEntity * a_SeenPlayer)
+{
+ m_Target = a_SeenPlayer;
+}
+
+
+
+
+
+void cMonster::EventLosePlayer(void)
+{
+ m_Target = NULL;
+ m_EMState = IDLE;
+}
+
+
+
+
+
+void cMonster::InStateIdle(float a_Dt)
+{
+ if (m_bMovingToDestination)
+ {
+ return; // Still getting there
+ }
+
+ m_IdleInterval += a_Dt;
+
+ if (m_IdleInterval > 1)
+ {
+ // At this interval the results are predictable
+ int rem = m_World->GetTickRandomNumber(6) + 1;
+ m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds
+
+ Vector3d Dist;
+ Dist.x = (double)m_World->GetTickRandomNumber(10) - 5;
+ Dist.z = (double)m_World->GetTickRandomNumber(10) - 5;
+
+ if ((Dist.SqrLength() > 2) && (rem >= 3))
+ {
+ Vector3d Destination(GetPosX() + Dist.x, 0, GetPosZ() + Dist.z);
+
+ int NextHeight = FindFirstNonAirBlockPosition(Destination.x, Destination.z);
+
+ if (IsNextYPosReachable(NextHeight))
+ {
+ Destination.y = NextHeight;
+ MoveToPosition(Destination);
+ }
+ }
+ }
+}
+
+
+
+
+
+// What to do if in Chasing State
+// This state should always be defined in each child class
+void cMonster::InStateChasing(float a_Dt)
+{
+ UNUSED(a_Dt);
+}
+
+
+
+
+
+// What to do if in Escaping State
+void cMonster::InStateEscaping(float a_Dt)
+{
+ UNUSED(a_Dt);
+
+ if (m_Target != NULL)
+ {
+ Vector3d newloc = GetPosition();
+ newloc.x = (m_Target->GetPosition().x < newloc.x)? (newloc.x + m_SightDistance): (newloc.x - m_SightDistance);
+ newloc.z = (m_Target->GetPosition().z < newloc.z)? (newloc.z + m_SightDistance): (newloc.z - m_SightDistance);
+ MoveToPosition(newloc);
+ }
+ else
+ {
+ m_EMState = IDLE; // This shouldnt be required but just to be safe
+ }
+}
+
+
+
+
+
+void cMonster::GetMonsterConfig(const AString & a_Name)
+{
+ cRoot::Get()->GetMonsterConfig()->AssignAttributes(this, a_Name);
+}
+
+
+
+
+
+bool cMonster::IsUndead(void)
+{
+ return false;
+}
+
+
+
+
+
+AString cMonster::MobTypeToString(cMonster::eType a_MobType)
+{
+ // Mob types aren't sorted, so we need to search linearly:
+ for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
+ {
+ if (g_MobTypeNames[i].m_Type == a_MobType)
+ {
+ return g_MobTypeNames[i].m_lcName;
+ }
+ }
+
+ // Not found:
+ return "";
+}
+
+
+
+
+
+cMonster::eType cMonster::StringToMobType(const AString & a_Name)
+{
+ AString lcName = StrToLower(a_Name);
+
+ // Binary-search for the lowercase name:
+ int lo = 0, hi = ARRAYCOUNT(g_MobTypeNames) - 1;
+ while (hi - lo > 1)
+ {
+ int mid = (lo + hi) / 2;
+ int res = strcmp(g_MobTypeNames[mid].m_lcName, lcName.c_str());
+ if (res == 0)
+ {
+ return g_MobTypeNames[mid].m_Type;
+ }
+ if (res < 0)
+ {
+ lo = mid;
+ }
+ else
+ {
+ hi = mid;
+ }
+ }
+ // Range has collapsed to at most two elements, compare each:
+ if (strcmp(g_MobTypeNames[lo].m_lcName, lcName.c_str()) == 0)
+ {
+ return g_MobTypeNames[lo].m_Type;
+ }
+ if ((lo != hi) && (strcmp(g_MobTypeNames[hi].m_lcName, lcName.c_str()) == 0))
+ {
+ return g_MobTypeNames[hi].m_Type;
+ }
+
+ // Not found:
+ return mtInvalidType;
+}
+
+
+
+
+
+cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
+{
+ // Passive-agressive mobs are counted in mob spawning code as passive
+
+ switch (a_Type)
+ {
+ case mtBat: return mfAmbient;
+ case mtBlaze: return mfHostile;
+ case mtCaveSpider: return mfHostile;
+ case mtChicken: return mfPassive;
+ case mtCow: return mfPassive;
+ case mtCreeper: return mfHostile;
+ case mtEnderDragon: return mfNoSpawn;
+ case mtEnderman: return mfHostile;
+ case mtGhast: return mfHostile;
+ case mtGiant: return mfNoSpawn;
+ case mtHorse: return mfPassive;
+ case mtIronGolem: return mfPassive;
+ case mtMagmaCube: return mfHostile;
+ case mtMooshroom: return mfHostile;
+ case mtOcelot: return mfPassive;
+ case mtPig: return mfPassive;
+ case mtSheep: return mfPassive;
+ case mtSilverfish: return mfHostile;
+ case mtSkeleton: return mfHostile;
+ case mtSlime: return mfHostile;
+ case mtSnowGolem: return mfNoSpawn;
+ case mtSpider: return mfHostile;
+ case mtSquid: return mfWater;
+ case mtVillager: return mfPassive;
+ case mtWitch: return mfHostile;
+ case mtWither: return mfNoSpawn;
+ case mtWolf: return mfHostile;
+ case mtZombie: return mfHostile;
+ case mtZombiePigman: return mfHostile;
+
+ case mtInvalidType: break;
+ }
+ ASSERT(!"Unhandled mob type");
+ return mfUnhandled;
+}
+
+
+
+
+
+int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily)
+{
+ switch (a_MobFamily)
+ {
+ case mfHostile: return 40;
+ case mfPassive: return 40;
+ case mfAmbient: return 40;
+ case mfWater: return 400;
+ case mfNoSpawn: return -1;
+ case mfUnhandled: break;
+ }
+ ASSERT(!"Unhandled mob family");
+ return -1;
+}
+
+
+
+
+
+cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
+{
+ cFastRandom Random;
+ cMonster * toReturn = NULL;
+
+ // Create the mob entity
+ switch (a_MobType)
+ {
+ case mtMagmaCube:
+ {
+ toReturn = new cMagmaCube(Random.NextInt(2) + 1);
+ break;
+ }
+ case mtSlime:
+ {
+ toReturn = new cSlime(1 << Random.NextInt(3)); // Size 1, 2 or 4
+ break;
+ }
+ case mtSkeleton:
+ {
+ // TODO: Actual detection of spawning in Nether
+ toReturn = new cSkeleton((Random.NextInt(1) == 0) ? false : true);
+ break;
+ }
+ case mtVillager:
+ {
+ int VillagerType = Random.NextInt(6);
+ if (VillagerType == 6)
+ {
+ // Give farmers a better chance of spawning
+ VillagerType = 0;
+ }
+
+ toReturn = new cVillager((cVillager::eVillagerType)VillagerType);
+ break;
+ }
+ case mtHorse:
+ {
+ // Horses take a type (species), a colour, and a style (dots, stripes, etc.)
+ int HorseType = Random.NextInt(7);
+ int HorseColor = Random.NextInt(6);
+ int HorseStyle = Random.NextInt(6);
+ int HorseTameTimes = Random.NextInt(6) + 1;
+
+ if ((HorseType == 5) || (HorseType == 6) || (HorseType == 7))
+ {
+ // Increase chances of normal horse (zero)
+ HorseType = 0;
+ }
+
+ toReturn = new cHorse(HorseType, HorseColor, HorseStyle, HorseTameTimes);
+ break;
+ }
+
+ case mtBat: toReturn = new cBat(); break;
+ case mtBlaze: toReturn = new cBlaze(); break;
+ case mtCaveSpider: toReturn = new cCaveSpider(); break;
+ case mtChicken: toReturn = new cChicken(); break;
+ case mtCow: toReturn = new cCow(); break;
+ case mtCreeper: toReturn = new cCreeper(); break;
+ case mtEnderDragon: toReturn = new cEnderDragon(); break;
+ case mtEnderman: toReturn = new cEnderman(); break;
+ case mtGhast: toReturn = new cGhast(); break;
+ case mtGiant: toReturn = new cGiant(); break;
+ case mtIronGolem: toReturn = new cIronGolem(); break;
+ case mtMooshroom: toReturn = new cMooshroom(); break;
+ case mtOcelot: toReturn = new cOcelot(); break;
+ case mtPig: toReturn = new cPig(); break;
+ case mtSheep: toReturn = new cSheep(); break;
+ case mtSilverfish: toReturn = new cSilverfish(); break;
+ case mtSnowGolem: toReturn = new cSnowGolem(); break;
+ case mtSpider: toReturn = new cSpider(); break;
+ case mtSquid: toReturn = new cSquid(); break;
+ case mtWitch: toReturn = new cWitch(); break;
+ case mtWither: toReturn = new cWither(); break;
+ case mtWolf: toReturn = new cWolf(); break;
+ case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter
+ case mtZombiePigman: toReturn = new cZombiePigman(); break;
+ default:
+ {
+ ASSERT(!"Unhandled mob type whilst trying to spawn mob!");
+ }
+ }
+ return toReturn;
+}
+
+
+
+
+
+void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth)
+{
+ MTRand r1;
+ int Count = r1.randInt() % (a_Max + 1 - a_Min) + a_Min;
+ if (Count > 0)
+ {
+ a_Drops.push_back(cItem(a_Item, Count, a_ItemHealth));
+ }
+}
+
+
+
+
+
+void cMonster::AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short a_Item, short a_ItemHealth)
+{
+ MTRand r1;
+ int Count = r1.randInt() % 1000;
+ if (Count < (a_Chance * 10))
+ {
+ a_Drops.push_back(cItem(a_Item, 1, a_ItemHealth));
+ }
+}
+
+
+
+
+
+void cMonster::AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, short a_LootingLevel)
+{
+ MTRand r1;
+ int Count = r1.randInt() % 200;
+ if (Count < (5 + a_LootingLevel))
+ {
+ int Rare = r1.randInt() % a_Items.Size();
+ a_Drops.push_back(a_Items.at(Rare));
+ }
+}
+
+
+
+
+
+void cMonster::AddRandomArmorDropItem(cItems & a_Drops, short a_LootingLevel)
+{
+ MTRand r1;
+ if (r1.randInt() % 200 < ((m_DropChanceHelmet * 200) + (a_LootingLevel * 2)))
+ {
+ if (!GetEquippedHelmet().IsEmpty()) a_Drops.push_back(GetEquippedHelmet());
+ }
+
+ if (r1.randInt() % 200 < ((m_DropChanceChestplate * 200) + (a_LootingLevel * 2)))
+ {
+ if (!GetEquippedChestplate().IsEmpty()) a_Drops.push_back(GetEquippedChestplate());
+ }
+
+ if (r1.randInt() % 200 < ((m_DropChanceLeggings * 200) + (a_LootingLevel * 2)))
+ {
+ if (!GetEquippedLeggings().IsEmpty()) a_Drops.push_back(GetEquippedLeggings());
+ }
+
+ if (r1.randInt() % 200 < ((m_DropChanceBoots * 200) + (a_LootingLevel * 2)))
+ {
+ if (!GetEquippedBoots().IsEmpty()) a_Drops.push_back(GetEquippedBoots());
+ }
+}
+
+
+
+
+
+void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel)
+{
+ MTRand r1;
+ if (r1.randInt() % 200 < ((m_DropChanceWeapon * 200) + (a_LootingLevel * 2)))
+ {
+ if (!GetEquippedWeapon().IsEmpty()) a_Drops.push_back(GetEquippedWeapon());
+ }
+}
+
+
+
+
+
+void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
+{
+ if (!m_BurnsInDaylight)
+ {
+ return;
+ }
+
+ int RelY = POSY_TOINT;
+ if ((RelY < 0) || (RelY >= cChunkDef::Height))
+ {
+ // Outside the world
+ return;
+ }
+
+ int RelX = POSX_TOINT - GetChunkX() * cChunkDef::Width;
+ int RelZ = POSZ_TOINT - GetChunkZ() * cChunkDef::Width;
+
+ if (!a_Chunk.IsLightValid())
+ {
+ m_World->QueueLightChunk(GetChunkX(), GetChunkZ());
+ return;
+ }
+
+ if (
+ (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight
+ (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
+ (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
+ !IsOnFire() && // Not already burning
+ GetWorld()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT) // Not raining
+ )
+ {
+ // Burn for 100 ticks, then decide again
+ StartBurning(100);
+ }
+}
+
+
+
+
+cMonster::eFamily cMonster::GetMobFamily(void) const
+{
+ return FamilyFromType(m_MobType);
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Monster.h b/src/Mobs/Old Mobs/Monster.h
new file mode 100644
index 000000000..cdbd26c09
--- /dev/null
+++ b/src/Mobs/Old Mobs/Monster.h
@@ -0,0 +1,271 @@
+
+#pragma once
+
+#include "../Entities/Pawn.h"
+#include "../Defines.h"
+#include "../BlockID.h"
+#include "../Item.h"
+#include "../Enchantments.h"
+
+
+
+
+
+class cClientHandle;
+class cWorld;
+
+
+
+
+// tolua_begin
+class cMonster :
+ public cPawn
+{
+ typedef cPawn super;
+public:
+ /// This identifies individual monster type, as well as their network type-ID
+ enum eType
+ {
+ mtInvalidType = -1,
+
+ mtBat = E_META_SPAWN_EGG_BAT,
+ mtBlaze = E_META_SPAWN_EGG_BLAZE,
+ mtCaveSpider = E_META_SPAWN_EGG_CAVE_SPIDER,
+ mtChicken = E_META_SPAWN_EGG_CHICKEN,
+ mtCow = E_META_SPAWN_EGG_COW,
+ mtCreeper = E_META_SPAWN_EGG_CREEPER,
+ mtEnderDragon = E_META_SPAWN_EGG_ENDER_DRAGON,
+ mtEnderman = E_META_SPAWN_EGG_ENDERMAN,
+ mtGhast = E_META_SPAWN_EGG_GHAST,
+ mtGiant = E_META_SPAWN_EGG_GIANT,
+ mtHorse = E_META_SPAWN_EGG_HORSE,
+ mtIronGolem = E_META_SPAWN_EGG_IRON_GOLEM,
+ mtMagmaCube = E_META_SPAWN_EGG_MAGMA_CUBE,
+ mtMooshroom = E_META_SPAWN_EGG_MOOSHROOM,
+ mtOcelot = E_META_SPAWN_EGG_OCELOT,
+ mtPig = E_META_SPAWN_EGG_PIG,
+ mtSheep = E_META_SPAWN_EGG_SHEEP,
+ mtSilverfish = E_META_SPAWN_EGG_SILVERFISH,
+ mtSkeleton = E_META_SPAWN_EGG_SKELETON,
+ mtSlime = E_META_SPAWN_EGG_SLIME,
+ mtSnowGolem = E_META_SPAWN_EGG_SNOW_GOLEM,
+ mtSpider = E_META_SPAWN_EGG_SPIDER,
+ mtSquid = E_META_SPAWN_EGG_SQUID,
+ mtVillager = E_META_SPAWN_EGG_VILLAGER,
+ mtWitch = E_META_SPAWN_EGG_WITCH,
+ mtWither = E_META_SPAWN_EGG_WITHER,
+ mtWolf = E_META_SPAWN_EGG_WOLF,
+ mtZombie = E_META_SPAWN_EGG_ZOMBIE,
+ mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN,
+ } ;
+
+ enum eFamily
+ {
+ mfHostile = 0, // Spider, Zombies ...
+ mfPassive = 1, // Cows, Pigs
+ mfAmbient = 2, // Bats
+ mfWater = 3, // Squid
+
+ mfNoSpawn,
+ mfUnhandled, // Nothing. Be sure this is the last and the others are in order
+ } ;
+
+ // tolua_end
+
+ enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState;
+ enum MPersonality{PASSIVE, AGGRESSIVE, COWARDLY} m_EMPersonality;
+
+ /** Creates the mob object.
+ If a_ConfigName is not empty, the configuration is loaded using GetMonsterConfig()
+ a_MobType is the type of the mob (also 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, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
+
+ CLASS_PROTODEF(cMonster)
+
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
+
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
+ virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
+ virtual bool ReachedDestination(void);
+
+ // tolua_begin
+ eType GetMobType(void) const {return m_MobType; }
+ eFamily GetMobFamily(void) const;
+ // tolua_end
+
+ virtual void CheckEventSeePlayer(void);
+ virtual void EventSeePlayer(cEntity * a_Player);
+
+ /// Reads the monster configuration for the specified monster name and assigns it to this object.
+ void GetMonsterConfig(const AString & a_Name);
+
+ /** Returns whether this mob is undead (skeleton, zombie, etc.) */
+ virtual bool IsUndead(void);
+
+ virtual void EventLosePlayer(void);
+ virtual void CheckEventLostPlayer(void);
+
+ virtual void InStateIdle (float a_Dt);
+ virtual void InStateChasing (float a_Dt);
+ virtual void InStateEscaping(float a_Dt);
+
+ int GetAttackRate() { return (int)m_AttackRate; }
+ void SetAttackRate(float a_AttackRate) { m_AttackRate = a_AttackRate; }
+ void SetAttackRange(int a_AttackRange) { m_AttackRange = a_AttackRange; }
+ void SetAttackDamage(int a_AttackDamage) { m_AttackDamage = a_AttackDamage; }
+ void SetSightDistance(int a_SightDistance) { m_SightDistance = a_SightDistance; }
+
+ float GetDropChanceWeapon() { return m_DropChanceWeapon; }
+ float GetDropChanceHelmet() { return m_DropChanceHelmet; }
+ float GetDropChanceChestplate() { return m_DropChanceChestplate; }
+ float GetDropChanceLeggings() { return m_DropChanceLeggings; }
+ float GetDropChanceBoots() { return m_DropChanceBoots; }
+ bool CanPickUpLoot() { return m_CanPickUpLoot; }
+ void SetDropChanceWeapon(float a_DropChanceWeapon) { m_DropChanceWeapon = a_DropChanceWeapon; }
+ void SetDropChanceHelmet(float a_DropChanceHelmet) { m_DropChanceHelmet = a_DropChanceHelmet; }
+ void SetDropChanceChestplate(float a_DropChanceChestplate) { m_DropChanceChestplate = a_DropChanceChestplate; }
+ void SetDropChanceLeggings(float a_DropChanceLeggings) { m_DropChanceLeggings = a_DropChanceLeggings; }
+ void SetDropChanceBoots(float a_DropChanceBoots) { m_DropChanceBoots = a_DropChanceBoots; }
+ void SetCanPickUpLoot(bool a_CanPickUpLoot) { m_CanPickUpLoot = a_CanPickUpLoot; }
+
+ /// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick
+ void SetBurnsInDaylight(bool a_BurnsInDaylight) { m_BurnsInDaylight = a_BurnsInDaylight; }
+
+ // Overridables to handle ageable mobs
+ virtual bool IsBaby (void) const { return false; }
+ virtual bool IsTame (void) const { return false; }
+ virtual bool IsSitting (void) const { return false; }
+
+ // tolua_begin
+
+ /// Translates MobType enum to a string, empty string if unknown
+ static AString MobTypeToString(eType a_MobType);
+
+ /// Translates MobType string to the enum, mtInvalidType if not recognized
+ static eType StringToMobType(const AString & a_MobTypeName);
+
+ /// Returns the mob family based on the type
+ static eFamily FamilyFromType(eType a_MobType);
+
+ /// Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family
+ static int GetSpawnDelay(cMonster::eFamily a_MobFamily);
+
+ // tolua_end
+
+ /** Creates a new object of the specified mob.
+ a_MobType is the type of the mob to be created
+ Asserts and returns null if mob type is not specified
+ */
+ static cMonster * NewMonsterFromType(eType a_MobType);
+
+protected:
+
+ /* ======= PATHFINDING ======= */
+
+ /** A pointer to the entity this mobile is aiming to reach */
+ cEntity * m_Target;
+ /** Coordinates of the next position that should be reached */
+ Vector3d m_Destination;
+ /** Coordinates for the ultimate, final destination. */
+ Vector3d m_FinalDestination;
+ /** Returns if the ultimate, final destination has been reached */
+ bool ReachedFinalDestination(void);
+
+ /** Stores if mobile is currently moving towards the ultimate, final destination */
+ bool m_bMovingToDestination;
+
+ /** Finds the first non-air block position (not the highest, as cWorld::GetHeight does)
+ If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
+ If current Y is solid, goes up to find first nonsolid block, and returns that */
+ int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
+ /** Returns if a monster can actually reach a given height by jumping or walking */
+ inline bool IsNextYPosReachable(int a_PosY)
+ {
+ return (
+ (a_PosY <= POSY_TOINT) ||
+ DoesPosYRequireJump(a_PosY)
+ );
+ }
+ /** Returns if a monster can reach a given height by jumping */
+ inline bool DoesPosYRequireJump(int a_PosY)
+ {
+ return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1));
+ }
+
+ /** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */
+ std::vector<Vector3i> m_TraversedCoordinates;
+ /** Returns if coordinate is in the traversed list */
+ bool IsCoordinateInTraversedList(Vector3i a_Coords);
+
+ /** Finds the next place to go
+ This is based on the ultimate, final destination and the current position, as well as the traversed coordinates, and any environmental hazards */
+ void TickPathFinding(void);
+ /** Finishes a pathfinding task, be it due to failure or something else */
+ inline void FinishPathFinding(void)
+ {
+ m_TraversedCoordinates.clear();
+ m_bMovingToDestination = false;
+ }
+ /** Sets the body yaw and head yaw/pitch based on next/ultimate destinations */
+ void SetPitchAndYawFromDestination(void);
+
+ /* =========================== */
+ /* ========= FALLING ========= */
+
+ virtual void HandleFalling(void);
+ int m_LastGroundHeight;
+
+ /* =========================== */
+
+ float m_IdleInterval;
+ float m_DestroyTimer;
+
+ eType m_MobType;
+
+ AString m_SoundHurt;
+ AString m_SoundDeath;
+
+ float m_AttackRate;
+ int m_AttackDamage;
+ int m_AttackRange;
+ float m_AttackInterval;
+ int m_SightDistance;
+
+ float m_DropChanceWeapon;
+ float m_DropChanceHelmet;
+ float m_DropChanceChestplate;
+ float m_DropChanceLeggings;
+ float m_DropChanceBoots;
+ bool m_CanPickUpLoot;
+
+ void HandleDaylightBurning(cChunk & a_Chunk);
+ bool m_BurnsInDaylight;
+
+ /** Adds a random number of a_Item between a_Min and a_Max to itemdrops a_Drops*/
+ void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0);
+
+ /** Adds a item a_Item with the chance of a_Chance (in percent) to itemdrops a_Drops*/
+ void AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short a_Item, short a_ItemHealth = 0);
+
+ /** Adds one rare item out of the list of rare items a_Items modified by the looting level a_LootingLevel(I-III or custom) to the itemdrop a_Drops*/
+ void AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, short a_LootingLevel);
+
+ /** Adds armor that is equipped with the chance saved in m_DropChance[...] (this will be greter than 1 if piccked up or 0.085 + (0.01 per LootingLevel) if born with) to the drop*/
+ void AddRandomArmorDropItem(cItems & a_Drops, short a_LootingLevel);
+
+ /** Adds weapon that is equipped with the chance saved in m_DropChance[...] (this will be greter than 1 if piccked up or 0.085 + (0.01 per LootingLevel) if born with) to the drop*/
+ void AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel);
+
+
+} ; // tolua_export
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Mooshroom.cpp b/src/Mobs/Old Mobs/Mooshroom.cpp
new file mode 100644
index 000000000..81bd3e3b4
--- /dev/null
+++ b/src/Mobs/Old Mobs/Mooshroom.cpp
@@ -0,0 +1,75 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Mooshroom.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+
+
+
+
+
+cMooshroom::cMooshroom(void) :
+ super("Mooshroom", mtMooshroom, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3)
+{
+}
+
+
+
+
+
+void cMooshroom::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_LEATHER);
+ AddRandomDropItem(a_Drops, 1, 3 + LootingLevel, IsOnFire() ? E_ITEM_STEAK : E_ITEM_RAW_BEEF);
+}
+
+
+
+
+
+void cMooshroom::OnRightClicked(cPlayer & a_Player)
+{
+ switch (a_Player.GetEquippedItem().m_ItemType)
+ {
+ case E_ITEM_BUCKET:
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ a_Player.GetInventory().AddItem(E_ITEM_MILK);
+ }
+ } break;
+ case E_ITEM_BOWL:
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ a_Player.GetInventory().AddItem(E_ITEM_MUSHROOM_SOUP);
+ }
+ } break;
+ case E_ITEM_SHEARS:
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.UseEquippedItem();
+ }
+
+ cItems Drops;
+ Drops.push_back(cItem(E_BLOCK_RED_MUSHROOM, 5, 0));
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
+ m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), cMonster::mtCow);
+ Destroy();
+ } break;
+ }
+}
+
diff --git a/src/Mobs/Old Mobs/Mooshroom.h b/src/Mobs/Old Mobs/Mooshroom.h
new file mode 100644
index 000000000..fb002c2bf
--- /dev/null
+++ b/src/Mobs/Old Mobs/Mooshroom.h
@@ -0,0 +1,28 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cMooshroom :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cMooshroom(void);
+
+ CLASS_PROTODEF(cMooshroom)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+
+ virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Ocelot.h b/src/Mobs/Old Mobs/Ocelot.h
new file mode 100644
index 000000000..f2727d354
--- /dev/null
+++ b/src/Mobs/Old Mobs/Ocelot.h
@@ -0,0 +1,26 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cOcelot :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cOcelot(void) :
+ super("Ocelot", mtOcelot, "mob.cat.hitt", "mob.cat.hitt", 0.6, 0.8)
+ {
+ }
+
+ CLASS_PROTODEF(cOcelot)
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/Old Mobs/PassiveAggressiveMonster.cpp
new file mode 100644
index 000000000..24501b1ba
--- /dev/null
+++ b/src/Mobs/Old Mobs/PassiveAggressiveMonster.cpp
@@ -0,0 +1,41 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "PassiveAggressiveMonster.h"
+
+#include "../Entities/Player.h"
+
+
+
+
+
+cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
+ super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
+{
+ m_EMPersonality = PASSIVE;
+}
+
+
+
+
+
+bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+
+ if ((m_Target != NULL) && (m_Target->IsPlayer()))
+ {
+ if (!((cPlayer *)m_Target)->IsGameModeCreative())
+ {
+ m_EMState = CHASING;
+ }
+ }
+ return true;
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/PassiveAggressiveMonster.h b/src/Mobs/Old Mobs/PassiveAggressiveMonster.h
new file mode 100644
index 000000000..a0da50e8e
--- /dev/null
+++ b/src/Mobs/Old Mobs/PassiveAggressiveMonster.h
@@ -0,0 +1,23 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cPassiveAggressiveMonster :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
+
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/PassiveMonster.cpp b/src/Mobs/Old Mobs/PassiveMonster.cpp
new file mode 100644
index 000000000..2861d7314
--- /dev/null
+++ b/src/Mobs/Old Mobs/PassiveMonster.cpp
@@ -0,0 +1,65 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "PassiveMonster.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
+ super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
+{
+ m_EMPersonality = PASSIVE;
+}
+
+
+
+
+
+bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+ if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL))
+ {
+ m_EMState = ESCAPING;
+ }
+ return true;
+}
+
+
+
+
+
+void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_EMState == ESCAPING)
+ {
+ CheckEventLostPlayer();
+ }
+ cItem FollowedItem = GetFollowedItem();
+ if (FollowedItem.IsEmpty())
+ {
+ return;
+ }
+ cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance);
+ if (a_Closest_Player != NULL)
+ {
+ if (a_Closest_Player->GetEquippedItem().IsEqual(FollowedItem))
+ {
+ Vector3d PlayerPos = a_Closest_Player->GetPosition();
+ MoveToPosition(PlayerPos);
+ }
+ }
+}
+
+
+
+
+
diff --git a/src/Mobs/Old Mobs/PassiveMonster.h b/src/Mobs/Old Mobs/PassiveMonster.h
new file mode 100644
index 000000000..70574585a
--- /dev/null
+++ b/src/Mobs/Old Mobs/PassiveMonster.h
@@ -0,0 +1,30 @@
+
+#pragma once
+
+#include "Monster.h"
+
+
+
+
+
+class cPassiveMonster :
+ public cMonster
+{
+ typedef cMonster super;
+
+public:
+ cPassiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
+
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ /// When hit by someone, run away
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ /** Returns the item that the animal of this class follows when a player holds it in hand
+ Return an empty item not to follow (default). */
+ virtual const cItem GetFollowedItem(void) const { return cItem(); }
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Pig.cpp b/src/Mobs/Old Mobs/Pig.cpp
new file mode 100644
index 000000000..1f77cf613
--- /dev/null
+++ b/src/Mobs/Old Mobs/Pig.cpp
@@ -0,0 +1,100 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Pig.h"
+#include "../Entities/Player.h"
+#include "../World.h"
+
+
+
+
+
+cPig::cPig(void) :
+ super("Pig", mtPig, "mob.pig.say", "mob.pig.death", 0.9, 0.9),
+ m_bIsSaddled(false)
+{
+}
+
+
+
+
+
+void cPig::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 1, 3 + LootingLevel, IsOnFire() ? E_ITEM_COOKED_PORKCHOP : E_ITEM_RAW_PORKCHOP);
+ if (m_bIsSaddled)
+ {
+ a_Drops.push_back(cItem(E_ITEM_SADDLE, 1));
+ }
+}
+
+
+
+
+
+void cPig::OnRightClicked(cPlayer & a_Player)
+{
+ if (m_bIsSaddled)
+ {
+ if (m_Attachee != NULL)
+ {
+ if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
+ {
+ // This player is already sitting in, they want out.
+ a_Player.Detach();
+ return;
+ }
+
+ if (m_Attachee->IsPlayer())
+ {
+ // Another player is already sitting in here, cannot attach
+ return;
+ }
+
+ // Detach whatever is sitting in this pig now:
+ m_Attachee->Detach();
+ }
+
+ // Attach the player to this pig
+ a_Player.AttachTo(this);
+ }
+ else if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SADDLE)
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+
+ // Set saddle state & broadcast metadata
+ m_bIsSaddled = true;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
+void cPig::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ // If the attachee player is holding a carrot-on-stick, let them drive this pig:
+ if (m_bIsSaddled && (m_Attachee != NULL))
+ {
+ if (m_Attachee->IsPlayer() && (m_Attachee->GetEquippedWeapon().m_ItemType == E_ITEM_CARROT_ON_STICK))
+ {
+ MoveToPosition((m_Attachee->GetPosition()) + (m_Attachee->GetLookVector()*10));
+ m_bMovingToDestination = true;
+ }
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Pig.h b/src/Mobs/Old Mobs/Pig.h
new file mode 100644
index 000000000..534a0ca6f
--- /dev/null
+++ b/src/Mobs/Old Mobs/Pig.h
@@ -0,0 +1,36 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cPig :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cPig(void);
+
+ CLASS_PROTODEF(cPig)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_CARROT); }
+
+ bool IsSaddled(void) const { return m_bIsSaddled; }
+
+private:
+
+ bool m_bIsSaddled;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Sheep.cpp b/src/Mobs/Old Mobs/Sheep.cpp
new file mode 100644
index 000000000..9fb47201d
--- /dev/null
+++ b/src/Mobs/Old Mobs/Sheep.cpp
@@ -0,0 +1,154 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Sheep.h"
+#include "../BlockID.h"
+#include "../Entities/Player.h"
+#include "../World.h"
+#include "FastRandom.h"
+
+
+
+
+
+cSheep::cSheep(int a_Color) :
+ super("Sheep", mtSheep, "mob.sheep.say", "mob.sheep.say", 0.6, 1.3),
+ m_IsSheared(false),
+ m_WoolColor(a_Color),
+ m_TimeToStopEating(-1)
+{
+ // Generate random wool color.
+ if (m_WoolColor == -1)
+ {
+ m_WoolColor = GenerateNaturalRandomColor();
+ }
+
+ if ((m_WoolColor < 0) || (m_WoolColor > 15))
+ {
+ m_WoolColor = 0;
+ }
+}
+
+
+
+
+
+void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ if (!m_IsSheared)
+ {
+ a_Drops.push_back(cItem(E_BLOCK_WOOL, 1, m_WoolColor));
+ }
+}
+
+
+
+
+
+void cSheep::OnRightClicked(cPlayer & a_Player)
+{
+ const cItem & EquippedItem = a_Player.GetEquippedItem();
+ if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
+ {
+ m_IsSheared = true;
+ m_World->BroadcastEntityMetadata(*this);
+ a_Player.UseEquippedItem();
+
+ cItems Drops;
+ int NumDrops = m_World->GetTickRandomNumber(2) + 1;
+ Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor));
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
+ m_World->BroadcastSoundEffect("mob.sheep.shear", GetPosX(), GetPosY(), GetPosZ(), 1.0f, 1.0f);
+ }
+ else if ((EquippedItem.m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - EquippedItem.m_ItemDamage))
+ {
+ m_WoolColor = 15 - EquippedItem.m_ItemDamage;
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ m_World->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
+void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+ int PosX = POSX_TOINT;
+ int PosY = POSY_TOINT - 1;
+ int PosZ = POSZ_TOINT;
+
+ if ((PosY <= 0) || (PosY > cChunkDef::Height))
+ {
+ return;
+ }
+
+ if (m_TimeToStopEating > 0)
+ {
+ m_bMovingToDestination = false; // The sheep should not move when he's eating
+ m_TimeToStopEating--;
+
+ if (m_TimeToStopEating == 0)
+ {
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
+ {
+ // The sheep ate the grass so we change it to dirt
+ m_World->SetBlock(PosX, PosY, PosZ, E_BLOCK_DIRT, 0);
+ GetWorld()->BroadcastSoundParticleEffect(2001, PosX, PosY, PosX, E_BLOCK_GRASS);
+ m_IsSheared = false;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+ }
+ }
+ else
+ {
+ if (m_World->GetTickRandomNumber(600) == 1)
+ {
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
+ {
+ m_World->BroadcastEntityStatus(*this, esSheepEating);
+ m_TimeToStopEating = 40;
+ }
+ }
+ }
+}
+
+
+
+
+
+NIBBLETYPE cSheep::GenerateNaturalRandomColor(void)
+{
+ cFastRandom Random;
+ int Chance = Random.NextInt(101);
+
+ if (Chance <= 81)
+ {
+ return E_META_WOOL_WHITE;
+ }
+ else if (Chance <= 86)
+ {
+ return E_META_WOOL_BLACK;
+ }
+ else if (Chance <= 91)
+ {
+ return E_META_WOOL_GRAY;
+ }
+ else if (Chance <= 96)
+ {
+ return E_META_WOOL_LIGHTGRAY;
+ }
+ else if (Chance <= 99)
+ {
+ return E_META_WOOL_BROWN;
+ }
+ else
+ {
+ return E_META_WOOL_PINK;
+ }
+}
+
diff --git a/src/Mobs/Old Mobs/Sheep.h b/src/Mobs/Old Mobs/Sheep.h
new file mode 100644
index 000000000..28e1c7254
--- /dev/null
+++ b/src/Mobs/Old Mobs/Sheep.h
@@ -0,0 +1,50 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cSheep :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+
+ /** The number is the color of the sheep.
+ Use E_META_WOOL_* constants for the wool color.
+ If you type -1, the server will generate a random color
+ with the GenerateNaturalRandomColor() function. */
+ cSheep(int a_Color = -1);
+
+ CLASS_PROTODEF(cSheep)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
+
+ /** Generates a random color for the sheep like the vanilla server.
+ The percent's where used are from the wiki: http://minecraft.gamepedia.com/Sheep#Breeding */
+ static NIBBLETYPE GenerateNaturalRandomColor(void);
+
+ bool IsSheared(void) const { return m_IsSheared; }
+ void SetSheared(bool a_IsSheared) { m_IsSheared = a_IsSheared; }
+
+ int GetFurColor(void) const { return m_WoolColor; }
+ void SetFurColor(int a_WoolColor) { m_WoolColor = a_WoolColor; }
+
+private:
+ bool m_IsSheared;
+ int m_WoolColor;
+ int m_TimeToStopEating;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Silverfish.h b/src/Mobs/Old Mobs/Silverfish.h
new file mode 100644
index 000000000..2df333dbc
--- /dev/null
+++ b/src/Mobs/Old Mobs/Silverfish.h
@@ -0,0 +1,26 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cSilverfish :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cSilverfish(void) :
+ super("Silverfish", mtSilverfish, "mob.silverfish.hit", "mob.silverfish.kill", 0.3, 0.7)
+ {
+ }
+
+ CLASS_PROTODEF(cSilverfish)
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Skeleton.cpp b/src/Mobs/Old Mobs/Skeleton.cpp
new file mode 100644
index 000000000..cd707f4bb
--- /dev/null
+++ b/src/Mobs/Old Mobs/Skeleton.cpp
@@ -0,0 +1,107 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Skeleton.h"
+#include "../World.h"
+#include "../Entities/ArrowEntity.h"
+#include "ClientHandle.h"
+
+
+
+
+cSkeleton::cSkeleton(bool IsWither) :
+ super("Skeleton", mtSkeleton, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8),
+ m_bIsWither(IsWither)
+{
+ SetBurnsInDaylight(true);
+}
+
+
+
+
+
+void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ if (IsWither())
+ {
+ AddRandomUncommonDropItem(a_Drops, 33.0f, E_ITEM_COAL);
+ cItems RareDrops;
+ RareDrops.Add(cItem(E_ITEM_HEAD, 1, 1));
+ AddRandomRareDropItem(a_Drops, RareDrops, LootingLevel);
+ }
+ else
+ {
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_ARROW);
+
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_BONE);
+ AddRandomArmorDropItem(a_Drops, LootingLevel);
+ AddRandomWeaponDropItem(a_Drops, LootingLevel);
+}
+
+
+
+
+
+void cSkeleton::MoveToPosition(const Vector3d & a_Position)
+{
+ // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
+ if (
+ !IsOnFire() &&
+ (m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8)
+ )
+ {
+ m_bMovingToDestination = false;
+ return;
+ }
+
+ super::MoveToPosition(a_Position);
+}
+
+
+
+
+
+void cSkeleton::Attack(float a_Dt)
+{
+ m_AttackInterval += a_Dt * m_AttackRate;
+
+ if (m_Target != NULL && m_AttackInterval > 3.0)
+ {
+ // Setting this higher gives us more wiggle room for attackrate
+ Vector3d Speed = GetLookVector() * 20;
+ Speed.y = Speed.y + 1;
+ cArrowEntity * Arrow = new cArrowEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed);
+ if (Arrow == NULL)
+ {
+ return;
+ }
+ if (!Arrow->Initialize(*m_World))
+ {
+ delete Arrow;
+ Arrow = NULL;
+ return;
+ }
+ m_World->BroadcastSpawnEntity(*Arrow);
+ m_AttackInterval = 0.0;
+ }
+}
+
+
+
+
+
+void cSkeleton::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ super::SpawnOn(a_ClientHandle);
+ a_ClientHandle.SendEntityEquipment(*this, 0, cItem(E_ITEM_BOW));
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Skeleton.h b/src/Mobs/Old Mobs/Skeleton.h
new file mode 100644
index 000000000..577588b32
--- /dev/null
+++ b/src/Mobs/Old Mobs/Skeleton.h
@@ -0,0 +1,37 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cSkeleton :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cSkeleton(bool IsWither);
+
+ CLASS_PROTODEF(cSkeleton)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void MoveToPosition(const Vector3d & a_Position) override;
+ virtual void Attack(float a_Dt) override;
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+
+ virtual bool IsUndead(void) override { return true; }
+
+ bool IsWither(void) const { return m_bIsWither; }
+
+private:
+
+ bool m_bIsWither;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Slime.cpp b/src/Mobs/Old Mobs/Slime.cpp
new file mode 100644
index 000000000..b709ec664
--- /dev/null
+++ b/src/Mobs/Old Mobs/Slime.cpp
@@ -0,0 +1,106 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Slime.h"
+#include "FastRandom.h"
+#include "World.h"
+
+
+
+
+
+cSlime::cSlime(int a_Size) :
+ super("Slime",
+ mtSlime,
+ Printf("mob.slime.%s", GetSizeName(a_Size).c_str()),
+ Printf("mob.slime.%s", GetSizeName(a_Size).c_str()),
+ 0.6 * a_Size,
+ 0.6 * a_Size
+ ),
+ m_Size(a_Size)
+{
+ SetMaxHealth(a_Size * a_Size);
+ SetAttackDamage(a_Size);
+}
+
+
+
+
+
+void cSlime::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+
+ // Only slimes with the size 1 can drop slimeballs.
+ if (m_Size == 1)
+ {
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_SLIMEBALL);
+ }
+}
+
+
+
+
+
+void cSlime::Attack(float a_Dt)
+{
+ if (m_Size > 1)
+ {
+ // Only slimes larger than size 1 attack a player.
+ super::Attack(a_Dt);
+ }
+}
+
+
+
+
+
+void cSlime::KilledBy(TakeDamageInfo & a_TDI)
+{
+ if (GetHealth() > 0)
+ {
+ return;
+ }
+
+ if (m_Size != 1)
+ {
+ cFastRandom Random;
+ int SpawnAmount = 2 + Random.NextInt(3);
+
+ for (int i = 0; i < SpawnAmount; ++i)
+ {
+ double AddX = (i % 2 - 0.5) * m_Size / 4.0;
+ double AddZ = (i / 2 - 0.5) * m_Size / 4.0;
+
+ cSlime * NewSlime = new cSlime(m_Size / 2);
+ NewSlime->SetPosition(GetPosX() + AddX, GetPosY() + 0.5, GetPosZ() + AddZ);
+ NewSlime->SetYaw(Random.NextFloat(1.0f) * 360.0f);
+ m_World->SpawnMobFinalize(NewSlime);
+ }
+ }
+ super::KilledBy(a_TDI);
+}
+
+
+
+
+
+const AString cSlime::GetSizeName(int a_Size) const
+{
+ if (a_Size > 1)
+ {
+ return "big";
+ }
+ else
+ {
+ return "small";
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Slime.h b/src/Mobs/Old Mobs/Slime.h
new file mode 100644
index 000000000..f0b800f94
--- /dev/null
+++ b/src/Mobs/Old Mobs/Slime.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cSlime :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ /** Creates a slime of the specified size; size can be 1, 2 or 4, with 1 is the smallest and 4 is the tallest. */
+ cSlime(int a_Size);
+
+ CLASS_PROTODEF(cSlime)
+
+ // cAggressiveMonster overrides:
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void Attack(float a_Dt) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
+ int GetSize(void) const { return m_Size; }
+
+ /** Returns the text describing the slime's size, as used by the client's resource subsystem for sounds.
+ Returns either "big" or "small". */
+ const AString GetSizeName(int a_Size) const;
+
+protected:
+
+ /** Size of the slime, with 1 being the smallest.
+ Vanilla uses sizes 1, 2 and 4 only. */
+ int m_Size;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/SnowGolem.cpp b/src/Mobs/Old Mobs/SnowGolem.cpp
new file mode 100644
index 000000000..76334d970
--- /dev/null
+++ b/src/Mobs/Old Mobs/SnowGolem.cpp
@@ -0,0 +1,46 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "SnowGolem.h"
+#include "../World.h"
+
+
+
+
+
+cSnowGolem::cSnowGolem(void) :
+ super("SnowGolem", mtSnowGolem, "", "", 0.4, 1.8)
+{
+}
+
+
+
+
+
+void cSnowGolem::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ UNUSED(a_Killer);
+ AddRandomDropItem(a_Drops, 0, 15, E_ITEM_SNOWBALL);
+}
+
+
+
+
+
+void cSnowGolem::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+ if (IsBiomeNoDownfall(m_World->GetBiomeAt((int) floor(GetPosX()), (int) floor(GetPosZ()))))
+ {
+ TakeDamage(*this);
+ }
+ else
+ {
+ BLOCKTYPE BlockBelow = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()) - 1, (int) floor(GetPosZ()));
+ BLOCKTYPE Block = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()));
+ if (Block == E_BLOCK_AIR && cBlockInfo::IsSolid(BlockBelow))
+ {
+ m_World->SetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()), E_BLOCK_SNOW, 0);
+ }
+ }
+}
diff --git a/src/Mobs/Old Mobs/SnowGolem.h b/src/Mobs/Old Mobs/SnowGolem.h
new file mode 100644
index 000000000..aba89e52d
--- /dev/null
+++ b/src/Mobs/Old Mobs/SnowGolem.h
@@ -0,0 +1,26 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cSnowGolem :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cSnowGolem(void);
+
+ CLASS_PROTODEF(cSnowGolem)
+
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Spider.cpp b/src/Mobs/Old Mobs/Spider.cpp
new file mode 100644
index 000000000..8b978ff6b
--- /dev/null
+++ b/src/Mobs/Old Mobs/Spider.cpp
@@ -0,0 +1,35 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Spider.h"
+
+
+
+
+
+cSpider::cSpider(void) :
+ super("Spider", mtSpider, "mob.spider.say", "mob.spider.death", 1.4, 0.9)
+{
+}
+
+
+
+
+
+void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_STRING);
+ if ((a_Killer != NULL) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf")))
+ {
+ AddRandomUncommonDropItem(a_Drops, 33.0f, E_ITEM_SPIDER_EYE);
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Spider.h b/src/Mobs/Old Mobs/Spider.h
new file mode 100644
index 000000000..813d2e266
--- /dev/null
+++ b/src/Mobs/Old Mobs/Spider.h
@@ -0,0 +1,25 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cSpider :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cSpider(void);
+
+ CLASS_PROTODEF(cSpider)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Squid.cpp b/src/Mobs/Old Mobs/Squid.cpp
new file mode 100644
index 000000000..bd0e141a0
--- /dev/null
+++ b/src/Mobs/Old Mobs/Squid.cpp
@@ -0,0 +1,62 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Squid.h"
+#include "../Vector3.h"
+#include "../Chunk.h"
+
+
+
+
+
+cSquid::cSquid(void) :
+ super("Squid", mtSquid, "", "", 0.95, 0.95)
+{
+}
+
+
+
+
+
+void cSquid::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ // Drops 0-3 Ink Sacs
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 3 + LootingLevel, E_ITEM_DYE, E_META_DYE_BLACK);
+}
+
+
+
+
+
+void cSquid::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ // We must first process current location, and only then tick, otherwise we risk processing a location in a chunk
+ // that is not where the entity currently resides (FS #411)
+
+ Vector3d Pos = GetPosition();
+
+ // TODO: Not a real behavior, but cool :D
+ int RelY = (int)floor(Pos.y);
+ if ((RelY < 0) || (RelY >= cChunkDef::Height))
+ {
+ return;
+ }
+ int RelX = (int)floor(Pos.x) - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = (int)floor(Pos.z) - a_Chunk.GetPosZ() * cChunkDef::Width;
+ BLOCKTYPE BlockType;
+ if (a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockType) && !IsBlockWater(BlockType) && !IsOnFire())
+ {
+ // Burn for 10 ticks, then decide again
+ StartBurning(10);
+ }
+
+ super::Tick(a_Dt, a_Chunk);
+}
+
+
+
diff --git a/src/Mobs/Old Mobs/Squid.h b/src/Mobs/Old Mobs/Squid.h
new file mode 100644
index 000000000..b57340427
--- /dev/null
+++ b/src/Mobs/Old Mobs/Squid.h
@@ -0,0 +1,31 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cSquid :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+ cSquid();
+
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ CLASS_PROTODEF(cSquid)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+
+ // Squids do not drown (or float)
+ virtual void HandleAir(void) override {}
+ virtual void SetSwimState(cChunk & a_Chunk) override {}
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Villager.cpp b/src/Mobs/Old Mobs/Villager.cpp
new file mode 100644
index 000000000..1cdac7c74
--- /dev/null
+++ b/src/Mobs/Old Mobs/Villager.cpp
@@ -0,0 +1,197 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Villager.h"
+#include "../World.h"
+#include "../BlockArea.h"
+#include "../Blocks/BlockHandler.h"
+#include "../BlockInServerPluginInterface.h"
+
+
+
+
+
+cVillager::cVillager(eVillagerType VillagerType) :
+ super("Villager", mtVillager, "", "", 0.6, 1.8),
+ m_ActionCountDown(-1),
+ m_Type(VillagerType),
+ m_VillagerAction(false)
+{
+}
+
+
+
+
+
+bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (!super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+
+ if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer())
+ {
+ if (m_World->GetTickRandomNumber(5) == 3)
+ {
+ m_World->BroadcastEntityStatus(*this, esVillagerAngry);
+ }
+ }
+ return true;
+}
+
+
+
+
+
+void cVillager::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_ActionCountDown > -1)
+ {
+ m_ActionCountDown--;
+ if (m_ActionCountDown == 0)
+ {
+ switch (m_Type)
+ {
+ case vtFarmer:
+ {
+ HandleFarmerPlaceCrops();
+ }
+ }
+ }
+ return;
+ }
+
+ if (m_VillagerAction)
+ {
+ switch (m_Type)
+ {
+ case vtFarmer:
+ {
+ HandleFarmerTryHarvestCrops();
+ }
+ }
+ m_VillagerAction = false;
+ return;
+ }
+
+ // Don't always try to do a special action. Each tick has 1% to do a special action.
+ if (m_World->GetTickRandomNumber(99) != 0)
+ {
+ return;
+ }
+
+ switch (m_Type)
+ {
+ case vtFarmer:
+ {
+ HandleFarmerPrepareFarmCrops();
+ }
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Farmer functions.
+void cVillager::HandleFarmerPrepareFarmCrops()
+{
+ if (!m_World->VillagersShouldHarvestCrops())
+ {
+ return;
+ }
+
+ cBlockArea Surrounding;
+ /// Read a 11x7x11 area.
+ Surrounding.Read(
+ m_World,
+ (int) GetPosX() - 5,
+ (int) GetPosX() + 5,
+ (int) GetPosY() - 3,
+ (int) GetPosY() + 3,
+ (int) GetPosZ() - 5,
+ (int) GetPosZ() + 5
+ );
+
+ for (int I = 0; I < 5; I++)
+ {
+ for (int Y = 0; Y < 6; Y++)
+ {
+ // Pick random coordinates and check for crops.
+ int X = m_World->GetTickRandomNumber(11);
+ int Z = m_World->GetTickRandomNumber(11);
+
+ // A villager can't farm this.
+ if (!IsBlockFarmable(Surrounding.GetRelBlockType(X, Y, Z)))
+ {
+ continue;
+ }
+ if (Surrounding.GetRelBlockMeta(X, Y, Z) != 0x7)
+ {
+ continue;
+ }
+
+ m_VillagerAction = true;
+ m_CropsPos = Vector3i((int) GetPosX() + X - 5, (int) GetPosY() + Y - 3, (int) GetPosZ() + Z - 5);
+ MoveToPosition(Vector3f((float) (m_CropsPos.x + 0.5), (float) m_CropsPos.y, (float) (m_CropsPos.z + 0.5)));
+ return;
+ } // for Y loop.
+ } // Repeat the procces 5 times.
+}
+
+
+
+
+
+void cVillager::HandleFarmerTryHarvestCrops()
+{
+ // Harvest the crops if the villager isn't moving and if the crops are closer then 2 blocks.
+ if (!m_bMovingToDestination && (GetPosition() - m_CropsPos).Length() < 2)
+ {
+ // Check if the blocks didn't change while the villager was walking to the coordinates.
+ BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
+ if (IsBlockFarmable(CropBlock) && m_World->GetBlockMeta(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z) == 0x7)
+ {
+ cBlockHandler * Handler = cBlockInfo::GetHandler(CropBlock);
+ cChunkInterface ChunkInterface(m_World->GetChunkMap());
+ cBlockInServerPluginInterface PluginInterface(*m_World);
+ Handler->DropBlock(ChunkInterface, *m_World, PluginInterface, this, m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
+ m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_AIR, 0);
+ m_ActionCountDown = 20;
+ }
+ }
+}
+
+
+
+
+void cVillager::HandleFarmerPlaceCrops()
+{
+ // Check if there is still farmland at the spot where the crops were.
+ if (m_World->GetBlock(m_CropsPos.x, m_CropsPos.y - 1, m_CropsPos.z) == E_BLOCK_FARMLAND)
+ {
+ m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_CROPS, 0);
+ }
+}
+
+
+
+
+
+bool cVillager::IsBlockFarmable(BLOCKTYPE a_BlockType)
+{
+ switch (a_BlockType)
+ {
+ case E_BLOCK_CROPS:
+ case E_BLOCK_POTATOES:
+ case E_BLOCK_CARROTS:
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/src/Mobs/Old Mobs/Villager.h b/src/Mobs/Old Mobs/Villager.h
new file mode 100644
index 000000000..aa81f0790
--- /dev/null
+++ b/src/Mobs/Old Mobs/Villager.h
@@ -0,0 +1,66 @@
+
+#pragma once
+
+#include "PassiveMonster.h"
+
+
+
+
+
+class cVillager :
+ public cPassiveMonster
+{
+ typedef cPassiveMonster super;
+
+public:
+
+ enum eVillagerType
+ {
+ vtFarmer = 0,
+ vtLibrarian = 1,
+ vtPriest = 2,
+ vtBlacksmith = 3,
+ vtButcher = 4,
+ vtGeneric = 5,
+ vtMax
+ } ;
+
+ cVillager(eVillagerType VillagerType);
+
+ CLASS_PROTODEF(cVillager)
+
+ // cEntity overrides
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
+
+ // cVillager functions
+ /** return true if the given blocktype are: crops, potatoes or carrots.*/
+ bool IsBlockFarmable(BLOCKTYPE a_BlockType);
+
+ // Farmer functions
+ /** Searches in a 11x7x11 area for crops. If it found some it will navigate to them.*/
+ void HandleFarmerPrepareFarmCrops();
+
+ /** Looks if the farmer has reached it's destination, and if it's still crops and the destination is closer then 2 blocks it will harvest them.*/
+ void HandleFarmerTryHarvestCrops();
+
+ /** Replaces the crops he harvested.*/
+ void HandleFarmerPlaceCrops();
+
+ // Get and set functions.
+ int GetVilType(void) const { return m_Type; }
+ Vector3i GetCropsPos(void) const { return m_CropsPos; }
+ bool DoesHaveActionActivated(void) const { return m_VillagerAction; }
+
+private:
+
+ int m_ActionCountDown;
+ int m_Type;
+ bool m_VillagerAction;
+ Vector3i m_CropsPos;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Witch.cpp b/src/Mobs/Old Mobs/Witch.cpp
new file mode 100644
index 000000000..6956f7b7a
--- /dev/null
+++ b/src/Mobs/Old Mobs/Witch.cpp
@@ -0,0 +1,47 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Witch.h"
+
+
+
+
+
+cWitch::cWitch(void) :
+ super("Witch", mtWitch, "", "", 0.6, 1.8)
+{
+}
+
+
+
+
+
+void cWitch::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ MTRand r1;
+ int DropTypeCount = (r1.randInt() % 3) + 1;
+ for (int i = 0; i < DropTypeCount; i++)
+ {
+ int DropType = r1.randInt() % 7;
+ switch (DropType)
+ {
+ case 0: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GLASS_BOTTLE); break;
+ case 1: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GLOWSTONE_DUST); break;
+ case 2: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER); break;
+ case 3: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_REDSTONE_DUST); break;
+ case 4: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_SPIDER_EYE); break;
+ case 5: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_STICK); break;
+ case 6: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_SUGAR); break;
+ }
+ }
+ AddRandomWeaponDropItem(a_Drops, LootingLevel);
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Witch.h b/src/Mobs/Old Mobs/Witch.h
new file mode 100644
index 000000000..bd059f61d
--- /dev/null
+++ b/src/Mobs/Old Mobs/Witch.h
@@ -0,0 +1,28 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+#include "../MersenneTwister.h"
+
+
+
+
+
+class cWitch :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cWitch();
+
+ CLASS_PROTODEF(cWitch)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+
+ bool IsAngry(void) const {return ((m_EMState == ATTACKING) || (m_EMState == CHASING)); }
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Wither.cpp b/src/Mobs/Old Mobs/Wither.cpp
new file mode 100644
index 000000000..578b47995
--- /dev/null
+++ b/src/Mobs/Old Mobs/Wither.cpp
@@ -0,0 +1,136 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Wither.h"
+
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cWither::cWither(void) :
+ super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
+ m_WitherInvulnerableTicks(220)
+{
+ SetMaxHealth(300);
+}
+
+
+
+
+
+bool cWither::IsArmored(void) const
+{
+ return GetHealth() <= (GetMaxHealth() / 2);
+}
+
+
+
+
+
+bool cWither::Initialize(cWorld & a_World)
+{
+ // Set health before BroadcastSpawnEntity()
+ SetHealth(GetMaxHealth() / 3);
+
+ return super::Initialize(a_World);
+}
+
+
+
+
+
+bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (a_TDI.DamageType == dtDrowning)
+ {
+ return false;
+ }
+
+ if (m_WitherInvulnerableTicks > 0)
+ {
+ return false;
+ }
+
+ if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
+ {
+ return false;
+ }
+
+ return super::DoTakeDamage(a_TDI);
+}
+
+
+
+
+
+void cWither::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_WitherInvulnerableTicks > 0)
+ {
+ unsigned int NewTicks = m_WitherInvulnerableTicks - 1;
+
+ if (NewTicks == 0)
+ {
+ m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
+ }
+
+ m_WitherInvulnerableTicks = NewTicks;
+
+ if ((NewTicks % 10) == 0)
+ {
+ Heal(10);
+ }
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cWither::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ AddRandomDropItem(a_Drops, 1, 1, E_ITEM_NETHER_STAR);
+}
+
+
+
+
+
+void cWither::KilledBy(TakeDamageInfo & a_TDI)
+{
+ super::KilledBy(a_TDI);
+
+ class cPlayerCallback : public cPlayerListCallback
+ {
+ Vector3f m_Pos;
+
+ virtual bool Item(cPlayer * a_Player)
+ {
+ // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one
+ double Dist = (a_Player->GetPosition() - m_Pos).Length();
+ if (Dist < 50.0)
+ {
+ // If player is close, award achievement
+ a_Player->AwardAchievement(achKillWither);
+ }
+ return false;
+ }
+
+ public:
+ cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
+
+ } PlayerCallback(GetPosition());
+
+ m_World->ForEachPlayer(PlayerCallback);
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Wither.h b/src/Mobs/Old Mobs/Wither.h
new file mode 100644
index 000000000..2403823ed
--- /dev/null
+++ b/src/Mobs/Old Mobs/Wither.h
@@ -0,0 +1,45 @@
+
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cWither :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cWither(void);
+
+ CLASS_PROTODEF(cWither)
+
+ unsigned int GetWitherInvulnerableTicks(void) const { return m_WitherInvulnerableTicks; }
+
+ void SetWitherInvulnerableTicks(unsigned int a_Ticks) { m_WitherInvulnerableTicks = a_Ticks; }
+
+ /** Returns whether the wither is invulnerable to arrows. */
+ bool IsArmored(void) const;
+
+ // cEntity overrides
+ virtual bool Initialize(cWorld & a_World) override;
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
+ virtual bool IsUndead(void) override { return true; }
+
+private:
+
+ /** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
+ unsigned int m_WitherInvulnerableTicks;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Wolf.cpp b/src/Mobs/Old Mobs/Wolf.cpp
new file mode 100644
index 000000000..4fe1ff1d6
--- /dev/null
+++ b/src/Mobs/Old Mobs/Wolf.cpp
@@ -0,0 +1,246 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Wolf.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+#include "../Items/ItemHandler.h"
+
+
+
+
+
+cWolf::cWolf(void) :
+ super("Wolf", mtWolf, "mob.wolf.hurt", "mob.wolf.death", 0.6, 0.8),
+ m_IsSitting(false),
+ m_IsTame(false),
+ m_IsBegging(false),
+ m_IsAngry(false),
+ m_OwnerName(""),
+ m_CollarColor(14)
+{
+}
+
+
+
+
+
+bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (super::DoTakeDamage(a_TDI))
+ {
+ return false;
+ }
+
+ if (!m_IsTame)
+ {
+ m_IsAngry = true;
+ }
+ m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
+ return true;
+}
+
+
+
+
+void cWolf::Attack(float a_Dt)
+{
+ UNUSED(a_Dt);
+
+ if ((m_Target != NULL) && (m_Target->IsPlayer()))
+ {
+ if (((cPlayer *)m_Target)->GetName() != m_OwnerName)
+ {
+ super::Attack(a_Dt);
+ }
+ }
+ else
+ {
+ super::Attack(a_Dt);
+ }
+}
+
+
+
+
+
+void cWolf::OnRightClicked(cPlayer & a_Player)
+{
+ if (!IsTame() && !IsAngry())
+ {
+ // If the player is holding a bone, try to tame the wolf:
+ if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_BONE)
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+
+ if (m_World->GetTickRandomNumber(7) == 0)
+ {
+ // Taming succeeded
+ SetMaxHealth(20);
+ SetIsTame(true);
+ SetOwner(a_Player.GetName(), a_Player.GetUUID());
+ m_World->BroadcastEntityStatus(*this, esWolfTamed);
+ m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
+ }
+ else
+ {
+ // Taming failed
+ m_World->BroadcastEntityStatus(*this, esWolfTaming);
+ m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
+ }
+ }
+ }
+ else if (IsTame())
+ {
+ // Feed the wolf, restoring its health, or dye its collar:
+ switch (a_Player.GetEquippedItem().m_ItemType)
+ {
+ case E_ITEM_RAW_BEEF:
+ case E_ITEM_STEAK:
+ case E_ITEM_RAW_PORKCHOP:
+ case E_ITEM_COOKED_PORKCHOP:
+ case E_ITEM_RAW_CHICKEN:
+ case E_ITEM_COOKED_CHICKEN:
+ case E_ITEM_ROTTEN_FLESH:
+ {
+ if (m_Health < m_MaxHealth)
+ {
+ Heal(ItemHandler(a_Player.GetEquippedItem().m_ItemType)->GetFoodInfo().FoodLevel);
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ }
+ break;
+ }
+ case E_ITEM_DYE:
+ {
+ if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
+ {
+ SetCollarColor(15 - a_Player.GetEquippedItem().m_ItemDamage);
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ }
+ break;
+ }
+ default:
+ {
+ if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
+ {
+ SetIsSitting(!IsSitting());
+ }
+ }
+ }
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cWolf::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ if (!IsAngry())
+ {
+ cMonster::Tick(a_Dt, a_Chunk);
+ }
+ else
+ {
+ super::Tick(a_Dt, a_Chunk);
+ }
+
+ cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance);
+ if (a_Closest_Player != NULL)
+ {
+ switch (a_Closest_Player->GetEquippedItem().m_ItemType)
+ {
+ case E_ITEM_BONE:
+ case E_ITEM_RAW_BEEF:
+ case E_ITEM_STEAK:
+ case E_ITEM_RAW_CHICKEN:
+ case E_ITEM_COOKED_CHICKEN:
+ case E_ITEM_ROTTEN_FLESH:
+ case E_ITEM_RAW_PORKCHOP:
+ case E_ITEM_COOKED_PORKCHOP:
+ {
+ if (!IsBegging())
+ {
+ SetIsBegging(true);
+ m_World->BroadcastEntityMetadata(*this);
+ }
+
+ m_FinalDestination = a_Closest_Player->GetPosition(); // So that we will look at a player holding food
+
+ // Don't move to the player if the wolf is sitting.
+ if (!IsSitting())
+ {
+ MoveToPosition(a_Closest_Player->GetPosition());
+ }
+
+ break;
+ }
+ default:
+ {
+ if (IsBegging())
+ {
+ SetIsBegging(false);
+ m_World->BroadcastEntityMetadata(*this);
+ }
+ }
+ }
+ }
+
+ if (IsTame() && !IsSitting())
+ {
+ TickFollowPlayer();
+ }
+ else if (IsSitting())
+ {
+ m_bMovingToDestination = false;
+ }
+}
+
+
+
+
+
+void cWolf::TickFollowPlayer()
+{
+ class cCallback :
+ public cPlayerListCallback
+ {
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ OwnerPos = a_Player->GetPosition();
+ return false;
+ }
+ public:
+ Vector3d OwnerPos;
+ } Callback;
+
+ if (m_World->DoWithPlayer(m_OwnerName, Callback))
+ {
+ // The player is present in the world, follow him:
+ double Distance = (Callback.OwnerPos - GetPosition()).Length();
+ if (Distance > 30)
+ {
+ Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z);
+ TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
+ }
+ else
+ {
+ MoveToPosition(Callback.OwnerPos);
+ }
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Wolf.h b/src/Mobs/Old Mobs/Wolf.h
new file mode 100644
index 000000000..7500854f8
--- /dev/null
+++ b/src/Mobs/Old Mobs/Wolf.h
@@ -0,0 +1,61 @@
+
+#pragma once
+
+#include "PassiveAggressiveMonster.h"
+#include "../Entities/Entity.h"
+
+
+
+
+
+class cWolf :
+ public cPassiveAggressiveMonster
+{
+ typedef cPassiveAggressiveMonster super;
+
+public:
+ cWolf(void);
+
+ CLASS_PROTODEF(cWolf)
+
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void TickFollowPlayer();
+ virtual void Attack(float a_Dt) override;
+
+ // Get functions
+ bool IsSitting (void) const { return m_IsSitting; }
+ bool IsTame (void) const { return m_IsTame; }
+ bool IsBegging (void) const { return m_IsBegging; }
+ bool IsAngry (void) const { return m_IsAngry; }
+ AString GetOwnerName (void) const { return m_OwnerName; }
+ AString GetOwnerUUID (void) const { return m_OwnerUUID; }
+ int GetCollarColor(void) const { return m_CollarColor; }
+
+ // Set functions
+ void SetIsSitting (bool a_IsSitting) { m_IsSitting = a_IsSitting; }
+ void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; }
+ void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; }
+ void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; }
+ void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; }
+ void SetOwner (const AString & a_NewOwnerName, const AString & a_NewOwnerUUID)
+ {
+ m_OwnerName = a_NewOwnerName;
+ m_OwnerUUID = a_NewOwnerUUID;
+ }
+
+protected:
+
+ bool m_IsSitting;
+ bool m_IsTame;
+ bool m_IsBegging;
+ bool m_IsAngry;
+ AString m_OwnerName;
+ AString m_OwnerUUID;
+ int m_CollarColor;
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Zombie.cpp b/src/Mobs/Old Mobs/Zombie.cpp
new file mode 100644
index 000000000..30225c32d
--- /dev/null
+++ b/src/Mobs/Old Mobs/Zombie.cpp
@@ -0,0 +1,62 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Zombie.h"
+#include "../World.h"
+#include "../LineBlockTracer.h"
+
+
+
+
+
+cZombie::cZombie(bool a_IsVillagerZombie) :
+ super("Zombie", mtZombie, "mob.zombie.hurt", "mob.zombie.death", 0.6, 1.8),
+ m_IsVillagerZombie(a_IsVillagerZombie),
+ m_IsConverting(false)
+{
+ SetBurnsInDaylight(true);
+}
+
+
+
+
+
+void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_ROTTEN_FLESH);
+ cItems RareDrops;
+ RareDrops.Add(cItem(E_ITEM_IRON));
+ RareDrops.Add(cItem(E_ITEM_CARROT));
+ RareDrops.Add(cItem(E_ITEM_POTATO));
+ AddRandomRareDropItem(a_Drops, RareDrops, LootingLevel);
+ AddRandomArmorDropItem(a_Drops, LootingLevel);
+ AddRandomWeaponDropItem(a_Drops, LootingLevel);
+}
+
+
+
+
+
+void cZombie::MoveToPosition(const Vector3d & a_Position)
+{
+ // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
+ if (
+ !IsOnFire() &&
+ (m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8)
+ )
+ {
+ m_bMovingToDestination = false;
+ return;
+ }
+
+ super::MoveToPosition(a_Position);
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/Zombie.h b/src/Mobs/Old Mobs/Zombie.h
new file mode 100644
index 000000000..118b6e6e7
--- /dev/null
+++ b/src/Mobs/Old Mobs/Zombie.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "AggressiveMonster.h"
+
+
+
+
+
+class cZombie :
+ public cAggressiveMonster
+{
+ typedef cAggressiveMonster super;
+
+public:
+ cZombie(bool a_IsVillagerZombie);
+
+ CLASS_PROTODEF(cZombie)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void MoveToPosition(const Vector3d & a_Position) override;
+
+ virtual bool IsUndead(void) override { return true; }
+
+ bool IsVillagerZombie(void) const { return m_IsVillagerZombie; }
+ bool IsConverting (void) const { return m_IsConverting; }
+
+private:
+
+ bool m_IsVillagerZombie;
+ bool m_IsConverting;
+
+} ;
+
+
+
+
diff --git a/src/Mobs/Old Mobs/ZombiePigman.cpp b/src/Mobs/Old Mobs/ZombiePigman.cpp
new file mode 100644
index 000000000..05350f877
--- /dev/null
+++ b/src/Mobs/Old Mobs/ZombiePigman.cpp
@@ -0,0 +1,53 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "ZombiePigman.h"
+#include "../World.h"
+
+
+
+
+
+cZombiePigman::cZombiePigman(void) :
+ super("ZombiePigman", mtZombiePigman, "mob.zombiepig.zpighurt", "mob.zombiepig.zpigdeath", 0.6, 1.8)
+{
+}
+
+
+
+
+
+void cZombiePigman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+{
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_ROTTEN_FLESH);
+ AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_GOLD_NUGGET);
+
+ cItems RareDrops;
+ RareDrops.Add(cItem(E_ITEM_GOLD));
+ AddRandomRareDropItem(a_Drops, RareDrops, LootingLevel);
+ AddRandomArmorDropItem(a_Drops, LootingLevel);
+ AddRandomWeaponDropItem(a_Drops, LootingLevel);
+}
+
+
+
+
+
+void cZombiePigman::KilledBy(TakeDamageInfo & a_TDI)
+{
+ super::KilledBy(a_TDI);
+
+ if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
+ {
+ // TODO: Anger all nearby zombie pigmen
+ // TODO: In vanilla, if one player angers ZPs, do they attack any nearby player, or only that one attacker?
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Old Mobs/ZombiePigman.h b/src/Mobs/Old Mobs/ZombiePigman.h
new file mode 100644
index 000000000..bae0115eb
--- /dev/null
+++ b/src/Mobs/Old Mobs/ZombiePigman.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "PassiveAggressiveMonster.h"
+
+
+
+
+
+class cZombiePigman :
+ public cPassiveAggressiveMonster
+{
+ typedef cPassiveAggressiveMonster super;
+
+public:
+ cZombiePigman(void);
+
+ CLASS_PROTODEF(cZombiePigman)
+
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
+ virtual bool IsUndead(void) override { return true; }
+} ;
+
+
+
+