summaryrefslogtreecommitdiffstats
path: root/src/Mobs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs')
-rw-r--r--src/Mobs/AggressiveMonster.cpp12
-rw-r--r--src/Mobs/CaveSpider.cpp15
-rw-r--r--src/Mobs/CaveSpider.h1
-rw-r--r--src/Mobs/Creeper.cpp30
-rw-r--r--src/Mobs/Horse.cpp2
-rw-r--r--src/Mobs/IronGolem.h2
-rw-r--r--src/Mobs/Monster.cpp91
-rw-r--r--src/Mobs/Monster.h35
-rw-r--r--src/Mobs/Pig.cpp20
-rw-r--r--src/Mobs/Pig.h1
-rw-r--r--src/Mobs/Sheep.cpp53
-rw-r--r--src/Mobs/Sheep.h19
-rw-r--r--src/Mobs/Skeleton.cpp22
-rw-r--r--src/Mobs/Skeleton.h4
-rw-r--r--src/Mobs/Villager.cpp6
-rw-r--r--src/Mobs/Villager.h5
-rw-r--r--src/Mobs/Wither.cpp4
-rw-r--r--src/Mobs/Wither.h2
-rw-r--r--src/Mobs/Wolf.cpp8
-rw-r--r--src/Mobs/Zombie.cpp7
-rw-r--r--src/Mobs/Zombie.h2
-rw-r--r--src/Mobs/ZombiePigman.cpp6
-rw-r--r--src/Mobs/ZombiePigman.h2
23 files changed, 238 insertions, 111 deletions
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 85b122034..5f5b1853d 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -42,7 +42,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt)
MoveToPosition(m_Target->GetPosition());
}
}
-}
+}
@@ -95,12 +95,14 @@ void cAggressiveMonster::Attack(float a_Dt)
{
m_AttackInterval += a_Dt * m_AttackRate;
- if ((m_Target != NULL) && (m_AttackInterval > 3.0))
+ if ((m_Target == NULL) || (m_AttackInterval < 3.0))
{
- // Setting this higher gives us more wiggle room for attackrate
- m_AttackInterval = 0.0;
- m_Target->TakeDamage(dtMobAttack, this, m_AttackDamage, 0);
+ return;
}
+
+ // Setting this higher gives us more wiggle room for attackrate
+ m_AttackInterval = 0.0;
+ m_Target->TakeDamage(dtMobAttack, this, m_AttackDamage, 0);
}
diff --git a/src/Mobs/CaveSpider.cpp b/src/Mobs/CaveSpider.cpp
index 1157b81f9..118a6e93b 100644
--- a/src/Mobs/CaveSpider.cpp
+++ b/src/Mobs/CaveSpider.cpp
@@ -27,6 +27,21 @@ void cCaveSpider::Tick(float a_Dt, cChunk & a_Chunk)
+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;
diff --git a/src/Mobs/CaveSpider.h b/src/Mobs/CaveSpider.h
index be9f174f9..3f8b2cece 100644
--- a/src/Mobs/CaveSpider.h
+++ b/src/Mobs/CaveSpider.h
@@ -17,6 +17,7 @@ public:
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/Creeper.cpp b/src/Mobs/Creeper.cpp
index a7b97f604..02718edf8 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -37,13 +37,13 @@ void cCreeper::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_bIsBlowing)
{
- m_ExplodingTimer += 1;
+ 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
+ Destroy(); // Just in case we aren't killed by the explosion
}
}
}
@@ -67,9 +67,27 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
}
AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);
- if ((a_Killer != NULL) && (a_Killer->IsProjectile()))
+ if ((a_Killer != NULL) && a_Killer->IsProjectile() && (((cProjectileEntity *)a_Killer)->GetCreatorUniqueID() >= 0))
{
- if (((cMonster *)((cProjectileEntity *)a_Killer)->GetCreator())->GetMobType() == mtSkeleton)
+ 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);
@@ -107,7 +125,7 @@ void cCreeper::Attack(float a_Dt)
if (!m_bIsBlowing)
{
- m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ 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);
}
@@ -125,7 +143,7 @@ void cCreeper::OnRightClicked(cPlayer & a_Player)
{
a_Player.UseEquippedItem();
}
- m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ 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/Horse.cpp b/src/Mobs/Horse.cpp
index 9d130301f..67a09d4ab 100644
--- a/src/Mobs/Horse.cpp
+++ b/src/Mobs/Horse.cpp
@@ -63,7 +63,7 @@ void cHorse::Tick(float a_Dt, cChunk & a_Chunk)
m_Attachee->Detach();
m_bIsRearing = true;
}
- }
+ }
else
{
m_bIsTame = true;
diff --git a/src/Mobs/IronGolem.h b/src/Mobs/IronGolem.h
index 41c60438c..30f9bedff 100644
--- a/src/Mobs/IronGolem.h
+++ b/src/Mobs/IronGolem.h
@@ -19,7 +19,7 @@ public:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- // Iron golems do not drown
+ // Iron golems do not drown nor float
virtual void HandleAir(void) override {}
virtual void SetSwimState(cChunk & a_Chunk) override {}
} ;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 89329dace..78ac36f91 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -46,8 +46,8 @@ static const struct
{cMonster::mtSheep, "sheep"},
{cMonster::mtSilverfish, "silverfish"},
{cMonster::mtSkeleton, "skeleton"},
- {cMonster::mtSnowGolem, "snowgolem"},
{cMonster::mtSlime, "slime"},
+ {cMonster::mtSnowGolem, "snowgolem"},
{cMonster::mtSpider, "spider"},
{cMonster::mtSquid, "squid"},
{cMonster::mtVillager, "villager"},
@@ -62,7 +62,7 @@ static const struct
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cMonster:
cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height)
@@ -115,12 +115,10 @@ void cMonster::TickPathFinding()
const int PosY = POSY_TOINT;
const int PosZ = POSZ_TOINT;
- m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z);
-
std::vector<Vector3d> m_PotentialCoordinates;
m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ));
- static const struct // Define which directions to try to move to
+ static const struct // Define which directions to try to move to
{
int x, z;
} gCrossCoords[] =
@@ -201,19 +199,6 @@ void cMonster::TickPathFinding()
-void cMonster::MoveToPosition(const Vector3f & a_Position)
-{
- FinishPathFinding();
-
- m_FinalDestination = a_Position;
- m_bMovingToDestination = true;
- TickPathFinding();
-}
-
-
-
-
-
void cMonster::MoveToPosition(const Vector3d & a_Position)
{
FinishPathFinding();
@@ -227,15 +212,7 @@ void cMonster::MoveToPosition(const Vector3d & a_Position)
bool cMonster::IsCoordinateInTraversedList(Vector3i a_Coords)
{
- for (std::vector<Vector3i>::const_iterator itr = m_TraversedCoordinates.begin(); itr != m_TraversedCoordinates.end(); ++itr)
- {
- if (itr->Equals(a_Coords))
- {
- return true;
- }
- }
-
- return false;
+ return (std::find(m_TraversedCoordinates.begin(), m_TraversedCoordinates.end(), a_Coords) != m_TraversedCoordinates.end());
}
@@ -296,17 +273,15 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_bOnGround)
{
- m_Destination.y = FindFirstNonAirBlockPosition(m_Destination.x, m_Destination.z);
-
if (DoesPosYRequireJump((int)floor(m_Destination.y)))
{
m_bOnGround = false;
- AddSpeedY(5.2); // Jump!!
+ AddSpeedY(5.2); // Jump!!
}
}
Vector3f Distance = m_Destination - GetPosition();
- if(!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
+ if(!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
{
Distance.y = 0;
Distance.Normalize();
@@ -325,20 +300,20 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
AddSpeedZ(Distance.z);
if (m_EMState == ESCAPING)
- { //Runs Faster when escaping :D otherwise they just walk away
+ { // 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
+ 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
+ TickPathFinding(); // We have reached the next point in our path, calculate another point
}
}
}
@@ -353,13 +328,13 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
// 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);
@@ -435,6 +410,7 @@ void cMonster::HandleFalling()
+
int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
{
int PosY = POSY_TOINT;
@@ -478,7 +454,7 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
if (!m_SoundHurt.empty() && (m_Health > 0))
{
- m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
+ m_World->BroadcastSoundEffect(m_SoundHurt, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
}
if (a_TDI.Attacker != NULL)
@@ -492,12 +468,12 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
-void cMonster::KilledBy(cEntity * a_Killer)
+void cMonster::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
if (m_SoundHurt != "")
{
- m_World->BroadcastSoundEffect(m_SoundDeath, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
+ m_World->BroadcastSoundEffect(m_SoundDeath, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
}
int Reward;
switch (m_MobType)
@@ -558,7 +534,7 @@ void cMonster::KilledBy(cEntity * a_Killer)
break;
}
}
- if ((a_Killer != NULL) && (!IsBaby()))
+ if ((a_TDI.Attacker != NULL) && (!IsBaby()))
{
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
}
@@ -569,8 +545,8 @@ void cMonster::KilledBy(cEntity * a_Killer)
-//Checks to see if EventSeePlayer should be fired
-//monster sez: Do I see the player
+// 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()
@@ -587,7 +563,7 @@ void cMonster::CheckEventSeePlayer(void)
void cMonster::CheckEventLostPlayer(void)
-{
+{
if (m_Target != NULL)
{
if ((m_Target->GetPosition() - GetPosition()).Length() > m_SightDistance)
@@ -630,7 +606,7 @@ void cMonster::InStateIdle(float a_Dt)
{
if (m_bMovingToDestination)
{
- return; // Still getting there
+ return; // Still getting there
}
m_IdleInterval += a_Dt;
@@ -639,7 +615,7 @@ void cMonster::InStateIdle(float a_Dt)
{
// 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
+ 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;
@@ -706,6 +682,25 @@ void cMonster::GetMonsterConfig(const AString & a_Name)
+bool cMonster::IsUndead(void)
+{
+ switch (GetMobType())
+ {
+ case mtZombie:
+ case mtZombiePigman:
+ case mtSkeleton:
+ case mtWither:
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
AString cMonster::MobTypeToString(cMonster::eType a_MobType)
{
// Mob types aren't sorted, so we need to search linearly:
@@ -900,7 +895,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
case mtMooshroom: toReturn = new cMooshroom(); break;
case mtOcelot: toReturn = new cOcelot(); break;
case mtPig: toReturn = new cPig(); break;
- case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter
+ case mtSheep: toReturn = new cSheep(); break;
case mtSilverfish: toReturn = new cSilverfish(); break;
case mtSnowGolem: toReturn = new cSnowGolem(); break;
case mtSpider: toReturn = new cSpider(); break;
@@ -908,7 +903,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
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 mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter
case mtZombiePigman: toReturn = new cZombiePigman(); break;
default:
{
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 7d7e90eb2..4af7cf4f1 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -61,13 +61,13 @@ public:
enum eFamily
{
- mfHostile = 0, // Spider, Zombies ...
- mfPassive = 1, // Cows, Pigs
- mfAmbient = 2, // Bats
- mfWater = 3, // Squid
+ 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
+ mfUnhandled, // Nothing. Be sure this is the last and the others are in order
} ;
// tolua_end
@@ -76,9 +76,9 @@ public:
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
+ 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);
@@ -90,10 +90,9 @@ public:
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
- virtual void MoveToPosition(const Vector3f & a_Position);
- virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
+ virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
virtual bool ReachedDestination(void);
// tolua_begin
@@ -107,6 +106,9 @@ public:
/// 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.) */
+ bool IsUndead(void);
+
virtual void EventLosePlayer(void);
virtual void CheckEventLostPlayer(void);
@@ -178,6 +180,7 @@ protected:
/** 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 */
@@ -229,7 +232,7 @@ protected:
AString m_SoundHurt;
AString m_SoundDeath;
- float m_AttackRate;
+ float m_AttackRate;
int m_AttackDamage;
int m_AttackRange;
float m_AttackInterval;
@@ -246,13 +249,13 @@ protected:
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);
+ 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);
+ 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);
+ 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);
@@ -261,7 +264,7 @@ protected:
void AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel);
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Mobs/Pig.cpp b/src/Mobs/Pig.cpp
index e862f5aaa..1f77cf613 100644
--- a/src/Mobs/Pig.cpp
+++ b/src/Mobs/Pig.cpp
@@ -78,3 +78,23 @@ void cPig::OnRightClicked(cPlayer & a_Player)
+
+
+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/Pig.h b/src/Mobs/Pig.h
index d434324c1..313af2f44 100644
--- a/src/Mobs/Pig.h
+++ b/src/Mobs/Pig.h
@@ -19,6 +19,7 @@ public:
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); }
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 5a6b760af..7335848b7 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -5,6 +5,7 @@
#include "../BlockID.h"
#include "../Entities/Player.h"
#include "../World.h"
+#include "FastRandom.h"
@@ -16,6 +17,16 @@ cSheep::cSheep(int a_Color) :
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;
+ }
}
@@ -37,7 +48,7 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player)
{
const cItem & EquippedItem = a_Player.GetEquippedItem();
- if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
+ if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
{
m_IsSheared = true;
m_World->BroadcastEntityMetadata(*this);
@@ -51,6 +62,7 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
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))
{
@@ -81,12 +93,12 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
if (m_TimeToStopEating > 0)
{
- m_bMovingToDestination = false; // The sheep should not move when he's eating
+ 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
+ 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);
@@ -109,3 +121,38 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
}
}
+
+
+
+
+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/Sheep.h b/src/Mobs/Sheep.h
index 402e8e61c..5ffd3e4fe 100644
--- a/src/Mobs/Sheep.h
+++ b/src/Mobs/Sheep.h
@@ -13,21 +13,32 @@ class cSheep :
typedef cPassiveMonster super;
public:
- cSheep(int a_Color);
-
+
+ /** 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/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index e3357185d..cd707f4bb 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -4,6 +4,7 @@
#include "Skeleton.h"
#include "../World.h"
#include "../Entities/ArrowEntity.h"
+#include "ClientHandle.h"
@@ -47,13 +48,12 @@ void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cSkeleton::MoveToPosition(const Vector3f & a_Position)
+void cSkeleton::MoveToPosition(const Vector3d & a_Position)
{
- // If the destination is in the sun and if it is not night AND the skeleton isn't on fire then block the movement.
+ // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
if (
!IsOnFire() &&
- (m_World->GetTimeOfDay() < 13187) &&
- (m_World->GetBlockSkyLight((int) a_Position.x, (int) a_Position.y, (int) a_Position.z) == 15)
+ (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;
@@ -91,3 +91,17 @@ void cSkeleton::Attack(float a_Dt)
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/Skeleton.h b/src/Mobs/Skeleton.h
index 8f31b42e1..efb670c83 100644
--- a/src/Mobs/Skeleton.h
+++ b/src/Mobs/Skeleton.h
@@ -18,8 +18,10 @@ public:
CLASS_PROTODEF(cSkeleton);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- virtual void MoveToPosition(const Vector3f & a_Position) override;
+ virtual void MoveToPosition(const Vector3d & a_Position) override;
virtual void Attack(float a_Dt) override;
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+
bool IsWither(void) const { return m_bIsWither; };
private:
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index 41283acf4..1cdac7c74 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -55,7 +55,7 @@ void cVillager::Tick(float a_Dt, cChunk & a_Chunk)
{
switch (m_Type)
{
- case vtFarmer:
+ case vtFarmer:
{
HandleFarmerPlaceCrops();
}
@@ -138,8 +138,8 @@ void cVillager::HandleFarmerPrepareFarmCrops()
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.
+ } // for Y loop.
+ } // Repeat the procces 5 times.
}
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index abde48407..068dfd835 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -37,9 +37,8 @@ public:
/** return true if the given blocktype are: crops, potatoes or carrots.*/
bool IsBlockFarmable(BLOCKTYPE a_BlockType);
- //////////////////////////////////////////////////////////////////
// Farmer functions
- /** It searches in a 11x7x11 area for crops. If it found some it will navigate to them.*/
+ /** 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.*/
@@ -49,7 +48,7 @@ public:
void HandleFarmerPlaceCrops();
// Get and set functions.
- int GetVilType(void) const { return m_Type; }
+ int GetVilType(void) const { return m_Type; }
Vector3i GetCropsPos(void) const { return m_CropsPos; }
bool DoesHaveActionActivated(void) const { return m_VillagerAction; }
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index da4cc7765..578b47995 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -103,9 +103,9 @@ void cWither::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cWither::KilledBy(cEntity * a_Killer)
+void cWither::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
class cPlayerCallback : public cPlayerListCallback
{
diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h
index 03a320788..7d76f70f5 100644
--- a/src/Mobs/Wither.h
+++ b/src/Mobs/Wither.h
@@ -29,7 +29,7 @@ public:
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(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
private:
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index e6268abc7..5bb97d30e 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -36,7 +36,7 @@ bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
{
m_IsAngry = true;
}
- m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
+ m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
return true;
}
@@ -114,7 +114,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
}
case E_ITEM_DYE:
{
- if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
+ 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())
@@ -126,7 +126,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
}
default:
{
- if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
+ if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
{
SetIsSitting(!IsSitting());
}
@@ -172,7 +172,7 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk)
m_World->BroadcastEntityMetadata(*this);
}
- m_FinalDestination = a_Closest_Player->GetPosition(); // So that we will look at a player holding food
+ 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())
diff --git a/src/Mobs/Zombie.cpp b/src/Mobs/Zombie.cpp
index f19e096ee..30225c32d 100644
--- a/src/Mobs/Zombie.cpp
+++ b/src/Mobs/Zombie.cpp
@@ -42,13 +42,12 @@ void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cZombie::MoveToPosition(const Vector3f & a_Position)
+void cZombie::MoveToPosition(const Vector3d & a_Position)
{
- // If the destination is in the sun and if it is not night AND the zombie isn't on fire then block the movement.
+ // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
if (
!IsOnFire() &&
- (m_World->GetTimeOfDay() < 13187) &&
- (m_World->GetBlockSkyLight((int)a_Position.x, (int)a_Position.y, (int)a_Position.z) == 15)
+ (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;
diff --git a/src/Mobs/Zombie.h b/src/Mobs/Zombie.h
index 1ba368f9c..c56409570 100644
--- a/src/Mobs/Zombie.h
+++ b/src/Mobs/Zombie.h
@@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cZombie);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- virtual void MoveToPosition(const Vector3f & a_Position) override;
+ virtual void MoveToPosition(const Vector3d & a_Position) override;
bool IsVillagerZombie(void) const {return m_IsVillagerZombie; }
bool IsConverting (void) const {return m_IsConverting; }
diff --git a/src/Mobs/ZombiePigman.cpp b/src/Mobs/ZombiePigman.cpp
index c9d94face..05350f877 100644
--- a/src/Mobs/ZombiePigman.cpp
+++ b/src/Mobs/ZombiePigman.cpp
@@ -37,11 +37,11 @@ void cZombiePigman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cZombiePigman::KilledBy(cEntity * a_Killer)
+void cZombiePigman::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
- if ((a_Killer != NULL) && (a_Killer->IsPlayer()))
+ 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/ZombiePigman.h b/src/Mobs/ZombiePigman.h
index ab3cebf6d..a2ebc87cb 100644
--- a/src/Mobs/ZombiePigman.h
+++ b/src/Mobs/ZombiePigman.h
@@ -17,7 +17,7 @@ public:
CLASS_PROTODEF(cZombiePigman);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
} ;