173 lines
5.9 KiB
C++
173 lines
5.9 KiB
C++
#include "cutscene/CutsceneDatabase.h"
|
|
|
|
#include "utils/Utils.h"
|
|
#include <iostream>
|
|
|
|
namespace ZL
|
|
{
|
|
extern const char* CONST_ZIP_FILE;
|
|
}
|
|
|
|
namespace ZL::Cutscene {
|
|
|
|
EasingType CutsceneDatabase::parseEasingType(const std::string& value) {
|
|
if (value == "EaseInSine") return EasingType::EaseInSine;
|
|
if (value == "EaseOutSine") return EasingType::EaseOutSine;
|
|
if (value == "EaseInOutSine") return EasingType::EaseInOutSine;
|
|
if (value == "EaseInQuad") return EasingType::EaseInQuad;
|
|
if (value == "EaseOutQuad") return EasingType::EaseOutQuad;
|
|
if (value == "EaseInOutQuad") return EasingType::EaseInOutQuad;
|
|
if (value == "EaseInCubic") return EasingType::EaseInCubic;
|
|
if (value == "EaseOutCubic") return EasingType::EaseOutCubic;
|
|
if (value == "EaseInOutCubic") return EasingType::EaseInOutCubic;
|
|
return EasingType::Linear;
|
|
}
|
|
|
|
CutsceneAnchor CutsceneDatabase::parseCutsceneAnchor(const std::string& value) {
|
|
if (value == "TopLeft") return CutsceneAnchor::TopLeft;
|
|
if (value == "TopRight") return CutsceneAnchor::TopRight;
|
|
if (value == "BottomRight") return CutsceneAnchor::BottomRight;
|
|
if (value == "BottomLeft") return CutsceneAnchor::BottomLeft;
|
|
if (value == "Custom") return CutsceneAnchor::Custom;
|
|
return CutsceneAnchor::Center;
|
|
}
|
|
|
|
CutsceneLine CutsceneDatabase::parseCutsceneLine(const json& j) {
|
|
CutsceneLine line;
|
|
line.speaker = j.value("speaker", "");
|
|
line.text = j.value("text", "");
|
|
line.portrait = j.value("portrait", "");
|
|
line.sfx = j.value("sfx", "");
|
|
line.background = j.value("background", "");
|
|
line.backgroundWidth = j.value("backgroundWidth", 0);
|
|
line.backgroundHeight= j.value("backgroundHeight", 0);
|
|
line.luaCallback = j.value("luaCallback", "");
|
|
line.durationMs = j.value("durationMs", 0);
|
|
line.waitForConfirm = j.value("waitForConfirm", false);
|
|
line.questUnlock = j.value("questUnlock", "");
|
|
line.questComplete = j.value("questComplete", "");
|
|
line.questFail = j.value("questFail", "");
|
|
line.objectiveComplete = j.value("objectiveComplete", "");
|
|
line.objectiveVisible = j.value("objectiveVisible", "");
|
|
return line;
|
|
}
|
|
|
|
CutsceneCameraPose CutsceneDatabase::parseCutsceneCameraPose(const json& j) {
|
|
CutsceneCameraPose pose;
|
|
pose.anchor = parseCutsceneAnchor(j.value("anchor", "Center"));
|
|
pose.centerX = j.value("centerX", 0.5f);
|
|
pose.centerY = j.value("centerY", 0.5f);
|
|
pose.zoom = j.value("zoom", 1.0f);
|
|
pose.rotationDeg = j.value("rotationDeg", 0.0f);
|
|
return pose;
|
|
}
|
|
|
|
CutsceneCameraSegment CutsceneDatabase::parseCutsceneCameraSegment(const json& j) {
|
|
CutsceneCameraSegment segment;
|
|
segment.durationMs = j.value("durationMs", 0);
|
|
segment.easing = parseEasingType(j.value("easing", "EaseInOutSine"));
|
|
if (j.contains("from") && j["from"].is_object()) {
|
|
segment.from = parseCutsceneCameraPose(j["from"]);
|
|
}
|
|
if (j.contains("to") && j["to"].is_object()) {
|
|
segment.to = parseCutsceneCameraPose(j["to"]);
|
|
}
|
|
else {
|
|
segment.to = segment.from;
|
|
}
|
|
return segment;
|
|
}
|
|
|
|
CutsceneImageCue CutsceneDatabase::parseCutsceneImageCue(const json& j) {
|
|
CutsceneImageCue cue;
|
|
cue.path = j.value("path", "");
|
|
cue.startMs = j.value("startMs", 0);
|
|
cue.endMs = j.value("endMs", 0);
|
|
cue.fadeInMs = j.value("fadeInMs", 0);
|
|
cue.fadeOutMs = j.value("fadeOutMs", 0);
|
|
return cue;
|
|
}
|
|
|
|
StaticCutsceneDefinition CutsceneDatabase::parseCutscene(const json& j) {
|
|
StaticCutsceneDefinition cutscene;
|
|
cutscene.id = j.value("id", "");
|
|
cutscene.background = j.value("background", "");
|
|
cutscene.backgroundWidth = j.value("backgroundWidth", 1280);
|
|
cutscene.backgroundHeight= j.value("backgroundHeight", 720);
|
|
cutscene.music = j.value("music", "");
|
|
cutscene.skippable = j.value("skippable", true);
|
|
cutscene.durationMs = j.value("durationMs", 0);
|
|
cutscene.fadeOutMs = j.value("fadeOutMs", 0);
|
|
cutscene.fadeInMs = j.value("fadeInMs", 0);
|
|
cutscene.endFadeOutMs = j.value("endFadeOutMs", 0);
|
|
cutscene.endFadeInMs = j.value("endFadeInMs", 0);
|
|
cutscene.onFadeInCallback= j.value("onFadeInCallback", "");
|
|
|
|
if (j.contains("cameraTrack") && j["cameraTrack"].is_array()) {
|
|
for (const auto& item : j["cameraTrack"]) {
|
|
cutscene.cameraTrack.push_back(parseCutsceneCameraSegment(item));
|
|
}
|
|
}
|
|
if (j.contains("images") && j["images"].is_array()) {
|
|
for (const auto& item : j["images"]) {
|
|
cutscene.images.push_back(parseCutsceneImageCue(item));
|
|
}
|
|
}
|
|
if (j.contains("lines") && j["lines"].is_array()) {
|
|
for (const auto& item : j["lines"]) {
|
|
cutscene.lines.push_back(parseCutsceneLine(item));
|
|
}
|
|
}
|
|
return cutscene;
|
|
}
|
|
|
|
bool CutsceneDatabase::loadFromFile(const std::string& path) {
|
|
cutscenes.clear();
|
|
|
|
std::string raw;
|
|
try {
|
|
if (strlen(ZL::CONST_ZIP_FILE) == 0) {
|
|
raw = readTextFile(path);
|
|
}
|
|
else {
|
|
auto buf = readFileFromZIP(path, ZL::CONST_ZIP_FILE);
|
|
if (buf.empty()) {
|
|
std::cerr << "[cutscene] Failed to read " << path << " from zip\n";
|
|
throw std::runtime_error("Failed to load cutscene file: " + path);
|
|
}
|
|
raw.assign(buf.begin(), buf.end());
|
|
}
|
|
}
|
|
catch (const std::exception& e) {
|
|
std::cerr << "[cutscene] Failed to open " << path << ": " << e.what() << "\n";
|
|
throw std::runtime_error("Failed to load cutscene file: " + path);
|
|
}
|
|
|
|
json root;
|
|
try {
|
|
root = json::parse(raw);
|
|
}
|
|
catch (const std::exception& e) {
|
|
std::cerr << "[cutscene] JSON parse error in " << path << ": " << e.what() << "\n";
|
|
return false;
|
|
}
|
|
|
|
if (root.contains("cutscenes") && root["cutscenes"].is_array()) {
|
|
for (const auto& item : root["cutscenes"]) {
|
|
StaticCutsceneDefinition cutscene = parseCutscene(item);
|
|
if (!cutscene.id.empty()) {
|
|
cutscenes[cutscene.id] = std::move(cutscene);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const StaticCutsceneDefinition* CutsceneDatabase::findCutscene(const std::string& id) const {
|
|
auto it = cutscenes.find(id);
|
|
return (it != cutscenes.end()) ? &it->second : nullptr;
|
|
}
|
|
|
|
} // namespace ZL::Cutscene
|