Cuberite
A lightweight, fast and extensible game server for Minecraft
Monster.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 "IncludeAllMonsters.h"
5 #include "LineBlockTracer.h"
6 #include "../BlockInfo.h"
7 #include "../Root.h"
8 #include "../Server.h"
9 #include "../ClientHandle.h"
10 #include "../Items/ItemHandler.h"
11 #include "../World.h"
12 #include "../EffectID.h"
13 #include "../Entities/Player.h"
14 #include "../Entities/ExpOrb.h"
15 #include "../MonsterConfig.h"
16 #include "../BoundingBox.h"
17 
18 #include "Items/ItemSpawnEgg.h"
19 
20 #include "../Chunk.h"
21 #include "../FastRandom.h"
22 
23 #include "PathFinder.h"
24 #include "../Entities/LeashKnot.h"
25 
26 
27 
33 static const struct
34 {
36  const char * m_lcName;
37  const char * m_VanillaName;
38  const char * m_VanillaNameNBT;
39 } g_MobTypeNames[] =
40 {
41  {mtBat, "bat", "Bat", "bat"},
42  {mtBlaze, "blaze", "Blaze", "blaze"},
43  {mtCaveSpider, "cavespider", "CaveSpider", "cave_spider"},
44  {mtChicken, "chicken", "Chicken", "chicken"},
45  {mtCow, "cow", "Cow", "cow"},
46  {mtCreeper, "creeper", "Creeper", "creeper"},
47  {mtEnderman, "enderman", "Enderman", "enderman"},
48  {mtEndermite, "endermite", "Endermite", "endermite"},
49  {mtEnderDragon, "enderdragon", "EnderDragon", "ender_dragon"},
50  {mtGhast, "ghast", "Ghast", "ghast"},
51  {mtGiant, "giant", "Giant", "giant"},
52  {mtGuardian, "guardian", "Guardian", "guardian"},
53  {mtHorse, "horse", "EntityHorse", "horse"},
54  {mtIronGolem, "irongolem", "VillagerGolem", "iron_golem"},
55  {mtMagmaCube, "magmacube", "LavaSlime", "magma_cube"},
56  {mtMooshroom, "mooshroom", "MushroomCow", "mooshroom"},
57  {mtOcelot, "ocelot", "Ozelot", "ocelot"},
58  {mtPig, "pig", "Pig", "pig"},
59  {mtRabbit, "rabbit", "Rabbit", "rabbit"},
60  {mtSheep, "sheep", "Sheep", "sheep"},
61  {mtSilverfish, "silverfish", "Silverfish", "silverfish"},
62  {mtSkeleton, "skeleton", "Skeleton", "skeleton"},
63  {mtSlime, "slime", "Slime", "slime"},
64  {mtSnowGolem, "snowgolem", "SnowMan", "snow_golem"},
65  {mtSpider, "spider", "Spider", "spider"},
66  {mtSquid, "squid", "Squid", "squid"},
67  {mtVillager, "villager", "Villager", "villager"},
68  {mtWitch, "witch", "Witch", "witch"},
69  {mtWither, "wither", "WitherBoss", "wither"},
70  {mtWitherSkeleton, "witherskeleton", "WitherSkeleton", "wither_skeleton"},
71  {mtWolf, "wolf", "Wolf", "wolf"},
72  {mtZombie, "zombie", "Zombie", "zombie"},
73  {mtZombiePigman, "zombiepigman", "PigZombie", "zombie_pigman"},
74  {mtZombieVillager, "zombievillager", "ZombieVillager", "zombie_villager"},
75 } ;
76 
77 
78 
79 
80 
82 // cMonster:
83 
84 cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, const AString & a_SoundAmbient, float a_Width, float a_Height)
85  : Super(etMonster, a_Width, a_Height)
86  , m_EMState(IDLE)
87  , m_EMPersonality(AGGRESSIVE)
88  , m_PathFinder(a_Width, a_Height)
89  , m_PathfinderActivated(false)
90  , m_JumpCoolDown(0)
91  , m_IdleInterval(0)
92  , m_DestroyTimer(0)
93  , m_MobType(a_MobType)
94  , m_CustomName()
95  , m_CustomNameAlwaysVisible(false)
96  , m_SoundHurt(a_SoundHurt)
97  , m_SoundDeath(a_SoundDeath)
98  , m_SoundAmbient(a_SoundAmbient)
99  , m_AttackRate(3)
100  , m_AttackDamage(1)
101  , m_AttackRange(1)
102  , m_AttackCoolDownTicksLeft(0)
103  , m_SightDistance(25)
104  , m_DropChanceWeapon(0.085f)
105  , m_DropChanceHelmet(0.085f)
106  , m_DropChanceChestplate(0.085f)
107  , m_DropChanceLeggings(0.085f)
108  , m_DropChanceBoots(0.085f)
109  , m_CanPickUpLoot(true)
110  , m_TicksSinceLastDamaged(100)
111  , m_BurnsInDaylight(false)
112  , m_RelativeWalkSpeed(1)
113  , m_Age(1)
114  , m_AgingTimer(TPS * 60 * 20) // about 20 minutes
115  , m_WasLastTargetAPlayer(false)
116  , m_LeashedTo(nullptr)
117  , m_LeashToPos(nullptr)
118  , m_IsLeashActionJustDone(false)
119  , m_CanBeLeashed(GetMobFamily() == eFamily::mfPassive)
120  , m_LovePartner(nullptr)
121  , m_LoveTimer(0)
122  , m_LoveCooldown(0)
123  , m_MatingTimer(0)
124  , m_Target(nullptr)
125 {
126  if (!a_ConfigName.empty())
127  {
128  GetMonsterConfig(a_ConfigName);
129  }
130 
131  // Prevent mobs spawning at the same time from making sounds simultaneously
133 }
134 
135 
136 
137 
138 
140 {
141  SetTarget(nullptr); // Tell them we're no longer targeting them.
142 
143  if (m_LovePartner != nullptr)
144  {
146  }
147 
148  if (IsLeashed())
149  {
150  cEntity * LeashedTo = GetLeashedTo();
151  Unleash(false, true);
152 
153  // Remove leash knot if there are no more mobs leashed to
154  if (!LeashedTo->HasAnyMobLeashed() && LeashedTo->IsLeashKnot())
155  {
156  LeashedTo->Destroy();
157  }
158  }
159 
160  Super::OnRemoveFromWorld(a_World);
161 }
162 
163 
164 
165 
166 
168 {
169  a_Client.SendSpawnMob(*this);
170 
171  if (IsLeashed())
172  {
173  a_Client.SendLeashEntity(*this, *this->GetLeashedTo());
174  }
175 }
176 
177 
178 
179 
180 
182 {
184  {
185  return;
186  }
187 
188  if (m_JumpCoolDown <= 0)
189  {
191  {
192  if (
193  (IsOnGround() && (GetSpeed().SqrLength() <= 0.5)) || // If walking on the ground, we need to slow down first, otherwise we miss the jump
194  IsInWater()
195  )
196  {
197  m_bOnGround = false;
198  m_JumpCoolDown = 20;
199  AddPosY(1.6); // Jump!!
200  SetSpeedY(1);
201  SetSpeedX(3.2 * (m_NextWayPointPosition.x - GetPosition().x)); // Move forward in a preset speed.
202  SetSpeedZ(3.2 * (m_NextWayPointPosition.z - GetPosition().z)); // The numbers were picked based on trial and error
203  }
204  }
205  }
206  else
207  {
208  --m_JumpCoolDown;
209  }
210 
212  if ((std::abs(Distance.x) > 0.05) || (std::abs(Distance.z) > 0.05))
213  {
214  Distance.y = 0;
215  Distance.Normalize();
216 
217  if (m_bOnGround)
218  {
219  Distance *= 2.5f;
220  }
221  else if (IsInWater())
222  {
223  Distance *= 1.3f;
224  }
225  else
226  {
227  // Don't let the mob move too much if he's falling.
228  Distance *= 0.25f;
229  }
230  // Apply walk speed:
232  /* Reduced default speed.
233  Close to Vanilla, easier for mobs to follow m_NextWayPointPositions, hence
234  better pathfinding. */
235  Distance *= 0.5;
236  AddSpeedX(Distance.x);
237  AddSpeedZ(Distance.z);
238  }
239 }
240 
241 
242 
243 
244 
245 void cMonster::MoveToPosition(const Vector3d & a_Position)
246 {
247  m_FinalDestination = a_Position;
248  m_PathfinderActivated = true;
249 }
250 
251 
252 
253 
254 
256 {
257  m_PathfinderActivated = false;
258 }
259 
260 
261 
262 
263 
264 void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
265 {
266  Super::Tick(a_Dt, a_Chunk);
267  if (!IsTicking())
268  {
269  // The base class tick destroyed us
270  return;
271  }
273 
274  ASSERT((GetTarget() == nullptr) || (GetTarget()->IsPawn() && (GetTarget()->GetWorld() == GetWorld())));
276  {
278  }
279 
280  if (m_Health <= 0)
281  {
282  // The mob is dead, but we're still animating the "puff" they leave when they die
283  m_DestroyTimer += a_Dt;
284  if (m_DestroyTimer > std::chrono::seconds(1))
285  {
286  Destroy();
287  }
288  return;
289  }
290 
291  if (m_TicksSinceLastDamaged < 100)
292  {
294  }
295 
296  // Process the undead burning in daylight.
297  HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk));
298 
299  bool a_IsFollowingPath = false;
300  if (m_PathfinderActivated && (GetMobType() != mtGhast)) // Pathfinder is currently disabled for ghasts, which have their own flying mechanism
301  {
302  if (ReachedFinalDestination() || (m_LeashToPos != nullptr))
303  {
304  StopMovingToPosition(); // Simply sets m_PathfinderActivated to false.
305  }
306  else
307  {
308  // Note that m_NextWayPointPosition is actually returned by GetNextWayPoint)
310  {
312  {
313  /* If I burn in daylight, and I won't burn where I'm standing, and I'll burn in my next position, and at least one of those is true:
314  1. I am idle
315  2. I was not hurt by a player recently.
316  Then STOP. */
317  if (
320  !WouldBurnAt(GetPosition(), *Chunk)
321  )
322  {
323  // If we burn in daylight, and we would burn at the next step, and we won't burn where we are right now, and we weren't provoked recently:
325  }
326  else
327  {
328  a_IsFollowingPath = true; // Used for proper body / head orientation only.
329  MoveToWayPoint(*Chunk);
330  }
331  break;
332  }
334  {
336  break;
337  }
338  default:
339  {
340 
341  }
342  }
343  }
344  }
345 
346  SetPitchAndYawFromDestination(a_IsFollowingPath);
347 
348  switch (m_EMState)
349  {
350  case IDLE:
351  {
352  // If enemy passive we ignore checks for player visibility.
353  InStateIdle(a_Dt, a_Chunk);
354  break;
355  }
356  case CHASING:
357  {
358  // If we do not see a player anymore skip chasing action.
359  InStateChasing(a_Dt, a_Chunk);
360  break;
361  }
362  case ESCAPING:
363  {
364  InStateEscaping(a_Dt, a_Chunk);
365  break;
366  }
367  case ATTACKING: break;
368  } // switch (m_EMState)
369 
370  // Leash calculations
371  CalcLeashActions(a_Dt);
372 
374 
375  // Ambient mob sounds
376  if (!m_SoundAmbient.empty() && (--m_AmbientSoundTimer <= 0))
377  {
378  auto & Random = GetRandomProvider();
379  auto ShouldPlaySound = Random.RandBool();
380  if (ShouldPlaySound)
381  {
382  auto SoundPitchMultiplier = 1.0f + (Random.RandReal(1.0f) - Random.RandReal(1.0f)) * 0.2f;
383  m_World->BroadcastSoundEffect(m_SoundAmbient, GetPosition(), 1.0f, SoundPitchMultiplier * 1.0f);
384  }
385  m_AmbientSoundTimer = 100;
386  }
387 
388  if (m_AgingTimer > 0)
389  {
390  m_AgingTimer--;
391  if ((m_AgingTimer <= 0) && IsBaby())
392  {
393  SetAge(1);
395  }
396  }
397 }
398 
399 
400 
401 
402 
403 void cMonster::CalcLeashActions(std::chrono::milliseconds a_Dt)
404 {
405  // This mob just spotted in the world and [m_LeashToPos not null] shows that should be leashed to a leash knot at m_LeashToPos.
406  // This keeps trying until knot is found. Leash knot may be in a different chunk that needn't or can't be loaded yet.
407  if (!IsLeashed() && (m_LeashToPos != nullptr))
408  {
410  if (LeashKnot != nullptr)
411  {
412  LeashTo(*LeashKnot);
413  SetLeashToPos(nullptr);
414  }
415  }
416 
417  if (!IsLeashed())
418  {
419  return;
420  }
421 
422  static const double CloseFollowDistance = 1.8; // The closest the mob will path towards the leashed to entity
423  static const double LeashNaturalLength = 5.0; // The closest the mob is actively pulled towards the entity
424  static const double LeashMaximumLength = 10.0; // Length where the leash breaks
425  static const double LeashSpringConstant = 20.0; // How stiff the leash is
426 
427  const auto LeashedToPos = m_LeashedTo->GetPosition();
428  const auto Displacement = LeashedToPos - GetPosition();
429  const auto Distance = Displacement.Length();
430  const auto Direction = Displacement.NormalizeCopy();
431 
432  // If the leash is over-extended, break the leash:
433  if (Distance > LeashMaximumLength)
434  {
435  LOGD("Leash broken (distance)");
436  Unleash(false);
437  return;
438  }
439 
440  // If the mob isn't following close enough, pull the mob towards the leashed to entity:
441  if (Distance > LeashNaturalLength)
442  {
443  // Accelerate monster towards the leashed to entity:
444  const auto Extension = Distance - LeashNaturalLength;
445  auto Acceleration = Direction * (Extension * LeashSpringConstant);
446 
447  // Stop mobs from floating up when on the ground
448  if (IsOnGround() && (Acceleration.y < std::abs(GetGravity())))
449  {
450  Acceleration.y = 0.0;
451  }
452 
453  // Apply the acceleration
454  using namespace std::chrono;
455  AddSpeed(Acceleration * duration_cast<duration<double>>(a_Dt).count());
456  }
457 
458  // Passively follow the leashed to entity:
459  if (Distance > CloseFollowDistance)
460  {
461  const Vector3d TargetBlock((LeashedToPos - Direction * CloseFollowDistance).Floor());
462  // Move to centre of target block face
463  MoveToPosition(TargetBlock + Vector3d{ 0.5, 0.0, 0.5 });
464  }
465 }
466 
467 
468 
469 
470 
471 void cMonster::SetPitchAndYawFromDestination(bool a_IsFollowingPath)
472 {
473  Vector3d BodyDistance;
474  if (!a_IsFollowingPath)
475  {
476  if (GetTarget() == nullptr)
477  {
478  // Avoid dirtying head position when nothing will change
479  // Thus avoids creating unnecessary network traffic
480  return;
481  }
482 
483  BodyDistance = GetTarget()->GetPosition() - GetPosition();
484  }
485  else
486  {
487  BodyDistance = m_NextWayPointPosition - GetPosition();
488  }
489 
490  double BodyRotation, BodyPitch;
491  BodyDistance.Normalize();
492  VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, BodyRotation, BodyPitch);
493  SetYaw(BodyRotation);
494 
495  Vector3d HeadDistance;
496  if (GetTarget() != nullptr)
497  {
498  if (GetTarget()->IsPlayer()) // Look at a player
499  {
500  HeadDistance = GetTarget()->GetPosition() - GetPosition();
501  }
502  else // Look at some other entity
503  {
504  HeadDistance = GetTarget()->GetPosition() - GetPosition();
505  // HeadDistance.y = GetTarget()->GetPosY() + GetHeight();
506  }
507  }
508  else // Look straight
509  {
510  HeadDistance = BodyDistance;
511  HeadDistance.y = 0;
512  }
513 
514  double HeadRotation, HeadPitch;
515  HeadDistance.Normalize();
516  VectorToEuler(HeadDistance.x, HeadDistance.y, HeadDistance.z, HeadRotation, HeadPitch);
517  if ((std::abs(BodyRotation - HeadRotation) < 70) && (std::abs(HeadPitch) < 60))
518  {
519  SetHeadYaw(HeadRotation);
520  SetPitch(-HeadPitch);
521  }
522  else
523  {
524  SetHeadYaw(BodyRotation);
525  SetPitch(0);
526  }
527 }
528 
529 
530 
531 
532 
534 {
537 }
538 
539 
540 
541 
542 
543 int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
544 {
545  auto Position = GetPosition().Floor();
546  Position.y = Clamp(Position.y, 0, cChunkDef::Height);
547 
548  if (!cBlockInfo::IsSolid(m_World->GetBlock(Position)))
549  {
550  while (!cBlockInfo::IsSolid(m_World->GetBlock(Position)) && (Position.y > 0))
551  {
552  Position.y--;
553  }
554 
555  return Position.y + 1;
556  }
557  else
558  {
559  while ((Position.y < cChunkDef::Height) && cBlockInfo::IsSolid(m_World->GetBlock(Position)))
560  {
561  Position.y++;
562  }
563 
564  return Position.y;
565  }
566 }
567 
568 
569 
570 
571 
573 {
574  if (!Super::DoTakeDamage(a_TDI))
575  {
576  return false;
577  }
578 
579  if (!m_SoundHurt.empty() && (m_Health > 0))
580  {
582  }
583 
584  if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn())
585  {
586  if (
587  (!a_TDI.Attacker->IsPlayer()) ||
588  (static_cast<cPlayer *>(a_TDI.Attacker)->CanMobsTarget())
589  )
590  {
591  SetTarget(static_cast<cPawn*>(a_TDI.Attacker));
592  }
594  }
595  return true;
596 }
597 
598 
599 
600 
601 
603 {
604  Super::KilledBy(a_TDI);
605  if (m_SoundHurt != "")
606  {
608  }
609 
610  if (IsTame())
611  {
612  if ((m_MobType == mtWolf) || (m_MobType == mtOcelot) || (m_MobType == mtCat) || (m_MobType == mtParrot))
613  {
614  BroadcastDeathMessage(a_TDI);
615  }
616  }
617 
618  int Reward;
619  switch (m_MobType)
620  {
621  // Animals
622  case mtChicken:
623  case mtCow:
624  case mtHorse:
625  case mtPig:
626  case mtRabbit:
627  case mtSheep:
628  case mtSquid:
629  case mtMooshroom:
630  case mtOcelot:
631  case mtWolf:
632  {
633  Reward = GetRandomProvider().RandInt(1, 3);
634  break;
635  }
636 
637  // Monsters
638  case mtCaveSpider:
639  case mtCreeper:
640  case mtEnderman:
641  case mtGhast:
642  case mtGuardian:
643  case mtSilverfish:
644  case mtSkeleton:
645  case mtSpider:
646  case mtWitch:
647  case mtWitherSkeleton:
648  case mtZombie:
649  case mtZombiePigman:
650  case mtZombieVillager:
651  case mtSlime:
652  case mtMagmaCube:
653  {
654  Reward = GetRandomProvider().RandInt(6, 8);
655  break;
656  }
657  case mtEndermite:
658  {
659  Reward = 3;
660  break;
661  }
662  case mtBlaze:
663  {
664  Reward = 10;
665  break;
666  }
667 
668  // Bosses
669  case mtEnderDragon:
670  {
671  Reward = 12000;
672  break;
673  }
674  case mtWither:
675  {
676  Reward = 50;
677  break;
678  }
679 
680  default:
681  {
682  Reward = 0;
683  break;
684  }
685  }
686  if ((a_TDI.Attacker != nullptr) && (!IsBaby()))
687  {
689  }
690  m_DestroyTimer = std::chrono::milliseconds(0);
691 }
692 
693 
694 
695 
696 
698 {
699  Super::OnRightClicked(a_Player);
700 
701  const cItem & EquippedItem = a_Player.GetEquippedItem();
702  if ((EquippedItem.m_ItemType == E_ITEM_NAME_TAG) && !EquippedItem.m_CustomName.empty())
703  {
704  SetCustomName(EquippedItem.m_CustomName);
705  if (!a_Player.IsGameModeCreative())
706  {
707  a_Player.GetInventory().RemoveOneEquippedItem();
708  }
709  }
710 
711  // Using leashes
712  m_IsLeashActionJustDone = false;
713  if (IsLeashed() && (GetLeashedTo() == &a_Player)) // a player can only unleash a mob leashed to him
714  {
715  Unleash(!a_Player.IsGameModeCreative());
716  }
717  else if (IsLeashed())
718  {
719  // Mob is already leashed but client anticipates the server action and draws a leash link, so we need to send current leash to cancel it
720  m_World->BroadcastLeashEntity(*this, *this->GetLeashedTo());
721  }
722  else if (CanBeLeashed() && (EquippedItem.m_ItemType == E_ITEM_LEASH))
723  {
724  if (!a_Player.IsGameModeCreative())
725  {
726  a_Player.GetInventory().RemoveOneEquippedItem();
727  }
728  LeashTo(a_Player);
729  }
730 }
731 
732 
733 
734 
735 
736 // Checks to see if EventSeePlayer should be fired
737 // monster sez: Do I see the player
739 {
740  if (GetTarget() != nullptr)
741  {
742  return;
743  }
744 
745  cPlayer * TargetPlayer = nullptr;
746  double ClosestDistance = m_SightDistance * m_SightDistance;
747  const auto MyHeadPosition = GetPosition().addedY(GetHeight());
748 
749  // Enumerate all players within sight:
750  m_World->ForEachPlayer([this, &TargetPlayer, &ClosestDistance, MyHeadPosition](cPlayer & a_Player)
751  {
752  if (!a_Player.CanMobsTarget())
753  {
754  return false;
755  }
756 
757  const auto TargetHeadPosition = a_Player.GetPosition().addedY(a_Player.GetHeight());
758  const auto TargetDistance = (TargetHeadPosition - MyHeadPosition).SqrLength();
759 
760  // TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to.
761  if (
762  (TargetDistance < ClosestDistance) &&
763  cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava)
764  )
765  {
766  TargetPlayer = &a_Player;
767  ClosestDistance = TargetDistance;
768  }
769 
770  return false;
771  });
772 
773  // Target him if suitable player found:
774  if (TargetPlayer != nullptr)
775  {
776  EventSeePlayer(TargetPlayer, a_Chunk);
777  }
778 }
779 
780 
781 
782 
783 
784 void cMonster::CheckEventLostPlayer(const std::chrono::milliseconds a_Dt)
785 {
786  const auto Target = GetTarget();
787 
788  if (Target == nullptr)
789  {
790  return;
791  }
792 
793  // Check if the player died, is in creative mode, etc:
794  if (Target->IsPlayer() && !static_cast<cPlayer *>(Target)->CanMobsTarget())
795  {
796  EventLosePlayer();
797  return;
798  }
799 
800  // Check if the target is too far away:
801  if (!Target->GetBoundingBox().DoesIntersect({ GetPosition(), m_SightDistance * 2.0 }))
802  {
803  EventLosePlayer();
804  return;
805  }
806 
807  const auto MyHeadPosition = GetPosition().addedY(GetHeight());
808  const auto TargetHeadPosition = Target->GetPosition().addedY(Target->GetHeight());
809  if (!cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava))
810  {
811  if ((m_LoseSightAbandonTargetTimer += a_Dt) > std::chrono::seconds(4))
812  {
813  EventLosePlayer();
814  }
815  }
816  else
817  {
818  // Subtract the amount of time we "handled" instead of setting to zero, so we don't ignore a large a_Dt of say, 8s:
819  m_LoseSightAbandonTargetTimer -= std::min(std::chrono::milliseconds(4000), m_LoseSightAbandonTargetTimer);
820  }
821 }
822 
823 
824 
825 
826 
827 // What to do if player is seen
828 // default to change state to chasing
829 void cMonster::EventSeePlayer(cPlayer * a_SeenPlayer, cChunk & a_Chunk)
830 {
831  UNUSED(a_Chunk);
832  SetTarget(a_SeenPlayer);
833 }
834 
835 
836 
837 
838 
840 {
841  SetTarget(nullptr);
842 
843  m_EMState = IDLE;
844  m_LoseSightAbandonTargetTimer = std::chrono::seconds::zero();
845 }
846 
847 
848 
849 
850 
851 void cMonster::InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
852 {
854  {
855  return; // Still getting there
856  }
857 
858  m_IdleInterval += a_Dt;
859 
860  if (m_IdleInterval > std::chrono::seconds(1))
861  {
862  auto & Random = GetRandomProvider();
863 
864  // At this interval the results are predictable
865  int rem = Random.RandInt(1, 7);
866  m_IdleInterval -= std::chrono::seconds(1); // So nothing gets dropped when the server hangs for a few seconds
867 
868  Vector3d Dist;
869  Dist.x = static_cast<double>(Random.RandInt(-5, 5));
870  Dist.z = static_cast<double>(Random.RandInt(-5, 5));
871 
872  if ((Dist.SqrLength() > 2) && (rem >= 3))
873  {
874 
875  Vector3d Destination(GetPosX() + Dist.x, GetPosition().y, GetPosZ() + Dist.z);
876 
877  cChunk * Chunk = a_Chunk.GetNeighborChunk(static_cast<int>(Destination.x), static_cast<int>(Destination.z));
878  if ((Chunk == nullptr) || !Chunk->IsValid())
879  {
880  return;
881  }
882 
884  NIBBLETYPE BlockMeta;
885  int RelX = static_cast<int>(Destination.x) - Chunk->GetPosX() * cChunkDef::Width;
886  int RelZ = static_cast<int>(Destination.z) - Chunk->GetPosZ() * cChunkDef::Width;
887  int YBelowUs = static_cast<int>(Destination.y) - 1;
888  if (YBelowUs >= 0)
889  {
890  Chunk->GetBlockTypeMeta(RelX, YBelowUs, RelZ, BlockType, BlockMeta);
891  if (BlockType != E_BLOCK_STATIONARY_WATER) // Idle mobs shouldn't enter water on purpose
892  {
893  MoveToPosition(Destination);
894  }
895  }
896  }
897  }
898 }
899 
900 
901 
902 
903 
904 // What to do if in Chasing State
905 // This state should always be defined in each child class
906 void cMonster::InStateChasing(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
907 {
908  UNUSED(a_Dt);
909 }
910 
911 
912 
913 
914 
915 // What to do if in Escaping State
916 void cMonster::InStateEscaping(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
917 {
918  UNUSED(a_Dt);
919 
920  if (GetTarget() != nullptr)
921  {
922  Vector3d newloc = GetPosition();
923  newloc.x = (GetTarget()->GetPosition().x < newloc.x)? (newloc.x + m_SightDistance): (newloc.x - m_SightDistance);
924  newloc.z = (GetTarget()->GetPosition().z < newloc.z)? (newloc.z + m_SightDistance): (newloc.z - m_SightDistance);
925  MoveToPosition(newloc);
926  }
927  else
928  {
929  m_EMState = IDLE; // This shouldnt be required but just to be safe
930  }
931 }
932 
933 
934 
935 
936 
938 {
939  m_AttackCoolDownTicksLeft = static_cast<int>(TPS * m_AttackRate); // A second has 20 ticks, an attack rate of 1 means 1 hit every second
940 }
941 
942 
943 
944 
945 
946 void cMonster::SetCustomName(const AString & a_CustomName)
947 {
948  m_CustomName = a_CustomName;
949 
950  // The maximal length is 64
951  if (a_CustomName.length() > 64)
952  {
953  m_CustomName = a_CustomName.substr(0, 64);
954  }
955 
956  if (m_World != nullptr)
957  {
959  }
960 }
961 
962 
963 
964 
965 
966 void cMonster::SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible)
967 {
968  m_CustomNameAlwaysVisible = a_CustomNameAlwaysVisible;
969  if (m_World != nullptr)
970  {
972  }
973 }
974 
975 
976 
977 
978 
980 {
981  cRoot::Get()->GetMonsterConfig()->AssignAttributes(this, a_Name);
982 }
983 
984 
985 
986 
987 
989 {
990  return false;
991 }
992 
993 
994 
995 
996 
998 {
999  return false;
1000 }
1001 
1002 
1003 
1004 
1005 
1007 {
1008  // Mob types aren't sorted, so we need to search linearly:
1009  for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
1010  {
1011  if (g_MobTypeNames[i].m_Type == a_MobType)
1012  {
1013  return g_MobTypeNames[i].m_lcName;
1014  }
1015  }
1016 
1017  // Not found:
1018  return "";
1019 }
1020 
1021 
1022 
1023 
1024 
1026 {
1027  // Mob types aren't sorted, so we need to search linearly:
1028  for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
1029  {
1030  if (g_MobTypeNames[i].m_Type == a_MobType)
1031  {
1032  return g_MobTypeNames[i].m_VanillaName;
1033  }
1034  }
1035 
1036  // Not found:
1037  return "";
1038 }
1039 
1040 
1041 
1042 
1043 
1045 {
1046  // Mob types aren't sorted, so we need to search linearly:
1047  for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
1048  {
1049  if (g_MobTypeNames[i].m_Type == a_MobType)
1050  {
1051  return g_MobTypeNames[i].m_VanillaNameNBT;
1052  }
1053  }
1054 
1055  // Not found:
1056  return "";
1057 }
1058 
1059 
1060 
1061 
1062 
1064 {
1065  AString lcName = StrToLower(a_Name);
1066 
1067  // Search Cuberite name:
1068  for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
1069  {
1070  if (strcmp(g_MobTypeNames[i].m_lcName, lcName.c_str()) == 0)
1071  {
1072  return g_MobTypeNames[i].m_Type;
1073  }
1074  }
1075 
1076  // Not found. Search Vanilla name:
1077  for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
1078  {
1079  if (strcmp(StrToLower(g_MobTypeNames[i].m_VanillaName).c_str(), lcName.c_str()) == 0)
1080  {
1081  return g_MobTypeNames[i].m_Type;
1082  }
1083  }
1084 
1085  // Search in NBT name
1086  for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
1087  {
1088  if (strcmp(StrToLower(g_MobTypeNames[i].m_VanillaNameNBT).c_str(), lcName.c_str()) == 0)
1089  {
1090  return g_MobTypeNames[i].m_Type;
1091  }
1092  }
1093 
1094  // Not found:
1095  return mtInvalidType;
1096 }
1097 
1098 
1099 
1100 
1101 
1103 {
1104  // Passive-agressive mobs are counted in mob spawning code as passive
1105 
1106  switch (a_Type)
1107  {
1108  case mtBat: return mfAmbient;
1109  case mtBlaze: return mfHostile;
1110  case mtCat: return mfPassive;
1111  case mtCaveSpider: return mfHostile;
1112  case mtChicken: return mfPassive;
1113  case mtCod: return mfWater;
1114  case mtCow: return mfPassive;
1115  case mtCreeper: return mfHostile;
1116  case mtDolphin: return mfWater;
1117  case mtDonkey: return mfPassive;
1118  case mtDrowned: return mfHostile;
1119  case mtElderGuardian: return mfHostile;
1120  case mtEnderDragon: return mfNoSpawn;
1121  case mtEnderman: return mfHostile;
1122  case mtEndermite: return mfHostile;
1123  case mtEvoker: return mfHostile;
1124  case mtFox: return mfPassive;
1125  case mtGhast: return mfHostile;
1126  case mtGiant: return mfNoSpawn;
1127  case mtGuardian: return mfWater; // Just because they have special spawning conditions. TODO: If Watertemples have been added, this needs to be edited!
1128  case mtHoglin: return mfHostile;
1129  case mtHorse: return mfPassive;
1130  case mtHusk: return mfHostile;
1131  case mtIllusioner: return mfHostile;
1132  case mtIronGolem: return mfPassive;
1133  case mtLlama: return mfPassive;
1134  case mtMagmaCube: return mfHostile;
1135  case mtMooshroom: return mfPassive;
1136  case mtMule: return mfPassive;
1137  case mtOcelot: return mfPassive;
1138  case mtPanda: return mfPassive;
1139  case mtParrot: return mfPassive;
1140  case mtPhantom: return mfHostile;
1141  case mtPig: return mfPassive;
1142  case mtPiglin: return mfHostile;
1143  case mtPiglinBrute: return mfHostile;
1144  case mtPillager: return mfHostile;
1145  case mtPolarBear: return mfPassive;
1146  case mtPufferfish: return mfWater;
1147  case mtRabbit: return mfPassive;
1148  case mtRavager: return mfHostile;
1149  case mtSalmon: return mfWater;
1150  case mtSheep: return mfPassive;
1151  case mtShulker: return mfHostile;
1152  case mtSilverfish: return mfHostile;
1153  case mtSkeleton: return mfHostile;
1154  case mtSkeletonHorse: return mfPassive;
1155  case mtSlime: return mfHostile;
1156  case mtSnowGolem: return mfNoSpawn;
1157  case mtSpider: return mfHostile;
1158  case mtSquid: return mfWater;
1159  case mtStray: return mfHostile;
1160  case mtStrider: return mfHostile;
1161  case mtTraderLlama: return mfPassive;
1162  case mtTropicalFish: return mfWater;
1163  case mtTurtle: return mfWater; // I'm not quite sure
1164  case mtVex: return mfHostile;
1165  case mtVindicator: return mfHostile;
1166  case mtVillager: return mfPassive;
1167  case mtWanderingTrader: return mfPassive;
1168  case mtWitch: return mfHostile;
1169  case mtWither: return mfNoSpawn;
1170  case mtWitherSkeleton: return mfHostile;
1171  case mtWolf: return mfPassive;
1172  case mtZoglin: return mfHostile;
1173  case mtZombie: return mfHostile;
1174  case mtZombieHorse: return mfPassive;
1175  case mtZombiePigman: return mfHostile;
1176  case mtZombieVillager: return mfHostile;
1177  case mtInvalidType: break;
1178  }
1179  UNREACHABLE("Unhandled mob type");
1180 }
1181 
1182 
1183 
1184 
1185 
1187 {
1188  switch (a_MobFamily)
1189  {
1190  case mfHostile: return 40_tick;
1191  case mfPassive: return 40_tick;
1192  case mfAmbient: return 40_tick;
1193  case mfWater: return 400_tick;
1194  case mfNoSpawn: return -1_tick;
1195  }
1196  UNREACHABLE("Unhandled mob family");
1197 }
1198 
1199 
1200 
1201 
1202 
1204 void cMonster::SetTarget (cPawn * a_NewTarget)
1205 {
1206  ASSERT((a_NewTarget == nullptr) || (IsTicking()));
1207  if (m_Target == a_NewTarget)
1208  {
1209  return;
1210  }
1211  cPawn * OldTarget = m_Target;
1212  m_Target = a_NewTarget;
1213 
1214  if (OldTarget != nullptr)
1215  {
1216  // Notify the old target that we are no longer targeting it.
1217  OldTarget->NoLongerTargetingMe(this);
1218  }
1219 
1220  if (a_NewTarget != nullptr)
1221  {
1222  ASSERT(a_NewTarget->IsTicking());
1223  // Notify the new target that we are now targeting it.
1224  m_Target->TargetingMe(this);
1226  }
1227 
1228 }
1229 
1230 
1231 
1232 
1233 
1235 {
1236  m_Target = nullptr;
1237 }
1238 
1239 
1240 
1241 
1242 
1244 {
1245  return m_Target;
1246 }
1247 
1248 
1249 
1250 
1251 
1252 std::unique_ptr<cMonster> cMonster::NewMonsterFromType(eMonsterType a_MobType)
1253 {
1254  auto & Random = GetRandomProvider();
1255 
1256  // Create the mob entity
1257  switch (a_MobType)
1258  {
1259  case mtMagmaCube:
1260  {
1261  return std::make_unique<cMagmaCube>(1 << Random.RandInt(2)); // Size 1, 2 or 4
1262  }
1263  case mtSlime:
1264  {
1265  return std::make_unique<cSlime>(1 << Random.RandInt(2)); // Size 1, 2 or 4
1266  }
1267  case mtVillager: return std::make_unique<cVillager>(cVillager::GetRandomProfession());
1268  case mtHorse:
1269  {
1270  // Horses take a type (species), a colour, and a style (dots, stripes, etc.)
1271  int HorseType = Random.RandInt(7);
1272  int HorseColor = Random.RandInt(6);
1273  int HorseStyle = Random.RandInt(4);
1274  int HorseTameTimes = Random.RandInt(1, 6);
1275 
1276  if ((HorseType == 5) || (HorseType == 6) || (HorseType == 7))
1277  {
1278  // Increase chances of normal horse (zero)
1279  HorseType = 0;
1280  }
1281 
1282  return std::make_unique<cHorse>(HorseType, HorseColor, HorseStyle, HorseTameTimes);
1283  }
1284  case mtZombieVillager:
1285  {
1286  return std::make_unique<cZombieVillager>(cVillager::GetRandomProfession());
1287  }
1288  case mtBat: return std::make_unique<cBat>();
1289  case mtBlaze: return std::make_unique<cBlaze>();
1290  case mtCaveSpider: return std::make_unique<cCaveSpider>();
1291  case mtChicken: return std::make_unique<cChicken>();
1292  case mtCow: return std::make_unique<cCow>();
1293  case mtCreeper: return std::make_unique<cCreeper>();
1294  case mtEnderDragon: return std::make_unique<cEnderDragon>();
1295  case mtEndermite: return std::make_unique<cEndermite>();
1296  case mtEnderman: return std::make_unique<cEnderman>();
1297  case mtGhast: return std::make_unique<cGhast>();
1298  case mtGiant: return std::make_unique<cGiant>();
1299  case mtGuardian: return std::make_unique<cGuardian>();
1300  case mtIronGolem: return std::make_unique<cIronGolem>();
1301  case mtMooshroom: return std::make_unique<cMooshroom>();
1302  case mtOcelot: return std::make_unique<cOcelot>();
1303  case mtPig: return std::make_unique<cPig>();
1304  case mtRabbit: return std::make_unique<cRabbit>();
1305  case mtSheep: return std::make_unique<cSheep>();
1306  case mtSilverfish: return std::make_unique<cSilverfish>();
1307  case mtSkeleton: return std::make_unique<cSkeleton>();
1308  case mtSnowGolem: return std::make_unique<cSnowGolem>();
1309  case mtSpider: return std::make_unique<cSpider>();
1310  case mtSquid: return std::make_unique<cSquid>();
1311  case mtWitch: return std::make_unique<cWitch>();
1312  case mtWither: return std::make_unique<cWither>();
1313  case mtWitherSkeleton: return std::make_unique<cWitherSkeleton>();
1314  case mtWolf: return std::make_unique<cWolf>();
1315  case mtZombie: return std::make_unique<cZombie>();
1316  case mtZombiePigman: return std::make_unique<cZombiePigman>();
1317  default:
1318  {
1319  ASSERT(!"Unhandled mob type whilst trying to spawn mob!");
1320  return nullptr;
1321  }
1322  }
1323 }
1324 
1325 
1326 
1327 
1328 
1330 {
1331  m_LovePartner = a_Partner;
1332  m_MatingTimer = 50; // about 3 seconds of mating
1333 }
1334 
1335 
1336 
1337 
1338 
1340 {
1341  m_LovePartner = nullptr;
1342  m_LoveTimer = 0;
1343  m_MatingTimer = 0;
1344  m_LoveCooldown = TPS * 60 * 5; // 5 minutes
1345 
1346  // when an animal is in love mode, the client only stops sending the hearts if we let them know it's in cooldown, which is done with the "age" metadata
1348 }
1349 
1350 
1351 
1352 
1353 
1355 {
1356  // if we have a partner, mate
1357  if (m_LovePartner != nullptr)
1358  {
1359 
1360  if (m_MatingTimer > 0)
1361  {
1362  // If we should still mate, keep bumping into them until baby is made
1364  MoveToPosition(Pos);
1365  }
1366  else
1367  {
1368  // Mating finished. Spawn baby
1369  Vector3f Pos = (GetPosition() + m_LovePartner->GetPosition()) * 0.5;
1370  UInt32 BabyID = m_World->SpawnMob(Pos.x, Pos.y, Pos.z, GetMobType(), true);
1371 
1372  cMonster * Baby = nullptr;
1373 
1374  m_World->DoWithEntityByID(BabyID, [&](cEntity & a_Entity)
1375  {
1376  Baby = static_cast<cMonster *>(&a_Entity);
1377  return true;
1378  });
1379 
1380  if (Baby != nullptr)
1381  {
1382  Baby->InheritFromParents(this, m_LovePartner);
1383  }
1384 
1385  m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, GetRandomProvider().RandInt(1, 6));
1386 
1387  m_World->DoWithPlayerByUUID(m_Feeder, [&] (cPlayer & a_Player)
1388  {
1391  {
1393  }
1394  return true;
1395  });
1397  ResetLoveMode();
1398  }
1399  }
1400  else
1401  {
1402  // We have no partner, so we just chase the player if they have our breeding item
1403  cItems FollowedItems;
1404  GetFollowedItems(FollowedItems);
1405  if (FollowedItems.Size() > 0)
1406  {
1407  m_World->DoWithNearestPlayer(GetPosition(), static_cast<float>(m_SightDistance), [&](cPlayer & a_Player) -> bool
1408  {
1409  const cItem & EquippedItem = a_Player.GetEquippedItem();
1410  if (FollowedItems.ContainsType(EquippedItem))
1411  {
1412  Vector3d PlayerPos = a_Player.GetPosition();
1413  MoveToPosition(PlayerPos);
1414  }
1415 
1416  return true;
1417  });
1418  }
1419  }
1420 
1421  // If we are in love mode but we have no partner, search for a partner neabry
1422  if (m_LoveTimer > 0)
1423  {
1424  if (m_LovePartner == nullptr)
1425  {
1426  m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8), [=](cEntity & a_Entity)
1427  {
1428  // If the entity is not a monster, don't breed with it
1429  // Also, do not self-breed
1430  if ((a_Entity.GetEntityType() != etMonster) || (&a_Entity == this))
1431  {
1432  return false;
1433  }
1434 
1435  auto & Me = static_cast<cMonster &>(*this);
1436  auto & PotentialPartner = static_cast<cMonster &>(a_Entity);
1437 
1438  // If the potential partner is not of the same species, don't breed with it
1439  if (PotentialPartner.GetMobType() != Me.GetMobType())
1440  {
1441  return false;
1442  }
1443 
1444  // If the potential partner is not in love
1445  // Or they already have a mate, do not breed with them
1446  if ((!PotentialPartner.IsInLove()) || (PotentialPartner.GetPartner() != nullptr))
1447  {
1448  return false;
1449  }
1450 
1451  // All conditions met, let's breed!
1452  PotentialPartner.EngageLoveMode(&Me);
1453  Me.EngageLoveMode(&PotentialPartner);
1454  return true;
1455  });
1456  }
1457 
1458  m_LoveTimer--;
1459  }
1460  if (m_MatingTimer > 0)
1461  {
1462  m_MatingTimer--;
1463  }
1464  if (m_LoveCooldown > 0)
1465  {
1466  m_LoveCooldown--;
1467  }
1468 }
1469 
1470 
1471 
1472 
1473 
1475 {
1476 
1477  const cItem & EquippedItem = a_Player.GetEquippedItem();
1478 
1479  // If a player holding breeding items right-clicked me, go into love mode
1480  if ((m_LoveCooldown == 0) && !IsInLove() && !IsBaby())
1481  {
1482  cItems Items;
1483  GetBreedingItems(Items);
1484  if (Items.ContainsType(EquippedItem.m_ItemType))
1485  {
1486  if (!a_Player.IsGameModeCreative())
1487  {
1488  a_Player.GetInventory().RemoveOneEquippedItem();
1489  }
1490  m_LoveTimer = TPS * 30; // half a minute
1492  }
1493  }
1494  // If a player holding my spawn egg right-clicked me, spawn a new baby
1495  if (EquippedItem.m_ItemType == E_ITEM_SPAWN_EGG)
1496  {
1498  if (
1499  (MonsterType == m_MobType) &&
1500  (m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), m_MobType, true) != cEntity::INVALID_ID) // Spawning succeeded
1501  )
1502  {
1503  if (!a_Player.IsGameModeCreative())
1504  {
1505  // The mob was spawned, "use" the item:
1506  a_Player.GetInventory().RemoveOneEquippedItem();
1507  }
1508  }
1509  }
1510  // Stores feeder UUID for statistic tracking
1511  m_Feeder = a_Player.GetUUID();
1512 }
1513 
1514 
1515 
1516 
1517 
1518 void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth)
1519 {
1520  auto Count = GetRandomProvider().RandInt(a_Min, a_Max);
1521  auto MaxStackSize = static_cast<unsigned int>(cItem(a_Item).GetMaxStackSize());
1522  while (Count > MaxStackSize)
1523  {
1524  a_Drops.emplace_back(a_Item, MaxStackSize, a_ItemHealth);
1525  Count -= MaxStackSize;
1526  }
1527  if (Count > 0)
1528  {
1529  a_Drops.emplace_back(a_Item, Count, a_ItemHealth);
1530  }
1531 }
1532 
1533 
1534 
1535 
1536 
1537 void cMonster::AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short a_Item, short a_ItemHealth)
1538 {
1539  if (GetRandomProvider().RandBool(a_Chance / 100.0))
1540  {
1541  a_Drops.emplace_back(a_Item, static_cast<char>(1), a_ItemHealth);
1542  }
1543 }
1544 
1545 
1546 
1547 
1548 
1549 void cMonster::AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, unsigned int a_LootingLevel)
1550 {
1551  auto & r1 = GetRandomProvider();
1552  if (r1.RandBool((5 + a_LootingLevel) / 200.0))
1553  {
1554  size_t Rare = r1.RandInt<size_t>(a_Items.Size() - 1);
1555  a_Drops.push_back(a_Items.at(Rare));
1556  }
1557 }
1558 
1559 
1560 
1561 
1562 
1563 void cMonster::AddRandomArmorDropItem(cItems & a_Drops, unsigned int a_LootingLevel)
1564 {
1565  auto & r1 = GetRandomProvider();
1566 
1567  double LootingBonus = a_LootingLevel / 100.0;
1568 
1569  if (r1.RandBool(m_DropChanceHelmet + LootingBonus))
1570  {
1571  if (!GetEquippedHelmet().IsEmpty())
1572  {
1573  a_Drops.push_back(GetEquippedHelmet());
1574  }
1575  }
1576 
1577  if (r1.RandBool(m_DropChanceChestplate + LootingBonus))
1578  {
1579  if (!GetEquippedChestplate().IsEmpty())
1580  {
1581  a_Drops.push_back(GetEquippedChestplate());
1582  }
1583  }
1584 
1585  if (r1.RandBool(m_DropChanceLeggings + LootingBonus))
1586  {
1587  if (!GetEquippedLeggings().IsEmpty())
1588  {
1589  a_Drops.push_back(GetEquippedLeggings());
1590  }
1591  }
1592 
1593  if (r1.RandBool(m_DropChanceBoots + LootingBonus))
1594  {
1595  if (!GetEquippedBoots().IsEmpty())
1596  {
1597  a_Drops.push_back(GetEquippedBoots());
1598  }
1599  }
1600 }
1601 
1602 
1603 
1604 
1605 
1606 void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, unsigned int a_LootingLevel)
1607 {
1608  if (GetRandomProvider().RandBool(m_DropChanceWeapon + (a_LootingLevel / 100.0)))
1609  {
1610  if (!GetEquippedWeapon().IsEmpty())
1611  {
1612  a_Drops.push_back(GetEquippedWeapon());
1613  }
1614  }
1615 }
1616 
1617 
1618 
1619 
1620 
1621 void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn)
1622 {
1623  if (!m_BurnsInDaylight)
1624  {
1625  return;
1626  }
1627 
1628  int RelY = POSY_TOINT;
1629  if ((RelY < 0) || (RelY >= cChunkDef::Height))
1630  {
1631  // Outside the world
1632  return;
1633  }
1634  if (!a_Chunk.IsLightValid())
1635  {
1637  return;
1638  }
1639 
1640  if (!IsOnFire() && WouldBurn)
1641  {
1642  // Burn for 100 ticks, then decide again
1643  StartBurning(100);
1644  }
1645 }
1646 
1647 
1648 
1649 
1650 
1651 bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
1652 {
1653  // If the Y coord is out of range, return the most logical result without considering anything else:
1654  int RelY = FloorC(a_Location.y);
1655  if (RelY >= cChunkDef::Height)
1656  {
1657  // Always burn above the world
1658  return true;
1659  }
1660  if (RelY <= 0)
1661  {
1662  // The mob is about to die, no point in burning
1663  return false;
1664  }
1665 
1666  PREPARE_REL_AND_CHUNK(a_Location, a_Chunk);
1667  if (!RelSuccess)
1668  {
1669  return false;
1670  }
1671 
1672  if (
1673  (Chunk->GetBlock(Rel) != E_BLOCK_SOULSAND) && // Not on soulsand
1674  (GetWorld()->GetTimeOfDay() < 13000_tick) && // Daytime
1675  Chunk->IsWeatherSunnyAt(Rel.x, Rel.z) && // Not raining
1676  !IsInWater() // Isn't swimming
1677  )
1678  {
1679  int MobHeight = CeilC(a_Location.y + GetHeight()) - 1; // The block Y coord of the mob's head
1680  if (MobHeight >= cChunkDef::Height)
1681  {
1682  return true;
1683  }
1684  // Start with the highest block and scan down to just above the mob's head.
1685  // If a non transparent is found, return false (do not burn). Otherwise return true.
1686  // Note that this loop is not a performance concern as transparent blocks are rare and the loop almost always bailes out
1687  // instantly.(An exception is e.g. standing under a long column of glass).
1688  int CurrentBlock = Chunk->GetHeight(Rel.x, Rel.z);
1689  while (CurrentBlock > MobHeight)
1690  {
1691  BLOCKTYPE Block = Chunk->GetBlock(Rel.x, CurrentBlock, Rel.z);
1692  if (
1693  // Do not burn if a block above us meets one of the following conditions:
1695  (Block == E_BLOCK_LEAVES) ||
1696  (Block == E_BLOCK_NEW_LEAVES) ||
1697  (IsBlockWater(Block))
1698  )
1699  {
1700  return false;
1701  }
1702  --CurrentBlock;
1703  }
1704  return true;
1705 
1706  }
1707  return false;
1708 }
1709 
1710 
1711 
1712 
1713 
1715 {
1716  return FamilyFromType(m_MobType);
1717 }
1718 
1719 
1720 
1721 
1722 
1723 void cMonster::LeashTo(cEntity & a_Entity, bool a_ShouldBroadcast)
1724 {
1725  // Do nothing if already leashed
1726  if (m_LeashedTo != nullptr)
1727  {
1728  return;
1729  }
1730 
1731  m_LeashedTo = &a_Entity;
1732 
1733  a_Entity.AddLeashedMob(this);
1734 
1735  if (a_ShouldBroadcast)
1736  {
1737  m_World->BroadcastLeashEntity(*this, a_Entity);
1738  }
1739 
1740  m_IsLeashActionJustDone = true;
1741 }
1742 
1743 
1744 
1745 
1746 
1747 void cMonster::Unleash(bool a_ShouldDropLeashPickup, bool a_ShouldBroadcast)
1748 {
1749  // Do nothing if not leashed
1750  if (m_LeashedTo == nullptr)
1751  {
1752  return;
1753  }
1754 
1756 
1757  m_LeashedTo = nullptr;
1758 
1759  if (a_ShouldDropLeashPickup)
1760  {
1761  cItems Pickups;
1762  Pickups.Add(cItem(E_ITEM_LEASH, 1, 0));
1763  GetWorld()->SpawnItemPickups(Pickups, GetPosX() + 0.5, GetPosY() + 0.5, GetPosZ() + 0.5);
1764  }
1765 
1766  if (a_ShouldBroadcast)
1767  {
1769  }
1770 
1771  m_IsLeashActionJustDone = true;
1772 }
1773 
1774 
1775 
1776 
1777 
1778 void cMonster::Unleash(bool a_ShouldDropLeashPickup)
1779 {
1780  Unleash(a_ShouldDropLeashPickup, true);
1781 }
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:10
@ E_BLOCK_NEW_LEAVES
Definition: BlockType.h:180
@ E_BLOCK_LEAVES
Definition: BlockType.h:28
@ E_BLOCK_SOULSAND
Definition: BlockType.h:103
@ E_BLOCK_STATIONARY_WATER
Definition: BlockType.h:19
@ E_ITEM_SPAWN_EGG
Definition: BlockType.h:429
@ E_ITEM_LEASH
Definition: BlockType.h:467
@ E_ITEM_NAME_TAG
Definition: BlockType.h:468
#define PREPARE_REL_AND_CHUNK(Position, OriginalChunk)
Definition: Chunk.h:32
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
constexpr const int TPS
Constant to calculate ticks from seconds "ticks per second".
Definition: Defines.h:16
void VectorToEuler(double a_X, double a_Y, double a_Z, double &a_Pan, double &a_Pitch)
Definition: Defines.h:597
#define POSX_TOINT
Definition: Entity.h:31
#define POSZ_TOINT
Definition: Entity.h:33
#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z)
Definition: Entity.h:36
#define POSY_TOINT
Definition: Entity.h:32
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
#define UNREACHABLE(x)
Definition: Globals.h:288
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
unsigned int UInt32
Definition: Globals.h:157
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
Definition: Globals.h:336
std::chrono::duration< signed int, std::ratio_multiply< std::chrono::milliseconds::period, std::ratio< 50 > >> cTickTime
Definition: Globals.h:364
std::enable_if< std::is_arithmetic< T >::value, C >::type CeilC(T a_Value)
Ceils a value, then casts it to C (an int by default).
Definition: Globals.h:354
#define ASSERT(x)
Definition: Globals.h:276
#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
#define LOGD
Definition: LoggerSimple.h:83
eMonsterType m_Type
Definition: Monster.cpp:35
const char * m_VanillaNameNBT
Definition: Monster.cpp:38
const char * m_VanillaName
Definition: Monster.cpp:37
static const struct @17 g_MobTypeNames[]
Map for eType <-> string Needs to be alpha-sorted by the strings, because binary search is used in St...
const char * m_lcName
Definition: Monster.cpp:36
eMonsterType
Identifies individual monster type.
Definition: MonsterTypes.h:11
@ mtZombieVillager
Definition: MonsterTypes.h:82
@ mtVindicator
Definition: MonsterTypes.h:72
@ mtElderGuardian
Definition: MonsterTypes.h:25
@ mtHoglin
Definition: MonsterTypes.h:35
@ mtSkeleton
Definition: MonsterTypes.h:59
@ mtSheep
Definition: MonsterTypes.h:56
@ mtEndermite
Definition: MonsterTypes.h:28
@ mtPiglin
Definition: MonsterTypes.h:48
@ mtTurtle
Definition: MonsterTypes.h:69
@ mtPolarBear
Definition: MonsterTypes.h:51
@ mtDolphin
Definition: MonsterTypes.h:22
@ mtMagmaCube
Definition: MonsterTypes.h:40
@ mtWanderingTrader
Definition: MonsterTypes.h:73
@ mtWolf
Definition: MonsterTypes.h:77
@ mtStray
Definition: MonsterTypes.h:65
@ mtRabbit
Definition: MonsterTypes.h:53
@ mtTraderLlama
Definition: MonsterTypes.h:67
@ mtCat
Definition: MonsterTypes.h:16
@ mtZombie
Definition: MonsterTypes.h:79
@ mtOcelot
Definition: MonsterTypes.h:43
@ mtRavager
Definition: MonsterTypes.h:54
@ mtDonkey
Definition: MonsterTypes.h:23
@ mtVex
Definition: MonsterTypes.h:70
@ mtEnderman
Definition: MonsterTypes.h:27
@ mtTropicalFish
Definition: MonsterTypes.h:68
@ mtHusk
Definition: MonsterTypes.h:36
@ mtCaveSpider
Definition: MonsterTypes.h:17
@ mtEvoker
Definition: MonsterTypes.h:29
@ mtPhantom
Definition: MonsterTypes.h:46
@ mtShulker
Definition: MonsterTypes.h:57
@ mtPufferfish
Definition: MonsterTypes.h:52
@ mtWither
Definition: MonsterTypes.h:75
@ mtSkeletonHorse
Definition: MonsterTypes.h:60
@ mtPig
Definition: MonsterTypes.h:47
@ mtDrowned
Definition: MonsterTypes.h:24
@ mtVillager
Definition: MonsterTypes.h:71
@ mtHorse
Definition: MonsterTypes.h:34
@ mtZombieHorse
Definition: MonsterTypes.h:80
@ mtWitch
Definition: MonsterTypes.h:74
@ mtCow
Definition: MonsterTypes.h:20
@ mtSalmon
Definition: MonsterTypes.h:55
@ mtEnderDragon
Definition: MonsterTypes.h:26
@ mtPiglinBrute
Definition: MonsterTypes.h:49
@ mtMooshroom
Definition: MonsterTypes.h:41
@ mtSquid
Definition: MonsterTypes.h:64
@ mtInvalidType
Definition: MonsterTypes.h:12
@ mtBat
Definition: MonsterTypes.h:14
@ mtIllusioner
Definition: MonsterTypes.h:37
@ mtChicken
Definition: MonsterTypes.h:18
@ mtGiant
Definition: MonsterTypes.h:32
@ mtSnowGolem
Definition: MonsterTypes.h:62
@ mtFox
Definition: MonsterTypes.h:30
@ mtBlaze
Definition: MonsterTypes.h:15
@ mtLlama
Definition: MonsterTypes.h:39
@ mtIronGolem
Definition: MonsterTypes.h:38
@ mtCreeper
Definition: MonsterTypes.h:21
@ mtSpider
Definition: MonsterTypes.h:63
@ mtMule
Definition: MonsterTypes.h:42
@ mtPillager
Definition: MonsterTypes.h:50
@ mtGhast
Definition: MonsterTypes.h:31
@ mtParrot
Definition: MonsterTypes.h:45
@ mtSilverfish
Definition: MonsterTypes.h:58
@ mtZoglin
Definition: MonsterTypes.h:78
@ mtPanda
Definition: MonsterTypes.h:44
@ mtCod
Definition: MonsterTypes.h:19
@ mtStrider
Definition: MonsterTypes.h:66
@ mtZombiePigman
Definition: MonsterTypes.h:85
@ mtSlime
Definition: MonsterTypes.h:61
@ mtWitherSkeleton
Definition: MonsterTypes.h:76
@ mtGuardian
Definition: MonsterTypes.h:33
#define WAYPOINT_RADIUS
Definition: PathFinder.h:5
BlockType
Definition: BlockTypes.h:4
Direction
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
std::string AString
Definition: StringUtils.h:11
unsigned char Distance(const BlockState Block)
static bool IsSolid(BLOCKTYPE Block)
Is this block solid (player cannot walk through)?
Definition: BlockInfo.cpp:892
static bool IsTransparent(BLOCKTYPE Block)
Is a block transparent? (https://minecraft.wiki/w/Opacity)
Definition: BlockInfo.cpp:961
Represents two sets of coords, minimum and maximum for each direction.
Definition: BoundingBox.h:24
Definition: Chunk.h:36
int GetPosX(void) const
Definition: Chunk.h:131
bool IsLightValid(void) const
Definition: Chunk.h:83
cChunk * GetNeighborChunk(int a_BlockX, int a_BlockZ)
Returns the chunk into which the specified block belongs, by walking the neighbors.
Definition: Chunk.cpp:1806
bool IsValid(void) const
Returns true iff the chunk block data is valid (loaded / generated)
Definition: Chunk.h:58
int GetPosZ(void) const
Definition: Chunk.h:132
void GetBlockTypeMeta(Vector3i a_RelPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: Chunk.cpp:1757
static const int Width
Definition: ChunkDef.h:124
static const int Height
Definition: ChunkDef.h:125
void SendLeashEntity(const cEntity &a_Entity, const cEntity &a_EntityLeashedTo)
void SendSpawnMob(const cMonster &a_Mob)
cEntity * Attacker
Definition: Entity.h:62
Definition: Entity.h:76
const Vector3d & GetSpeed(void) const
Exported in ManualBindings.
Definition: Entity.h:300
float m_Health
Definition: Entity.h:584
void SetPitch(double a_Pitch)
Definition: Entity.cpp:2136
int GetChunkZ(void) const
Definition: Entity.h:208
void AddPosY(double a_AddPosY)
Definition: Entity.h:240
void AddSpeedX(double a_AddSpeedX)
Definition: Entity.cpp:2203
bool IsPlayer(void) const
Definition: Entity.h:160
void SetHeadYaw(double a_HeadYaw)
Definition: Entity.cpp:2102
void BroadcastDeathMessage(TakeDamageInfo &a_TDI)
Announces a death message on chat about killing the entity.
Definition: Entity.cpp:2349
void SetSpeedX(double a_SpeedX)
Sets the speed in the X axis, leaving the other speed components intact.
Definition: Entity.cpp:2167
virtual bool IsInWater(void) const
Returns true if any part of the entity is in a water block.
Definition: Entity.h:501
void AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeedZ)
Definition: Entity.cpp:2194
void SetYaw(double a_Yaw)
Definition: Entity.cpp:2125
virtual cItem GetEquippedLeggings(void) const
Returns the currently equipped leggings; empty item if none.
Definition: Entity.h:342
int GetChunkX(void) const
Definition: Entity.h:207
static const UInt32 INVALID_ID
Special ID that is considered an "invalid value", signifying no entity.
Definition: Entity.h:128
void SetSpeedY(double a_SpeedY)
Sets the speed in the Y axis, leaving the other speed components intact.
Definition: Entity.cpp:2176
bool IsTicking(void) const
Returns true if the entity is valid and ticking.
Definition: Entity.cpp:2259
float GetGravity(void) const
Definition: Entity.h:280
void SetSpeedZ(double a_SpeedZ)
Sets the speed in the Z axis, leaving the other speed components intact.
Definition: Entity.cpp:2185
double GetPosX(void) const
Definition: Entity.h:195
virtual cItem GetEquippedBoots(void) const
Returns the currently equipped boots; empty item if none.
Definition: Entity.h:345
cWorld * m_World
Definition: Entity.h:624
double GetPosZ(void) const
Definition: Entity.h:197
void Destroy()
Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet.
Definition: Entity.cpp:243
eEntityType GetEntityType(void) const
Definition: Entity.h:156
virtual bool IsOnFire(void) const
Definition: Entity.h:489
void AddLeashedMob(cMonster *a_Monster)
Adds a mob to the leashed list of mobs.
Definition: Entity.cpp:2299
bool IsLeashKnot(void) const
Definition: Entity.h:172
double GetPosY(void) const
Definition: Entity.h:196
void AddSpeedZ(double a_AddSpeedZ)
Definition: Entity.cpp:2221
bool IsPawn(void) const
Definition: Entity.h:163
virtual bool IsOnGround(void) const
Returns whether the entity is on ground or not.
Definition: Entity.h:519
float GetHeight(void) const
Definition: Entity.h:193
virtual cItem GetEquippedWeapon(void) const
Returns the curently equipped weapon; empty item if none.
Definition: Entity.h:333
virtual bool DoTakeDamage(TakeDamageInfo &a_TDI)
Makes this entity take damage specified in the a_TDI.
Definition: Entity.cpp:404
bool m_bOnGround
Stores if the entity is on the ground.
Definition: Entity.h:604
virtual cItem GetEquippedHelmet(void) const
Returns the currently equipped helmet; empty item if none.
Definition: Entity.h:336
virtual void OnRightClicked(cPlayer &a_Player)
Called when the specified player right-clicks this entity.
Definition: Entity.h:524
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:297
@ etMonster
Definition: Entity.h:94
bool HasAnyMobLeashed() const
Returs whether the entity has any mob leashed to it.
Definition: Entity.h:557
void RemoveLeashedMob(cMonster *a_Monster)
Removes a mob from the leashed list of mobs.
Definition: Entity.cpp:2311
virtual void BroadcastMovementUpdate(const cClientHandle *a_Exclude=nullptr)
Updates clients of changes in the entity.
Definition: Entity.cpp:1966
void StartBurning(int a_TicksLeftBurning)
Puts the entity on fire for the specified amount of ticks.
Definition: Entity.cpp:1908
cWorld * GetWorld(void) const
Definition: Entity.h:190
virtual cItem GetEquippedChestplate(void) const
Returns the currently equipped chestplate; empty item if none.
Definition: Entity.h:339
static cLeashKnot * FindKnotAtPos(cWorldInterface &a_WorldInterface, Vector3i a_BlockPos)
Returns the leash knot entity representing the knot at the specified position.
Definition: LeashKnot.cpp:142
Definition: Pawn.h:17
virtual void HandleFalling(void)
Definition: Pawn.cpp:297
void TargetingMe(cMonster *a_Monster)
Add the monster to the list of monsters targeting this pawn.
Definition: Pawn.cpp:285
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Definition: Pawn.cpp:32
bool m_bTouchGround
Definition: Pawn.h:105
virtual void OnRemoveFromWorld(cWorld &a_World) override
Called when the entity is removed from a world.
Definition: Pawn.cpp:556
void NoLongerTargetingMe(cMonster *a_Monster)
Remove the monster from the list of monsters targeting this pawn.
Definition: Pawn.cpp:265
virtual void KilledBy(TakeDamageInfo &a_TDI) override
Called when the health drops below zero.
Definition: Pawn.cpp:129
Definition: Player.h:29
void AwardAchievement(CustomStatistic a_Ach)
Awards the player an achievement.
Definition: Player.cpp:1372
StatisticsManager & GetStatistics()
Return the associated statistic and achievement manager.
Definition: Player.h:237
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
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 CanMobsTarget(void) const
Returns true if the player can be targeted by Mobs.
Definition: Player.cpp:1061
IntType RandInt(IntType a_Min, IntType a_Max)
Return a random IntType in the range [a_Min, a_Max].
Definition: FastRandom.h:78
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
AString m_CustomName
Definition: Item.h:167
char GetMaxStackSize(void) const
Returns the maximum amount of stacked items of this type.
Definition: Item.cpp:207
short m_ItemType
Definition: Item.h:163
short m_ItemDamage
Definition: Item.h:165
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
size_t Size(void) const
Definition: Item.h:238
bool ContainsType(const cItem &a_Item)
Definition: Item.cpp:787
void Add(const cItem &a_Item)
Definition: Item.h:233
static eMonsterType ItemDamageToMonsterType(short a_ItemDamage)
Converts the Spawn egg item damage to the monster type to spawn.
Definition: ItemSpawnEgg.h:64
static bool LineOfSightTrace(cWorld &a_World, const Vector3d &a_Start, const Vector3d &a_End, int a_Sight)
Returns true if the two positions are within line of sight (not obscured by blocks).
cMonster(const AString &a_ConfigName, eMonsterType a_MobType, const AString &a_SoundHurt, const AString &a_SoundDeath, const AString &a_SoundAmbient, float a_Width, float a_Height)
Creates the mob object.
Definition: Monster.cpp:84
std::chrono::milliseconds m_IdleInterval
Definition: Monster.h:299
int m_LoveCooldown
If above 0, the monster is in cooldown mode and will refuse to breed.
Definition: Monster.h:376
int m_AmbientSoundTimer
Definition: Monster.h:330
void SetPitchAndYawFromDestination(bool a_IsFollowingPath)
Sets the body yaw and head yaw.
Definition: Monster.cpp:471
cPathFinder m_PathFinder
The pathfinder instance handles pathfinding for this monster.
Definition: Monster.h:255
virtual bool IsNetherNative(void)
Returns whether this mob spawns in the Nether in Vanilla.
Definition: Monster.cpp:988
void ResetAttackCooldown()
Definition: Monster.cpp:937
void SetCustomName(const AString &a_CustomName)
Sets the custom name of the monster.
Definition: Monster.cpp:946
double m_RelativeWalkSpeed
Definition: Monster.h:328
static AString MobTypeToVanillaName(eMonsterType a_MobType)
Translates MobType enum to the vanilla name of the mob, empty string if unknown.
Definition: Monster.cpp:1025
eFamily GetMobFamily(void) const
Definition: Monster.cpp:1714
virtual void InStateChasing(std::chrono::milliseconds a_Dt, cChunk &a_Chunk)
Definition: Monster.cpp:906
int m_JumpCoolDown
Definition: Monster.h:297
Vector3d m_FinalDestination
Coordinates for the ultimate, final destination.
Definition: Monster.h:264
virtual void CheckEventLostPlayer(std::chrono::milliseconds a_Dt)
Definition: Monster.cpp:784
bool WouldBurnAt(Vector3d a_Location, cChunk &a_Chunk)
Definition: Monster.cpp:1651
int m_SightDistance
Definition: Monster.h:314
AString m_SoundHurt
Definition: Monster.h:306
virtual void GetFollowedItems(cItems &a_Items)
Returns the items that the animal of this class follows when a player holds it in hand.
Definition: Monster.h:223
static cTickTime GetSpawnDelay(cMonster::eFamily a_MobFamily)
Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family.
Definition: Monster.cpp:1186
virtual bool IsTame(void) const
Definition: Monster.h:152
void LoveTick(void)
Does the whole love and breeding processing.
Definition: Monster.cpp:1354
virtual void SpawnOn(cClientHandle &a_ClientHandle) override
Descendants override this function to send a command to the specified client to spawn the entity on t...
Definition: Monster.cpp:167
void AddRandomRareDropItem(cItems &a_Drops, cItems &a_Items, unsigned int a_LootingLevel)
Adds one rare item out of the list of rare items a_Items modified by the looting level a_LootingLevel...
Definition: Monster.cpp:1549
virtual void KilledBy(TakeDamageInfo &a_TDI) override
Called when the health drops below zero.
Definition: Monster.cpp:602
cUUID m_Feeder
Remembers the player is was last fed by for statistics tracking.
Definition: Monster.h:370
static std::unique_ptr< cMonster > NewMonsterFromType(eMonsterType a_MobType)
Creates a new object of the specified mob.
Definition: Monster.cpp:1252
void SetAge(int a_Age)
Definition: Monster.h:158
void SetTarget(cPawn *a_NewTarget)
Sets the target that this mob will chase.
Definition: Monster.cpp:1204
void SetLeashToPos(Vector3d *pos)
Sets entity position to where is leashed this mob.
Definition: Monster.h:103
void GetMonsterConfig(const AString &a_Name)
Reads the monster configuration for the specified monster name and assigns it to this object.
Definition: Monster.cpp:979
cMonster * m_LovePartner
The monster's breeding partner.
Definition: Monster.h:367
virtual void HandleFalling(void) override
Definition: Monster.cpp:533
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
float m_DropChanceChestplate
Definition: Monster.h:319
void AddRandomDropItem(cItems &a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth=0)
Adds a random number of a_Item between a_Min and a_Max to itemdrops a_Drops.
Definition: Monster.cpp:1518
void MoveToWayPoint(cChunk &a_Chunk)
Move in a straight line to the next waypoint in the path, will jump if needed.
Definition: Monster.cpp:181
bool m_PathfinderActivated
Stores if pathfinder is being used - set when final destination is set, and unset when stopped moving...
Definition: Monster.h:258
static eFamily FamilyFromType(eMonsterType a_MobType)
Returns the mob family based on the type.
Definition: Monster.cpp:1102
cPawn * GetTarget()
Returns the current target.
Definition: Monster.cpp:1243
void HandleDaylightBurning(cChunk &a_Chunk, bool WouldBurn)
Definition: Monster.cpp:1621
float m_DropChanceWeapon
Definition: Monster.h:317
void EngageLoveMode(cMonster *a_Partner)
Start the mating process.
Definition: Monster.cpp:1329
void UnsafeUnsetTarget()
Unset the target without notifying the target entity.
Definition: Monster.cpp:1234
@ mfNoSpawn
Definition: Monster.h:35
@ mfAmbient
Definition: Monster.h:32
@ mfWater
Definition: Monster.h:33
@ mfPassive
Definition: Monster.h:31
@ mfHostile
Definition: Monster.h:30
cPawn * m_Target
A pointer to the entity this mobile is aiming to reach.
Definition: Monster.h:385
virtual void GetBreedingItems(cItems &a_Items)
Returns the items that make the animal breed - this is usually the same as the ones that make the ani...
Definition: Monster.h:226
virtual bool DoTakeDamage(TakeDamageInfo &a_TDI) override
Makes this entity take damage specified in the a_TDI.
Definition: Monster.cpp:572
virtual void InStateEscaping(std::chrono::milliseconds a_Dt, cChunk &a_Chunk)
Definition: Monster.cpp:916
bool IsLeashed() const
Returns whether the monster is leashed to an entity.
Definition: Monster.h:86
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
float m_DropChanceBoots
Definition: Monster.h:321
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
virtual bool IsUndead(void)
Returns whether this mob is undead (skeleton, zombie, etc.)
Definition: Monster.cpp:997
int m_AgingTimer
Definition: Monster.h:333
eMonsterType GetMobType(void) const
Definition: Monster.h:70
bool IsInLove() const
Returns whether the monster has just been fed and is ready to mate.
Definition: Monster.h:241
cEntity * m_LeashedTo
Entity leashed to.
Definition: Monster.h:338
cEntity * GetLeashedTo() const
Returns the entity to where this mob is leashed, returns nullptr if it's not leashed.
Definition: Monster.h:95
static AString MobTypeToString(eMonsterType a_MobType)
Translates MobType enum to a string, empty string if unknown.
Definition: Monster.cpp:1006
int m_MatingTimer
The monster is engaged in mating, once this reaches zero, a baby will be born.
Definition: Monster.h:379
float m_DropChanceHelmet
Definition: Monster.h:318
void Unleash(bool a_ShouldDropLeashPickup)
Unleash the monster.
Definition: Monster.cpp:1778
eMonsterType m_MobType
Definition: Monster.h:302
AString m_SoundAmbient
Definition: Monster.h:308
@ IDLE
Definition: Monster.h:40
@ CHASING
Definition: Monster.h:40
@ ATTACKING
Definition: Monster.h:40
@ ESCAPING
Definition: Monster.h:40
std::chrono::milliseconds m_DestroyTimer
Definition: Monster.h:300
void AddRandomWeaponDropItem(cItems &a_Drops, unsigned int a_LootingLevel)
Adds weapon that is equipped with the chance saved in m_DropChance... to the drop.
Definition: Monster.cpp:1606
AString m_CustomName
Definition: Monster.h:303
void AddRandomArmorDropItem(cItems &a_Drops, unsigned int a_LootingLevel)
Adds armor that is equipped with the chance saved in m_DropChance... to the drop.
Definition: Monster.cpp:1563
Vector3d m_NextWayPointPosition
Coordinates of the next position that should be reached.
Definition: Monster.h:261
bool m_IsLeashActionJustDone
Mob has ben leashed or unleashed in current player action.
Definition: Monster.h:344
bool DoesPosYRequireJump(double a_PosY)
Returns whether the monster needs to jump to reach a given height.
Definition: Monster.h:283
enum cMonster::MState m_EMState
bool m_WasLastTargetAPlayer
Definition: Monster.h:335
virtual void EventSeePlayer(cPlayer *a_Player, cChunk &a_Chunk)
Definition: Monster.cpp:829
std::chrono::milliseconds m_LoseSightAbandonTargetTimer
Definition: Monster.h:315
double m_AttackRate
Definition: Monster.h:310
bool m_CustomNameAlwaysVisible
Definition: Monster.h:304
bool m_BurnsInDaylight
Definition: Monster.h:327
int m_TicksSinceLastDamaged
Definition: Monster.h:323
void ResetLoveMode()
Finish the mating process.
Definition: Monster.cpp:1339
virtual void EventLosePlayer(void)
Definition: Monster.cpp:839
void SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible)
Sets the custom name visiblity of this monster.
Definition: Monster.cpp:966
void LeashTo(cEntity &a_Entity, bool a_ShouldBroadcast=true)
Leash the monster to an entity.
Definition: Monster.cpp:1723
int m_AttackCoolDownTicksLeft
Definition: Monster.h:313
std::unique_ptr< Vector3d > m_LeashToPos
Entity pos where this mob was leashed to.
Definition: Monster.h:341
virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk &a_Chunk)
Definition: Monster.cpp:851
bool CanBeLeashed() const
Returns whether the mob can be leashed.
Definition: Monster.h:80
virtual void InheritFromParents(cMonster *a_Parent1, cMonster *a_Parent2)
Called after the baby is born, allows the baby to inherit the parents' properties (color,...
Definition: Monster.h:229
float m_DropChanceLeggings
Definition: Monster.h:320
bool ReachedFinalDestination(void)
Returns if the ultimate, final destination has been reached.
Definition: Monster.h:273
void RightClickFeed(cPlayer &a_Player)
Right click call to process feeding.
Definition: Monster.cpp:1474
bool IsBaby(void) const
Definition: Monster.h:156
void CalcLeashActions(std::chrono::milliseconds a_Dt)
Leash calculations inside Tick function.
Definition: Monster.cpp:403
void AddRandomUncommonDropItem(cItems &a_Drops, float a_Chance, short a_Item, short a_ItemHealth=0)
Adds a item a_Item with the chance of a_Chance (in percent) to itemdrops a_Drops.
Definition: Monster.cpp:1537
static AString MobTypeToVanillaNBT(eMonsterType a_MobType)
Translates the MobType enum to the vanilla nbt name.
Definition: Monster.cpp:1044
int m_LoveTimer
If above 0, the monster is in love mode, and will breed if a nearby monster is also in love mode.
Definition: Monster.h:373
virtual void CheckEventSeePlayer(cChunk &a_Chunk)
Definition: Monster.cpp:738
AString m_SoundDeath
Definition: Monster.h:307
virtual void OnRemoveFromWorld(cWorld &a_World) override
Called when the entity is removed from a world.
Definition: Monster.cpp:139
static eMonsterType StringToMobType(const AString &a_MobTypeName)
Translates MobType string to the enum, mtInvalidType if not recognized.
Definition: Monster.cpp:1063
void StopMovingToPosition()
Stops pathfinding.
Definition: Monster.cpp:255
ePathFinderStatus GetNextWayPoint(cChunk &a_Chunk, const Vector3d &a_Source, Vector3d *a_Destination, Vector3d *a_OutputWaypoint, bool a_DontCare=false)
Updates the PathFinder's internal state and returns a waypoint.
Definition: PathFinder.cpp:23
static eVillagerType GetRandomProfession()
Returns a random Profession.
Definition: Villager.cpp:405
void AssignAttributes(cMonster *a_Monster, const AString &a_Name)
static cRoot * Get()
Definition: Root.h:52
cMonsterConfig * GetMonsterConfig(void)
Definition: Root.h:90
std::unordered_map< CustomStatistic, StatValue > Custom
Vector3< T > addedY(T a_AddY) const
Returns a copy of this vector moved by the specified amount on the y axis.
Definition: Vector3.h:314
T x
Definition: Vector3.h:17
Vector3< int > Floor(void) const
Returns a new Vector3i with coords set to std::floor() of this vector's coords.
Definition: Vector3.h:177
T y
Definition: Vector3.h:17
void Normalize(void)
Definition: Vector3.h:49
T z
Definition: Vector3.h:17
double SqrLength(void) const
Definition: Vector3.h:105
Definition: World.h:53
virtual void BroadcastUnleashEntity(const cEntity &a_Entity) override
bool DoWithPlayerByUUID(const cUUID &a_PlayerUUID, cPlayerListCallback a_Callback)
Finds the player over his uuid and calls the callback.
Definition: World.cpp:2339
UInt32 SpawnExperienceOrb(Vector3d a_Pos, int a_Reward)
Spawns an experience orb at the given location with the given reward.
Definition: World.cpp:1894
void QueueLightChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_Callback={})
Queues a chunk for lighting; a_Callback is called after the chunk is lighted.
Definition: World.cpp:2676
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
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Returns the block type at the specified position.
Definition: World.h:363
bool DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback a_Callback)
Calls the callback if the entity with the specified ID is found, with the entity object as the callba...
Definition: World.cpp:2464
virtual bool ForEachEntityInBox(const cBoundingBox &a_Box, cEntityCallback a_Callback) override
Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Definition: World.cpp:2445
virtual void BroadcastLeashEntity(const cEntity &a_Entity, const cEntity &a_EntityLeashedTo) override
void SpawnItemPickups(const cItems &a_Pickups, Vector3i a_BlockPos, double a_FlyAwaySpeed=1.0, bool a_IsPlayerCreated=false)
Spawns item pickups for each item in the list.
Definition: World.cpp:1806
virtual std::vector< UInt32 > SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) override
Spawns experience orbs of the specified total value at the given location.
Definition: World.cpp:1915
virtual void BroadcastSoundEffect(const AString &a_SoundName, Vector3d a_Position, float a_Volume, float a_Pitch, 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
virtual bool ForEachPlayer(cPlayerListCallback a_Callback) override
Calls the callback for each player in the list; returns true if all players processed,...
Definition: World.cpp:2266