Improved tamed wolf pack cooperation and projectile reactions
This commit is contained in:
parent
30b95fcc4e
commit
439b3304f4
@ -191,7 +191,7 @@ MaxHealth=26
|
||||
SightDistance=25.0
|
||||
|
||||
[Wolf]
|
||||
AttackDamage=4.0
|
||||
AttackDamage=8.0
|
||||
AttackRange=2.0
|
||||
AttackRate=1
|
||||
MaxHealth=20
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
} ;
|
||||
bool Results[] = {true, true, true, false, true, false};
|
||||
double LineCoeffs[] = {2, 0.25, 0.5, 0, 0.25, 0};
|
||||
|
||||
|
||||
for (size_t i = 0; i < ARRAYCOUNT(LineDefs) / 2; i++)
|
||||
{
|
||||
double LineCoeff;
|
||||
@ -106,6 +106,16 @@ cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Hei
|
||||
|
||||
|
||||
|
||||
cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_CubeLength) :
|
||||
m_Min(a_Pos.x - a_CubeLength / 2, a_Pos.y - a_CubeLength / 2, a_Pos.z - a_CubeLength / 2),
|
||||
m_Max(a_Pos.x + a_CubeLength / 2, a_Pos.y + a_CubeLength / 2, a_Pos.z + a_CubeLength / 2)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBoundingBox::cBoundingBox(const cBoundingBox & a_Orig) :
|
||||
m_Min(a_Orig.m_Min),
|
||||
m_Max(a_Orig.m_Max)
|
||||
@ -269,10 +279,10 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d &
|
||||
a_Face = BLOCK_FACE_NONE; // No faces hit
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
eBlockFace Face = BLOCK_FACE_NONE;
|
||||
double Coeff = Vector3d::NO_INTERSECTION;
|
||||
|
||||
|
||||
// Check each individual bbox face for intersection with the line, remember the one with the lowest coeff
|
||||
double c = a_Line1.LineCoeffToXYPlane(a_Line2, a_Min.z);
|
||||
if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
|
||||
@ -310,13 +320,13 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d &
|
||||
Face = (a_Line1.x > a_Line2.x) ? BLOCK_FACE_XP : BLOCK_FACE_XM;
|
||||
Coeff = c;
|
||||
}
|
||||
|
||||
|
||||
if (Coeff >= Vector3d::NO_INTERSECTION)
|
||||
{
|
||||
// There has been no intersection
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
a_LineCoeff = Coeff;
|
||||
a_Face = Face;
|
||||
return true;
|
||||
|
@ -27,56 +27,57 @@ public:
|
||||
cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ);
|
||||
cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max);
|
||||
cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height);
|
||||
cBoundingBox(const Vector3d & a_Pos, double a_CubeLength);
|
||||
cBoundingBox(const cBoundingBox & a_Orig);
|
||||
|
||||
|
||||
/** Moves the entire boundingbox by the specified offset */
|
||||
void Move(double a_OffX, double a_OffY, double a_OffZ);
|
||||
|
||||
|
||||
/** Moves the entire boundingbox by the specified offset */
|
||||
void Move(const Vector3d & a_Off);
|
||||
|
||||
|
||||
/** Expands the bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each direction) */
|
||||
void Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ);
|
||||
|
||||
|
||||
/** Returns true if the two bounding boxes intersect */
|
||||
bool DoesIntersect(const cBoundingBox & a_Other);
|
||||
|
||||
|
||||
/** Returns the union of the two bounding boxes */
|
||||
cBoundingBox Union(const cBoundingBox & a_Other);
|
||||
|
||||
|
||||
/** Returns true if the point is inside the bounding box */
|
||||
bool IsInside(const Vector3d & a_Point);
|
||||
|
||||
|
||||
/** Returns true if the point is inside the bounding box */
|
||||
bool IsInside(double a_X, double a_Y, double a_Z);
|
||||
|
||||
|
||||
/** Returns true if a_Other is inside this bounding box */
|
||||
bool IsInside(cBoundingBox & a_Other);
|
||||
|
||||
|
||||
/** Returns true if a boundingbox specified by a_Min and a_Max is inside this bounding box */
|
||||
bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max);
|
||||
|
||||
|
||||
/** Returns true if the specified point is inside the bounding box specified by its min / max corners */
|
||||
static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point);
|
||||
|
||||
|
||||
/** Returns true if the specified point is inside the bounding box specified by its min / max corners */
|
||||
static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z);
|
||||
|
||||
|
||||
/** Returns true if this bounding box is intersected by the line specified by its two points
|
||||
Also calculates the distance along the line in which the intersection occurs (0 .. 1)
|
||||
Only forward collisions (a_LineCoeff >= 0) are returned. */
|
||||
bool CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face);
|
||||
|
||||
|
||||
/** Returns true if the specified bounding box is intersected by the line specified by its two points
|
||||
Also calculates the distance along the line in which the intersection occurs (0 .. 1) and the face hit (BLOCK_FACE_ constants)
|
||||
Only forward collisions (a_LineCoeff >= 0) are returned. */
|
||||
static bool CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face);
|
||||
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
||||
/** Calculates the intersection of the two bounding boxes; returns true if nonempty */
|
||||
bool Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection);
|
||||
|
||||
|
||||
double GetMinX(void) const { return m_Min.x; }
|
||||
double GetMinY(void) const { return m_Min.y; }
|
||||
double GetMinZ(void) const { return m_Min.z; }
|
||||
@ -84,14 +85,14 @@ public:
|
||||
double GetMaxX(void) const { return m_Max.x; }
|
||||
double GetMaxY(void) const { return m_Max.y; }
|
||||
double GetMaxZ(void) const { return m_Max.z; }
|
||||
|
||||
|
||||
const Vector3d & GetMin(void) const { return m_Min; }
|
||||
const Vector3d & GetMax(void) const { return m_Max; }
|
||||
|
||||
|
||||
protected:
|
||||
Vector3d m_Min;
|
||||
Vector3d m_Max;
|
||||
|
||||
|
||||
} ; // tolua_export
|
||||
|
||||
|
||||
|
@ -1642,7 +1642,7 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
|
||||
m_Me->AddFoodExhaustion(0.3);
|
||||
if (a_Entity->IsPawn())
|
||||
{
|
||||
m_Me->NotifyFriendlyWolves(static_cast<cPawn*>(a_Entity));
|
||||
m_Me->NotifyNearbyWolves(static_cast<cPawn*>(a_Entity), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
}
|
||||
|
||||
// a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount); // TODO fix knockback.
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 0); // Until knockback is fixed.
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), Damage, 0); // Until knockback is fixed.
|
||||
|
||||
if (IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming())
|
||||
{
|
||||
|
@ -238,6 +238,47 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
|
||||
|
||||
|
||||
|
||||
void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_RawDamage, double a_KnockbackAmount)
|
||||
{
|
||||
class cNotifyWolves : public cEntityCallback
|
||||
{
|
||||
public:
|
||||
|
||||
cEntity * m_Entity;
|
||||
eDamageType m_DamageType;
|
||||
int m_RawDamage;
|
||||
double m_KnockbackAmount;
|
||||
|
||||
virtual bool Item(cEntity * a_Attacker) override
|
||||
{
|
||||
cPawn * Attacker;
|
||||
if (a_Attacker->IsPawn())
|
||||
{
|
||||
Attacker = static_cast<cPawn*>(a_Attacker);
|
||||
}
|
||||
else
|
||||
{
|
||||
Attacker = nullptr;
|
||||
}
|
||||
|
||||
|
||||
int FinalDamage = m_RawDamage - m_Entity->GetArmorCoverAgainst(Attacker, m_DamageType, m_RawDamage);
|
||||
m_Entity->TakeDamage(m_DamageType, Attacker, m_RawDamage, FinalDamage, m_KnockbackAmount);
|
||||
return true;
|
||||
}
|
||||
} Callback;
|
||||
|
||||
Callback.m_Entity = this;
|
||||
Callback.m_DamageType = a_DamageType;
|
||||
Callback.m_RawDamage = a_RawDamage;
|
||||
Callback.m_KnockbackAmount = a_KnockbackAmount;
|
||||
m_World->DoWithEntityByID(a_AttackerID, Callback);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount)
|
||||
{
|
||||
TakeDamageInfo TDI;
|
||||
|
@ -263,6 +263,9 @@ public:
|
||||
/** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */
|
||||
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount);
|
||||
|
||||
/** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */
|
||||
void TakeDamage(eDamageType a_DamageType, UInt32 a_Attacker, int a_RawDamage, double a_KnockbackAmount);
|
||||
|
||||
/** Makes this entity take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage() */
|
||||
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount);
|
||||
|
||||
|
@ -862,7 +862,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if (a_TDI.Attacker->IsPawn())
|
||||
{
|
||||
NotifyFriendlyWolves(static_cast<cPawn*>(a_TDI.Attacker));
|
||||
NotifyNearbyWolves(static_cast<cPawn*>(a_TDI.Attacker), true);
|
||||
}
|
||||
}
|
||||
m_Stats.AddValue(statDamageTaken, FloorC<StatValue>(a_TDI.FinalDamage * 10 + 0.5));
|
||||
@ -875,7 +875,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
|
||||
|
||||
void cPlayer::NotifyFriendlyWolves(cPawn * a_Opponent)
|
||||
void cPlayer::NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved)
|
||||
{
|
||||
ASSERT(a_Opponent != nullptr);
|
||||
class LookForWolves : public cEntityCallback
|
||||
@ -883,10 +883,12 @@ void cPlayer::NotifyFriendlyWolves(cPawn * a_Opponent)
|
||||
public:
|
||||
cPlayer * m_Player;
|
||||
cPawn * m_Attacker;
|
||||
bool m_IsPlayerInvolved;
|
||||
|
||||
LookForWolves(cPlayer * a_Me, cPawn * a_MyAttacker) :
|
||||
LookForWolves(cPlayer * a_Me, cPawn * a_MyAttacker, bool a_PlayerInvolved) :
|
||||
m_Player(a_Me),
|
||||
m_Attacker(a_MyAttacker)
|
||||
m_Attacker(a_MyAttacker),
|
||||
m_IsPlayerInvolved(a_PlayerInvolved)
|
||||
{
|
||||
}
|
||||
|
||||
@ -898,14 +900,14 @@ void cPlayer::NotifyFriendlyWolves(cPawn * a_Opponent)
|
||||
if (Mob->GetMobType() == mtWolf)
|
||||
{
|
||||
cWolf * Wolf = static_cast<cWolf*>(Mob);
|
||||
Wolf->NearbyPlayerIsFighting(m_Player, m_Attacker);
|
||||
Wolf->ReceiveNearbyFightInfo(m_Player->GetUUID(), m_Attacker, m_IsPlayerInvolved);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} Callback(this, a_Opponent);
|
||||
} Callback(this, a_Opponent, a_IsPlayerInvolved);
|
||||
|
||||
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16, 16), Callback);
|
||||
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16), Callback);
|
||||
}
|
||||
|
||||
|
||||
|
@ -499,8 +499,11 @@ public:
|
||||
Assumes that all the blocks are in currently loaded chunks. */
|
||||
bool PlaceBlocks(const sSetBlockVector & a_Blocks);
|
||||
|
||||
/** Notify friendly wolves that we took damage or did damage to an entity so that they might assist us. */
|
||||
void NotifyFriendlyWolves(cPawn * a_Opponent);
|
||||
/** Notify nearby wolves that the player or one of the player's wolves took damage or did damage to an entity
|
||||
@param a_Opponent the opponent we're fighting.
|
||||
@param a_IsPlayerInvolved Should be true if the player took or did damage, and false if one of the player's wolves took or did damage.
|
||||
*/
|
||||
void NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved);
|
||||
|
||||
// cEntity overrides:
|
||||
virtual bool IsCrouched (void) const override { return m_IsCrouched; }
|
||||
|
@ -314,26 +314,24 @@ void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_
|
||||
|
||||
void cProjectileEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
if (a_EntityHit.IsPawn() && (GetCreatorName() != "")) // If we're hitting a mob or a player and we were created by a player
|
||||
{
|
||||
UNUSED(a_HitPos);
|
||||
|
||||
// If we were created by a player and we hit a pawn, notify attacking player's wolves
|
||||
if (a_EntityHit.IsPawn() && (GetCreatorName() != ""))
|
||||
{
|
||||
class cNotifyWolves : public cEntityCallback
|
||||
{
|
||||
public:
|
||||
cPawn * m_EntityHit;
|
||||
|
||||
cNotifyWolves(cPawn * a_Entity) :
|
||||
m_EntityHit(a_Entity)
|
||||
virtual bool Item(cEntity * a_Hitter) override
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Item(cEntity * a_Player) override
|
||||
{
|
||||
static_cast<cPlayer*>(a_Player)->NotifyFriendlyWolves(m_EntityHit);
|
||||
static_cast<cPlayer*>(a_Hitter)->NotifyNearbyWolves(m_EntityHit, true);
|
||||
return true;
|
||||
}
|
||||
} Callback(static_cast<cPawn*>(&a_EntityHit));
|
||||
} Callback;
|
||||
|
||||
Callback.m_EntityHit = static_cast<cPawn*>(&a_EntityHit);
|
||||
m_World->DoWithEntityByID(GetCreatorUniqueID(), Callback);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d &
|
||||
}
|
||||
}
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), TotalDamage, 1);
|
||||
|
||||
m_DestroyTimer = 5;
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ cWolf::cWolf(void) :
|
||||
m_IsBegging(false),
|
||||
m_IsAngry(false),
|
||||
m_OwnerName(""),
|
||||
m_CollarColor(E_META_DYE_ORANGE)
|
||||
m_CollarColor(E_META_DYE_ORANGE),
|
||||
m_NotificationCooldown(0)
|
||||
{
|
||||
m_RelativeWalkSpeed = 2;
|
||||
}
|
||||
@ -29,15 +30,42 @@ cWolf::cWolf(void) :
|
||||
|
||||
bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
cEntity * PreviousTarget = m_Target;
|
||||
if (!super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_IsTame)
|
||||
if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn())
|
||||
{
|
||||
m_IsAngry = true;
|
||||
cPawn * Pawn = static_cast<cPawn*>(m_Target);
|
||||
if (Pawn->IsPlayer())
|
||||
{
|
||||
if (m_IsTame)
|
||||
{
|
||||
if ((static_cast<cPlayer*>(Pawn)->GetUUID() == m_OwnerUUID))
|
||||
{
|
||||
m_Target = 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
|
||||
return true;
|
||||
}
|
||||
@ -46,56 +74,94 @@ bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
|
||||
|
||||
void cWolf::NotifyAlliesOfFight(cPawn * a_Opponent)
|
||||
{
|
||||
if (GetOwnerName() == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_NotificationCooldown = 15;
|
||||
class cCallback : public cPlayerListCallback
|
||||
{
|
||||
virtual bool Item(cPlayer * a_Player) override
|
||||
{
|
||||
a_Player->NotifyNearbyWolves(m_Opponent, false);
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
cPawn * m_Opponent;
|
||||
} Callback;
|
||||
|
||||
Callback.m_Opponent = a_Opponent;
|
||||
m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback);
|
||||
}
|
||||
|
||||
bool cWolf::Attack(std::chrono::milliseconds a_Dt)
|
||||
{
|
||||
UNUSED(a_Dt);
|
||||
|
||||
if ((m_Target != nullptr) && (m_Target->IsPlayer()))
|
||||
{
|
||||
if (static_cast<cPlayer *>(m_Target)->GetName() != m_OwnerName)
|
||||
{
|
||||
return super::Attack(a_Dt);
|
||||
}
|
||||
else
|
||||
if (static_cast<cPlayer *>(m_Target)->GetUUID() == m_OwnerUUID)
|
||||
{
|
||||
m_Target = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return super::Attack(a_Dt);
|
||||
}
|
||||
|
||||
return false;
|
||||
NotifyAlliesOfFight(static_cast<cPawn*>(m_Target));
|
||||
return super::Attack(a_Dt);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWolf::NearbyPlayerIsFighting(cPlayer * a_Player, cPawn * a_Opponent)
|
||||
void cWolf::ReceiveNearbyFightInfo(AString a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved)
|
||||
{
|
||||
if (a_Opponent == nullptr)
|
||||
if (
|
||||
(a_Opponent == nullptr) || IsSitting() || (!IsTame()) ||
|
||||
(!a_Opponent->IsPawn()) || (a_PlayerID != m_OwnerUUID)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((m_Target == nullptr) && (a_Player->GetName() == m_OwnerName) && !IsSitting() && (a_Opponent->IsPawn()))
|
||||
|
||||
// If we already have a target
|
||||
if (m_Target != nullptr)
|
||||
{
|
||||
m_Target = a_Opponent;
|
||||
if (m_Target->IsPlayer() && static_cast<cPlayer *>(m_Target)->GetName() == m_OwnerName)
|
||||
// If a wolf is asking for help and we already have a target, do nothing
|
||||
if (!a_IsPlayerInvolved)
|
||||
{
|
||||
m_Target = nullptr; // Our owner has hurt himself, avoid attacking them.
|
||||
return;
|
||||
}
|
||||
if (m_Target->IsMob() && static_cast<cMonster *>(m_Target)->GetMobType() == mtWolf)
|
||||
// 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
|
||||
else if (m_World->GetTickRandomNumber(9)> 4)
|
||||
{
|
||||
cWolf * Wolf = static_cast<cWolf *>(m_Target);
|
||||
if (Wolf->GetOwnerUUID() == GetOwnerUUID())
|
||||
{
|
||||
m_Target = nullptr; // Our owner attacked one of their wolves. Abort attacking wolf.
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
m_Target = a_Opponent;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -156,7 +222,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.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog?
|
||||
{
|
||||
SetCollarColor(a_Player.GetEquippedItem().m_ItemDamage);
|
||||
if (!a_Player.IsGameModeCreative())
|
||||
@ -168,7 +234,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.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog?
|
||||
{
|
||||
SetIsSitting(!IsSitting());
|
||||
}
|
||||
@ -188,6 +254,10 @@ 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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -275,13 +345,13 @@ void cWolf::TickFollowPlayer()
|
||||
virtual bool Item(cPlayer * a_Player) override
|
||||
{
|
||||
OwnerPos = a_Player->GetPosition();
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
Vector3d OwnerPos;
|
||||
} Callback;
|
||||
|
||||
if (m_World->DoWithPlayer(m_OwnerName, Callback))
|
||||
if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback))
|
||||
{
|
||||
// The player is present in the world, follow him:
|
||||
double Distance = (Callback.OwnerPos - GetPosition()).Length();
|
||||
|
@ -18,6 +18,7 @@ public:
|
||||
|
||||
CLASS_PROTODEF(cWolf)
|
||||
|
||||
void NotifyAlliesOfFight(cPawn * a_Opponent);
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
@ -45,13 +46,14 @@ public:
|
||||
m_OwnerUUID = a_NewOwnerUUID;
|
||||
}
|
||||
|
||||
/** Notfies the wolf that the player a_Player is being attacked by a_Attacker.
|
||||
The wolf will then defend the player by attacking a_Attacker if all these conditions are met:
|
||||
- a_Player is the wolf's owner.
|
||||
- The wolf is not already attacking a mob.
|
||||
- The wolf is not sitting.
|
||||
This is called by cPlayer::NotifyFriendlyWolves whenever a player takes or deals damage and a wolf is nearby. */
|
||||
void NearbyPlayerIsFighting(cPlayer * a_Player, cPawn * a_Opponent);
|
||||
/** Notfies the wolf of a nearby fight.
|
||||
The wolf may then decide to attack a_Opponent.
|
||||
If a_IsPlayer is true, then the player whose ID is a_PlayerID is fighting a_Opponent
|
||||
If false, then a wolf owned by the player whose ID is a_PlayerID is fighting a_Opponent
|
||||
@param a_PlayerID The ID of the fighting player, or the ID of the owner whose wolf is fighting.
|
||||
@param a_Opponent The opponent who is being faught.
|
||||
@param a_IsPlayerInvolved Whether the fighter a player or a wolf. */
|
||||
void ReceiveNearbyFightInfo(AString a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved);
|
||||
|
||||
virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
@ -64,6 +66,7 @@ protected:
|
||||
AString m_OwnerName;
|
||||
AString m_OwnerUUID;
|
||||
int m_CollarColor;
|
||||
int m_NotificationCooldown;
|
||||
} ;
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user