Files
minecraft-pe-0.6.1/src/world/entity/PathfinderMob.cpp
2026-03-02 22:04:18 +03:00

249 lines
5.9 KiB
C++
Executable File

#include "PathfinderMob.h"
#include "../level/Level.h"
#include "../phys/Vec3.h"
#include "../../util/Mth.h"
#include "../../util/PerfTimer.h"
#include "../../SharedConstants.h"
#include "ai/Sensing.h"
PathfinderMob::PathfinderMob( Level* level )
: super(level),
//navigation(this, level, 16),
attackTargetId(0),
holdGround(false),
fleeTime(0)//,
//pathfinderMask(0)
{
sensing = new Sensing(this);
navigation = new PathNavigation(this, level, 16);
}
PathfinderMob::~PathfinderMob() {
delete navigation;
delete sensing;
}
bool PathfinderMob::canSpawn()
{
return super::canSpawn() && getWalkTargetValue(Mth::floor(x), Mth::floor(bb.y0), Mth::floor(z)) >= 0;
}
bool PathfinderMob::isPathFinding()
{
return !path.isEmpty();
}
void PathfinderMob::setPath( Path& path )
{
this->path = path;
}
Entity* PathfinderMob::getAttackTarget()
{
if (attackTargetId == 0) return NULL;
return level->getEntity(attackTargetId);
}
void PathfinderMob::setAttackTarget( Entity* attacker )
{
attackTargetId = attacker? attacker->entityId : 0;
}
bool PathfinderMob::shouldHoldGround()
{
return false;
}
void PathfinderMob::updateAi()
{
TIMER_PUSH("ai");
if (fleeTime > 0) fleeTime--;
holdGround = shouldHoldGround();
float maxDist = 16;
Entity* attackTarget = NULL;
if (attackTargetId == 0) {
attackTarget = findAttackTarget();
if (attackTarget != NULL) {
level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0);
attackTargetId = attackTarget->entityId;
//LOGI("path.empty: %d\n", path.isEmpty());
}
} else {
attackTarget = level->getEntity(attackTargetId);
if (!attackTarget || !attackTarget->isAlive()) {
attackTargetId = 0;
attackTarget = NULL;
} else {
attackTargetId = attackTarget->entityId;
float d = attackTarget->distanceTo(this);
if (canSee(attackTarget)) {
checkHurtTarget(attackTarget, d);
} else {
checkCantSeeTarget(attackTarget, d);
}
}
}
TIMER_POP();
/*
* if (holdGround) { xxa = 0; yya = 0; jumping = false; return; }
*/
bool doStroll = false;
if (!holdGround && (attackTarget != NULL && (path.isEmpty() || random.nextInt(20) == 0))) {
level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0);
} else if (!holdGround) {
if (path.isEmpty() && (random.nextInt(180) == 0)) {
doStroll = true;
} else {
if (random.nextInt(120) == 0) doStroll = true;
else if (fleeTime > 0 && (fleeTime&7) == 1) doStroll = true;
}
}
if (doStroll) {
if (noActionTime < SharedConstants::TicksPerSecond * 5) {
findRandomStrollLocation();
}
}
int yFloor = Mth::floor(bb.y0 + .5f);
bool inWater = isInWater();
bool inLava = isInLava();
xRot = 0;
if (path.isEmpty() || random.nextInt(100) == 0) {
//super::serverAiStep();
super::updateAi();
return;
}
TIMER_PUSH("followpath");
Vec3 target = path.currentPos(this);
float r = bbWidth * 2;
bool looping = true;
while (looping && target.distanceToSqr(x, target.y, z) < r * r) {
path.next();
if (path.isDone()) {
looping = false;
path.destroy();
} else target = path.currentPos(this);
}
jumping = false;
if (looping) {
float xd = target.x - x;
float zd = target.z - z;
float yd = target.y - yFloor;
// float yRotOld = yRot;
float yRotD = (float) (Mth::atan2(zd, xd) * 180 / Mth::PI) - 90;
float rotDiff = yRotD - yRot;
yya = runSpeed;
while (rotDiff < -180)
rotDiff += 360;
while (rotDiff >= 180)
rotDiff -= 360;
if (rotDiff > MAX_TURN) {
rotDiff = MAX_TURN;
// yya *= 0.2;
}
if (rotDiff < -MAX_TURN) {
rotDiff = -MAX_TURN;
// yya *= 0.2;
}
yRot += rotDiff;
if (holdGround) {
if (attackTarget != NULL) {
float xd2 = attackTarget->x - x;
float zd2 = attackTarget->z - z;
float oldyRot = yRot;
yRot = (float) (Mth::atan2(zd2, xd2) * 180 / Mth::PI) - 90;
rotDiff = ((oldyRot - yRot) + 90) * Mth::PI / 180;
xxa = -Mth::sin(rotDiff) * yya * 1.0f;
yya = Mth::cos(rotDiff) * yya * 1.0f;
}
}
if (yd > 0) {
jumping = true;
}
}
if (attackTarget != NULL) {
lookAt(attackTarget, 30, 30);
}
if (this->horizontalCollision && !isPathFinding()) jumping = true;
if (random.nextFloat() < 0.8f && (inWater || inLava)) jumping = true;
TIMER_POP();
}
void PathfinderMob::findRandomStrollLocation()
{
TIMER_PUSH("stroll");
bool hasBest = false;
int xBest = -1;
int yBest = -1;
int zBest = -1;
float best = -99999;
for (int i = 0; i < 10; i++) {
int xt = Mth::floor(x + random.nextInt(13) - 6);
int yt = Mth::floor(y + random.nextInt(7) - 3);
int zt = Mth::floor(z + random.nextInt(13) - 6);
float value = getWalkTargetValue(xt, yt, zt);
if (value > best) {
best = value;
xBest = xt;
yBest = yt;
zBest = zt;
hasBest = true;
}
}
if (hasBest) {
//LOGI("Finding a new strolling location! %d, %d, %d (%d, %d, %d) for %p\n", xBest, yBest, zBest, (int)x, (int)y, (int)z, this);
level->findPath(&path, this, xBest, yBest, zBest, 10, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0);
}
TIMER_POP();
}
void PathfinderMob::checkHurtTarget( Entity* target, float d )
{
}
void PathfinderMob::checkCantSeeTarget( Entity* target, float d )
{
if (d > 32)
attackTargetId = 0;
}
float PathfinderMob::getWalkTargetValue( int x, int y, int z )
{
return 0;
}
Entity* PathfinderMob::findAttackTarget()
{
return NULL;
}
float PathfinderMob::getWalkingSpeedModifier() {
float speed = super::getWalkingSpeedModifier();
if (fleeTime > 0) speed *= 2;
return speed;
}
int PathfinderMob::getNoActionTime() {
return noActionTime;
}
PathNavigation* PathfinderMob::getNavigation() {
return navigation;
}