Files
mcpe/source/world/entity/ItemEntity.cpp
2023-12-02 21:04:21 +03:00

166 lines
4.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 "ItemEntity.hpp"
#include "world/level/Level.hpp"
void ItemEntity::_init(ItemInstance* itemInstance)
{
field_E0 = 0;
field_E4 = 0;
field_EC = 0;
m_health = 5;
// @NOTE: not setting render type
field_E8 = 2 * float(M_PI) * Mth::random();
setSize(0.25f, 0.25f);
field_84 = field_8C * 0.5f;
m__itemInstance = itemInstance ? *itemInstance : ItemInstance(0, 0, 0);
m_pItemInstance = &m__itemInstance;
}
void ItemEntity::_init(ItemInstance* itemInstance, float x, float y, float z)
{
_init(itemInstance);
m_renderType = RENDER_ITEM;
setPos(x, y, z);
m_yaw = 360.0f * Mth::random();
m_vel.y = 0.2f;
m_vel.x = Mth::random() * 0.2f - 0.1f;
m_vel.z = Mth::random() * 0.2f - 0.1f;
}
void ItemEntity::burn(int damage)
{
hurt(nullptr, damage);
}
bool ItemEntity::hurt(Entity* pCulprit, int damage)
{
markHurt();
m_health -= damage;
if (m_health < 0)
remove();
return false;
}
bool ItemEntity::isInWater()
{
return m_pLevel->checkAndHandleWater(m_hitbox, Material::water, this);
}
void ItemEntity::playerTouch(Player* player)
{
// Here, this would give the item to the player, and remove the item entity.
if (field_E4 != 0)
return;
Inventory* pInventory = player->m_pInventory;
pInventory->addItem(m_pItemInstance);
// No "random.pop" sound.
if (m_pItemInstance->m_amount <= 0)
remove();
}
void ItemEntity::tick()
{
Entity::tick();
if (field_E4 > 0)
field_E4--;
field_3C = m_pos;
m_vel.y -= 0.04f;
if (m_pLevel->getMaterial(Mth::floor(m_pos.x), Mth::floor(m_pos.y), Mth::floor(m_pos.z)) == Material::lava)
{
// give it a small bounce upwards
m_vel.y = 0.2f;
m_vel.x = 0.2f * (sharedRandom.nextFloat() - sharedRandom.nextFloat());
m_vel.z = 0.2f * (sharedRandom.nextFloat() - sharedRandom.nextFloat());
}
checkInTile(m_pos.x, m_pos.y, m_pos.z);
move(m_vel.x, m_vel.y, m_vel.z);
float dragFactor = 0.98f;
if (field_7C)
{
dragFactor = 0.588f;
TileID tile = m_pLevel->getTile(Mth::floor(m_pos.x), Mth::floor(m_hitbox.min.y) - 1, Mth::floor(m_pos.z));
if (tile > 0)
dragFactor = Tile::tiles[tile]->m_acceleration * 0.98f;
}
m_vel.x *= dragFactor;
m_vel.z *= dragFactor;
m_vel.y *= 0.98f;
if (field_7C)
m_vel.y *= -0.5f;
field_EC++;
field_E0++;
//despawn after 5 minutes
if (field_E0 >= 6000)
remove();
}
void ItemEntity::checkInTile(float x, float y, float z)
{
int xfl = Mth::floor(x);
int yfl = Mth::floor(y);
int zfl = Mth::floor(z);
if (!Tile::solid[m_pLevel->getTile(xfl, yfl, zfl)])
return;
bool solidXN = Tile::solid[m_pLevel->getTile(xfl - 1, yfl, zfl)];
bool solidXP = Tile::solid[m_pLevel->getTile(xfl + 1, yfl, zfl)];
bool solidYN = Tile::solid[m_pLevel->getTile(xfl, yfl - 1, zfl)];
bool solidYP = Tile::solid[m_pLevel->getTile(xfl, yfl + 1, zfl)];
bool solidZN = Tile::solid[m_pLevel->getTile(xfl, yfl, zfl - 1)];
bool solidZP = Tile::solid[m_pLevel->getTile(xfl, yfl, zfl + 1)];
float mindist = 9999.0f;
int mindir = -1;
float xdiff = x - float(xfl);
float ydiff = y - float(yfl);
float zdiff = z - float(zfl);
if (!solidXN && xdiff < mindist) mindist = xdiff, mindir = 0;
if (!solidXP && 1.0f - xdiff < mindist) mindist = 1.0f - xdiff, mindir = 1;
if (!solidYN && ydiff < mindist) mindist = ydiff, mindir = 2;
if (!solidYP && 1.0f - ydiff < mindist) mindist = 1.0f - ydiff, mindir = 3;
if (!solidZN && zdiff < mindist) mindist = zdiff, mindir = 4;
if (!solidZP && 1.0f - zdiff < mindist) mindist = 1.0f - zdiff, mindir = 5;
(void)mindist;
// the -1 case will be handled accordingly
float force = 0.1f + 0.2f * sharedRandom.nextFloat();
switch (mindir)
{
case 0: m_vel.x = -force; break;
case 1: m_vel.x = force; break;
case 2: m_vel.y = -force; break;
case 3: m_vel.y = force; break;
case 4: m_vel.z = -force; break;
case 5: m_vel.z = force; break;
}
}