Files
minecraft-pe-0.6.1/src/world/entity/Entity.cpp
Shredder d7d887f882 few additions and bug fixes
Added Hand Sway (not an option yet) from b1,8

Fire works properly in multiplayer now and also renders on undead mobs in sunlight now

hopefully fixed bow stuck bug on touchscreen devices

Fire on entites uses updated rendering from b1.6.6

Shadow bug fix attempt the 15th

Added looking at block in debug screen

Zombie Pigman now renders his hat layer

Temporarily disabled most randomlevelsource cave, canyon and tall grass code just for this commit to test performance
2026-05-23 05:29:47 +05:00

973 lines
22 KiB
C++
Executable File

#include "Entity.h"
#include "EntityPos.h"
#include "../level/Level.h"
#include "../level/tile/LiquidTile.h"
#include "item/ItemEntity.h"
#include "../item/ItemInstance.h"
#include "../../nbt/CompoundTag.h"
#include "../../util/PerfTimer.h"
int
Entity::entityCounter = 0;
Random
Entity::sharedRandom(getEpochTimeS());
Entity::Entity( Level* level )
: level(level),
viewScale(1.0f),
blocksBuilding(false),
onGround(false),
wasInWater(false),
collision(false),
hurtMarked(false),
slide(true),
isStuckInWeb(false),
removed(false),
reallyRemoveIfPlayer(false),
canRemove(true), //@todo: remove
noPhysics(false),
firstTick(true),
bbWidth(0.6f),
bbHeight(1.8f),
heightOffset(0 / 16.0f),
bb(0,0,0,0,0,0),
ySlideOffset(0),
fallDistance(0),
footSize(0),
invulnerableTime(0),
pushthrough(0),
airCapacity(TOTAL_AIR_SUPPLY),
airSupply(TOTAL_AIR_SUPPLY),
xOld(0),yOld(0),zOld(0),
horizontalCollision(false), verticalCollision(false),
x(0), y(0), z(0),
xo(0),yo(0),zo(0),xd(0),yd(0),zd(0),
xRot(0), yRot(0),
xRotO(0), yRotO(0),
xChunk(0), yChunk(0), zChunk(0),
inChunk(false),
fireImmune(false),
onFire(0),
flameTime(1),
walkDist(0), walkDistO(0),
tickCount(0),
entityRendererId(ER_DEFAULT_RENDERER),
nextStep(1),
makeStepSound(true),
invisible(false)
{
_init();
entityId = ++entityCounter;
//ref = Ref<Entity>::create(this);
setPos(0, 0, 0);
}
Entity::~Entity() {
//if (ref->isUnique())
// delete ref;
}
SynchedEntityData* Entity::getEntityData() {
return NULL;
}
const SynchedEntityData* Entity::getEntityData() const {
return NULL;
}
bool Entity::isInWall() {
int xt = Mth::floor(x);
int yt = Mth::floor(y + getHeadHeight());
int zt = Mth::floor(z);
return level->isSolidBlockingTile(xt, yt, zt);
}
void Entity::resetPos(bool clearMore) {
if (level == NULL) return;
while (y > 0) {
setPos(x, y, z);
if (level->getCubes(this, bb).size() == 0) break;
y += 1;
}
xd = yd = zd = 0;
xRot = 0;
}
bool Entity::isInWater() {
return level->checkAndHandleWater(bb.grow(0, -0.4f, 0), Material::water, this);
}
bool Entity::isInLava() {
return level->containsMaterial(bb.grow(-0.1f, -0.4f, -0.1f), Material::lava);
}
bool Entity::isFree(float xa, float ya, float za, float grow) {
AABB box = bb.grow(grow, grow, grow).cloneMove(xa, ya, za);
const std::vector<AABB>& aABBs = level->getCubes(this, box);
if (aABBs.size() > 0) return false;
if (level->containsAnyLiquid(box)) return false;
return true;
}
bool Entity::isFree(float xa, float ya, float za) {
AABB box = bb.cloneMove(xa, ya, za);
const std::vector<AABB>& aABBs = level->getCubes(this, box);
if (aABBs.size() > 0) return false;
if (level->containsAnyLiquid(box)) return false;
return true;
}
//static void __attribute__((noinline)) setPositionFromBbox(Entity* e) { // @RPI
// const AABB& bb = e->bb;
// e->x = (e->bb.x0 + e->bb.x1) / 2.0f;
// e->y = bb.y0 + e->heightOffset - e->ySlideOffset;
// e->z = (bb.z0 + bb.z1) / 2.0f;
//}
/*public*/
void Entity::move(float xa, float ya, float za) {
//if (std::abs(xa) + std::abs(ya) + std::abs(za) < 0.00001f) //@RPI
// return;
if (noPhysics) {
bb.move(xa, ya, za);
x = (bb.x0 + bb.x1) / 2.0f;
y = bb.y0 + heightOffset - ySlideOffset;
z = (bb.z0 + bb.z1) / 2.0f;
return;
}
TIMER_PUSH("move");
float xo = x;
float zo = z;
if (isStuckInWeb) {
isStuckInWeb = false;
xa *= .25f;
ya *= .05f;
za *= .25f;
xd = .0f;
yd = .0f;
zd = .0f;
}
float xaOrg = xa;
float yaOrg = ya;
float zaOrg = za;
AABB bbOrg = bb;
bool sneaking = onGround && isSneaking();
if (sneaking) {
float d = 0.05f;
while (xa != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, 0)).empty()) {
if (xa < d && xa >= -d) xa = 0;
else if (xa > 0) xa -= d;
else xa += d;
xaOrg = xa;
}
while (za != 0 && level->getCubes(this, bb.cloneMove(0, -1.0, za)).empty()) {
if (za < d && za >= -d) za = 0;
else if (za > 0) za -= d;
else za += d;
zaOrg = za;
}
while (xa != 0 && za != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, za)).empty()) {
if (xa < d && xa >= -d) xa = 0;
else if (xa > 0) xa -= d;
else xa += d;
if (za < d && za >= -d) za = 0;
else if (za > 0) za -= d;
else za += d;
xaOrg = xa;
zaOrg = za;
}
}
std::vector<AABB>& aABBs = level->getCubes(this, bb.expand(xa, ya, za));
// LAND FIRST, then x and z
for (unsigned int i = 0; i < aABBs.size(); i++)
ya = aABBs[i].clipYCollide(bb, ya);
bb.move(0, ya, 0);
if (!slide && yaOrg != ya) {
xa = ya = za = 0;
}
bool og = onGround || (yaOrg != ya && yaOrg < 0);
for (unsigned int i = 0; i < aABBs.size(); i++)
xa = aABBs[i].clipXCollide(bb, xa);
bb.move(xa, 0, 0);
if (!slide && xaOrg != xa) {
xa = ya = za = 0;
}
for (unsigned int i = 0; i < aABBs.size(); i++)
za = aABBs[i].clipZCollide(bb, za);
bb.move(0, 0, za);
if (!slide && zaOrg != za) {
xa = ya = za = 0;
}
if (footSize > 0 && og && (ySlideOffset < 0.05f) && ((xaOrg != xa) || (zaOrg != za))) {
float xaN = xa;
float yaN = ya;
float zaN = za;
xa = xaOrg;
ya = footSize;
za = zaOrg;
AABB normal = bb;
bb.set(bbOrg);
aABBs = level->getCubes(this, bb.expand(xa, ya, za));
// LAND FIRST, then x and z
for (unsigned int i = 0; i < aABBs.size(); i++)
ya = aABBs[i].clipYCollide(bb, ya);
bb.move(0, ya, 0);
if (!slide && yaOrg != ya) {
xa = ya = za = 0;
}
for (unsigned int i = 0; i < aABBs.size(); i++)
xa = aABBs[i].clipXCollide(bb, xa);
bb.move(xa, 0, 0);
if (!slide && xaOrg != xa) {
xa = ya = za = 0;
}
for (unsigned int i = 0; i < aABBs.size(); i++)
za = aABBs[i].clipZCollide(bb, za);
bb.move(0, 0, za);
if (!slide && zaOrg != za) {
xa = ya = za = 0;
}
if (xaN * xaN + zaN * zaN >= xa * xa + za * za) {
xa = xaN;
ya = yaN;
za = zaN;
bb.set(normal);
} else {
ySlideOffset += 0.5f;
}
}
TIMER_POP_PUSH("rest");
x = (bb.x0 + bb.x1) / 2.0f;
y = bb.y0 + heightOffset - ySlideOffset;
z = (bb.z0 + bb.z1) / 2.0f;
horizontalCollision = (xaOrg != xa) || (zaOrg != za);
verticalCollision = (yaOrg != ya);
onGround = yaOrg != ya && yaOrg < 0;
collision = horizontalCollision || verticalCollision;
checkFallDamage(ya, onGround);
if (xaOrg != xa) xd = 0;
if (yaOrg != ya) yd = 0;
if (zaOrg != za) zd = 0;
float xm = x - xo;
float zm = z - zo;
if (makeStepSound && !sneaking) {
walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6f;
int xt = Mth::floor(x);
int yt = Mth::floor(y - 0.2f - this->heightOffset);
int zt = Mth::floor(z);
int t = level->getTile(xt, yt, zt);
if (t == 0) {
int under = level->getTile(xt, yt-1, zt);
if (Tile::fence->id == under || Tile::fenceGate->id == under) {
t = under;
}
}
if (walkDist > nextStep && t > 0) {
nextStep = ((int) walkDist) + 1;
playStepSound(xt, yt, zt, t);
//Tile::tiles[t]->stepOn(level, xt, yt, zt, this); //@todo: step
}
}
int x0 = Mth::floor(bb.x0);
int y0 = Mth::floor(bb.y0);
int z0 = Mth::floor(bb.z0);
int x1 = Mth::floor(bb.x1);
int y1 = Mth::floor(bb.y1);
int z1 = Mth::floor(bb.z1);
if (level->hasChunksAt(x0, y0, z0, x1, y1, z1)) {
for (int x = x0; x <= x1; x++)
for (int y = y0; y <= y1; y++)
for (int z = z0; z <= z1; z++) {
int t = level->getTile(x, y, z);
if (t > 0) {
Tile::tiles[t]->entityInside(level, x, y, z, this);
}
}
}
ySlideOffset *= 0.4f;
bool water = this->isInWater();
if (level->containsFireTile(bb)) {
burn(1);
if (!water) {
onFire++;
if (onFire == 0) onFire = 20 * 15;
}
} else {
if (onFire <= 0) {
onFire = -flameTime;
}
}
if (water && onFire > 0) {
//level.playSound(this-> "random.fizz", 0.7f, 1.6f + (random.nextFloat() - random.nextFloat()) * 0.4f);
onFire = -flameTime;
}
TIMER_POP();
}
void Entity::makeStuckInWeb() {
isStuckInWeb = true;
fallDistance = 0;
}
/*public virtual*/
bool Entity::isUnderLiquid(const Material* material) {
float yp = y + getHeadHeight();
int xt = Mth::floor(x);
int yt = Mth::floor((float)Mth::floor(yp));
int zt = Mth::floor(z);
int t = level->getTile(xt, yt, zt);
if (t != 0 && Tile::tiles[t]->material == material) {
float hh = LiquidTile::getHeight(level->getData(xt, yt, zt)) - 1 / 9.0f;
float h = yt + 1 - hh;
return yp < h;
}
return false;
}
/*protected virtual*/
void Entity::setPos(EntityPos* pos)
{
if (pos->move) setPos(pos->x, pos->y, pos->z);
else setPos(x, y, z);
if (pos->rot) setRot(pos->yRot, pos->xRot);
else setRot(yRot, xRot);
}
void Entity::setPos( float x, float y, float z )
{
this->x = x;
this->y = y;
this->z = z;
float w = bbWidth / 2;
float h = bbHeight;
bb.set(x - w, y - heightOffset + ySlideOffset, z - w, x + w, y - heightOffset + ySlideOffset + h, z + w);
}
/*virtual*/
float Entity::getBrightness(float a) {
int xTile = Mth::floor(x);
float hh = (bb.y1 - bb.y0) * 0.66f;
int yTile = Mth::floor(y - this->heightOffset + hh);
int zTile = Mth::floor(z);
if (level->hasChunksAt(Mth::floor(bb.x0), Mth::floor(bb.y0), Mth::floor(bb.z0), Mth::floor(bb.x1), Mth::floor(bb.y1), Mth::floor(bb.z1))) {
return level->getBrightness(xTile, yTile, zTile);
}
return 0;
}
bool Entity::operator==( Entity& rhs )
{
return entityId == rhs.entityId;
}
int Entity::hashCode()
{
return entityId;
}
void Entity::remove()
{
removed = true;
}
void Entity::setSize( float w, float h )
{
bbWidth = w;
bbHeight = h;
}
void Entity::setRot( float yRot, float xRot )
{
this->yRot = yRotO = yRot;
this->xRot = xRotO = xRot;
}
void Entity::turn( float xo, float yo )
{
float xRotOld = xRot;
float yRotOld = yRot;
yRot += xo * 0.15f;
xRot -= yo * 0.15f;
if (xRot < -90) xRot = -90;
if (xRot > 90) xRot = 90;
xRotO += xRot - xRotOld;
yRotO += yRot - yRotOld;
}
void Entity::interpolateTurn( float xo, float yo )
{
yRot += xo * 0.15f;
xRot -= yo * 0.15f;
if (xRot < -90) xRot = -90;
if (xRot > 90) xRot = 90;
}
void Entity::tick()
{
baseTick();
}
void Entity::setOnFire(int numberOfSeconds)
{
int newValue = numberOfSeconds * 20;
if (onFire < newValue)
{
onFire = newValue;
}
}
void Entity::baseTick()
{
TIMER_PUSH("entityBaseTick");
tickCount++;
walkDistO = walkDist;
xo = x;
yo = y;
zo = z;
xRotO = xRot;
yRotO = yRot;
if (isInWater()) {
if (!wasInWater && !firstTick) {
float speed = sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f;
if (speed > 1) speed = 1;
level->playSound(this, "random.splash", speed, 1 + (sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.4f);
float yt = floorf(bb.y0);
for (int i = 0; i < 1 + bbWidth * 20; i++) {
float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
level->addParticle(PARTICLETYPE(bubble), x + xo, yt + 1, z + zo, xd, yd - sharedRandom.nextFloat() * 0.2f, zd);
}
//for (int i = 0; i < 1 + bbWidth * 20; i++) {
// float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
// float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
// level->addParticle(PARTICLETYPE(splash), x + xo, yt + 1, z + zo, xd, yd, zd);
//}
}
fallDistance = 0;
wasInWater = true;
onFire = 0;
} else {
wasInWater = false;
}
if (level->isClientSide) {
onFire = 0;
} else {
if (onFire > 0) {
if (fireImmune) {
onFire -= 4;
if (onFire < 0) onFire = 0;
} else {
if (onFire % 20 == 0) {
hurt(NULL, 1);
}
onFire--;
}
}
}
if (isInLava()) {
lavaHurt();
}
if (y < -64) {
outOfWorld();
}
//if (!level->isOnline) {
// setSharedFlag(FLAG_ONFIRE, onFire > 0);
//}
firstTick = false;
TIMER_POP();
}
void Entity::outOfWorld()
{
remove();
}
void Entity::checkFallDamage( float ya, bool onGround )
{
if (onGround) {
if (fallDistance > 0) {
if(isMob()) {
int xt = Mth::floor(x);
int yt = Mth::floor(y - 0.2f - heightOffset);
int zt = Mth::floor(z);
int t = level->getTile(xt, yt, zt);
if (t == 0 && level->getTile(xt, yt - 1, zt) == Tile::fence->id) {
t = level->getTile(xt, yt - 1, zt);
}
if (t > 0) {
Tile::tiles[t]->fallOn(level, xt, yt, zt, this, fallDistance);
}
}
causeFallDamage(fallDistance);
fallDistance = 0;
}
} else {
if (ya < 0) fallDistance -= ya;
}
}
void Entity::causeFallDamage( float fallDamage2 )
{
}
float Entity::getHeadHeight()
{
return 0;
}
void Entity::moveRelative( float xa, float za, float speed )
{
float dist = sqrt(xa * xa + za * za);
if (dist < 0.01f) return;
if (dist < 1) dist = 1;
dist = speed / dist;
xa *= dist;
za *= dist;
float sin_ = (float) sin(yRot * Mth::PI / 180);
float cos_ = (float) cos(yRot * Mth::PI / 180);
xd += xa * cos_ - za * sin_;
zd += za * cos_ + xa * sin_;
}
void Entity::setLevel( Level* level )
{
this->level = level;
}
void Entity::moveTo( float x, float y, float z, float yRot, float xRot )
{
this->xOld = this->xo = this->x = x;
this->yOld = this->yo = this->y = y + heightOffset;
this->zOld = this->zo = this->z = z;
this->yRot = this->yRotO = yRot;
this->xRot = this->xRotO = xRot;
this->setPos(this->x, this->y, this->z);
}
float Entity::distanceTo( Entity* e )
{
float xd = (float) (x - e->x);
float yd = (float) (y - e->y);
float zd = (float) (z - e->z);
return sqrt(xd * xd + yd * yd + zd * zd);
}
float Entity::distanceTo( float x2, float y2, float z2 )
{
float xd = (x - x2);
float yd = (y - y2);
float zd = (z - z2);
return sqrt(xd * xd + yd * yd + zd * zd);
}
float Entity::distanceToSqr( float x2, float y2, float z2 )
{
float xd = (x - x2);
float yd = (y - y2);
float zd = (z - z2);
return xd * xd + yd * yd + zd * zd;
}
float Entity::distanceToSqr( Entity* e )
{
float xd = x - e->x;
float yd = y - e->y;
float zd = z - e->z;
return xd * xd + yd * yd + zd * zd;
}
void Entity::playerTouch( Player* player )
{
}
void Entity::push( Entity* e )
{
float xa = e->x - x;
float za = e->z - z;
float dd = Mth::absMax(xa, za);
if (dd >= 0.01f) {
dd = sqrt(dd);
xa /= dd;
za /= dd;
float pow = 1 / dd;
if (pow > 1) pow = 1;
xa *= pow;
za *= pow;
xa *= 0.05f;
za *= 0.05f;
xa *= 1 - pushthrough;
za *= 1 - pushthrough;
this->push(-xa, 0, -za);
e->push(xa, 0, za);
}
}
void Entity::push( float xa, float ya, float za )
{
xd += xa;
yd += ya;
zd += za;
}
void Entity::markHurt()
{
this->hurtMarked = true;
}
bool Entity::hurt( Entity* source, int damage )
{
markHurt();
return false;
}
void Entity::reset() {
this->_init();
}
void Entity::_init() {
xo = xOld = x;
yo = yOld = y;
zo = zOld = z;
xRotO = xRot;
yRotO = yRot;
onFire = 0;
removed = false;
fallDistance = 0;
}
bool Entity::intersects( float x0, float y0, float z0, float x1, float y1, float z1 )
{
return bb.intersects(x0, y0, z0, x1, y1, z1);
}
bool Entity::isPickable()
{
return false;
}
bool Entity::isPushable()
{
return false;
}
bool Entity::isShootable()
{
return false;
}
void Entity::awardKillScore( Entity* victim, int score )
{
}
bool Entity::shouldRender( Vec3& c )
{
if (invisible) return false;
float xd = x - c.x;
float yd = y - c.y;
float zd = z - c.z;
float distance = xd * xd + yd * yd + zd * zd;
return shouldRenderAtSqrDistance(distance);
}
bool Entity::shouldRenderAtSqrDistance( float distance )
{
float size = bb.getSize();
size *= 64.0f * viewScale;
return distance < size * size;
}
bool Entity::isCreativeModeAllowed()
{
return false;
}
float Entity::getShadowHeightOffs()
{
return bbHeight / 2;
}
bool Entity::isAlive()
{
return !removed;
}
bool Entity::interact( Player* player )
{
return false;
}
void Entity::lerpTo( float x, float y, float z, float yRot, float xRot, int steps )
{
setPos(x, y, z);
setRot(yRot, xRot);
}
float Entity::getPickRadius()
{
return 0.1f;
}
void Entity::lerpMotion( float xd, float yd, float zd )
{
this->xd = xd;
this->yd = yd;
this->zd = zd;
}
void Entity::animateHurt()
{
}
void Entity::setEquippedSlot( int slot, int item, int auxValue )
{
}
bool Entity::isSneaking()
{
return false;
}
bool Entity::isPlayer()
{
return false;
}
void Entity::lavaHurt() {
if (fireImmune) {
} else {
hurt(NULL, 4);
onFire = 30 * SharedConstants::TicksPerSecond;
}
}
// AABB getCollideBox() {
// return NULL;
// }
void Entity::burn(int dmg) {
if (!fireImmune) {
hurt(NULL, dmg);
}
}
// std::string getTexture() {
// return NULL;
// }
bool Entity::save(CompoundTag* entityTag) {
int id = getEntityTypeId();
if (removed || id == 0) {
return false;
}
entityTag->putInt("id", id);
saveWithoutId(entityTag);
return true;
}
void Entity::saveWithoutId(CompoundTag* entityTag) {
entityTag->put("Pos", ListTagFloatAdder (x) (y) (z).tag);
entityTag->put("Motion", ListTagFloatAdder (xd) (yd) (zd).tag);
entityTag->put("Rotation", ListTagFloatAdder (yRot) (xRot).tag);
entityTag->putFloat("FallDistance", fallDistance);
entityTag->putShort("Fire", (short) onFire);
entityTag->putShort("Air", (short) airSupply);
entityTag->putBoolean("OnGround", onGround);
addAdditonalSaveData(entityTag);
}
bool Entity::load( CompoundTag* tag )
{
ListTag* pos = tag->getList("Pos");
ListTag* motion = tag->getList("Motion");
ListTag* rotation = tag->getList("Rotation");
setPos(0, 0, 0);
xd = motion->getFloat(0);
yd = motion->getFloat(1);
zd = motion->getFloat(2);
if (Mth::abs(xd) > 10.0) {
xd = 0;
}
if (Mth::abs(yd) > 10.0) {
yd = 0;
}
if (Mth::abs(zd) > 10.0) {
zd = 0;
}
float xx = pos->getFloat(0);
float yy = pos->getFloat(1);
float zz = pos->getFloat(2);
// Add a small padding if standing next to the world edges
const float padding = bbWidth * 0.5f + 0.001f;
xx = Mth::clamp(xx, padding, (float)LEVEL_WIDTH - padding);
zz = Mth::clamp(zz, padding, (float)LEVEL_DEPTH - padding);
xo = xOld = x = xx;
yo = yOld = y = yy;
zo = zOld = z = zz;
yRotO = yRot = fmod( rotation->getFloat(0), 360.0f);
xRotO = xRot = fmod( rotation->getFloat(1), 360.0f);
fallDistance= tag->getFloat("FallDistance");
onFire = tag->getShort("Fire");
airSupply = tag->getShort("Air");
onGround = tag->getBoolean("OnGround");
setPos(x, y, z);
readAdditionalSaveData(tag);
return (tag->errorState == 0);
}
// /*protected*/ const String getEncodeId() {
// return EntityIO.getEncodeId(this->;
// }
ItemEntity* Entity::spawnAtLocation(int resource, int count) {
return spawnAtLocation(resource, count, 0);
}
ItemEntity* Entity::spawnAtLocation(int resource, int count, float yOffs) {
return spawnAtLocation(new ItemInstance(resource, count, 0), yOffs);
}
ItemEntity* Entity::spawnAtLocation(ItemInstance* itemInstance, float yOffs) {
ItemEntity* ie = new ItemEntity(level, x, y + yOffs, z, *itemInstance);
{ //@todo:itementity
delete itemInstance;
itemInstance = NULL;
}
ie->throwTime = 10;
level->addEntity(ie);
return ie;
}
bool Entity::isOnFire() {
return onFire > 0;// || getSharedFlag(FLAG_ONFIRE);
}
bool Entity::interactPreventDefault() {
return false;
}
// AABB getCollideAgainstBox(Entity entity) {
// return NULL;
// }
// Vec3 getLookAngle() {
// return NULL;
// }
// void prepareCustomTextures() {
// }
// ItemInstance[] getEquipmentSlots() {
// return NULL;
// }
bool Entity::isItemEntity() {
return false;
}
bool Entity::isHangingEntity() {
return false;
}
int Entity::getAuxData() {
return 0;
}
void Entity::playStepSound( int xt, int yt, int zt, int t ) {
const Tile::SoundType* soundType = Tile::tiles[t]->soundType;
if (level->getTile(xt, yt + 1, zt) == Tile::topSnow->id) {
soundType = Tile::topSnow->soundType;
level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch()); // was * 0.15f
} else if (!Tile::tiles[t]->material->isLiquid()) {
level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch());
}
}