diff options
Diffstat (limited to 'src/Mobs')
-rw-r--r-- | src/Mobs/AggressiveMonster.cpp | 12 | ||||
-rw-r--r-- | src/Mobs/CaveSpider.cpp | 15 | ||||
-rw-r--r-- | src/Mobs/CaveSpider.h | 1 | ||||
-rw-r--r-- | src/Mobs/Creeper.cpp | 30 | ||||
-rw-r--r-- | src/Mobs/Horse.cpp | 2 | ||||
-rw-r--r-- | src/Mobs/IronGolem.h | 2 | ||||
-rw-r--r-- | src/Mobs/Monster.cpp | 91 | ||||
-rw-r--r-- | src/Mobs/Monster.h | 35 | ||||
-rw-r--r-- | src/Mobs/Pig.cpp | 20 | ||||
-rw-r--r-- | src/Mobs/Pig.h | 1 | ||||
-rw-r--r-- | src/Mobs/Sheep.cpp | 53 | ||||
-rw-r--r-- | src/Mobs/Sheep.h | 19 | ||||
-rw-r--r-- | src/Mobs/Skeleton.cpp | 22 | ||||
-rw-r--r-- | src/Mobs/Skeleton.h | 4 | ||||
-rw-r--r-- | src/Mobs/Villager.cpp | 6 | ||||
-rw-r--r-- | src/Mobs/Villager.h | 5 | ||||
-rw-r--r-- | src/Mobs/Wither.cpp | 4 | ||||
-rw-r--r-- | src/Mobs/Wither.h | 2 | ||||
-rw-r--r-- | src/Mobs/Wolf.cpp | 8 | ||||
-rw-r--r-- | src/Mobs/Zombie.cpp | 7 | ||||
-rw-r--r-- | src/Mobs/Zombie.h | 2 | ||||
-rw-r--r-- | src/Mobs/ZombiePigman.cpp | 6 | ||||
-rw-r--r-- | src/Mobs/ZombiePigman.h | 2 |
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; } ; |