lfs, current build

This commit is contained in:
2026-08-08 15:20:37 -04:00
parent 2efed2a443
commit a5904b917b
397 changed files with 215918 additions and 2458 deletions
+100 -142
View File
@@ -19,23 +19,24 @@ using namespace glm;
namespace game::state
{
namespace
void entity_debug_flags_apply(Entity& entity, bool isShowLayers, bool isShowNulls)
{
int durability_animation_index_get(const resource::xml::Schema& schema, const resource::xml::Anm2& anm2,
int durability, int durabilityMax)
{
if (durability >= durabilityMax) return -1;
entity.isShowLayers = isShowLayers;
entity.isShowNulls = isShowNulls;
}
auto animationName = schema.root()->animationChew + std::to_string(std::max(0, durability));
return anm2.animationMap.contains(animationName) ? anm2.animationMap.at(animationName) : -1;
}
int saved_item_id_get(const Schema& itemSchema, const Schema::Element& item)
{
if (item.id >= 0 && item.id < (int)itemSchema.items.size() && item.id < (int)itemSchema.anm2s.size())
return item.id;
return -1;
}
World::Focus Play::focus_get()
{
if (!isWindows) return World::CENTER;
if (text.is_scene_active()) return World::CENTER;
auto isToolsOpen = tools.isOpen && !menu.is_fullscreen_visible_get();
auto isToolsOpen = tools.isOpen;
return menu.isOpen && isToolsOpen ? World::MENU_TOOLS
: menu.isOpen ? World::MENU
: isToolsOpen ? World::TOOLS
@@ -48,34 +49,16 @@ namespace game::state
return root && root->type == Schema::Element::CURSOR;
}
void Play::start_sequence_begin()
void Play::debug_flags_apply()
{
auto& dialogue = character.data.dialogue;
auto* start = dialogue.get(Schema::Element::START);
if (!start) return;
character.play({.animation = start->animation,
.appendID = character.animation_append_id_get(),
.interrupt = Entity::Interrupt::NEVER});
character.update();
text.entry = nullptr;
text.isEnabled = false;
isWindows = false;
isStart = true;
isStartBegin = false;
isStartEnd = false;
}
void Play::end_sequence_begin()
{
auto& dialogue = character.data.dialogue;
if (!dialogue.get(Schema::Element::END)) return;
text.entry = nullptr;
text.isEnabled = false;
isEnd = true;
isEndBegin = false;
isEndEnd = false;
entity_debug_flags_apply(character, isShowLayers, isShowNulls);
entity_debug_flags_apply(cursor, isShowLayers, isShowNulls);
entity_debug_flags_apply(autofeedCursor, isShowLayers, isShowNulls);
areaManager.debug_flags_set(isShowLayers, isShowNulls);
for (auto& item : itemManager.items)
entity_debug_flags_apply(item, isShowLayers, isShowNulls);
for (auto& particle : particleManager.particles)
entity_debug_flags_apply(particle, isShowLayers, isShowNulls);
}
void Play::set(Resources& resources, int selectedCharacterIndex, enum Game game)
@@ -84,8 +67,8 @@ namespace game::state
auto* saveRoot = data.save.root();
auto isSaveValid = saveRoot && saveRoot->type == Schema::Element::SAVE;
auto* saveCharacter = isSaveValid ? data.save.child_get(*saveRoot, Schema::Element::CHARACTER) : nullptr;
auto* saveInventory = isSaveValid ? data.save.child_get(*saveRoot, Schema::Element::INVENTORY) : nullptr;
auto* saveItems = isSaveValid ? data.save.child_get(*saveRoot, Schema::Element::ITEMS) : nullptr;
auto* saveDiscovered = isSaveValid ? data.save.child_get(*saveRoot, Schema::Element::DISCOVERED) : nullptr;
auto* savePan = isSaveValid ? data.save.child_get(*saveRoot, Schema::Element::PAN) : nullptr;
auto* saveZoom = isSaveValid ? data.save.child_get(*saveRoot, Schema::Element::ZOOM) : nullptr;
auto& itemSchema = data.itemSchema;
@@ -96,12 +79,11 @@ namespace game::state
resources.last_character_save(selectedCharacterIndex);
cheatCodeIndex = 0;
cheatCodeStartTime = 0.0;
world = play::World{};
character = Entity(data, vec2(World::BOUNDS.x + World::BOUNDS.z * 0.5f, World::BOUNDS.w - World::BOUNDS.y));
character = Entity(data, vec2{});
character.digestionRate =
glm::clamp(character.digestionRate, characterRoot->digestionRateMin, characterRoot->digestionRateMax);
character.eatSpeed =
glm::clamp(character.eatSpeed, characterRoot->eatSpeedMinMultiplier, characterRoot->eatSpeedMaxMultiplier);
character.capacity =
glm::clamp(character.capacity, characterRoot->capacityMinCalories, characterRoot->capacityMaxCalories);
@@ -116,11 +98,16 @@ namespace game::state
}
character.totalCaloriesConsumed = saveCharacter ? saveCharacter->totalCaloriesConsumed : 0;
character.totalFoodItemsEaten = saveCharacter ? saveCharacter->totalFoodItemsEaten : 0;
character.totalItemsSpawned = saveCharacter ? saveCharacter->totalItemsSpawned : 0;
character.totalItemsConsumed = saveCharacter ? saveCharacter->totalItemsConsumed : 0;
character.totalPlaytimeSeconds = saveCharacter ? saveCharacter->totalPlaytimeSeconds : 0;
autofeed = play::Autofeed{};
characterManager = CharacterManager{};
particleManager = ParticleManager{};
areaManager = AreaManager{};
areaManager.set(character);
world.bounds_set(areaManager.bounds_get(character, World::BOUNDS));
character.position = {};
cursor = Entity{};
cursor.entityType = CURSOR;
@@ -143,24 +130,24 @@ namespace game::state
}
menu.inventory = play::menu::Inventory{};
for (auto* item : saveInventory ? data.save.children_get(*saveInventory, Schema::Element::ITEM)
: std::vector<Schema::Element*>{})
{
if (item->quantity == 0) continue;
menu.inventory.values[item->id] = item->quantity;
}
itemManager = ItemManager{};
itemManager.spawnDelayTicks = saveRoot ? saveRoot->spawnDelayTicks : 0;
itemManager.discoveredItemIDs.resize(itemSchema.items.size());
for (auto* item :
saveDiscovered ? data.save.children_get(*saveDiscovered, Schema::Element::ITEM) : std::vector<Schema::Element*>{})
{
auto itemID = saved_item_id_get(itemSchema, *item);
if (itemID != -1) itemManager.discoveredItemIDs[itemID] = true;
}
for (auto* item :
saveItems ? data.save.children_get(*saveItems, Schema::Element::ITEM) : std::vector<Schema::Element*>{})
{
auto& anm2 = itemSchema.anm2s.at(item->id);
auto& schemaItem = itemSchema.items.at(item->id);
auto durabilityMax = schemaItem.isDurability ? schemaItem.durability : itemSchema.durability;
auto animationIndex = durability_animation_index_get(itemSchema, anm2, item->durability, durabilityMax);
auto& saveItem = itemSchema.anm2s.at(item->id);
itemManager.items.emplace_back(saveItem, item->position, item->id, item->durability, animationIndex,
item->velocity, item->rotation);
auto itemID = saved_item_id_get(itemSchema, *item);
if (itemID == -1) continue;
auto& saveItem = itemSchema.anm2s[itemID];
itemManager.items.emplace_back(saveItem, item->position, itemID, item->velocity, item->rotation);
itemManager.discoveredItemIDs[itemID] = true;
}
imgui::style::widget_set(menuSchema.rounding);
@@ -169,6 +156,7 @@ namespace game::state
text.entry = nullptr;
text.isEnabled = false;
isPostgamePending = false;
#if DEBUG
menu.isCheats = true;
@@ -180,32 +168,29 @@ namespace game::state
if (character.stage_get() >= character.stage_max_get()) isPostgame = true;
if (isPostgame) menu.isCheats = true;
if (game == NEW_GAME) isWindows = false;
if (auto font = character.data.menuSchema.font.get()) ImGui::GetIO().FontDefault = font;
character.play({.animation = character.idle_animation_get(), .appendID = character.animation_append_id_get()});
character.update();
areaManager.set(character);
worldCanvas.size_set(imgui::to_vec2(ImGui::GetMainViewport()->Size));
world.set(character, worldCanvas, focus_get());
if (savePan) worldCanvas.pan = savePan->position;
if (saveZoom && saveZoom->zoom >= World::ZOOM_MIN)
{
worldCanvas.zoom = glm::clamp(World::ZOOM_MIN, saveZoom->zoom, World::ZOOM_MAX);
world.zoom_index_set(worldCanvas);
}
if (game == NEW_GAME && dialogue.get(Schema::Element::START)) start_sequence_begin();
if (game == NEW_GAME)
text.set(dialogue.dialogue_hook_entry_get(Schema::Element::START), character, false);
if (isPostgame)
{
isEnd = true;
isEndBegin = true;
isEndEnd = true;
isPostgamePending = false;
}
else
{
isEnd = false;
isEndBegin = false;
isEndEnd = false;
isPostgamePending = false;
}
}
@@ -231,6 +216,7 @@ namespace game::state
auto focus = focus_get();
auto& dialogue = character.data.dialogue;
auto isCursorEnabled = cursor_enabled_get();
character.totalPlaytimeSeconds += ImGui::GetIO().DeltaTime;
if (isCursorEnabled)
{
cursor.isVisible = true;
@@ -276,87 +262,55 @@ namespace game::state
}
}
if (isWindows)
auto isSceneActive = text.is_scene_active();
if (!isSceneActive)
{
auto isToolsDisabled = menu.is_fullscreen_visible_get();
auto uiAlpha = UI_ALPHA_MAX - menu.fullscreen_alpha_get();
tools.update(character, cursor, world, focus, worldCanvas, isToolsDisabled, uiAlpha);
info.update(resources, character, uiAlpha);
tools.update(character, cursor, world, focus, worldCanvas, false, UI_ALPHA_MAX);
menu.update(resources, itemManager, character, text, autofeed);
toasts.update();
}
auto isEndSequenceActive = isEndBegin && !isEndEnd;
itemManager.isDisabled = isEndSequenceActive;
characterManager.isDisabled = isEndSequenceActive;
itemManager.isDisabled = isSceneActive;
characterManager.isDisabled = isSceneActive;
if (text.isEnabled) text.update(character, worldCanvas);
if (isStart)
if (character.isJustStageFinal && !isPostgame && !isPostgamePending)
{
if (!isStartBegin)
auto* end = dialogue.dialogue_hook_entry_get(Schema::Element::END);
if (end)
{
if (auto animation = character.animation_get())
{
if (animation->isLoop || character.state == Entity::STOPPED)
{
auto* start = dialogue.get(Schema::Element::START);
text.set(start ? dialogue.dialogue_entry_get(*start) : nullptr, character);
isStartBegin = true;
}
}
text.set(end, character, false);
tools.isOpen = false;
menu.isOpen = false;
character.calories = 0;
character.digestionProgress = 0;
itemManager.heldItemIndex = -1;
isPostgamePending = true;
world.character_focus(character, worldCanvas, focus_get());
}
else if (!isStartEnd)
else
{
if (text.entry && text.is_terminal() && text.is_finished())
{
isWindows = true;
isStartEnd = true;
isStart = false;
world.character_focus(character, worldCanvas, focus_get());
}
isPostgame = true;
menu.isCheats = true;
}
}
if (character.isJustStageFinal && !isEnd && !isPostgame) isEnd = true;
if (isEnd)
if (isPostgamePending && text.is_terminal() && text.is_finished() && !text.is_scene_active())
{
if (!isEndBegin)
{
if (character.is_animation_finished())
{
auto* end = dialogue.get(Schema::Element::END);
text.set(end ? dialogue.dialogue_entry_get(*end) : nullptr, character);
isEndBegin = true;
isWindows = false;
tools.isOpen = false;
menu.isOpen = false;
character.calories = 0;
character.digestionProgress = 0;
itemManager.heldItemIndex = -1;
world.character_focus(character, worldCanvas, focus_get());
}
}
else if (!isEndEnd)
{
if (text.entry && text.is_terminal() && text.is_finished())
{
menu.isOpen = true;
isWindows = true;
isEndEnd = true;
isEnd = false;
isPostgame = true;
menu.isCheats = true;
world.character_focus(character, worldCanvas, focus_get());
}
}
menu.isOpen = true;
isPostgamePending = false;
isPostgame = true;
menu.isCheats = true;
world.character_focus(character, worldCanvas, focus_get());
}
autofeed.update(resources, character, autofeedCursor, menu.inventory, itemManager, characterManager, worldCanvas);
if (!text.is_scene_active())
autofeed.update(resources, character, autofeedCursor, menu.inventory, itemManager, characterManager, worldCanvas);
auto& interactionCursor = autofeed.active_get() ? autofeedCursor : cursor;
itemManager.isAutomation = autofeed.active_get();
itemManager.update(character, interactionCursor, areaManager, text, World::BOUNDS, worldCanvas);
itemManager.update(character, interactionCursor, areaManager, text, world.bounds, worldCanvas);
characterManager.update(character, interactionCursor, text, worldCanvas);
for (auto& particle : itemManager.particles)
particleManager.spawn(character.data, particle.label, particle.position);
@@ -371,6 +325,7 @@ namespace game::state
character.update();
areaManager.update(character);
world.bounds_set(areaManager.bounds_get(character, world.bounds));
particleManager.update();
cursor.update();
if (autofeed.active_get()) autofeedCursor.update();
@@ -396,13 +351,15 @@ namespace game::state
worldCanvas.bind();
worldCanvas.size_set(size);
worldCanvas.clear();
debug_flags_apply();
areaManager.render(character, textureShader, rectShader, worldCanvas);
character.render(textureShader, rectShader, worldCanvas);
for (auto& item : itemManager.items)
item.render(textureShader, rectShader, worldCanvas);
if (!text.is_scene_active())
for (auto& item : itemManager.items)
item.render(textureShader, rectShader, worldCanvas);
auto isCursorEnabled = cursor_enabled_get();
if (isCursorEnabled && autofeed.active_get()) autofeedCursor.render(textureShader, rectShader, worldCanvas);
@@ -423,9 +380,11 @@ namespace game::state
void Play::save(Resources& resources)
{
resource::xml::Schema save;
auto& itemSchema = character.data.itemSchema;
auto& root = save.element_add(resource::xml::Schema::Element::SAVE);
root.isPostgame = isPostgame;
root.isAlternateSpritesheet = character.spritesheetType == Entity::ALTERNATE;
root.spawnDelayTicks = itemManager.spawnDelayTicks;
auto& panElement = save.element_add(resource::xml::Schema::Element::PAN, 0);
panElement.position = worldCanvas.pan;
@@ -438,36 +397,35 @@ namespace game::state
characterElement.calories = character.calories;
characterElement.capacityCalories = character.capacity;
characterElement.digestionRate = character.digestionRate;
characterElement.eatSpeedMultiplier = character.eatSpeed;
characterElement.digestionProgress = character.digestionProgress;
characterElement.isDigesting = character.isDigesting;
characterElement.digestionTimer = character.digestionTimer;
characterElement.totalCaloriesConsumed = character.totalCaloriesConsumed;
characterElement.totalFoodItemsEaten = character.totalFoodItemsEaten;
auto inventoryIndex = (int)save.elements.size();
save.element_add(resource::xml::Schema::Element::INVENTORY, 0);
for (auto& [id, quantity] : menu.inventory.values)
{
if (quantity == 0) continue;
auto& item = save.element_add(resource::xml::Schema::Element::ITEM, inventoryIndex);
item.id = id;
item.quantity = quantity;
}
characterElement.totalItemsSpawned = character.totalItemsSpawned;
characterElement.totalItemsConsumed = character.totalItemsConsumed;
characterElement.totalPlaytimeSeconds = character.totalPlaytimeSeconds;
auto itemsIndex = (int)save.elements.size();
save.element_add(resource::xml::Schema::Element::ITEMS, 0);
for (auto& item : itemManager.items)
{
if (item.schemaID < 0 || item.schemaID >= (int)itemSchema.items.size()) continue;
auto& itemElement = save.element_add(resource::xml::Schema::Element::ITEM, itemsIndex);
itemElement.id = item.schemaID;
itemElement.durability = item.durability;
itemElement.position = item.position;
itemElement.velocity = item.velocity;
itemElement.rotation = *item.overrides[item.rotationOverrideID].frame.rotation;
}
auto discoveredIndex = (int)save.elements.size();
save.element_add(resource::xml::Schema::Element::DISCOVERED, 0);
for (int i = 0; i < (int)itemManager.discoveredItemIDs.size(); i++)
{
if (!itemManager.discoveredItemIDs[i]) continue;
auto& itemElement = save.element_add(resource::xml::Schema::Element::ITEM, discoveredIndex);
itemElement.id = i;
}
resources.character_save_set(characterIndex, save);
save.serialize(character.data.save_path_get());