#include "main.hpp" #include #include #include #include "../util/imgui.hpp" #include "../util/imgui/style.hpp" #include "../util/imgui/widget.hpp" #include "../util/math.hpp" using namespace game::resource; using namespace game::util; using namespace game::state::main; using namespace glm; namespace game::state { World::Focus Main::focus_get() { if (!isWindows) return World::CENTER; return menu.isOpen && tools.isOpen ? World::MENU_TOOLS : menu.isOpen ? World::MENU : tools.isOpen ? World::TOOLS : World::CENTER; } void Main::set(Resources& resources, int selectedCharacterIndex, enum Game game) { auto& data = resources.character_get(selectedCharacterIndex); auto& saveData = data.save; auto& itemSchema = data.itemSchema; auto& dialogue = data.dialogue; auto& menuSchema = data.menuSchema; this->characterIndex = selectedCharacterIndex; character = entity::Character(data, vec2(World::BOUNDS.x + World::BOUNDS.z * 0.5f, World::BOUNDS.w - World::BOUNDS.y)); auto isAlternateSpritesheet = (game == NEW_GAME && math::random_percent_roll(data.alternateSpritesheet.chanceOnNewGame)); if (isAlternateSpritesheet || saveData.isAlternateSpritesheet) { character.spritesheet_set(entity::Character::ALTERNATE); if (game == NEW_GAME) character.data.alternateSpritesheet.sound.play(); } character.totalCaloriesConsumed = saveData.totalCaloriesConsumed; character.totalFoodItemsEaten = saveData.totalFoodItemsEaten; characterManager = CharacterManager{}; cursor = entity::Cursor(character.data.cursorSchema.anm2); menu.inventory = Inventory{}; for (auto& [id, quantity] : saveData.inventory) { if (quantity == 0) continue; menu.inventory.values[id] = quantity; } itemManager = ItemManager{}; for (auto& item : saveData.items) { auto& anm2 = itemSchema.anm2s.at(item.id); auto chewAnimation = itemSchema.animations.chew + std::to_string(item.chewCount); auto animationIndex = item.chewCount > 0 ? anm2.animationMap[chewAnimation] : -1; auto& saveItem = itemSchema.anm2s.at(item.id); itemManager.items.emplace_back(saveItem, item.position, item.id, item.chewCount, animationIndex, item.velocity, item.rotation); } imgui::style::rounding_set(menuSchema.rounding); imgui::widget::sounds_set(&menuSchema.sounds.hover, &menuSchema.sounds.select); menu.play = Play(character); menu.play.totalPlays = saveData.totalPlays; menu.play.highScore = saveData.highScore; menu.play.bestCombo = saveData.bestCombo; menu.play.gradeCounts = saveData.gradeCounts; menu.play.isHighScoreAchieved = saveData.highScore > 0 ? true : false; menu.isChat = character.data.dialogue.help.is_valid() || character.data.dialogue.random.is_valid(); text.entry = nullptr; text.isEnabled = false; isPostgame = saveData.isPostgame; if (isPostgame) menu.isCheats = true; else menu.isCheats = false; if (game == NEW_GAME) isWindows = false; if (auto font = character.data.menuSchema.font.get()) ImGui::GetIO().FontDefault = font; character.play_default_animation(); character.tick(); worldCanvas.size_set(imgui::to_vec2(ImGui::GetMainViewport()->Size)); world.set(character, worldCanvas, focus_get()); if (game == NEW_GAME && dialogue.start.is_valid()) { character.queue_play({.animation = dialogue.start.animation, .isInterruptible = false}); character.tick(); isStart = true; } } void Main::exit(Resources& resources) { imgui::style::rounding_set(); imgui::widget::sounds_set(nullptr, nullptr); ImGui::GetIO().FontDefault = resources.font.get(); save(resources); } void Main::tick(Resources&) { character.tick(); cursor.tick(); menu.tick(); toasts.tick(); text.tick(character); for (auto& item : itemManager.items) item.tick(); } void Main::update(Resources& resources) { auto focus = focus_get(); auto& dialogue = character.data.dialogue; if (isWindows) { menu.update(resources, itemManager, character, cursor, text, worldCanvas); tools.update(character, cursor, world, focus, worldCanvas); info.update(resources, character); toasts.update(); } if (text.isEnabled) text.update(character); if (isStart) { if (!isStartBegin) { if (auto animation = character.animation_get()) { if (animation->isLoop || character.state == entity::Actor::STOPPED) { text.set(dialogue.get(dialogue.start.id), character); isStartBegin = true; } } } else if (!isStartEnd) { if (text.entry->is_last()) { isWindows = true; isStartEnd = true; isStart = false; world.character_focus(character, worldCanvas, focus_get()); } } } if (character.isJustStageFinal && !isEnd && !isPostgame) isEnd = true; if (isEnd) { if (!isEndBegin) { if (character.is_animation_finished()) { text.set(dialogue.get(dialogue.end.id), character); isEndBegin = true; isWindows = false; tools.isOpen = false; menu.isOpen = false; character.calories = 0; character.digestionProgress = 0; itemManager.items.clear(); itemManager.heldItemIndex = -1; world.character_focus(character, worldCanvas, focus_get()); } } else if (!isEndEnd) { if (text.entry->is_last()) { menu.isOpen = true; isWindows = true; isEndEnd = true; isEnd = false; isPostgame = true; } } } itemManager.update(character, cursor, areaManager, text, World::BOUNDS, worldCanvas); characterManager.update(character, cursor, text, worldCanvas); character.update(); cursor.update(); world.update(character, cursor, worldCanvas, focus); if (autosaveTime += ImGui::GetIO().DeltaTime; autosaveTime > AUTOSAVE_TIME || menu.configuration.isSave) { save(resources); autosaveTime = 0; menu.configuration.isSave = false; } } void Main::render(Resources& resources, Canvas& canvas) { auto& textureShader = resources.shaders[shader::TEXTURE]; auto& rectShader = resources.shaders[shader::RECT]; auto size = imgui::to_ivec2(ImGui::GetMainViewport()->Size); auto& bgTexture = character.data.areaSchema.areas.at(areaManager.get(character)).texture; auto windowModel = math::quad_model_get(vec2(size)); auto worldModel = math::quad_model_get(bgTexture.size); worldCanvas.bind(); worldCanvas.size_set(size); worldCanvas.clear(); worldCanvas.texture_render(textureShader, bgTexture.id, worldModel); character.render(textureShader, rectShader, worldCanvas); for (auto& item : itemManager.items) item.render(textureShader, rectShader, worldCanvas); if (menu.debug.isBoundsDisplay) { auto boundsModel = math::quad_model_get(glm::vec2(World::BOUNDS.z, World::BOUNDS.w), glm::vec2(World::BOUNDS.x, World::BOUNDS.y), glm::vec2(World::BOUNDS.x, World::BOUNDS.y) * 0.5f); worldCanvas.rect_render(rectShader, boundsModel); } worldCanvas.unbind(); canvas.bind(); canvas.texture_render(textureShader, worldCanvas.texture, windowModel); ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); cursor.render(textureShader, rectShader, canvas); canvas.unbind(); SDL_HideCursor(); } void Main::save(Resources& resources) { resource::xml::Save save; save.weight = character.weight; save.calories = character.calories; save.capacity = character.capacity; save.digestionRate = character.digestionRate; save.eatSpeed = character.eatSpeed; save.digestionProgress = character.digestionProgress; save.isDigesting = character.isDigesting; save.digestionTimer = character.digestionTimer; save.totalCaloriesConsumed = character.totalCaloriesConsumed; save.totalFoodItemsEaten = character.totalFoodItemsEaten; save.totalPlays = menu.play.totalPlays; save.highScore = menu.play.highScore; save.bestCombo = menu.play.bestCombo; save.gradeCounts = menu.play.gradeCounts; save.isPostgame = isPostgame; save.isAlternateSpritesheet = character.spritesheetType == entity::Character::ALTERNATE; for (auto& [id, quantity] : menu.inventory.values) { if (quantity == 0) continue; save.inventory[id] = quantity; } for (auto& item : itemManager.items) save.items.emplace_back(item.schemaID, item.chewCount, item.position, item.velocity, *item.overrides[item.rotationOverrideID].frame.rotation); save.isValid = true; resources.character_save_set(characterIndex, save); save.serialize(character.data.save_path_get()); toasts.push("Saving..."); } };