1
0
Fork 0
cuberite-2a/src/Mobs/Wolf.cpp

402 lines
7.6 KiB
C++
Raw Normal View History

#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"
2014-02-20 19:41:53 +00:00
#include "../Items/ItemHandler.h"
cWolf::cWolf(void) :
2017-02-15 05:05:24 +00:00
super("Wolf", mtWolf, "entity.wolf.hurt", "entity.wolf.death", 0.6, 0.8),
2013-11-10 20:24:36 +00:00
m_IsSitting(false),
m_IsTame(false),
2013-11-10 20:24:36 +00:00
m_IsBegging(false),
m_IsAngry(false),
2013-11-12 15:39:59 +00:00
m_OwnerName(""),
m_CollarColor(E_META_DYE_ORANGE),
m_NotificationCooldown(0)
{
m_RelativeWalkSpeed = 2;
}
2014-04-25 22:32:30 +00:00
bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
{
cPawn * PreviousTarget = GetTarget();
if (!super::DoTakeDamage(a_TDI))
2014-04-25 22:32:30 +00:00
{
return false;
}
if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn())
{
2016-11-20 17:10:54 +00:00
auto currTarget = GetTarget();
if ((currTarget != nullptr) && currTarget->IsPlayer())
{
if (m_IsTame)
{
2016-11-20 17:10:54 +00:00
if ((static_cast<cPlayer*>(currTarget)->GetUUID() == m_OwnerUUID))
{
SetTarget(PreviousTarget); // Do not attack owner
}
else
{
SetIsSitting(false);
NotifyAlliesOfFight(static_cast<cPawn*>(a_TDI.Attacker));
}
}
else
{
m_IsAngry = true;
}
}
else if (m_IsTame)
{
SetIsSitting(false);
NotifyAlliesOfFight(static_cast<cPawn*>(a_TDI.Attacker));
}
}
m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
2014-04-25 22:32:30 +00:00
return true;
}
2016-01-12 10:52:23 +00:00
void cWolf::NotifyAlliesOfFight(cPawn * a_Opponent)
{
if (GetOwnerName() == "")
{
return;
}
m_NotificationCooldown = 15;
m_World->DoWithPlayerByUUID(m_OwnerUUID, [=](cPlayer & a_Player)
{
a_Player.NotifyNearbyWolves(a_Opponent, false);
return false;
}
);
}
fix cavespider poisoning even if attack is in cooldown make attack function more responsive fix cavespider poisoning even if attack is in cooldown make attack function more responsive Merge branch 'cavespider-attack' of github.com:Gargaj/cuberite into cavespider-attack code style fix cavespider poisoning even if attack is in cooldown make attack function more responsive fix cavespider poisoning even if attack is in cooldown make attack function more responsive Merge branch 'cavespider-attack' of github.com:Gargaj/cuberite into cavespider-attack code style Merge branch 'cavespider-attack' of github.com:Gargaj/cuberite into cavespider-attack Merge branch 'master' into cavespider-attack Merge branch 'master' into cavespider-attack fix cavespider poisoning even if attack is in cooldown make attack function more responsive fix cavespider poisoning even if attack is in cooldown make attack function more responsive Merge branch 'cavespider-attack' of github.com:Gargaj/cuberite into cavespider-attack code style fix cavespider poisoning even if attack is in cooldown make attack function more responsive fix cavespider poisoning even if attack is in cooldown make attack function more responsive Merge branch 'cavespider-attack' of github.com:Gargaj/cuberite into cavespider-attack code style Merge branch 'cavespider-attack' of github.com:Gargaj/cuberite into cavespider-attack Merge branch 'master' into cavespider-attack Merge branch 'master' into cavespider-attack Merge branch 'cavespider-attack' of github.com:Gargaj/cuberite into cavespider-attack
2015-11-08 12:44:17 +00:00
bool cWolf::Attack(std::chrono::milliseconds a_Dt)
{
UNUSED(a_Dt);
if ((GetTarget() != nullptr) && (GetTarget()->IsPlayer()))
{
if (static_cast<cPlayer *>(GetTarget())->GetUUID() == m_OwnerUUID)
{
SetTarget(nullptr);
return false;
}
}
NotifyAlliesOfFight(static_cast<cPawn*>(GetTarget()));
return super::Attack(a_Dt);
}
2017-08-25 12:43:18 +00:00
void cWolf::ReceiveNearbyFightInfo(const cUUID & a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved)
{
if (
(a_Opponent == nullptr) || IsSitting() || (!IsTame()) ||
(!a_Opponent->IsPawn()) || (a_PlayerID != m_OwnerUUID)
)
{
return;
}
// If we already have a target
if (GetTarget() != nullptr)
{
// If a wolf is asking for help and we already have a target, do nothing
if (!a_IsPlayerInvolved)
2016-01-12 10:52:23 +00:00
{
return;
2016-01-12 10:52:23 +00:00
}
// If a player is asking for help and we already have a target,
// there's a 50% chance of helping and a 50% chance of doing nothing
// This helps spread a wolf pack's targets over several mobs
2017-06-13 19:35:30 +00:00
else if (GetRandomProvider().RandBool())
2016-01-12 10:52:23 +00:00
{
return;
2016-01-12 10:52:23 +00:00
}
}
if (a_Opponent->IsPlayer() && static_cast<cPlayer *>(a_Opponent)->GetUUID() == m_OwnerUUID)
{
return; // Our owner has hurt himself, avoid attacking them.
}
if (a_Opponent->IsMob() && static_cast<cMonster *>(a_Opponent)->GetMobType() == mtWolf)
{
cWolf * Wolf = static_cast<cWolf *>(a_Opponent);
if (Wolf->GetOwnerUUID() == GetOwnerUUID())
{
return; // Our owner attacked one of their wolves. Abort attacking wolf.
}
}
SetTarget(a_Opponent);
}
void cWolf::OnRightClicked(cPlayer & a_Player)
{
const cItem & EquippedItem = a_Player.GetEquippedItem();
const int EquippedItemType = EquippedItem.m_ItemType;
2013-11-10 20:55:32 +00:00
if (!IsTame() && !IsAngry())
{
2014-08-03 20:03:48 +00:00
// If the player is holding a bone, try to tame the wolf:
if (EquippedItemType == E_ITEM_BONE)
{
if (!a_Player.IsGameModeCreative())
{
a_Player.GetInventory().RemoveOneEquippedItem();
}
2017-06-13 19:35:30 +00:00
if (GetRandomProvider().RandBool(0.125))
{
2014-08-03 20:03:48 +00:00
// Taming succeeded
SetMaxHealth(20);
SetIsTame(true);
2014-08-03 20:03:48 +00:00
SetOwner(a_Player.GetName(), a_Player.GetUUID());
m_World->BroadcastEntityStatus(*this, esWolfTamed);
m_World->BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
}
else
{
2014-08-03 20:03:48 +00:00
// Taming failed
m_World->BroadcastEntityStatus(*this, esWolfTaming);
m_World->BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
}
}
}
else if (IsTame())
{
2014-08-03 20:03:48 +00:00
// Feed the wolf, restoring its health, or dye its collar:
switch (EquippedItemType)
{
2014-02-20 19:41:53 +00:00
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:
{
2014-02-20 19:41:53 +00:00
if (m_Health < m_MaxHealth)
{
Heal(ItemHandler(EquippedItemType)->GetFoodInfo(&EquippedItem).FoodLevel);
2014-02-20 19:41:53 +00:00
if (!a_Player.IsGameModeCreative())
{
a_Player.GetInventory().RemoveOneEquippedItem();
}
}
2014-02-20 19:41:53 +00:00
break;
}
case E_ITEM_DYE:
{
if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog?
2014-02-20 19:41:53 +00:00
{
SetCollarColor(EquippedItem.m_ItemDamage);
2014-02-20 19:41:53 +00:00
if (!a_Player.IsGameModeCreative())
{
a_Player.GetInventory().RemoveOneEquippedItem();
}
}
break;
}
2014-02-20 19:41:53 +00:00
default:
{
if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog?
2014-02-20 19:41:53 +00:00
{
SetIsSitting(!IsSitting());
}
}
}
}
2015-04-29 16:24:14 +00:00
m_World->BroadcastEntityMetadata(*this);
}
void cWolf::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
if (!IsAngry())
{
cMonster::Tick(a_Dt, a_Chunk);
if (m_NotificationCooldown > 0)
{
m_NotificationCooldown -= 1;
}
2013-11-10 20:55:32 +00:00
}
else
{
super::Tick(a_Dt, a_Chunk);
}
if (!IsTicking())
{
// The base class tick destroyed us
return;
}
if (GetTarget() == nullptr)
{
cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), static_cast<float>(m_SightDistance));
if (a_Closest_Player != nullptr)
{
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);
}
2014-02-16 13:47:55 +00:00
m_FinalDestination = a_Closest_Player->GetPosition(); // So that we will look at a player holding food
2014-02-16 17:08:49 +00:00
// 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);
}
}
}
}
}
else
{
if (IsSitting())
{
SetTarget(nullptr);
}
else
{
MoveToPosition(GetTarget()->GetPosition());
if (TargetIsInRange())
{
Attack(a_Dt);
}
}
}
2013-11-12 15:39:59 +00:00
2014-02-16 13:47:55 +00:00
if (IsTame() && !IsSitting())
2013-11-12 15:39:59 +00:00
{
TickFollowPlayer();
}
2014-02-16 17:08:49 +00:00
else if (IsSitting())
{
2015-04-29 16:24:14 +00:00
StopMovingToPosition();
2014-02-16 17:08:49 +00:00
}
2013-11-12 15:39:59 +00:00
}
void cWolf::TickFollowPlayer()
{
Vector3d OwnerPos;
bool OwnerFlying;
auto Callback = [&](cPlayer & a_Player)
{
OwnerPos = a_Player.GetPosition();
OwnerFlying = a_Player.IsFlying();
return true;
};
2014-02-16 13:47:55 +00:00
if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback))
{
// The player is present in the world, follow him:
double Distance = (OwnerPos - GetPosition()).Length();
if (Distance > 20)
2013-11-12 15:39:59 +00:00
{
if (!OwnerFlying)
{
OwnerPos.y = FindFirstNonAirBlockPosition(OwnerPos.x, OwnerPos.z);
TeleportToCoords(OwnerPos.x, OwnerPos.y, OwnerPos.z);
SetTarget(nullptr);
}
}
if (Distance < 2)
{
if (GetTarget() == nullptr)
{
StopMovingToPosition();
}
2013-11-12 15:39:59 +00:00
}
else
{
if (GetTarget() == nullptr)
{
if (!OwnerFlying)
{
MoveToPosition(OwnerPos);
}
}
}
}
2013-11-10 20:55:32 +00:00
}
void cWolf::InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
if (!IsTame())
{
cMonster::InStateIdle(a_Dt, a_Chunk);
}
}
2013-11-10 20:55:32 +00:00