mirror of
https://github.com/celisej567/mcpe.git
synced 2025-12-31 17:49:17 +03:00
1092 lines
19 KiB
C++
1092 lines
19 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 "Entity.hpp"
|
|
#include "Player.hpp"
|
|
#include "world/level/Level.hpp"
|
|
|
|
int Entity::entityCounter;
|
|
Random Entity::sharedRandom;
|
|
|
|
void Entity::_init()
|
|
{
|
|
m_bInAChunk = false;
|
|
m_chunkX = 0;
|
|
m_chunkY = 0;
|
|
m_chunkZ = 0;
|
|
field_20 = 0;
|
|
field_24 = 0;
|
|
field_28 = 0;
|
|
field_30 = 1.0f;
|
|
field_34 = 0;
|
|
m_pLevel = nullptr;
|
|
m_yaw = 0.0f;
|
|
m_pitch = 0.0f;
|
|
field_5C = 0.0f;
|
|
field_60 = 0.0f;
|
|
field_7C = false;
|
|
field_7D = false;
|
|
field_7E = false;
|
|
field_7F = false;
|
|
m_bHurt = false;
|
|
field_81 = 1;
|
|
m_bRemoved = false;
|
|
field_84 = 0.0f;
|
|
field_88 = 0.6f;
|
|
field_8C = 1.8f;
|
|
field_90 = 0.0f;
|
|
field_94 = 0.0f;
|
|
field_A4 = 0.0f;
|
|
field_A8 = 0.0f;
|
|
m_bNoCollision = false;
|
|
field_B0 = 0.0f;
|
|
field_B4 = 0;
|
|
field_B8 = 0;
|
|
field_BC = 300;
|
|
field_C0 = 0;
|
|
m_renderType = RENDER_NONE;
|
|
m_distanceFallen = 0.0f;
|
|
field_D0 = 300;
|
|
field_D4 = 0;
|
|
field_D5 = false;
|
|
field_D6 = true;
|
|
field_D8 = 1;
|
|
}
|
|
|
|
Entity::Entity(Level* pLevel)
|
|
{
|
|
_init();
|
|
|
|
m_pLevel = pLevel;
|
|
m_EntityID = ++entityCounter;
|
|
Entity::setPos(0, 0, 0);
|
|
}
|
|
|
|
Entity::~Entity()
|
|
{
|
|
}
|
|
|
|
void Entity::setLevel(Level* pLvl)
|
|
{
|
|
m_pLevel = pLvl;
|
|
}
|
|
|
|
void Entity::removed()
|
|
{
|
|
m_bRemoved = true;
|
|
}
|
|
|
|
void Entity::setPos(float x, float y, float z)
|
|
{
|
|
m_pos = Vec3(x, y, z);
|
|
|
|
float halfSize = field_88 / 2;
|
|
float lowY = y - field_84 + field_A4;
|
|
|
|
m_hitbox = AABB(
|
|
x - halfSize,
|
|
lowY,
|
|
z - halfSize,
|
|
x + halfSize,
|
|
lowY + field_8C,
|
|
z + halfSize);
|
|
}
|
|
|
|
void Entity::remove()
|
|
{
|
|
m_bRemoved = true;
|
|
}
|
|
|
|
int Entity::move(float x, float y, float z)
|
|
{
|
|
float x_1 = x, z_1 = z;
|
|
|
|
if (m_bNoCollision)
|
|
{
|
|
// just move it. Don't perform any kind of collision
|
|
m_hitbox.min.x += x;
|
|
m_hitbox.max.x += x;
|
|
m_hitbox.min.y += y;
|
|
m_hitbox.max.y += y;
|
|
m_hitbox.min.z += z;
|
|
m_hitbox.max.z += z;
|
|
|
|
m_pos.x = (m_hitbox.max.x + m_hitbox.min.x) / 2;
|
|
m_pos.z = (m_hitbox.max.z + m_hitbox.min.z) / 2;
|
|
m_pos.y = m_hitbox.min.y + field_84 - field_A4;
|
|
|
|
return 1300;
|
|
}
|
|
|
|
//@TODO: untangle the control flow
|
|
|
|
float x1, x2, x3, x4, x5, x6;
|
|
float x7, x8, x9, x10, x11, x12, x20;
|
|
float x_2, z_2, x_3, z_3;
|
|
float oldX, oldZ;
|
|
bool b1, b2, b3, b4, b5, b6;
|
|
AABB hitold;
|
|
|
|
oldX = m_pos.x; oldZ = m_pos.z;
|
|
|
|
x7 = m_hitbox.max.z;
|
|
x8 = m_hitbox.max.y;
|
|
x9 = m_hitbox.max.x;
|
|
x10 = m_hitbox.min.z;
|
|
x11 = m_hitbox.min.y;
|
|
x12 = m_hitbox.min.x;
|
|
|
|
x1 = m_hitbox.max.z;
|
|
x2 = m_hitbox.max.y;
|
|
x3 = m_hitbox.max.x;
|
|
x4 = m_hitbox.min.z;
|
|
x5 = m_hitbox.min.y;
|
|
x6 = m_hitbox.min.x;
|
|
|
|
if (!field_7C)
|
|
{
|
|
label_4:
|
|
|
|
z_2 = z_1;
|
|
b1 = x_1 < 0.0f;
|
|
b2 = x_1 > 0.0f;
|
|
x_2 = x_1;
|
|
b3 = z_1 < 0.0f;
|
|
b4 = z_1 > 0.0f;
|
|
b5 = false;
|
|
goto label_5;
|
|
}
|
|
|
|
if (!isSneaking())
|
|
goto label_4;
|
|
|
|
if (x_1 == 0.0f)
|
|
{
|
|
x_2 = x_1;
|
|
b1 = x_1 < 0.0f;
|
|
b2 = x_1 > 0.0f;
|
|
}
|
|
else
|
|
{
|
|
x_2 = x_1;
|
|
do
|
|
{
|
|
AABB aabb = m_hitbox;
|
|
aabb.move(x_1, -1.0f, 0);
|
|
|
|
AABBVector* cubes = m_pLevel->getCubes(this, aabb);
|
|
|
|
if (cubes->size())
|
|
break;
|
|
|
|
if (x_1 < 0.05f && x_1 >= -0.05f)
|
|
{
|
|
x_2 = 0.0f;
|
|
x_1 = 0.0f;
|
|
break;
|
|
}
|
|
|
|
// @BUG: See the z_1 part
|
|
if (x_1 <= 0.0f)
|
|
x_1 = x_1 + 0.05f;
|
|
else
|
|
x_1 = x_1 - 0.05f;
|
|
|
|
x_2 = x_1;
|
|
} while (x_1 != 0.0f);
|
|
|
|
b1 = x_1 < 0.0f;
|
|
b2 = x_1 > 0.0f;
|
|
}
|
|
|
|
if (z_1 == 0.0f)
|
|
{
|
|
z_2 = z_1;
|
|
b3 = z_1 < 0.0f;
|
|
b4 = z_1 > 0.0f;
|
|
}
|
|
else
|
|
{
|
|
z_2 = z_1;
|
|
do
|
|
{
|
|
AABB aabb = m_hitbox;
|
|
aabb.move(0, -1.0f, z_1);
|
|
|
|
AABBVector* cubes = m_pLevel->getCubes(this, aabb);
|
|
|
|
if (cubes->size())
|
|
break;
|
|
|
|
if (z_1 < 0.05f && z_1 >= -0.05f)
|
|
{
|
|
z_2 = 0.0f;
|
|
z_1 = 0.0f;
|
|
break;
|
|
}
|
|
|
|
//@BUG: wouldn't this loop forever? Since if z_1 == 0.025f, it'd oscillate between -0.025f and +0.025f...
|
|
if (z_1 <= 0.0f)
|
|
z_1 = z_1 + 0.05f;
|
|
else
|
|
z_1 = z_1 - 0.05f;
|
|
} while (z_1 != 0.0f);
|
|
b3 = z_1 < 0.0f;
|
|
b4 = z_1 > 0.0f;
|
|
}
|
|
|
|
b5 = true;
|
|
|
|
label_5:
|
|
if (b1) x6 += x_1;
|
|
if (b2) x3 += x_1;
|
|
if (y < 0.0f) x5 += y;
|
|
if (y > 0.0f) x2 += y;
|
|
if (b3) x4 += z;
|
|
if (b4) x1 += z;
|
|
|
|
AABB scanAABB(x6, x5, x4, x3, x2, x1);
|
|
AABBVector* pCubes = m_pLevel->getCubes(this, scanAABB);
|
|
|
|
float newY = y;
|
|
for (int i = 0; i < pCubes->size(); i++)
|
|
{
|
|
const AABB& aabb = pCubes->at(i);
|
|
newY = aabb.clipYCollide(m_hitbox, newY);
|
|
}
|
|
|
|
m_hitbox.move(0, newY, 0);
|
|
|
|
if (!field_81 && newY != y)
|
|
{
|
|
z_1 = 0.0f;
|
|
x_1 = 0.0f;
|
|
newY = 0.0f;
|
|
}
|
|
|
|
if (field_7C)
|
|
{
|
|
b6 = true;
|
|
}
|
|
else
|
|
{
|
|
b6 = y < 0.0f;
|
|
if (newY == y)
|
|
b6 = 0;
|
|
}
|
|
|
|
for (int i = 0; i < pCubes->size(); i++)
|
|
{
|
|
const AABB& aabb = pCubes->at(i);
|
|
x_1 = aabb.clipXCollide(m_hitbox, x_1);
|
|
}
|
|
|
|
m_hitbox.move(x_1, 0, 0);
|
|
|
|
if (!field_81 && x_1 != x_2)
|
|
{
|
|
z_1 = 0.0f;
|
|
x_1 = 0.0f;
|
|
newY = 0.0f;
|
|
}
|
|
|
|
for (int i = 0; i < pCubes->size(); i++)
|
|
{
|
|
const AABB& aabb = pCubes->at(i);
|
|
z_1 = aabb.clipZCollide(m_hitbox, z_1);
|
|
}
|
|
|
|
m_hitbox.move(0, 0, z_1);
|
|
|
|
if (!field_81 && z_1 != z_2)
|
|
{
|
|
z_1 = 0.0f;
|
|
x_1 = 0.0f;
|
|
newY = 0.0f;
|
|
}
|
|
|
|
x20 = field_A8;
|
|
if (x20 <= 0.0f || !b6)
|
|
{
|
|
label_44:
|
|
z_3 = z_1;
|
|
x_3 = x_1;
|
|
goto label_45;
|
|
}
|
|
|
|
if (field_A4 >= 0.05f || (x_2 == x_1 && z_2 == z_1))
|
|
goto label_44;
|
|
|
|
// oh come on, undoing all our work??
|
|
hitold = m_hitbox;
|
|
m_hitbox = AABB(x12, x11, x10, x9, x8, x7);
|
|
|
|
if (b1) x12 += x_2;
|
|
if (b2) x9 += x_2;
|
|
x8 += x20; //@BUG: missing if (x20 > 0) check?
|
|
if (x20 < 0.0f) x11 += x20;
|
|
if (b3) x10 += z_2;
|
|
if (b4) x7 += z_2;
|
|
|
|
{
|
|
AABB scanAABB2(x12, x11, x10, x9, x8, x7);
|
|
|
|
//@BUG: useless copy
|
|
//@BUG: this doesn't actually copy anything
|
|
*pCubes = *m_pLevel->getCubes(this, scanAABB2);
|
|
}
|
|
|
|
for (int i = 0; i < pCubes->size(); i++)
|
|
{
|
|
const AABB& aabb = pCubes->at(i);
|
|
x20 = aabb.clipYCollide(m_hitbox, x20);
|
|
}
|
|
|
|
m_hitbox.move(0, x20, 0);
|
|
|
|
if (field_81 || x20 == y)
|
|
{
|
|
z_3 = z_2;
|
|
x_3 = x_2;
|
|
}
|
|
else
|
|
{
|
|
x20 = 0.0f;
|
|
z_3 = 0.0f;
|
|
x_3 = 0.0f;
|
|
}
|
|
|
|
for (int i = 0; i < pCubes->size(); i++)
|
|
{
|
|
const AABB& aabb = pCubes->at(i);
|
|
x_3 = aabb.clipXCollide(m_hitbox, x_3);
|
|
}
|
|
|
|
m_hitbox.move(x_3, 0, 0);
|
|
|
|
if (!field_81 && x_2 != x_3)
|
|
{
|
|
x20 = 0.0f;
|
|
z_3 = 0.0f;
|
|
x_3 = 0.0f;
|
|
}
|
|
|
|
for (int i = 0; i < pCubes->size(); i++)
|
|
{
|
|
const AABB& aabb = pCubes->at(i);
|
|
z_3 = aabb.clipZCollide(m_hitbox, z_3);
|
|
}
|
|
|
|
m_hitbox.move(0, 0, z_3);
|
|
|
|
if (!field_81 && z_2 != z_3)
|
|
{
|
|
x20 = 0.0f;
|
|
z_3 = 0.0f;
|
|
x_3 = 0.0f;
|
|
}
|
|
|
|
// if we moved more this time than before?? no clue wtf this is about...
|
|
if (z_1 * z_1 + x_1 * x_1 < z_3 * z_3 + x_3 * x_3)
|
|
{
|
|
field_A4 += 0.5f;
|
|
newY = x20;
|
|
}
|
|
else
|
|
{
|
|
// don't get the rationale behind this at all...
|
|
m_hitbox = hitold;
|
|
z_3 = z_1;
|
|
x_3 = x_1;
|
|
}
|
|
|
|
label_45:
|
|
m_pos.x = (m_hitbox.min.x + m_hitbox.max.x) / 2;
|
|
m_pos.z = (m_hitbox.min.z + m_hitbox.max.z) / 2;
|
|
m_pos.y = m_hitbox.min.y - field_A4 + field_84;
|
|
|
|
field_7D = x_2 != x_3 || z_2 != z_3;
|
|
field_7F = field_7D || newY != y;
|
|
field_7C = y < 0.0f && newY != y;
|
|
field_7E = newY != y;
|
|
|
|
checkFallDamage(newY, field_7C);
|
|
|
|
if (x_2 != x_3) m_vel.x = 0.0;
|
|
if (newY != y) m_vel.y = 0.0;
|
|
if (z_2 != z_3) m_vel.z = 0.0;
|
|
|
|
if (!b5)
|
|
{
|
|
float diffX = (m_pos.x - oldX), diffZ = (m_pos.z - oldZ);
|
|
field_94 += Mth::sqrt(diffZ * diffZ + diffX * diffX) * 0.6f;
|
|
|
|
int tileX = Mth::floor(m_pos.x);
|
|
int tileY = Mth::floor(m_pos.y - 0.2f - field_84);
|
|
int tileZ = Mth::floor(m_pos.z);
|
|
|
|
TileID tileID = m_pLevel->getTile(tileX, tileY, tileZ);
|
|
|
|
if (tileID > 0 && field_94 > float(field_D8))
|
|
{
|
|
++field_D8;
|
|
bool bPlaySound = true;
|
|
|
|
const Tile::SoundType *sound = Tile::tiles[tileID]->m_pSound;
|
|
if (m_pLevel->getTile(tileX, tileY + 1, tileZ) == Tile::topSnow->m_ID)
|
|
sound = Tile::topSnow->m_pSound;
|
|
else if (Tile::tiles[tileID]->m_pMaterial->isLiquid())
|
|
bPlaySound = false;
|
|
|
|
if (bPlaySound)
|
|
m_pLevel->playSound(this, "step." + sound->m_name, sound->field_18 * 0.15f, sound->field_1C);
|
|
|
|
Tile::tiles[tileID]->stepOn(m_pLevel, tileX, tileY, tileZ, this);
|
|
}
|
|
}
|
|
|
|
// Check whether the entity is inside of any tiles.
|
|
|
|
int minX = Mth::floor(m_hitbox.min.x), minY = Mth::floor(m_hitbox.min.y), minZ = Mth::floor(m_hitbox.min.z),
|
|
maxX = Mth::floor(m_hitbox.max.x), maxY = Mth::floor(m_hitbox.max.y), maxZ = Mth::floor(m_hitbox.max.z);
|
|
|
|
if (m_pLevel->hasChunksAt(minX, minY, minZ, maxX, maxY, maxZ))
|
|
{
|
|
for (int x = minX; x <= maxX; x++)
|
|
for (int y = minY; y <= maxY; y++)
|
|
for (int z = minZ; z <= maxZ; z++)
|
|
{
|
|
TileID tileID = m_pLevel->getTile(x, y, z);
|
|
if (tileID > 0)
|
|
Tile::tiles[tileID]->entityInside(m_pLevel, x, y, z, this);
|
|
}
|
|
}
|
|
|
|
field_A4 *= 0.4f;
|
|
|
|
bool bIsInWater = isInWater();
|
|
|
|
if (m_pLevel->containsFireTile(m_hitbox))
|
|
{
|
|
burn(true);
|
|
|
|
if (bIsInWater)
|
|
{
|
|
label_76:
|
|
if (field_C0 > 0)
|
|
field_C0 = -field_C4;
|
|
|
|
return 1300;
|
|
}
|
|
|
|
field_C0++;
|
|
if (field_C0 == 0)
|
|
field_C0 = 300;
|
|
}
|
|
else
|
|
{
|
|
if (field_C0 <= 0)
|
|
field_C0 = -field_C4;
|
|
|
|
if (bIsInWater)
|
|
goto label_76;
|
|
}
|
|
|
|
return 1300;
|
|
}
|
|
|
|
void Entity::moveTo(float x, float y, float z, float yaw, float pitch)
|
|
{
|
|
y += field_84;
|
|
|
|
m_pos.x = x;
|
|
m_yaw = yaw;
|
|
field_3C.x = x;
|
|
field_98.x = x;
|
|
|
|
m_pos.z = z;
|
|
m_pitch = pitch;
|
|
field_3C.z = z;
|
|
field_98.z = z;
|
|
|
|
m_pos.y = y;
|
|
field_3C.y = y;
|
|
field_98.y = y;
|
|
|
|
setPos(x, y, z);
|
|
}
|
|
|
|
void Entity::absMoveTo(float x, float y, float z, float yaw, float pitch)
|
|
{
|
|
field_A4 = 0.0f;
|
|
|
|
field_5C = yaw;
|
|
m_yaw = yaw;
|
|
m_pitch = pitch;
|
|
field_60 = pitch;
|
|
|
|
m_pos.x = x;
|
|
field_3C.x = x;
|
|
m_pos.y = y;
|
|
field_3C.y = y;
|
|
m_pos.z = z;
|
|
field_3C.z = z;
|
|
|
|
//@WHAT: (yaw - yaw) == 0
|
|
if (yaw - yaw < -180.0f)
|
|
field_5C = yaw + 360.0f;
|
|
if (yaw - yaw >= 180.0f)
|
|
field_5C = field_5C - 360.0f;
|
|
|
|
setPos(this->m_pos.x, this->m_pos.y, this->m_pos.z);
|
|
return setRot(yaw, pitch);
|
|
}
|
|
|
|
void Entity::moveRelative(float x, float z, float y)
|
|
{
|
|
float d = sqrtf(x * x + z * z);
|
|
if (d < 0.01f) return;
|
|
if (d < 1.0f)
|
|
d = 1.0f;
|
|
|
|
y /= d;
|
|
x *= y;
|
|
z *= y;
|
|
|
|
float yaw = m_yaw * float(M_PI);
|
|
float syaw = sinf(yaw / 180.0f);
|
|
float cyaw = cosf(yaw / 180.0f);
|
|
|
|
m_vel.x += x * cyaw - z * syaw;
|
|
m_vel.z += x * syaw + z * cyaw;
|
|
}
|
|
|
|
void Entity::lerpTo(float x, float y, float z, float yaw, float pitch, int p)
|
|
{
|
|
setPos(x, y, z);
|
|
setRot(yaw, pitch);
|
|
}
|
|
|
|
void Entity::lerpMotion(float x, float y, float z)
|
|
{
|
|
m_vel = Vec3(x, y, z);
|
|
}
|
|
|
|
void Entity::turn(float yaw, float pitch)
|
|
{
|
|
float y_old = m_yaw;
|
|
float p_old = m_pitch;
|
|
|
|
m_yaw += yaw * 0.15f;
|
|
m_pitch -= pitch * 0.15f;
|
|
|
|
// can't rotate more than facing fully up or fully down
|
|
if (m_pitch < -90.0f)
|
|
m_pitch = -90.0f;
|
|
if (m_pitch > 90.0f)
|
|
m_pitch = 90.0f;
|
|
|
|
field_5C += m_yaw - y_old;
|
|
field_60 += m_pitch - p_old;
|
|
}
|
|
|
|
void Entity::reset()
|
|
{
|
|
// TODO is this it
|
|
field_98 = field_3C = m_pos;
|
|
field_5C = m_yaw;
|
|
field_60 = m_pitch;
|
|
m_bRemoved = false;
|
|
m_distanceFallen = 0.0f;
|
|
field_D5 = false;
|
|
field_C0 = 0;
|
|
}
|
|
|
|
void Entity::interpolateTurn(float yaw, float pitch)
|
|
{
|
|
m_yaw += yaw * 0.15f;
|
|
m_pitch -= pitch * 0.15f;
|
|
|
|
// can't rotate more than facing fully up or fully down
|
|
if (m_pitch < -90.0f)
|
|
m_pitch = -90.0f;
|
|
if (m_pitch > 90.0f)
|
|
m_pitch = 90.0f;
|
|
}
|
|
|
|
void Entity::tick()
|
|
{
|
|
baseTick();
|
|
}
|
|
|
|
void Entity::baseTick()
|
|
{
|
|
//@TODO: untangle the gotos
|
|
|
|
field_90 = field_94;
|
|
field_3C = m_pos;
|
|
field_B4++;
|
|
field_5C = m_yaw;
|
|
field_60 = m_pitch;
|
|
if (isInWater())
|
|
{
|
|
if (!field_D4 && !field_D6)
|
|
{
|
|
float dist = sqrtf(m_vel.y * m_vel.y + m_vel.x * m_vel.x * 0.2f + m_vel.z * m_vel.z * 0.2f) * 0.2f;
|
|
if (dist > 1.0f)
|
|
dist = 1.0f;
|
|
|
|
m_pLevel->playSound(this, "random.splash", dist, 1.0f + 0.4f * (sharedRandom.nextFloat() - sharedRandom.nextFloat()));
|
|
|
|
float f1 = floorf(m_hitbox.min.y);
|
|
|
|
for (int i = 0; float(i) < field_88 * 20.0f + 1.0f; i++)
|
|
{
|
|
m_pLevel->addParticle(
|
|
"bubble",
|
|
m_pos.x + field_88 * (sharedRandom.nextFloat() * 2.0f - 1.0f),
|
|
f1 + 1.0f,
|
|
m_pos.z + field_88 * (sharedRandom.nextFloat() * 2.0f - 1.0f),
|
|
m_vel.x,
|
|
m_vel.y - 0.2f * sharedRandom.nextFloat(),
|
|
m_vel.z
|
|
);
|
|
}
|
|
|
|
for (int i = 0; float(i) < field_88 * 20.0f + 1.0f; i++)
|
|
{
|
|
m_pLevel->addParticle(
|
|
"splash",
|
|
m_pos.x + field_88 * (sharedRandom.nextFloat() * 2.0f - 1.0f),
|
|
f1 + 1.0f,
|
|
m_pos.z + field_88 * (sharedRandom.nextFloat() * 2.0f - 1.0f),
|
|
m_vel.x,
|
|
m_vel.y - 0.2f * sharedRandom.nextFloat(),
|
|
m_vel.z
|
|
);
|
|
}
|
|
}
|
|
|
|
field_D4 = true;
|
|
field_C0 = 0;
|
|
m_distanceFallen = 0;
|
|
|
|
if (m_pLevel->m_bIsMultiplayer)
|
|
goto label_4;
|
|
}
|
|
else
|
|
{
|
|
field_D4 = false;
|
|
|
|
if (m_pLevel->m_bIsMultiplayer)
|
|
{
|
|
label_4:
|
|
field_C0 = 0;
|
|
goto label_5;
|
|
}
|
|
}
|
|
|
|
if (field_C0 <= 0)
|
|
{
|
|
label_5:
|
|
if (!isInLava())
|
|
goto label_6;
|
|
goto label_15;
|
|
}
|
|
|
|
if (field_D5)
|
|
{
|
|
field_C0 -= 4;
|
|
if (field_C0 < 0)
|
|
field_C0 = 0;
|
|
goto label_5;
|
|
}
|
|
|
|
if (field_C0 % 20 == 0)
|
|
{
|
|
hurt(nullptr, 1);
|
|
}
|
|
|
|
field_C0--;
|
|
|
|
if (isInLava())
|
|
{
|
|
label_15:
|
|
lavaHurt();
|
|
}
|
|
|
|
label_6:
|
|
if (m_pos.y < -64.0f)
|
|
outOfWorld();
|
|
|
|
field_D6 = false;
|
|
}
|
|
|
|
bool Entity::intersects(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
|
|
{
|
|
AABB aabb(minX, minY, minZ, maxX, maxY, maxZ);
|
|
return aabb.intersect(m_hitbox);
|
|
}
|
|
|
|
bool Entity::isFree(float offX, float offY, float offZ)
|
|
{
|
|
AABB aabb = m_hitbox;
|
|
aabb.move(offX, offY, offZ);
|
|
|
|
AABBVector* pCubes = m_pLevel->getCubes(this, aabb);
|
|
if (!pCubes)
|
|
return false;
|
|
|
|
return !m_pLevel->containsAnyLiquid(aabb);
|
|
}
|
|
|
|
bool Entity::isFree(float offX, float offY, float offZ, float expand)
|
|
{
|
|
AABB aabb = m_hitbox;
|
|
aabb.move(offX, offY, offZ);
|
|
aabb.grow(expand, expand, expand);
|
|
|
|
AABBVector* pCubes = m_pLevel->getCubes(this, aabb);
|
|
if (!pCubes)
|
|
return false;
|
|
|
|
return !m_pLevel->containsAnyLiquid(aabb);
|
|
}
|
|
|
|
bool Entity::isInWall()
|
|
{
|
|
return m_pLevel->isSolidTile(Mth::floor(m_pos.x), Mth::floor(m_pos.y + getHeadHeight()), Mth::floor(m_pos.z));
|
|
}
|
|
|
|
bool Entity::isInWater()
|
|
{
|
|
AABB aabb = m_hitbox;
|
|
aabb.grow(0, -0.4f, 0);
|
|
return m_pLevel->checkAndHandleWater(aabb, Material::water, this);
|
|
}
|
|
|
|
bool Entity::isInLava()
|
|
{
|
|
AABB aabb = m_hitbox;
|
|
aabb.grow(-0.1f, -0.4f, -0.1f);
|
|
return m_pLevel->containsMaterial(aabb, Material::lava);
|
|
}
|
|
|
|
bool Entity::isUnderLiquid(Material* pMtl)
|
|
{
|
|
int tileX = Mth::floor(m_pos.x);
|
|
int tileY = Mth::floor(m_pos.y + getHeadHeight());
|
|
int tileZ = Mth::floor(m_pos.z);
|
|
|
|
Tile* pTile = Tile::tiles[m_pLevel->getTile(tileX, tileY, tileZ)];
|
|
if (!pTile || pTile->m_pMaterial != pMtl)
|
|
return false;
|
|
|
|
int data = m_pLevel->getData(tileX, tileY, tileZ);
|
|
int level = data <= 7 ? data + 1 : 1;
|
|
|
|
return float(tileY) < float(tileY + 1) - (float(level) / 9.0f - 0.11111f);
|
|
}
|
|
|
|
float Entity::getHeadHeight()
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
float Entity::getShadowHeightOffs()
|
|
{
|
|
return field_8C / 2.0f;
|
|
}
|
|
|
|
float Entity::getBrightness(float f)
|
|
{
|
|
int tileX = Mth::floor(m_pos.x);
|
|
int tileY = Mth::floor(m_pos.y - field_84 + (m_hitbox.max.y - m_hitbox.min.y) * 0.66f);
|
|
int tileZ = Mth::floor(m_pos.z);
|
|
|
|
int minX = Mth::floor(m_hitbox.min.x);
|
|
int minY = Mth::floor(m_hitbox.min.y);
|
|
int minZ = Mth::floor(m_hitbox.min.z);
|
|
int maxX = Mth::floor(m_hitbox.max.x);
|
|
int maxY = Mth::floor(m_hitbox.max.y);
|
|
int maxZ = Mth::floor(m_hitbox.max.z);
|
|
|
|
if (!m_pLevel->hasChunksAt(minX, minY, minZ, maxX, maxY, maxZ))
|
|
return 0;
|
|
|
|
return m_pLevel->getBrightness(tileX, tileY, tileZ);
|
|
}
|
|
|
|
float Entity::distanceTo(Entity* pEnt)
|
|
{
|
|
return distanceTo(pEnt->m_pos.x, pEnt->m_pos.y, pEnt->m_pos.z);
|
|
}
|
|
|
|
float Entity::distanceTo(float x, float y, float z)
|
|
{
|
|
return sqrtf(distanceToSqr(x, y, z));
|
|
}
|
|
|
|
float Entity::distanceToSqr(Entity* pEnt)
|
|
{
|
|
return distanceToSqr(pEnt->m_pos.x, pEnt->m_pos.y, pEnt->m_pos.z);
|
|
}
|
|
|
|
float Entity::distanceToSqr(float x, float y, float z)
|
|
{
|
|
float diffX = m_pos.x - x;
|
|
float diffY = m_pos.y - y;
|
|
float diffZ = m_pos.z - z;
|
|
|
|
return diffX * diffX + diffY * diffY + diffZ * diffZ;
|
|
}
|
|
|
|
int Entity::interactPreventDefault()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bool Entity::interact(Player* player)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void Entity::playerTouch(Player* player)
|
|
{
|
|
|
|
}
|
|
|
|
void Entity::push(Entity* bud)
|
|
{
|
|
float diffX = bud->m_pos.x - m_pos.x;
|
|
float diffZ = bud->m_pos.z - m_pos.z;
|
|
float maxDiff = Mth::absMax(diffX, diffZ);
|
|
|
|
if (maxDiff < 0.01f) return;
|
|
|
|
float x1 = sqrtf(maxDiff);
|
|
float x2 = 1.0f / x1;
|
|
if (x2 > 1.0f)
|
|
x2 = 1.0f;
|
|
float x3 = 1.0f - this->field_B0;
|
|
float x4 = x3 * diffX / x1 * x2 * 0.05f;
|
|
float x5 = x3 * diffZ / x1 * x2 * 0.05f;
|
|
|
|
push(-x4, 0.0f, -x5);
|
|
bud->push(x4, 0.0f, x5);
|
|
}
|
|
|
|
void Entity::push(float x, float y, float z)
|
|
{
|
|
m_vel.x += x;
|
|
m_vel.y += y;
|
|
m_vel.z += z;
|
|
}
|
|
|
|
bool Entity::isPickable()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool Entity::isPushable()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool Entity::isShootable()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool Entity::isSneaking()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool Entity::isAlive()
|
|
{
|
|
return m_bRemoved;
|
|
}
|
|
|
|
bool Entity::isOnFire()
|
|
{
|
|
return field_C0 > 0;
|
|
}
|
|
|
|
bool Entity::isPlayer()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool Entity::isCreativeModeAllowed()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool Entity::shouldRender(Vec3& camPos)
|
|
{
|
|
return shouldRenderAtSqrDistance(distanceToSqr(camPos.x, camPos.y, camPos.z));
|
|
}
|
|
|
|
bool Entity::shouldRenderAtSqrDistance(float distSqr)
|
|
{
|
|
float maxDist = (field_30 * 64.0f) * (((m_hitbox.max.z - m_hitbox.min.z) + (m_hitbox.max.x - m_hitbox.min.x) + (m_hitbox.max.y - m_hitbox.min.y)) / 3.0f);
|
|
|
|
return maxDist * maxDist > distSqr;
|
|
}
|
|
|
|
bool Entity::hurt(Entity* pAttacker, int damage)
|
|
{
|
|
markHurt();
|
|
return 0;
|
|
}
|
|
|
|
void Entity::animateHurt()
|
|
{
|
|
|
|
}
|
|
|
|
float Entity::getPickRadius()
|
|
{
|
|
return 0.1f;
|
|
}
|
|
|
|
|
|
void Entity::awardKillScore(Entity* pKilled, int score)
|
|
{
|
|
|
|
}
|
|
|
|
void Entity::setEquippedSlot(int a, int b, int c)
|
|
{
|
|
|
|
}
|
|
|
|
void Entity::setRot(float yaw, float pitch)
|
|
{
|
|
m_yaw = yaw;
|
|
m_pitch = pitch;
|
|
}
|
|
|
|
void Entity::setSize(float rad, float height)
|
|
{
|
|
field_88 = rad;
|
|
field_8C = height;
|
|
}
|
|
|
|
void Entity::setPos(EntityPos* pPos)
|
|
{
|
|
if (pPos->m_bHasPos)
|
|
setPos(pPos->m_pos.x, pPos->m_pos.y, pPos->m_pos.z);
|
|
else
|
|
setPos(m_pos.x, m_pos.y, m_pos.z);
|
|
|
|
if (pPos->m_bHasRot)
|
|
setRot(pPos->m_yaw, pPos->m_pitch);
|
|
else
|
|
setRot(m_yaw, m_pitch);
|
|
}
|
|
|
|
void Entity::resetPos()
|
|
{
|
|
if (!m_pLevel)
|
|
// No level? Fine
|
|
return;
|
|
|
|
if (m_pos.y <= 0.0f)
|
|
// It's in the void. It's probably not inside of any tiles.
|
|
return;
|
|
|
|
// Push the entity up while it's inside solid tiles.
|
|
while (true)
|
|
{
|
|
setPos(m_pos.x, m_pos.y, m_pos.z);
|
|
|
|
AABBVector* pCubes = m_pLevel->getCubes(this, m_hitbox);
|
|
|
|
// if we aren't inside any tiles, great!
|
|
if (!pCubes->size())
|
|
break;
|
|
|
|
m_pos.y += 1.0f;
|
|
}
|
|
|
|
m_vel.x = 0.0f;
|
|
m_vel.y = 0.0f;
|
|
m_vel.z = 0.0f;
|
|
m_pitch = 0.0f;
|
|
}
|
|
|
|
void Entity::outOfWorld()
|
|
{
|
|
remove();
|
|
}
|
|
|
|
void Entity::checkFallDamage(float fDeltaY, bool bHitGround)
|
|
{
|
|
if (bHitGround)
|
|
{
|
|
if (m_distanceFallen > 0.0f)
|
|
{
|
|
causeFallDamage(m_distanceFallen);
|
|
m_distanceFallen = 0.0f;
|
|
}
|
|
}
|
|
else if (fDeltaY < 0.0f)
|
|
{
|
|
m_distanceFallen -= fDeltaY;
|
|
}
|
|
}
|
|
|
|
void Entity::causeFallDamage(float f)
|
|
{
|
|
// stub
|
|
}
|
|
|
|
void Entity::markHurt()
|
|
{
|
|
m_bHurt = true;
|
|
}
|
|
|
|
void Entity::burn(int x)
|
|
{
|
|
if (!field_D5)
|
|
hurt(nullptr, 4);
|
|
}
|
|
|
|
void Entity::lavaHurt()
|
|
{
|
|
if (!field_D5)
|
|
{
|
|
hurt(nullptr, 4);
|
|
field_C0 = 600;
|
|
}
|
|
}
|
|
|
|
int Entity::queryEntityRenderer()
|
|
{
|
|
// If field_C8 is equal to RENDER_DYNAMIC, EntityRenderDispatcher
|
|
// calls here. Used for sheared sheep.
|
|
return 0;
|
|
}
|
|
|
|
int Entity::hashCode()
|
|
{
|
|
return m_EntityID;
|
|
}
|
|
|
|
bool Entity::operator==(const Entity& other) const
|
|
{
|
|
return m_EntityID == other.m_EntityID;
|
|
}
|
|
|
|
bool Entity::isLocalPlayer()
|
|
{
|
|
return false;
|
|
}
|