From ad58a960e458e596e2a7a9f037487dbe8f4538cc Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Fri, 30 Jun 2023 11:44:42 +1000 Subject: [PATCH] bring player inspection back! --- source/game/StarPlayer.cpp | 26 ++++++++-- source/game/StarPlayer.hpp | 5 ++ .../game/interfaces/StarInspectableEntity.hpp | 4 +- source/game/items/StarInspectionTool.cpp | 52 ++++++++++++++----- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/source/game/StarPlayer.cpp b/source/game/StarPlayer.cpp index fc2a9a7..af8a2ed 100644 --- a/source/game/StarPlayer.cpp +++ b/source/game/StarPlayer.cpp @@ -1,4 +1,5 @@ #include "StarPlayer.hpp" +#include "StarEncode.hpp" #include "StarJsonExtra.hpp" #include "StarRoot.hpp" #include "StarSongbook.hpp" @@ -102,10 +103,6 @@ Player::Player(PlayerConfigPtr config, Uuid uuid) { m_techs = make_shared(); m_log = make_shared(); - m_description = strf("This {} seems to have nothing to say for {}self.", - m_identity.gender == Gender::Male ? "guy" : "gal", - m_identity.gender == Gender::Male ? "him" : "her"); - setModeType(PlayerMode::Casual); m_useDown = false; @@ -1524,6 +1521,10 @@ String Player::description() const { return m_description; } +void Player::setDescription(String const& description) { + m_description = description; +} + Direction Player::walkingDirection() const { return m_movementController->movingDirection(); } @@ -2107,6 +2108,19 @@ List Player::pullPendingChatActions() { return take(m_pendingChatActions); } +Maybe Player::inspectionLogName() const { + auto identifier = uniqueId(); + if (String* str = identifier.ptr()) { + auto hash = XXH3_128bits(str->utf8Ptr(), str->utf8Size()); + return String("Player #") + hexEncode((const char*)&hash, sizeof(hash)); + } + return identifier; +} + +Maybe Player::inspectionDescription(String const& species) const { + return m_description; +} + float Player::beamGunRadius() const { return m_tools->beamGunRadius(); } @@ -2228,6 +2242,10 @@ void Player::finalizeCreation() { m_statusController->resetAllResources(); m_effectEmitter->reset(); + + m_description = strf("This {} seems to have nothing to say for {}self.", + m_identity.gender == Gender::Male ? "guy" : "gal", + m_identity.gender == Gender::Male ? "him" : "her"); } bool Player::invisible() const { diff --git a/source/game/StarPlayer.hpp b/source/game/StarPlayer.hpp index aa6853f..c63fe15 100644 --- a/source/game/StarPlayer.hpp +++ b/source/game/StarPlayer.hpp @@ -53,6 +53,7 @@ class Player : public virtual ToolUserEntity, public virtual LoungingEntity, public virtual ChattyEntity, + public virtual InspectableEntity, public virtual DamageBarEntity, public virtual PortraitEntity, public virtual NametagEntity, @@ -172,6 +173,7 @@ public: bool forceNude() const; String description() const override; + void setDescription(String const& description); List lightSources() const override; @@ -377,6 +379,9 @@ public: List pullPendingChatActions() override; + Maybe inspectionLogName() const override; + Maybe inspectionDescription(String const& species) const override; + float beamGunRadius() const override; bool instrumentPlaying() override; diff --git a/source/game/interfaces/StarInspectableEntity.hpp b/source/game/interfaces/StarInspectableEntity.hpp index c5d175b..c1c4abc 100644 --- a/source/game/interfaces/StarInspectableEntity.hpp +++ b/source/game/interfaces/StarInspectableEntity.hpp @@ -1,13 +1,13 @@ #ifndef STAR_INSPECTABLE_ENTITY_HPP #define STAR_INSPECTABLE_ENTITY_HPP -#include "StarTileEntity.hpp" +#include "StarEntity.hpp" namespace Star { STAR_CLASS(InspectableEntity); -class InspectableEntity : public virtual TileEntity { +class InspectableEntity : public virtual Entity { public: // Default implementation returns true virtual bool inspectable() const; diff --git a/source/game/items/StarInspectionTool.cpp b/source/game/items/StarInspectionTool.cpp index 19e37d8..f3e9586 100644 --- a/source/game/items/StarInspectionTool.cpp +++ b/source/game/items/StarInspectionTool.cpp @@ -77,19 +77,23 @@ float InspectionTool::inspectionLevel(InspectableEntityPtr const& inspectable) c if (!initialized() || !inspectable->inspectable()) return 0; - float totalLevel = 0; + if (auto tileEntity = as(inspectable)) { + float totalLevel = 0; - // convert spaces to a set of world positions - Set spaceSet; - for (auto space : inspectable->spaces()) - spaceSet.add(inspectable->tilePosition() + space); + // convert spaces to a set of world positions + Set spaceSet; + for (auto space : tileEntity->spaces()) + spaceSet.add(tileEntity->tilePosition() + space); - for (auto space : spaceSet) { - float pointLevel = pointInspectionLevel(centerOfTile(space)); - if (pointLevel > 0 && hasLineOfSight(space, spaceSet)) - totalLevel += pointLevel; + for (auto space : spaceSet) { + float pointLevel = pointInspectionLevel(centerOfTile(space)); + if (pointLevel > 0 && hasLineOfSight(space, spaceSet)) + totalLevel += pointLevel; + } + return clamp(totalLevel / min(spaceSet.size(), m_fullInspectionSpaces), 0.0f, 1.0f); } - return clamp(totalLevel / min(spaceSet.size(), m_fullInspectionSpaces), 0.0f, 1.0f); + else + return pointInspectionLevel(inspectable->position()); } float InspectionTool::pointInspectionLevel(Vec2F const& position) const { @@ -116,13 +120,35 @@ InspectionTool::InspectionResult InspectionTool::inspect(Vec2F const& position) // if there's a candidate InspectableEntity at the position, make sure that entity's total inspection level // is above the minimum threshold - for (auto entity : world()->atTile(Vec2I::floor(position))) { + auto check = [&](InspectableEntityPtr entity) -> Maybe { if (entity->inspectable() && inspectionLevel(entity) >= m_minimumInspectionLevel) { if (m_allowScanning) - return {entity->inspectionDescription(species).value(), entity->inspectionLogName(), entity->entityId()}; + return { { entity->inspectionDescription(species).value(), entity->inspectionLogName(), entity->entityId() } }; else - return {entity->inspectionDescription(species).value(), {}, {}}; + return { { entity->inspectionDescription(species).value(), {}, {} } }; } + return {}; + }; + + + WorldGeometry geometry = world()->geometry(); + for (auto& entity : world()->query(RectF::withCenter(position, Vec2F::filled(FLT_EPSILON)), [&](InspectableEntityPtr const& entity) { + if (entity->entityType() == EntityType::Object) + return false; + else if (!geometry.rectContains(entity->metaBoundBox().translated(entity->position()), position)) + return false; + else { + auto hitPoly = entity->hitPoly(); + return hitPoly && geometry.polyContains(*hitPoly, position); + } + })) { + if (auto result = check(entity)) + return *result; + } + + for (auto& entity : world()->atTile(Vec2I::floor(position))) { + if (auto result = check(entity)) + return *result; } // check the inspection level at the selected tile