snivy
This commit is contained in:
@@ -311,6 +311,12 @@ namespace game::state
|
||||
auto& interactionCursor = autofeed.active_get() ? autofeedCursor : cursor;
|
||||
itemManager.isAutomation = autofeed.active_get();
|
||||
itemManager.update(character, interactionCursor, areaManager, text, world.bounds, worldCanvas);
|
||||
auto* itemRoot = character.data.itemSchema.root();
|
||||
for (int i = 0; i < itemManager.newItemFoundCount; i++)
|
||||
{
|
||||
toasts.push(character.data.strings.get(Strings::ToastNewItemFound));
|
||||
if (itemRoot) itemRoot->soundNewItem.play();
|
||||
}
|
||||
characterManager.update(character, interactionCursor, text, worldCanvas);
|
||||
for (auto& particle : itemManager.particles)
|
||||
particleManager.spawn(character.data, particle.label, particle.position);
|
||||
|
||||
+55
-18
@@ -15,10 +15,14 @@ namespace game::state::play
|
||||
{
|
||||
constexpr float CURSOR_SPEED = 9.0f;
|
||||
constexpr float DIGEST_CURSOR_SPEED = 3.0f;
|
||||
constexpr float CURSOR_ACCELERATION = 0.45f;
|
||||
constexpr float DIGEST_CURSOR_ACCELERATION = 0.15f;
|
||||
constexpr float CURSOR_SPEED_REFERENCE_AREA = 512.0f * 512.0f;
|
||||
constexpr float CURSOR_SPEED_SCALE_MIN = 0.5f;
|
||||
constexpr float CURSOR_SPEED_SCALE_MAX = 2.0f;
|
||||
constexpr float CURSOR_BRAKING_ACCELERATION_MULTIPLIER = 2.0f;
|
||||
constexpr float CALORIE_EPSILON = 0.001f;
|
||||
constexpr float CURSOR_TARGET_EPSILON = 0.001f;
|
||||
constexpr float FOOD_TIE_PICK_WEIGHT = 1.0f;
|
||||
|
||||
glm::vec2 rect_center(glm::vec4 rect) { return {rect.x + rect.z * 0.5f, rect.y + rect.w * 0.5f}; }
|
||||
@@ -31,21 +35,51 @@ namespace game::state::play
|
||||
value.z > 0.0f && value.w > 0.0f;
|
||||
}
|
||||
|
||||
bool move_toward(Entity& cursor, glm::vec2 target, float speed)
|
||||
bool move_toward(Entity& cursor, glm::vec2& velocity, glm::vec2 target, float speed, float acceleration)
|
||||
{
|
||||
if (!is_finite(cursor.position)) cursor.position = {};
|
||||
if (!is_finite(cursor.position))
|
||||
{
|
||||
cursor.position = {};
|
||||
velocity = {};
|
||||
}
|
||||
if (!is_finite(target)) return false;
|
||||
|
||||
auto delta = target - cursor.position;
|
||||
auto distance = glm::length(delta);
|
||||
if (!std::isfinite(distance)) return false;
|
||||
if (distance <= speed || distance <= 0.001f)
|
||||
if (distance <= CURSOR_TARGET_EPSILON)
|
||||
{
|
||||
cursor.position = target;
|
||||
velocity = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor.position += delta / distance * speed;
|
||||
auto targetSpeed = glm::min(speed, std::sqrt(CURSOR_BRAKING_ACCELERATION_MULTIPLIER * acceleration * distance));
|
||||
auto desiredVelocity = delta / distance * targetSpeed;
|
||||
auto velocityDelta = desiredVelocity - velocity;
|
||||
auto velocityDeltaDistance = glm::length(velocityDelta);
|
||||
if (!std::isfinite(velocityDeltaDistance))
|
||||
velocity = {};
|
||||
else if (velocityDeltaDistance > acceleration)
|
||||
velocity += velocityDelta / velocityDeltaDistance * acceleration;
|
||||
else
|
||||
velocity = desiredVelocity;
|
||||
|
||||
auto speedCurrent = glm::length(velocity);
|
||||
if (!std::isfinite(speedCurrent))
|
||||
{
|
||||
velocity = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
if (speedCurrent >= distance)
|
||||
{
|
||||
cursor.position = target;
|
||||
velocity = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor.position += velocity;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -224,13 +258,14 @@ namespace game::state::play
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void state_reset(Entity& cursor, bool& isItemMouseHeld, bool& isDigestMouseHeld, int& targetItemIndex,
|
||||
int& digestClickCooldown)
|
||||
void state_reset(Entity& cursor, glm::vec2& cursorVelocity, bool& isItemMouseHeld, bool& isDigestMouseHeld,
|
||||
int& targetItemIndex, int& digestClickCooldown)
|
||||
{
|
||||
isItemMouseHeld = false;
|
||||
isDigestMouseHeld = false;
|
||||
targetItemIndex = -1;
|
||||
digestClickCooldown = 0;
|
||||
cursorVelocity = {};
|
||||
if (!is_finite(cursor.position)) cursor.position = {};
|
||||
}
|
||||
}
|
||||
@@ -243,13 +278,13 @@ namespace game::state::play
|
||||
|
||||
if (!isEnabled)
|
||||
{
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
|
||||
if (character.isStageUp || character.isJustStageUp || character.isJustStageFinal)
|
||||
{
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -257,7 +292,7 @@ namespace game::state::play
|
||||
|
||||
if (!is_food(character, itemManager))
|
||||
{
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -271,6 +306,8 @@ namespace game::state::play
|
||||
auto speedScale = cursor_speed_scale_get(character);
|
||||
auto cursorSpeed = CURSOR_SPEED * speedScale;
|
||||
auto digestCursorSpeed = DIGEST_CURSOR_SPEED * speedScale;
|
||||
auto cursorAcceleration = CURSOR_ACCELERATION * speedScale;
|
||||
auto digestCursorAcceleration = DIGEST_CURSOR_ACCELERATION * speedScale;
|
||||
auto eatRect = glm::vec4{};
|
||||
auto isEatTarget = eat_rect_get(character, eatRect);
|
||||
|
||||
@@ -281,7 +318,7 @@ namespace game::state::play
|
||||
{
|
||||
isActive = false;
|
||||
cursor.isVisible = false;
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
auto& schemaItem = schema.items[heldItem.schemaID];
|
||||
@@ -290,7 +327,7 @@ namespace game::state::play
|
||||
{
|
||||
isActive = true;
|
||||
cursor.isVisible = true;
|
||||
move_toward(cursor, rect_center(eatRect), cursorSpeed);
|
||||
move_toward(cursor, cursorVelocity, rect_center(eatRect), cursorSpeed, cursorAcceleration);
|
||||
|
||||
itemInput.isMouseLeftDown = true;
|
||||
itemManager.inputOverride = itemInput;
|
||||
@@ -319,13 +356,13 @@ namespace game::state::play
|
||||
auto rect = item.rect();
|
||||
if (!is_finite(rect))
|
||||
{
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
|
||||
isActive = true;
|
||||
cursor.isVisible = true;
|
||||
move_toward(cursor, rect_center(rect), cursorSpeed);
|
||||
move_toward(cursor, cursorVelocity, rect_center(rect), cursorSpeed, cursorAcceleration);
|
||||
|
||||
auto isInItemRect = math::is_point_in_rectf(rect, cursor.position);
|
||||
|
||||
@@ -341,7 +378,7 @@ namespace game::state::play
|
||||
auto isWorldFood = is_world_food(character, itemManager);
|
||||
if (character.calories <= CALORIE_EPSILON && !isWorldFood)
|
||||
{
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -350,20 +387,20 @@ namespace game::state::play
|
||||
auto* interactArea = digestion_area_get(character);
|
||||
if (!interactArea)
|
||||
{
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
|
||||
auto rect = character.null_frame_rect(character.data.null_id_get(interactArea->null));
|
||||
if (!is_finite(rect))
|
||||
{
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
return;
|
||||
}
|
||||
auto radius = glm::max(1.0f, glm::min(rect.z, rect.w) * 0.25f);
|
||||
digestAngle += 0.08f;
|
||||
auto targetWorld = rect_center(rect) + glm::vec2(std::cos(digestAngle), std::sin(digestAngle)) * radius;
|
||||
auto isAtTarget = move_toward(cursor, targetWorld, digestCursorSpeed);
|
||||
auto isAtTarget = move_toward(cursor, cursorVelocity, targetWorld, digestCursorSpeed, digestCursorAcceleration);
|
||||
isActive = true;
|
||||
cursor.isVisible = true;
|
||||
|
||||
@@ -394,7 +431,7 @@ namespace game::state::play
|
||||
return;
|
||||
}
|
||||
|
||||
state_reset(cursor, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
state_reset(cursor, cursorVelocity, isItemMouseHeld, isDigestMouseHeld, targetItemIndex, digestClickCooldown);
|
||||
}
|
||||
|
||||
void Autofeed::toggle() { isEnabled = !isEnabled; }
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace game::state::play
|
||||
int targetItemIndex{-1};
|
||||
int digestClickCooldown{};
|
||||
float digestAngle{};
|
||||
glm::vec2 cursorVelocity{};
|
||||
bool isEnabled{};
|
||||
bool isActive{};
|
||||
|
||||
|
||||
@@ -226,6 +226,7 @@ namespace game::state::play
|
||||
if (isItemHovered != isItemHoveredPrevious && !isItemHovered) isJustItemHoveredStopped = true;
|
||||
if (spawnDelayTicks > 0) spawnDelayTicks--;
|
||||
if (discoveredItemIDs.size() != schema.items.size()) discoveredItemIDs.resize(schema.items.size());
|
||||
newItemFoundCount = 0;
|
||||
|
||||
for (auto& id : queuedItemIDs)
|
||||
{
|
||||
@@ -237,7 +238,11 @@ namespace game::state::play
|
||||
auto& anm2 = itemSchema.anm2s.at(id);
|
||||
items.emplace_back(anm2, position, id);
|
||||
character.totalItemsSpawned++;
|
||||
if (id >= 0 && id < (int)discoveredItemIDs.size()) discoveredItemIDs[id] = true;
|
||||
if (id >= 0 && id < (int)discoveredItemIDs.size())
|
||||
{
|
||||
if (!discoveredItemIDs[id]) newItemFoundCount++;
|
||||
discoveredItemIDs[id] = true;
|
||||
}
|
||||
particles_queue(itemSchema, resource::xml::Schema::Element::SUMMON, position);
|
||||
}
|
||||
queuedItemIDs.clear();
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace game::state::play
|
||||
|
||||
std::vector<int> queuedItemIDs{};
|
||||
std::vector<bool> discoveredItemIDs{};
|
||||
int newItemFoundCount{};
|
||||
int spawnDelayTicks{};
|
||||
struct Particle
|
||||
{
|
||||
|
||||
@@ -54,15 +54,15 @@ namespace game::state::play::menu
|
||||
{
|
||||
auto* settings = resources.settings.root();
|
||||
auto system = settings->measurementSystem == "Imperial" ? measurement::IMPERIAL : measurement::METRIC;
|
||||
auto weight = character.weight_get(system);
|
||||
auto weight = measurement::weight_display_get(character.weight, system);
|
||||
auto stage = character.stage_get();
|
||||
auto stageMax = character.stage_max_get();
|
||||
auto stageCount = character.stage_count_get();
|
||||
auto stageWeight = character.stage_threshold_get(stage, system);
|
||||
auto stageNextWeight = character.stage_threshold_next_get(system);
|
||||
auto unitString = (system == measurement::IMPERIAL ? "lbs" : "kg");
|
||||
auto stageWeight = measurement::weight_display_get(character.stage_threshold_get(stage), system);
|
||||
auto stageNextWeight = measurement::weight_display_get(character.stage_threshold_next_get(), system);
|
||||
|
||||
auto weightString = util::string::format_commas(weight, 2) + " " + unitString;
|
||||
auto weightString = util::string::format_commas(weight.value, measurement::WEIGHT_DISPLAY_DECIMAL_DIGITS) + " " +
|
||||
weight.unit;
|
||||
imgui::text_unformatted_fit_draw(weightString.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, Font::HEADER_2),
|
||||
Font::HEADER_2);
|
||||
ImGui::SetItemTooltip("%s", weightString.c_str());
|
||||
@@ -81,9 +81,9 @@ namespace game::state::play::menu
|
||||
ImGui::TextUnformatted(strings.get(Strings::InfoMaxedOut).c_str());
|
||||
else
|
||||
{
|
||||
ImGui::Text(strings.get(Strings::InfoStageStartFormat).c_str(), stageWeight, unitString);
|
||||
ImGui::Text(strings.get(Strings::InfoStageCurrentFormat).c_str(), weight, unitString);
|
||||
ImGui::Text(strings.get(Strings::InfoStageNextFormat).c_str(), stageNextWeight, unitString);
|
||||
ImGui::Text(strings.get(Strings::InfoStageStartFormat).c_str(), stageWeight.value, stageWeight.unit);
|
||||
ImGui::Text(strings.get(Strings::InfoStageCurrentFormat).c_str(), weight.value, weight.unit);
|
||||
ImGui::Text(strings.get(Strings::InfoStageNextFormat).c_str(), stageNextWeight.value, stageNextWeight.unit);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndTooltip();
|
||||
@@ -100,14 +100,26 @@ namespace game::state::play::menu
|
||||
|
||||
auto overstuffedPercent = std::max(ZERO_FLOAT, (calories - capacity) / (character.max_capacity() - capacity));
|
||||
auto caloriesColor = ImVec4(1.0f, 1.0f - overstuffedPercent, 1.0f - overstuffedPercent, 1.0f);
|
||||
auto capacityMax = character.max_capacity();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, caloriesColor);
|
||||
auto caloriesString = std::format("{:.0f} kcal / {:.0f} kcal", calories,
|
||||
character.is_over_capacity() ? character.max_capacity() : character.capacity);
|
||||
auto caloriesString = std::format("{:.0f} / {:.0f} kcal", calories, capacity);
|
||||
auto caloriesTooltipStart = std::format("{:.0f} / {:.0f} ", calories, capacity);
|
||||
auto caloriesTooltipEffective = std::format("({:.0f})", capacityMax);
|
||||
imgui::text_unformatted_fit_draw(caloriesString.c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, Font::HEADER_2), Font::HEADER_2);
|
||||
ImGui::SetItemTooltip("%s", caloriesString.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::BeginItemTooltip())
|
||||
{
|
||||
ImGui::TextUnformatted(caloriesTooltipStart.c_str());
|
||||
ImGui::SameLine(ZERO_FLOAT, ZERO_FLOAT);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
ImGui::TextUnformatted(caloriesTooltipEffective.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(ZERO_FLOAT, ZERO_FLOAT);
|
||||
ImGui::TextUnformatted(" kcal");
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
auto digestionProgress = character.isDigesting
|
||||
? (float)character.digestionTimer / character.data.root()->digestionTimerMax
|
||||
@@ -171,7 +183,7 @@ namespace game::state::play::menu
|
||||
ImGui::PopFont();
|
||||
};
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), resource::Font::HEADER_1);
|
||||
ImGui::PushFont(ImGui::GetFont(), resource::Font::HUGE);
|
||||
ImGui::SeparatorText(character.data.root()->name.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../../util/imgui/style.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/measurement.hpp"
|
||||
#include "../../util/string.hpp"
|
||||
#include "../../util/vector.hpp"
|
||||
|
||||
using namespace game::util;
|
||||
@@ -41,7 +42,7 @@ namespace game::state::select
|
||||
auto* saveRoot = save.root();
|
||||
auto isSaveValid = saveRoot && saveRoot->type == resource::xml::Schema::Element::SAVE;
|
||||
auto* savedCharacter = isSaveValid ? save.child_get(*saveRoot, resource::xml::Schema::Element::CHARACTER) : nullptr;
|
||||
auto weight = savedCharacter ? (double)savedCharacter->weightKilograms : (double)character->weight;
|
||||
auto weight = savedCharacter ? (double)savedCharacter->weightKilograms : (double)character->weightKilograms;
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_3);
|
||||
|
||||
@@ -74,8 +75,10 @@ namespace game::state::select
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
|
||||
ImGui::Text("Weight: %0.2f %s", system == IMPERIAL ? weight * KG_TO_LB : weight,
|
||||
system == IMPERIAL ? "lbs" : "kg");
|
||||
auto weightDisplay = weight_display_get(weight, system);
|
||||
auto weightString =
|
||||
string::format_commas(weightDisplay.value, WEIGHT_DISPLAY_DECIMAL_DIGITS) + " " + weightDisplay.unit;
|
||||
ImGui::Text("Weight: %s", weightString.c_str());
|
||||
auto stages = resources.characterPreviews[characterIndex].get_all(resource::xml::Schema::Element::STAGE);
|
||||
ImGui::Text("Stages: %i", (int)stages.size() + 1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user