mirror of
https://github.com/celisej567/mcpe.git
synced 2025-12-31 17:49:17 +03:00
240 lines
5.1 KiB
C++
240 lines
5.1 KiB
C++
/********************************************************************
|
|
Minecraft: Pocket Edition - Decompilation Project
|
|
Copyright (C) 2023 iProgramInCpp
|
|
|
|
The following code is licensed under the BSD 1 clause license.
|
|
SPDX-License-Identifier: BSD-1-Clause
|
|
********************************************************************/
|
|
#include "PathfinderMob.hpp"
|
|
#include "world/level/Level.hpp"
|
|
|
|
PathfinderMob::PathfinderMob(Level* pLevel) : Mob(pLevel)
|
|
{
|
|
field_BA0 = false;
|
|
field_BA4 = 0;
|
|
}
|
|
|
|
Entity* PathfinderMob::getAttackTarget()
|
|
{
|
|
return m_pAttackTarget;
|
|
}
|
|
|
|
void PathfinderMob::setAttackTarget(Entity* pEnt)
|
|
{
|
|
m_pAttackTarget = pEnt;
|
|
}
|
|
|
|
Entity* PathfinderMob::findAttackTarget()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
bool PathfinderMob::checkHurtTarget(Entity* pEnt, float f)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void PathfinderMob::checkCantSeeTarget(Entity* pEnt, float f)
|
|
{
|
|
if (f > 32.0f)
|
|
setAttackTarget(nullptr);
|
|
}
|
|
|
|
float PathfinderMob::getWalkTargetValue(int, int, int)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
bool PathfinderMob::shouldHoldGround()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void PathfinderMob::findRandomStrollLocation()
|
|
{
|
|
bool foundLocation = false;
|
|
|
|
float maxDist = -99999.0f;
|
|
int dx = -1, dy = -1, dz = -1;
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
int testX = Mth::floor(float(m_pos.x + m_random.nextInt(13)) - 6.0f);
|
|
int testY = Mth::floor(float(m_pos.y + m_random.nextInt(7)) - 3.0f);
|
|
int testZ = Mth::floor(float(m_pos.z + m_random.nextInt(13)) - 6.0f);
|
|
|
|
float wtv = getWalkTargetValue(testX, testY, testZ);
|
|
if (maxDist < wtv)
|
|
{
|
|
maxDist = wtv;
|
|
dx = testX;
|
|
dy = testY;
|
|
dz = testZ;
|
|
foundLocation = true;
|
|
}
|
|
}
|
|
|
|
if (foundLocation)
|
|
{
|
|
m_pLevel->findPath(&m_path, this, dx, dy, dz, 10.0f);
|
|
}
|
|
}
|
|
|
|
float PathfinderMob::getWalkingSpeedModifier()
|
|
{
|
|
float mod = Mob::getWalkingSpeedModifier();
|
|
|
|
if (field_BA4 > 0)
|
|
mod *= 2.0f;
|
|
|
|
return mod;
|
|
}
|
|
|
|
bool PathfinderMob::canSpawn()
|
|
{
|
|
if (!Mob::canSpawn())
|
|
return false;
|
|
|
|
return getWalkTargetValue(Mth::floor(m_pos.x), Mth::floor(m_hitbox.min.y), Mth::floor(m_pos.z)) >= 0.0f;
|
|
}
|
|
|
|
static Vec3 GetNodePosition(Node* pNode, Entity* pEnt)
|
|
{
|
|
float offset = float(int(pEnt->field_88 + 1.0f)) * 0.5f;
|
|
float fx = float(pNode->m_x) + offset;
|
|
float fz = float(pNode->m_z) + offset;
|
|
float fy = float(pNode->m_y);
|
|
return Vec3(fx, fy, fz);
|
|
}
|
|
|
|
void PathfinderMob::updateAi()
|
|
{
|
|
if (field_BA4 > 0)
|
|
field_BA4--;
|
|
|
|
field_BA0 = shouldHoldGround();
|
|
|
|
if (m_pAttackTarget)
|
|
{
|
|
if (!m_pAttackTarget->isAlive())
|
|
{
|
|
m_pAttackTarget = nullptr;
|
|
}
|
|
else
|
|
{
|
|
float dist = m_pAttackTarget->distanceTo(this);
|
|
|
|
if (canSee(m_pAttackTarget))
|
|
checkHurtTarget(m_pAttackTarget, dist);
|
|
else
|
|
checkCantSeeTarget(m_pAttackTarget, dist);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pAttackTarget = findAttackTarget();
|
|
if (m_pAttackTarget)
|
|
m_pLevel->findPath(&m_path, this, m_pAttackTarget, 16.0f);
|
|
}
|
|
|
|
if (!field_BA0 && m_pAttackTarget && (m_path.empty() || m_random.nextInt(20) != 0))
|
|
{
|
|
m_pLevel->findPath(&m_path, this, m_pAttackTarget, 16.0f);
|
|
}
|
|
else if (!field_BA0 && ((m_path.empty() && m_random.nextInt(180) == 0) || field_BA4 > 0 || m_random.nextInt(120) == 0))
|
|
{
|
|
if (field_AFC < 100)
|
|
findRandomStrollLocation();
|
|
}
|
|
|
|
|
|
m_pitch = 0.0f;
|
|
|
|
if (m_path.empty() || m_random.nextInt(100) == 0)
|
|
{
|
|
Mob::updateAi();
|
|
return;
|
|
}
|
|
|
|
// follow path
|
|
Node* pCurrNode = m_path.getCurrentNode();
|
|
Vec3 nodePos = GetNodePosition(pCurrNode, this);
|
|
|
|
// Skip all nodes that we are inside of.
|
|
float sqdbl = (field_88 * 2.0f) * (field_88 * 2.0f);
|
|
while (sqdbl > nodePos.distanceToSqr(Vec3(m_pos.x, nodePos.y, m_pos.z)))
|
|
{
|
|
m_path.advance();
|
|
|
|
if (m_path.endOfPath())
|
|
{
|
|
m_path.clear();
|
|
pCurrNode = nullptr;
|
|
break;
|
|
}
|
|
|
|
nodePos = GetNodePosition(pCurrNode, this);
|
|
}
|
|
|
|
field_B0C = false;
|
|
|
|
bool inWater = isInWater();
|
|
bool inLava = isInLava();
|
|
|
|
if (!pCurrNode)
|
|
{
|
|
float ang = Mth::atan2(nodePos.z - m_pos.z, nodePos.x - m_pos.x) * 180.0f / float(M_PI) - 90.0f;
|
|
float heightDiff = nodePos.y - Mth::floor(m_hitbox.min.y + 0.5f);
|
|
|
|
field_B04 = field_B14;
|
|
|
|
float angDiff = ang - m_yaw;
|
|
while (angDiff < -180.0f) angDiff += 360.0f;
|
|
while (angDiff >= 180.0f) angDiff -= 360.0f;
|
|
|
|
if (angDiff > +30.0f) angDiff = +30.0f;
|
|
if (angDiff < -30.0f) angDiff = -30.0f;
|
|
|
|
float oldYaw = m_yaw;
|
|
|
|
m_yaw += angDiff;
|
|
|
|
if (field_BA0 && m_pAttackTarget)
|
|
{
|
|
float ang2 = Mth::atan2(m_pAttackTarget->m_pos.z - m_pos.z, m_pAttackTarget->m_pos.x - m_pos.x) * 180.0f / float(M_PI) - 90.0f;
|
|
m_yaw = ang2;
|
|
|
|
float thing = ((((angDiff + oldYaw) - ang2) + 90.0f) * float(M_PI)) / 180.0f;
|
|
|
|
// @NOTE: Using old field_B04 value
|
|
field_B00 = -field_B04 * Mth::sin(thing);
|
|
field_B04 = field_B04 * Mth::cos(thing);
|
|
}
|
|
|
|
if (heightDiff > 0.0f)
|
|
field_B0C = true;
|
|
}
|
|
|
|
if (m_pAttackTarget)
|
|
lookAt(m_pAttackTarget, 30.0f, 30.0f);
|
|
|
|
// if we hit a wall while moving
|
|
if (field_7D && !isPathFinding())
|
|
field_B0C = true;
|
|
|
|
// if we're in water, try to swim up
|
|
if (m_random.nextFloat() < 0.8f && (inWater || inLava))
|
|
field_B0C = true;
|
|
}
|
|
|
|
void PathfinderMob::setPath(Path& path)
|
|
{
|
|
// @TODO: Not sure if it calls the destructor here. In original Minecraft, it doesn't.
|
|
m_path = path;
|
|
}
|
|
|
|
bool PathfinderMob::isPathFinding()
|
|
{
|
|
return !m_path.empty();
|
|
}
|