/******************************************************************** 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 "Player.hpp" #include "world/level/Level.hpp" Player::Player(Level* pLevel) : Mob(pLevel) { m_pInventory = nullptr; field_B94 = 0; m_score = 0; field_B9C = 0.0f; field_BA0 = 0.0f; field_BA4 = false; field_BA8 = 0; m_name = ""; field_BC4 = 0; m_bHaveRespawnPos = false; field_C8 = RENDER_HUMANOID; m_pInventory = new Inventory(this); field_84 = 1.62f; Pos pos = m_pLevel->getSharedSpawnPos(); moveTo(float(pos.x) + 0.5f, float(pos.y) + 1.0f, float(pos.z) + 0.5f, 0.0f, 0.0f); m_health = 20; m_class = "humanoid"; m_texture = "mob/char.png"; field_C4 = 20; field_B5C = 180.0f; } Player::~Player() { delete m_pInventory; } void Player::reset() { Mob::reset(); // TODO what fields to reset??? } void Player::remove() { Entity::remove(); } void Player::tick() { Mob::tick(); } bool Player::isInWall() { return Entity::isInWall(); } float Player::getHeadHeight() { return 0.12f; //@HUH: what? } bool Player::isShootable() { return true; } bool Player::isPlayer() { return true; } bool Player::isCreativeModeAllowed() { return true; } bool Player::hurt(Entity* pEnt, int damage) { //@HUH #ifndef TEST_SURVIVAL_MODE return false; #endif return Mob::hurt(pEnt, damage); } void Player::awardKillScore(Entity* pKilled, int score) { m_score += score; } void Player::resetPos() { field_84 = 1.62f; setSize(0.6f, 1.8f); Entity::resetPos(); m_health = 20; field_110 = 0; } void Player::die(Entity* pCulprit) { Mob::die(pCulprit); setSize(0.2f, 0.2f); setPos(m_pos.x, m_pos.y, m_pos.z); // update hitbox m_vel.y = 0.1f; if (pCulprit) { m_vel.x = -0.1f * Mth::cos(float((field_10C + m_yaw) * M_PI / 180.0)); m_vel.z = -0.1f * Mth::cos(float((field_10C + m_yaw) * M_PI / 180.0)); } else { m_vel.x = 0; m_vel.z = 0; } } void Player::aiStep() { field_B9C = field_BA0; float velLen = Mth::sqrt(m_vel.x * m_vel.x + m_vel.z * m_vel.z); float velYAtan = Mth::atan(m_vel.y * -0.2f), x1 = 0.0f; if (velLen > 0.1f) velLen = 0.1f; if (!field_7C) { if (m_health > 0) { velLen = 0; x1 = velYAtan * 15.0f; } else { velLen = x1 = 0.0f; } } if (m_health <= 0) velLen = 0.0f; field_BA0 += (velLen - field_BA0) * 0.4f; field_11C += (x1 - field_11C) * 0.8f; if (m_health <= 0) return; AABB scanAABB = m_hitbox; scanAABB.grow(1, 1, 1); EntityVector* pEnts = m_pLevel->getEntities(this, scanAABB); for (EntityVector::iterator it = pEnts->begin(); it != pEnts->end(); it++) { Entity* pEnt = *it; if (pEnt->m_bRemoved) continue; touch(pEnt); } } bool Player::isImmobile() { return m_health <= 0; } void Player::updateAi() { if (field_BA4) { field_BA8++; if (field_BA8 > 7) { field_BA8 = 0; field_BA4 = false; } } else { field_BA8 = 0; } field_F8 = field_BA8 * 0.125f; } void Player::defineSynchedData() { Mob::defineSynchedData(); } void Player::animateRespawn() { } int Player::addResource(int x) { return 0; } void Player::animateRespawn(Player*, Level*) { } void Player::attack(Entity* pEnt) { int atkDmg = m_pInventory->getAttackDamage(pEnt); if (atkDmg > 0) pEnt->hurt(this, atkDmg); } bool Player::canDestroy(Tile* pTile) { return true; } void Player::closeContainer() { } void Player::displayClientMessage(const std::string& msg) { } void Player::drop(ItemInstance* pItemInstance) { drop(pItemInstance, false); } void Player::drop(ItemInstance* pItemInstance, bool b) { if (!pItemInstance) return; ItemEntity* pItemEntity = new ItemEntity(m_pLevel, m_pos.x, m_pos.y - 0.3f + getHeadHeight(), m_pos.z, pItemInstance); pItemEntity->field_E4 = 40; if (b) { float throwPower = 0.5f * m_random.nextFloat(); float throwAngle = m_random.nextFloat(); pItemEntity->m_vel.x = -(throwPower * Mth::sin(2 * float(M_PI) * throwAngle)); pItemEntity->m_vel.z = (throwPower * Mth::cos(2 * float(M_PI) * throwAngle)); pItemEntity->m_vel.y = 0.2f; } else { pItemEntity->m_vel.x = -(Mth::sin(m_yaw / 180.0f * float(M_PI)) * Mth::cos(m_pitch / 180.0f * float(M_PI))) * 0.3f; pItemEntity->m_vel.z = (Mth::cos(m_yaw / 180.0f * float(M_PI)) * Mth::cos(m_pitch / 180.0f * float(M_PI))) * 0.3f; pItemEntity->m_vel.y = 0.1f - Mth::sin(m_pitch / 180.0f * float(M_PI)) * 0.3f; float f1 = m_random.nextFloat(); float f2 = m_random.nextFloat(); pItemEntity->m_vel.x += 0.02f * f2 * Mth::cos(2 * float(M_PI) * f1); pItemEntity->m_vel.y += 0.1f * (m_random.nextFloat() - m_random.nextFloat()); pItemEntity->m_vel.z += 0.02f * f2 * Mth::sin(2 * float(M_PI) * f1); } reallyDrop(pItemEntity); } void Player::drop() { } float Player::getDestroySpeed() { return 0.5f; } int Player::getInventorySlot(int x) { return 0; } Pos Player::getRespawnPosition() { return m_respawnPos; } int Player::getScore() { return m_score; } void Player::prepareCustomTextures() { } void Player::reallyDrop(ItemEntity* pEnt) { m_pLevel->addEntity(pEnt); } void Player::respawn() { } void Player::rideTick() { } void Player::setDefaultHeadHeight() { field_84 = 1.62f; } void Player::setRespawnPos(Pos* pos) { if (!pos) { m_bHaveRespawnPos = false; return; } m_bHaveRespawnPos = true; m_respawnPos.x = pos->x; m_respawnPos.y = pos->y; // @BUG: no m_respawnPos.z = pos->z ?? } void Player::startCrafting(int x, int y, int z) { } void Player::swing() { field_BA8 = -1; field_BA4 = true; } void Player::take(Entity* pEnt, int x) { } void Player::touch(Entity* pEnt) { pEnt->playerTouch(this); } void Player::interact(Entity* pEnt) { pEnt->interact(this); }