2017-09-19 04:34:08 -04:00
|
|
|
|
2017-08-21 04:46:41 -04:00
|
|
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
|
|
|
|
|
|
|
#include "LeashKnot.h"
|
|
|
|
#include "Player.h"
|
2018-08-28 20:51:25 -04:00
|
|
|
#include "../Mobs/Monster.h"
|
|
|
|
#include "../BoundingBox.h"
|
|
|
|
#include "../ClientHandle.h"
|
2017-08-21 04:46:41 -04:00
|
|
|
|
|
|
|
// Ticks to wait in Tick function to optimize calculations
|
|
|
|
#define TICK_STEP 10
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-09-29 08:59:24 -04:00
|
|
|
cLeashKnot::cLeashKnot(eBlockFace a_BlockFace, Vector3d a_Pos) :
|
2020-04-13 12:38:06 -04:00
|
|
|
Super(etLeashKnot, a_BlockFace, a_Pos),
|
2017-08-21 04:46:41 -04:00
|
|
|
m_ShouldSelfDestroy(false),
|
|
|
|
m_TicksToSelfDestroy(20 * 1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cLeashKnot::OnRightClicked(cPlayer & a_Player)
|
|
|
|
{
|
2020-04-13 12:38:06 -04:00
|
|
|
Super::OnRightClicked(a_Player);
|
2017-08-21 04:46:41 -04:00
|
|
|
|
|
|
|
TiePlayersLeashedMobs(a_Player, true);
|
|
|
|
|
|
|
|
GetWorld()->BroadcastEntityMetadata(*this); // Update clients
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-09-11 17:20:49 -04:00
|
|
|
void cLeashKnot::TiePlayersLeashedMobs(cPlayer & a_Player, bool a_ShouldBroadcast)
|
2017-08-21 04:46:41 -04:00
|
|
|
{
|
|
|
|
// Check leashed nearby mobs to tie them to this knot
|
2017-09-11 17:20:49 -04:00
|
|
|
// taking world from player (instead from this) because this can be called before entity was initialized
|
|
|
|
a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8, -4), [&](cEntity & a_Entity)
|
2017-08-21 04:46:41 -04:00
|
|
|
{
|
|
|
|
// If the entity is not a monster skip it
|
2017-09-11 17:20:49 -04:00
|
|
|
if (a_Entity.GetEntityType() != cEntity::eEntityType::etMonster)
|
2017-08-21 04:46:41 -04:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-11 17:20:49 -04:00
|
|
|
auto & PotentialLeashed = static_cast<cMonster&>(a_Entity);
|
2017-08-21 04:46:41 -04:00
|
|
|
|
|
|
|
// If can't be leashed skip it
|
2017-09-11 17:20:49 -04:00
|
|
|
if (!PotentialLeashed.CanBeLeashed())
|
2017-08-21 04:46:41 -04:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it's not leashed to the player skip it
|
|
|
|
if (
|
2017-09-11 17:20:49 -04:00
|
|
|
!PotentialLeashed.IsLeashed() ||
|
|
|
|
!PotentialLeashed.GetLeashedTo()->IsPlayer() ||
|
|
|
|
(PotentialLeashed.GetLeashedTo()->GetUniqueID() != a_Player.GetUniqueID())
|
2017-08-21 04:46:41 -04:00
|
|
|
)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// All conditions met, unleash from player and leash to fence
|
2017-09-11 17:20:49 -04:00
|
|
|
PotentialLeashed.Unleash(false, false);
|
|
|
|
PotentialLeashed.LeashTo(*this, a_ShouldBroadcast);
|
2017-08-21 04:46:41 -04:00
|
|
|
return false;
|
|
|
|
}
|
2017-09-11 17:20:49 -04:00
|
|
|
);
|
2017-08-21 04:46:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cLeashKnot::KilledBy(TakeDamageInfo & a_TDI)
|
|
|
|
{
|
2020-04-13 12:38:06 -04:00
|
|
|
Super::KilledBy(a_TDI);
|
2017-09-19 10:12:54 -04:00
|
|
|
m_World->BroadcastSoundEffect("entity.leashknot.break", GetPosition(), 1, 1);
|
2017-08-21 04:46:41 -04:00
|
|
|
Destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cLeashKnot::GetDrops(cItems & a_Items, cEntity * a_Killer)
|
|
|
|
{
|
|
|
|
if ((a_Killer != nullptr) && a_Killer->IsPlayer() && !static_cast<cPlayer *>(a_Killer)->IsGameModeCreative())
|
|
|
|
{
|
|
|
|
a_Items.push_back(cItem(E_ITEM_LEASH));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cLeashKnot::SpawnOn(cClientHandle & a_ClientHandle)
|
|
|
|
{
|
2020-04-13 12:38:06 -04:00
|
|
|
Super::SpawnOn(a_ClientHandle);
|
2020-04-20 15:46:04 -04:00
|
|
|
a_ClientHandle.SendSpawnEntity(*this);
|
2017-08-21 04:46:41 -04:00
|
|
|
a_ClientHandle.SendEntityMetadata(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-07-26 17:24:36 -04:00
|
|
|
|
2017-08-21 04:46:41 -04:00
|
|
|
void cLeashKnot::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
|
|
|
{
|
|
|
|
m_TicksAlive++;
|
|
|
|
|
|
|
|
if ((m_TicksAlive % TICK_STEP) != 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_ShouldSelfDestroy)
|
|
|
|
{
|
|
|
|
m_TicksToSelfDestroy -= TICK_STEP;
|
|
|
|
|
|
|
|
if (m_TicksToSelfDestroy <= 0)
|
|
|
|
{
|
|
|
|
Destroy();
|
2017-09-19 10:12:54 -04:00
|
|
|
m_World->BroadcastSoundEffect("entity.leashknot.break", GetPosition(), 1, 1);
|
2017-08-21 04:46:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cLeashKnot * cLeashKnot::FindKnotAtPos(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos)
|
|
|
|
{
|
2017-09-11 17:20:49 -04:00
|
|
|
cLeashKnot * LeashKnot = nullptr;
|
|
|
|
a_WorldInterface.ForEachEntityInBox(cBoundingBox(a_BlockPos, 0.5, 1), [&](cEntity & a_Entity)
|
2017-08-21 04:46:41 -04:00
|
|
|
{
|
2017-09-11 17:20:49 -04:00
|
|
|
if (a_Entity.IsLeashKnot())
|
2017-08-21 04:46:41 -04:00
|
|
|
{
|
2017-09-11 17:20:49 -04:00
|
|
|
LeashKnot = static_cast<cLeashKnot *>(&a_Entity);
|
2017-08-21 04:46:41 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-09-11 17:20:49 -04:00
|
|
|
);
|
2017-08-21 04:46:41 -04:00
|
|
|
|
2017-09-11 17:20:49 -04:00
|
|
|
return LeashKnot;
|
2017-08-21 04:46:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|