mirror of
https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1.git
synced 2026-03-30 20:13:31 +00:00
249 lines
5.9 KiB
C++
Executable File
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;
|
|
}
|