Cuberite
A lightweight, fast and extensible game server for Minecraft
Wolf.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "Wolf.h"
5 #include "../World.h"
6 #include "../Entities/Player.h"
7 #include "../Items/ItemHandler.h"
8 #include "../Items/ItemSpawnEgg.h"
9 
10 
11 
12 
13 
14 cWolf::cWolf(void) :
15  Super("Wolf", mtWolf, "entity.wolf.hurt", "entity.wolf.death", "entity.wolf.ambient", 0.6f, 0.85f),
16  m_IsSitting(false),
17  m_IsTame(false),
18  m_IsBegging(false),
19  m_IsAngry(false),
20  m_CollarColor(E_META_DYE_ORANGE),
21  m_NotificationCooldown(0)
22 {
24 }
25 
26 
27 
28 
29 
31 {
32  cPawn * PreviousTarget = GetTarget();
33  if (!Super::DoTakeDamage(a_TDI))
34  {
35  return false;
36  }
37 
38  if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn())
39  {
40  auto currTarget = GetTarget();
41  if ((currTarget != nullptr) && currTarget->IsPlayer())
42  {
43  if (m_IsTame)
44  {
45  if ((static_cast<cPlayer*>(currTarget)->GetUUID() == m_OwnerUUID))
46  {
47  SetTarget(PreviousTarget); // Do not attack owner
48  }
49  else
50  {
51  SetIsSitting(false);
52  NotifyAlliesOfFight(static_cast<cPawn*>(a_TDI.Attacker));
53  }
54  }
55  else
56  {
57  m_IsAngry = true;
58  }
59  }
60  else if (m_IsTame)
61  {
62  SetIsSitting(false);
63  NotifyAlliesOfFight(static_cast<cPawn*>(a_TDI.Attacker));
64  }
65  }
66 
67  m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
68  return true;
69 }
70 
71 
72 
73 
74 
76 {
77  if (GetOwnerName() == "")
78  {
79  return;
80  }
82 
84  {
85  a_Player.NotifyNearbyWolves(a_Opponent, false);
86  return false;
87  }
88  );
89 }
90 
91 
92 
93 
94 
95 bool cWolf::Attack(std::chrono::milliseconds a_Dt)
96 {
97  UNUSED(a_Dt);
98 
99  if ((GetTarget() != nullptr) && (GetTarget()->IsPlayer()))
100  {
101  if (static_cast<cPlayer *>(GetTarget())->GetUUID() == m_OwnerUUID)
102  {
103  SetTarget(nullptr);
104  return false;
105  }
106  }
107 
108  NotifyAlliesOfFight(static_cast<cPawn*>(GetTarget()));
109  return Super::Attack(a_Dt);
110 
111 }
112 
113 
114 
115 
116 
117 void cWolf::ReceiveNearbyFightInfo(const cUUID & a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved)
118 {
119  if (
120  (a_Opponent == nullptr) || IsSitting() || (!IsTame()) ||
121  (!a_Opponent->IsPawn()) || (a_PlayerID != m_OwnerUUID)
122  )
123  {
124  return;
125  }
126 
127  // If we already have a target
128  if (GetTarget() != nullptr)
129  {
130  // If a wolf is asking for help and we already have a target, do nothing
131  if (!a_IsPlayerInvolved)
132  {
133  return;
134  }
135  // If a player is asking for help and we already have a target,
136  // there's a 50% chance of helping and a 50% chance of doing nothing
137  // This helps spread a wolf pack's targets over several mobs
138  else if (GetRandomProvider().RandBool())
139  {
140  return;
141  }
142  }
143 
144  if (a_Opponent->IsPlayer() && static_cast<cPlayer *>(a_Opponent)->GetUUID() == m_OwnerUUID)
145  {
146  return; // Our owner has hurt himself, avoid attacking them.
147  }
148 
149  if (a_Opponent->IsMob() && static_cast<cMonster *>(a_Opponent)->GetMobType() == mtWolf)
150  {
151  cWolf * Wolf = static_cast<cWolf *>(a_Opponent);
152  if (Wolf->GetOwnerUUID() == GetOwnerUUID())
153  {
154  return; // Our owner attacked one of their wolves. Abort attacking wolf.
155  }
156  }
157 
158  SetTarget(a_Opponent);
159 
160 
161 }
162 
163 
164 
165 
166 
168 {
169  cMonster::OnRightClicked(a_Player);
170  const cItem & EquippedItem = a_Player.GetEquippedItem();
171  const int EquippedItemType = EquippedItem.m_ItemType;
172 
173  if (!IsTame() && !IsAngry())
174  {
175  // If the player is holding a bone, try to tame the wolf:
176  if (EquippedItemType == E_ITEM_BONE)
177  {
178  if (!a_Player.IsGameModeCreative())
179  {
180  a_Player.GetInventory().RemoveOneEquippedItem();
181  }
182 
183  if (GetRandomProvider().RandBool(0.125))
184  {
185  // Taming succeeded
186  SetMaxHealth(20);
187  SetIsTame(true);
188  SetOwner(a_Player.GetName(), a_Player.GetUUID());
190  }
191  else
192  {
193  // Taming failed
195  }
196  }
197  }
198  else if (IsTame())
199  {
200  if (a_Player.GetUUID() == m_OwnerUUID)
201  {
202  cMonster::RightClickFeed(a_Player);
203  }
204  // Feed the wolf, restoring its health, or dye its collar:
205  switch (EquippedItemType)
206  {
207  case E_ITEM_RAW_BEEF:
208  case E_ITEM_STEAK:
209  case E_ITEM_RAW_PORKCHOP:
211  case E_ITEM_RAW_CHICKEN:
213  case E_ITEM_ROTTEN_FLESH:
214  case E_ITEM_RAW_MUTTON:
215  case E_ITEM_RAW_RABBIT:
218  {
219  if (m_Health < m_MaxHealth)
220  {
221  Heal(EquippedItem.GetHandler().GetFoodInfo(&EquippedItem).FoodLevel);
222  if (!a_Player.IsGameModeCreative())
223  {
224  a_Player.GetInventory().RemoveOneEquippedItem();
225  }
226  }
227  else if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog?
228  {
229  if (IsBaby())
230  {
232  }
233  }
234  break;
235  }
236  case E_ITEM_DYE:
237  {
238  if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog?
239  {
240  SetCollarColor(EquippedItem.m_ItemDamage);
241  if (!a_Player.IsGameModeCreative())
242  {
243  a_Player.GetInventory().RemoveOneEquippedItem();
244  }
245  }
246  break;
247  }
248  // Multiplication is handled in cMonster. Just prevents from sitting down.
249  case E_ITEM_SPAWN_EGG:
250  {
251  break;
252  }
253  default:
254  {
255  if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog?
256  {
258  }
259  }
260  }
261  }
262 
263  if ((EquippedItemType == E_ITEM_SPAWN_EGG) && (!IsTame()))
264  {
266  if (
267  (MonsterType == m_MobType) &&
268  (m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), m_MobType, true) != cEntity::INVALID_ID)) // Spawning succeeded
269  {
270  if (!a_Player.IsGameModeCreative())
271  {
272  // The mob was spawned, "use" the item:
273  a_Player.GetInventory().RemoveOneEquippedItem();
274  }
275  }
276  }
277 
279 }
280 
281 
282 
283 
284 
285 void cWolf::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
286 {
287  if (!IsAngry())
288  {
289  cMonster::Tick(a_Dt, a_Chunk);
290  if (m_NotificationCooldown > 0)
291  {
293  }
294  }
295  else
296  {
297  Super::Tick(a_Dt, a_Chunk);
298  }
299 
300  if (!IsTicking())
301  {
302  // The base class tick destroyed us
303  return;
304  }
305 
306  if (GetTarget() == nullptr)
307  {
308  m_World->DoWithNearestPlayer(GetPosition(), static_cast<float>(m_SightDistance), [&](cPlayer & a_Player) -> bool
309  {
310  switch (a_Player.GetEquippedItem().m_ItemType)
311  {
312  case E_ITEM_BONE:
313  case E_ITEM_RAW_BEEF:
314  case E_ITEM_STEAK:
315  case E_ITEM_RAW_CHICKEN:
316  case E_ITEM_COOKED_CHICKEN:
317  case E_ITEM_ROTTEN_FLESH:
318  case E_ITEM_RAW_PORKCHOP:
319  case E_ITEM_COOKED_PORKCHOP:
320  {
321  if (!IsBegging())
322  {
323  SetIsBegging(true);
324  m_World->BroadcastEntityMetadata(*this);
325  }
326 
327  m_FinalDestination = a_Player.GetPosition(); // So that we will look at a player holding food
328 
329  // Don't move to the player if the wolf is sitting.
330  if (!IsSitting())
331  {
332  MoveToPosition(a_Player.GetPosition());
333  }
334 
335  break;
336  }
337  default:
338  {
339  if (IsBegging())
340  {
341  SetIsBegging(false);
342  m_World->BroadcastEntityMetadata(*this);
343  }
344  }
345  }
346 
347  return true;
348  });
349  }
350  else
351  {
352  if (IsSitting())
353  {
354  SetTarget(nullptr);
355  }
356  else
357  {
358  MoveToPosition(GetTarget()->GetPosition());
359  if (TargetIsInRange())
360  {
361  Attack(a_Dt);
362  }
363  }
364  }
365 
366  if (IsTame() && !IsSitting())
367  {
368  TickFollowPlayer();
369  }
370  else if (IsSitting())
371  {
372  StopMovingToPosition();
373  }
374 
376 }
377 
378 
379 
380 
381 
383 {
384  Vector3d OwnerPos;
385  bool OwnerFlying;
386  auto Callback = [&](cPlayer & a_Player)
387  {
388  OwnerPos = a_Player.GetPosition();
389  OwnerFlying = a_Player.IsFlying();
390  return true;
391  };
392 
393  if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback))
394  {
395  // The player is present in the world, follow him:
396  double Distance = (OwnerPos - GetPosition()).Length();
397  if (Distance > 20)
398  {
399  if (!OwnerFlying)
400  {
401  OwnerPos.y = FindFirstNonAirBlockPosition(OwnerPos.x, OwnerPos.z);
402  TeleportToCoords(OwnerPos.x, OwnerPos.y, OwnerPos.z);
403  SetTarget(nullptr);
404  }
405  }
406  if (Distance < 2)
407  {
408  if (GetTarget() == nullptr)
409  {
411  }
412  }
413  else
414  {
415  if (GetTarget() == nullptr)
416  {
417  if (!OwnerFlying)
418  {
419  MoveToPosition(OwnerPos);
420  }
421  }
422  }
423  }
424 }
425 
426 
427 
428 
429 
430 void cWolf::InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
431 {
432  if (!IsTame())
433  {
434  cMonster::InStateIdle(a_Dt, a_Chunk);
435  }
436 }
437 
438 
439 
440 
441 
442 void cWolf::InheritFromParents(cMonster * a_Parent1, cMonster * a_Parent2)
443 {
444  const auto Parent1 = static_cast<cWolf *>(a_Parent1);
445  const auto Parent2 = static_cast<cWolf *>(a_Parent2);
446  if (Parent1->GetOwnerUUID() == Parent2->GetOwnerUUID())
447  {
448  SetOwner(Parent1->GetOwnerName(), Parent2->GetOwnerUUID());
449  }
450  else
451  {
452  auto Parent1Age = Parent1->GetAge();
453  auto Parent2Age = Parent2->GetAge();
454 
455  if (Parent1Age > Parent2Age)
456  {
457  SetOwner(Parent2->GetOwnerName(), Parent2->GetOwnerUUID());
458  }
459  else
460  {
461  SetOwner(Parent1->GetOwnerName(), Parent1->GetOwnerUUID());
462  }
463  }
464 }
@ E_ITEM_RAW_RABBIT
Definition: BlockType.h:457
@ E_ITEM_RAW_CHICKEN
Definition: BlockType.h:410
@ E_ITEM_STEAK
Definition: BlockType.h:409
@ E_ITEM_ROTTEN_FLESH
Definition: BlockType.h:412
@ E_ITEM_RAW_PORKCHOP
Definition: BlockType.h:363
@ E_ITEM_DYE
Definition: BlockType.h:396
@ E_ITEM_COOKED_RABBIT
Definition: BlockType.h:458
@ E_ITEM_COOKED_CHICKEN
Definition: BlockType.h:411
@ E_ITEM_SPAWN_EGG
Definition: BlockType.h:429
@ E_ITEM_RAW_BEEF
Definition: BlockType.h:408
@ E_ITEM_RAW_MUTTON
Definition: BlockType.h:470
@ E_ITEM_COOKED_PORKCHOP
Definition: BlockType.h:364
@ E_ITEM_BONE
Definition: BlockType.h:397
@ E_ITEM_COOKED_MUTTON
Definition: BlockType.h:471
@ E_META_DYE_ORANGE
Definition: BlockType.h:1059
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
#define UNUSED
Definition: Globals.h:72
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default).
Definition: Globals.h:347
eMonsterType
Identifies individual monster type.
Definition: MonsterTypes.h:11
@ mtWolf
Definition: MonsterTypes.h:77
unsigned char Distance(const BlockState Block)
Definition: Chunk.h:36
cEntity * Attacker
Definition: Entity.h:62
Definition: Entity.h:76
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
Teleports to the coordinates specified.
Definition: Entity.cpp:1953
float m_Health
Definition: Entity.h:584
bool IsPlayer(void) const
Definition: Entity.h:160
static const UInt32 INVALID_ID
Special ID that is considered an "invalid value", signifying no entity.
Definition: Entity.h:128
bool IsTicking(void) const
Returns true if the entity is valid and ticking.
Definition: Entity.cpp:2259
float m_MaxHealth
Definition: Entity.h:585
double GetPosX(void) const
Definition: Entity.h:195
cWorld * m_World
Definition: Entity.h:624
double GetPosZ(void) const
Definition: Entity.h:197
double GetPosY(void) const
Definition: Entity.h:196
bool IsPawn(void) const
Definition: Entity.h:163
void SetMaxHealth(float a_MaxHealth)
Sets the maximum value for the health.
Definition: Entity.cpp:1887
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:297
virtual void Heal(int a_HitPoints)
Heals the specified amount of HPs.
Definition: Entity.cpp:890
bool IsMob(void) const
Definition: Entity.h:162
Definition: Pawn.h:17
Definition: Player.h:29
const AString & GetName(void) const
Definition: Player.cpp:1299
const cUUID & GetUUID(void) const
Returns the UUID that has been read from the client, or nil if not available.
Definition: Player.cpp:2431
const cItem & GetEquippedItem(void) const
Definition: Player.h:162
void NotifyNearbyWolves(cPawn *a_Opponent, bool a_IsPlayerInvolved)
Notify nearby wolves that the player or one of the player's wolves took damage or did damage to an en...
Definition: Player.cpp:831
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1025
cInventory & GetInventory(void)
Definition: Player.h:156
bool RemoveOneEquippedItem(void)
Removes one item out of the currently equipped item stack, returns true if successful,...
Definition: Inventory.cpp:232
Definition: Item.h:37
const cItemHandler & GetHandler(void) const
Returns the cItemHandler responsible for this item type.
Definition: Item.cpp:216
short m_ItemType
Definition: Item.h:163
short m_ItemDamage
Definition: Item.h:165
virtual FoodInfo GetFoodInfo(const cItem *a_Item) const
Returns the FoodInfo for this item.
static eMonsterType ItemDamageToMonsterType(short a_ItemDamage)
Converts the Spawn egg item damage to the monster type to spawn.
Definition: ItemSpawnEgg.h:64
virtual bool Attack(std::chrono::milliseconds a_Dt)
Try to perform attack returns true if attack was deemed successful (hit player, fired projectile,...
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
double m_RelativeWalkSpeed
Definition: Monster.h:328
int m_SightDistance
Definition: Monster.h:314
void LoveTick(void)
Does the whole love and breeding processing.
Definition: Monster.cpp:1354
void SetTarget(cPawn *a_NewTarget)
Sets the target that this mob will chase.
Definition: Monster.cpp:1204
virtual void MoveToPosition(const Vector3d &a_Position)
Engage pathfinder and tell it to calculate a path to a given position, and move the mob accordingly.
Definition: Monster.cpp:245
cPawn * GetTarget()
Returns the current target.
Definition: Monster.cpp:1243
virtual void OnRightClicked(cPlayer &a_Player) override
Called when the specified player right-clicks this entity.
Definition: Monster.cpp:697
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Definition: Monster.cpp:264
int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does) If current Y is ...
Definition: Monster.cpp:543
int m_AgingTimer
Definition: Monster.h:333
eMonsterType GetMobType(void) const
Definition: Monster.h:70
eMonsterType m_MobType
Definition: Monster.h:302
virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk &a_Chunk)
Definition: Monster.cpp:851
void RightClickFeed(cPlayer &a_Player)
Right click call to process feeding.
Definition: Monster.cpp:1474
bool IsBaby(void) const
Definition: Monster.h:156
void StopMovingToPosition()
Stops pathfinding.
Definition: Monster.cpp:255
virtual bool DoTakeDamage(TakeDamageInfo &a_TDI) override
Makes this entity take damage specified in the a_TDI.
Definition: Wolf.h:14
cWolf()
Definition: Wolf.cpp:14
virtual bool DoTakeDamage(TakeDamageInfo &a_TDI) override
Makes this entity take damage specified in the a_TDI.
Definition: Wolf.cpp:30
void SetIsTame(bool a_IsTame)
Definition: Wolf.h:41
void SetIsSitting(bool a_IsSitting)
Definition: Wolf.h:40
cUUID GetOwnerUUID(void) const
Definition: Wolf.h:36
AString GetOwnerName(void) const
Definition: Wolf.h:35
void SetOwner(const AString &a_NewOwnerName, const cUUID &a_NewOwnerUUID)
Definition: Wolf.h:45
void SetCollarColor(int a_CollarColor)
Definition: Wolf.h:44
cUUID m_OwnerUUID
Definition: Wolf.h:86
virtual void TickFollowPlayer()
Definition: Wolf.cpp:382
int m_NotificationCooldown
Definition: Wolf.h:88
bool IsSitting(void) const override
Definition: Wolf.h:31
virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Definition: Wolf.cpp:430
virtual void InheritFromParents(cMonster *a_Parent1, cMonster *a_Parent2) override
Called after the baby is born, allows the baby to inherit the parents' properties (color,...
Definition: Wolf.cpp:442
void NotifyAlliesOfFight(cPawn *a_Opponent)
Definition: Wolf.cpp:75
virtual bool Attack(std::chrono::milliseconds a_Dt) override
Try to perform attack returns true if attack was deemed successful (hit player, fired projectile,...
Definition: Wolf.cpp:95
void ReceiveNearbyFightInfo(const cUUID &a_PlayerUUID, cPawn *a_Opponent, bool a_IsPlayerInvolved)
Notfies the wolf of a nearby fight.
Definition: Wolf.cpp:117
bool IsAngry(void) const
Definition: Wolf.h:34
bool m_IsAngry
Definition: Wolf.h:84
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Definition: Wolf.cpp:285
bool IsTame(void) const override
Definition: Wolf.h:32
virtual void OnRightClicked(cPlayer &a_Player) override
Called when the specified player right-clicks this entity.
Definition: Wolf.cpp:167
bool m_IsTame
Definition: Wolf.h:82
Definition: UUID.h:11
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
bool DoWithPlayerByUUID(const cUUID &a_PlayerUUID, cPlayerListCallback a_Callback)
Finds the player over his uuid and calls the callback.
Definition: World.cpp:2339
virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby=false) override
Spawns a mob of the specified type.
Definition: World.cpp:2897
virtual void BroadcastEntityMetadata(const cEntity &a_Entity, const cClientHandle *a_Exclude=nullptr) override
virtual void BroadcastEntityAnimation(const cEntity &a_Entity, EntityAnimation a_Animation, const cClientHandle *a_Exclude=nullptr) override
bool DoWithNearestPlayer(Vector3d a_Pos, double a_RangeLimit, cPlayerListCallback a_Callback, bool a_CheckLineOfSight=true, bool a_IgnoreSpectator=true)
Calls the callback for nearest player for given position, Returns false if player not found,...
Definition: World.cpp:2356