mirror of
https://github.com/open-goal/jak-project
synced 2026-08-26 08:12:57 -04:00
tools: Some subtitle editor cleanup and add hint support (#1450)
* nrepl: detect a disconnected client better * tools: remove some duplicate code * tools: add hint playing support * lint: formatting
This commit is contained in:
@@ -39,25 +39,29 @@ bool write_subtitle_db_to_files(const GameSubtitleDB& db) {
|
||||
}
|
||||
file_contents += fmt::format("\n(\"{}\"", scene_name);
|
||||
if (scene_info.m_kind == SubtitleSceneKind::Hint) {
|
||||
file_contents += " :hint 0";
|
||||
file_contents += " :hint #x0";
|
||||
} else if (scene_info.m_kind == SubtitleSceneKind::HintNamed) {
|
||||
file_contents += fmt::format(" :hint #x{0:x}", scene_info.m_id);
|
||||
}
|
||||
file_contents += "\n";
|
||||
for (const auto& line : scene_info.m_lines) {
|
||||
// Clear screen entries
|
||||
if (line.line_utf8.empty()) {
|
||||
file_contents += fmt::format(" ({})\n", line.frame);
|
||||
} else {
|
||||
file_contents += fmt::format(" ({}", line.frame);
|
||||
if (line.offscreen && scene_info.m_kind == SubtitleSceneKind::Movie) {
|
||||
file_contents += " :offscreen";
|
||||
if (scene_info.m_lines.empty()) {
|
||||
file_contents += fmt::format(" ()\n");
|
||||
} else {
|
||||
for (const auto& line : scene_info.m_lines) {
|
||||
// Clear screen entries
|
||||
if (line.line_utf8.empty()) {
|
||||
file_contents += fmt::format(" ({})\n", line.frame);
|
||||
} else {
|
||||
file_contents += fmt::format(" ({}", line.frame);
|
||||
if (line.offscreen && scene_info.m_kind == SubtitleSceneKind::Movie) {
|
||||
file_contents += " :offscreen";
|
||||
}
|
||||
file_contents += fmt::format(" \"{}\"", line.speaker_utf8);
|
||||
// escape quotes
|
||||
std::string temp = line.line_utf8;
|
||||
temp = std::regex_replace(temp, std::regex("\""), "\\\"");
|
||||
file_contents += fmt::format(" \"{}\")\n", temp);
|
||||
}
|
||||
file_contents += fmt::format(" \"{}\"", line.speaker_utf8);
|
||||
// escape quotes
|
||||
std::string temp = line.line_utf8;
|
||||
temp = std::regex_replace(temp, std::regex("\""), "\\\"");
|
||||
file_contents += fmt::format(" \"{}\")\n", temp);
|
||||
}
|
||||
}
|
||||
file_contents += " )\n";
|
||||
|
||||
@@ -34,7 +34,13 @@ void ReplServer::post_init() {
|
||||
void ReplServer::ping_response(int socket) {
|
||||
std::string ping = fmt::format("Connected to OpenGOAL v{}.{} nREPL!",
|
||||
versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR);
|
||||
write_to_socket(socket, ping.c_str(), ping.size());
|
||||
auto resp = write_to_socket(socket, ping.c_str(), ping.size());
|
||||
if (resp == -1) {
|
||||
fmt::print("[nREPL:{}] Client Disconnected: {}\n", tcp_port, inet_ntoa(addr.sin_addr),
|
||||
ntohs(addr.sin_port), socket);
|
||||
close_socket(socket);
|
||||
client_sockets.erase(socket);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> ReplServer::get_msg() {
|
||||
|
||||
@@ -824,51 +824,21 @@
|
||||
[[157, 162], "a1", "dma-packet"]
|
||||
],
|
||||
"(top-level-login task-control)": [[165, "v1", "symbol"]],
|
||||
"(anon-function 227 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 286 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 366 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 367 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 368 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 369 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 380 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 383 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 390 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 393 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 400 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 403 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 435 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 445 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 455 task-control)": [
|
||||
[17, "v1", "float"]
|
||||
],
|
||||
"(anon-function 227 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 286 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 366 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 367 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 368 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 369 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 380 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 383 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 390 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 393 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 400 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 403 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 435 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 445 task-control)": [[17, "v1", "float"]],
|
||||
"(anon-function 455 task-control)": [[17, "v1", "float"]],
|
||||
"(method 18 game-info)": [
|
||||
[4, "v1", "symbol"],
|
||||
[5, "v1", "level-load-info"],
|
||||
@@ -5946,18 +5916,14 @@
|
||||
[67, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(method 56 ram-boss)": [
|
||||
[58, "v1", "(pointer ram-boss-proj)"]
|
||||
],
|
||||
"(method 56 ram-boss)": [[58, "v1", "(pointer ram-boss-proj)"]],
|
||||
|
||||
"(code ram-idle)": [
|
||||
[28, "v1", "art-joint-anim"],
|
||||
[98, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ram-give-fuel-cell)": [
|
||||
[69, "v1", "(pointer snowcam)"]
|
||||
],
|
||||
"(code ram-give-fuel-cell)": [[69, "v1", "(pointer snowcam)"]],
|
||||
|
||||
"(code snow-bumper-deactivate)": [
|
||||
[29, "v1", "art-joint-anim"],
|
||||
|
||||
@@ -43,7 +43,6 @@ SubtitleEditor::SubtitleEditor() : m_repl(8181) {
|
||||
m_subtitle_db = load_subtitle_project();
|
||||
m_filter = m_filter_placeholder;
|
||||
m_filter_hints = m_filter_placeholder;
|
||||
m_repl.connect();
|
||||
}
|
||||
|
||||
void SubtitleEditor::repl_set_continue_point(const std::string_view& continue_point) {
|
||||
@@ -70,6 +69,16 @@ std::string SubtitleEditor::repl_get_process_string(const std::string_view& enti
|
||||
process_name);
|
||||
}
|
||||
|
||||
void SubtitleEditor::repl_play_hint(const std::string_view& hint_name) {
|
||||
repl_reset_game();
|
||||
repl_set_continue_point("village1-hut");
|
||||
// TODO - move into water fountain
|
||||
m_repl.eval(
|
||||
fmt::format("(level-hint-spawn (game-text-id zero) \"{}\" (the-as entity #f) *entity-pool* "
|
||||
"(game-task none))",
|
||||
hint_name));
|
||||
}
|
||||
|
||||
void SubtitleEditor::repl_execute_cutscene_code(const SubtitleEditorDB::Entry& entry) {
|
||||
// Reset the game first to get to a known state
|
||||
repl_reset_game();
|
||||
@@ -150,7 +159,24 @@ void SubtitleEditor::draw_window() {
|
||||
draw_edit_options();
|
||||
draw_repl_options();
|
||||
|
||||
draw_current_cutscene();
|
||||
if (!m_current_scene) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_selected_text_color);
|
||||
}
|
||||
if (ImGui::TreeNode("Currently Selected Cutscene")) {
|
||||
ImGui::PopStyleColor();
|
||||
if (m_current_scene) {
|
||||
draw_subtitle_options(*m_current_scene, true);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255));
|
||||
ImGui::Text("Select a Scene from Below!");
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
} else {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("All Cutscenes")) {
|
||||
ImGui::InputText("New Scene Name", &m_new_scene_name);
|
||||
@@ -183,13 +209,50 @@ void SubtitleEditor::draw_window() {
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
// TODO - hints
|
||||
if (ImGui::TreeNode("All Hints")) {
|
||||
ImGui::InputText("New Scene Name", &m_new_scene_name);
|
||||
// TODO - make this a dropdown
|
||||
ImGui::InputText("New Scene ID (hex)", &m_new_scene_id);
|
||||
ImGui::InputText("New Scene Group", &m_new_scene_group);
|
||||
ImGui::InputText("Filter", &m_filter, ImGuiInputTextFlags_::ImGuiInputTextFlags_AutoSelectAll);
|
||||
if (is_scene_in_current_lang(m_new_scene_name)) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("Scene already exists with that name, no!");
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (m_new_scene_group.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("You must provide a group to sort the scene into!");
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (!is_scene_in_current_lang(m_new_scene_name) && !m_new_scene_group.empty()) {
|
||||
if (ImGui::Button("Add Scene")) {
|
||||
GameSubtitleSceneInfo newScene;
|
||||
newScene.m_name = m_new_scene_name;
|
||||
if (m_new_scene_id == "0") {
|
||||
newScene.m_kind = SubtitleSceneKind::Hint;
|
||||
newScene.m_id = strtoul(m_new_scene_id.c_str(), nullptr, 16);
|
||||
} else {
|
||||
newScene.m_kind = SubtitleSceneKind::HintNamed;
|
||||
newScene.m_id = strtoul(m_new_scene_id.c_str(), nullptr, 16);
|
||||
}
|
||||
newScene.m_sorting_group = m_new_scene_group;
|
||||
m_subtitle_db.m_banks.at(m_current_language)->add_scene(newScene);
|
||||
m_new_scene_name = "";
|
||||
}
|
||||
}
|
||||
|
||||
draw_all_hint_groups();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void SubtitleEditor::draw_edit_options() {
|
||||
if (ImGui::TreeNode("Editing Options")) {
|
||||
// TODO - validate these / make it a dropdown
|
||||
// - source of truth is the files
|
||||
ImGui::InputInt("Editing language ID", &m_current_language);
|
||||
ImGui::InputInt("Base language ID", &m_base_language);
|
||||
ImGui::Checkbox("Show missing cutscenes from base", &m_base_show_missing_cutscenes);
|
||||
@@ -252,6 +315,17 @@ void SubtitleEditor::draw_all_cutscene_groups() {
|
||||
}
|
||||
}
|
||||
|
||||
void SubtitleEditor::draw_all_hint_groups() {
|
||||
for (auto& group_name : m_subtitle_db.m_subtitle_groups->m_group_order) {
|
||||
ImGui::SetNextItemOpen(true);
|
||||
if (ImGui::TreeNode(group_name.c_str())) {
|
||||
draw_all_hints(group_name, false);
|
||||
draw_all_hints(group_name, true);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes) {
|
||||
auto& scenes =
|
||||
m_subtitle_db.m_banks.at(base_cutscenes ? m_base_language : m_current_language)->m_scenes;
|
||||
@@ -279,6 +353,7 @@ void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes
|
||||
if (base_cutscenes) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode(
|
||||
fmt::format("{}-{}", scene_name, base_cutscenes ? m_base_language : m_current_language)
|
||||
.c_str(),
|
||||
@@ -296,77 +371,7 @@ void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes
|
||||
m_subtitle_db.m_banks.at(m_current_language)->add_scene(scene_info);
|
||||
}
|
||||
}
|
||||
if (!m_repl.is_connected()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("REPL not connected, can't play!");
|
||||
ImGui::PopStyleColor();
|
||||
} else if (m_db.count(scene_info.m_name) > 0) {
|
||||
if (ImGui::Button("Play Scene")) {
|
||||
if (m_db.count(scene_info.m_name) == 1) {
|
||||
repl_execute_cutscene_code(m_db[scene_info.m_name]);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
ImGui::TextWrapped("You may have to click twice, load times cause issues");
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
if (ImGui::BeginCombo("Sorting Group", scene_info.m_sorting_group.c_str())) {
|
||||
for (size_t i = 0; i < m_subtitle_db.m_subtitle_groups->m_group_order.size(); ++i) {
|
||||
const bool isSelected = (scene_info.m_sorting_group_idx == (int)i);
|
||||
if (ImGui::Selectable(m_subtitle_db.m_subtitle_groups->m_group_order[i].c_str(),
|
||||
isSelected)) {
|
||||
// Remove from current group
|
||||
m_subtitle_db.m_subtitle_groups->remove_scene(scene_info.m_sorting_group,
|
||||
scene_info.m_name);
|
||||
// Add to new group
|
||||
scene_info.m_sorting_group_idx = i;
|
||||
scene_info.m_sorting_group = m_subtitle_db.m_subtitle_groups->m_group_order.at(i);
|
||||
m_subtitle_db.m_subtitle_groups->add_scene(scene_info.m_sorting_group,
|
||||
scene_info.m_name);
|
||||
}
|
||||
if (isSelected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
for (size_t i = 0; i < scene_info.m_lines.size(); i++) {
|
||||
auto& subtitleLine = scene_info.m_lines.at(i);
|
||||
std::string summary;
|
||||
if (subtitleLine.line_utf8.empty()) {
|
||||
summary = fmt::format("[{}] Clear Screen", subtitleLine.frame);
|
||||
} else {
|
||||
summary = fmt::format("[{}] {} - '{}...'", subtitleLine.frame, subtitleLine.speaker_utf8,
|
||||
subtitleLine.line_utf8.substr(0, 30));
|
||||
}
|
||||
if (subtitleLine.line_utf8.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
} else if (subtitleLine.offscreen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_offscreen_text_color);
|
||||
}
|
||||
if (ImGui::TreeNode(fmt::format("{}", i).c_str(), "%s", summary.c_str())) {
|
||||
if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::InputInt("Starting Frame", &subtitleLine.frame,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::InputText("Speaker", &subtitleLine.speaker_utf8,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
|
||||
ImGui::InputText("Text", &subtitleLine.line_utf8,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
|
||||
ImGui::Checkbox("Offscreen?", &subtitleLine.offscreen);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, m_warning_color);
|
||||
if (ImGui::Button("Remove Line")) {
|
||||
scene_info.m_lines.erase(scene_info.m_lines.begin() + i);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::TreePop();
|
||||
} else if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
draw_subtitle_options(scene_info);
|
||||
ImGui::TreePop();
|
||||
} else if (base_cutscenes || is_current_scene) {
|
||||
ImGui::PopStyleColor();
|
||||
@@ -374,126 +379,167 @@ void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes
|
||||
}
|
||||
}
|
||||
|
||||
void SubtitleEditor::draw_current_cutscene() {
|
||||
if (!m_current_scene) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_selected_text_color);
|
||||
}
|
||||
if (ImGui::TreeNode("Currently Selected Movie")) {
|
||||
ImGui::PopStyleColor();
|
||||
if (m_current_scene) {
|
||||
if (!m_repl.is_connected()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("REPL not connected, can't play!");
|
||||
void SubtitleEditor::draw_all_hints(std::string group_name, bool base_cutscenes) {
|
||||
auto& scenes =
|
||||
m_subtitle_db.m_banks.at(base_cutscenes ? m_base_language : m_current_language)->m_scenes;
|
||||
auto scenes_in_group = m_subtitle_db.m_subtitle_groups->m_groups[group_name];
|
||||
for (auto& scene_name : scenes_in_group) {
|
||||
if (scenes.count(scene_name) == 0) {
|
||||
continue;
|
||||
}
|
||||
auto& scene_info = scenes[scene_name];
|
||||
// Don't duplicate entries
|
||||
if (base_cutscenes && is_scene_in_current_lang(scene_name)) {
|
||||
continue;
|
||||
}
|
||||
if (scene_info.m_kind != SubtitleSceneKind::Hint &&
|
||||
scene_info.m_kind != SubtitleSceneKind::HintNamed) {
|
||||
continue;
|
||||
}
|
||||
if ((!m_filter.empty() && m_filter != m_filter_placeholder) &&
|
||||
scene_name.find(m_filter) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (base_cutscenes) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode(
|
||||
fmt::format("{}-{}", scene_name, base_cutscenes ? m_base_language : m_current_language)
|
||||
.c_str(),
|
||||
"%s", scene_name.c_str())) {
|
||||
if (base_cutscenes) {
|
||||
ImGui::PopStyleColor();
|
||||
} else if (m_db.count(m_current_scene->m_name) > 0) {
|
||||
if (ImGui::Button("Play Scene")) {
|
||||
if (m_db.count(m_current_scene->m_name) == 1) {
|
||||
repl_execute_cutscene_code(m_db[m_current_scene->m_name]);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
ImGui::TextWrapped("You may have to click twice, load times cause issues");
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
if (ImGui::BeginCombo("Sorting Group", m_current_scene->m_sorting_group.c_str())) {
|
||||
for (size_t i = 0; i < m_subtitle_db.m_subtitle_groups->m_group_order.size(); ++i) {
|
||||
const bool isSelected = (m_current_scene->m_sorting_group_idx == (int)i);
|
||||
if (ImGui::Selectable(m_subtitle_db.m_subtitle_groups->m_group_order[i].c_str(),
|
||||
isSelected)) {
|
||||
// Remove from current group
|
||||
m_subtitle_db.m_subtitle_groups->remove_scene(m_current_scene->m_sorting_group,
|
||||
m_current_scene->m_name);
|
||||
// Add to new group
|
||||
m_current_scene->m_sorting_group_idx = i;
|
||||
m_current_scene->m_sorting_group = m_subtitle_db.m_subtitle_groups->m_group_order.at(i);
|
||||
m_subtitle_db.m_subtitle_groups->add_scene(m_current_scene->m_sorting_group,
|
||||
m_current_scene->m_name);
|
||||
}
|
||||
if (isSelected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::InputInt("Frame Number", &m_current_scene_frame,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::InputText("Text", &m_current_scene_text,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
|
||||
ImGui::InputText("Speaker", &m_current_scene_speaker,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
|
||||
ImGui::Checkbox("Offscreen", &m_current_scene_offscreen);
|
||||
bool rendered_text_entry_btn = false;
|
||||
if (m_current_scene_frame < 0 || m_current_scene_text.empty() ||
|
||||
m_current_scene_speaker.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("Can't add a new text entry with the current fields!");
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
rendered_text_entry_btn = true;
|
||||
if (ImGui::Button("Add Text Entry")) {
|
||||
m_current_scene->add_line(m_current_scene_frame, "", m_current_scene_text, "",
|
||||
m_current_scene_speaker, m_current_scene_offscreen);
|
||||
if (base_cutscenes) {
|
||||
if (ImGui::Button("Copy from Base Language")) {
|
||||
m_subtitle_db.m_banks.at(m_current_language)->add_scene(scene_info);
|
||||
}
|
||||
}
|
||||
if (m_current_scene_frame < 0) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("Can't add a clear screen entry with the current fields!");
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
if (rendered_text_entry_btn) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Add Clear Screen Entry")) {
|
||||
m_current_scene->add_line(m_current_scene_frame, "", "", "", "", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::NewLine();
|
||||
for (size_t i = 0; i < m_current_scene->m_lines.size(); i++) {
|
||||
auto& subtitleLine = m_current_scene->m_lines.at(i);
|
||||
std::string summary;
|
||||
if (subtitleLine.line_utf8.empty()) {
|
||||
summary = fmt::format("[{}] Clear Screen", subtitleLine.frame);
|
||||
} else {
|
||||
summary = fmt::format("[{}] {} - '{}...'", subtitleLine.frame, subtitleLine.speaker_utf8,
|
||||
subtitleLine.line_utf8.substr(0, 30));
|
||||
}
|
||||
if (subtitleLine.line_utf8.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
} else if (subtitleLine.offscreen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_offscreen_text_color);
|
||||
}
|
||||
if (ImGui::TreeNode(fmt::format("{}", i).c_str(), "%s", summary.c_str())) {
|
||||
if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::InputInt("Starting Frame", &subtitleLine.frame,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::InputText("Speaker", &subtitleLine.speaker_utf8,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
|
||||
ImGui::InputText("Text", &subtitleLine.line_utf8,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
|
||||
ImGui::Checkbox("Offscreen?", &subtitleLine.offscreen);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, m_warning_color);
|
||||
if (ImGui::Button("Remove Line")) {
|
||||
m_current_scene->m_lines.erase(m_current_scene->m_lines.begin() + i);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::TreePop();
|
||||
} else if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255));
|
||||
ImGui::Text("Select a Scene from Below!");
|
||||
draw_subtitle_options(scene_info);
|
||||
ImGui::TreePop();
|
||||
} else if (base_cutscenes) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
} else {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
|
||||
void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool current_scene) {
|
||||
if (!m_repl.is_connected()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("REPL not connected, can't play!");
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
// Cutscenes
|
||||
if (scene.m_kind == SubtitleSceneKind::Movie && m_db.count(scene.m_name) > 0) {
|
||||
if (ImGui::Button("Play Scene")) {
|
||||
repl_execute_cutscene_code(m_db[scene.m_name]);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
ImGui::TextWrapped("You may have to click twice, load times cause issues");
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
// Hints
|
||||
else if (scene.m_kind == SubtitleSceneKind::Hint ||
|
||||
scene.m_kind == SubtitleSceneKind::HintNamed) {
|
||||
if (ImGui::Button("Play Hint")) {
|
||||
repl_play_hint(scene.m_name);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
ImGui::TextWrapped("You may have to click twice, load times cause issues");
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
}
|
||||
if (ImGui::BeginCombo("Sorting Group", scene.m_sorting_group.c_str())) {
|
||||
for (size_t i = 0; i < m_subtitle_db.m_subtitle_groups->m_group_order.size(); ++i) {
|
||||
const bool isSelected = (scene.m_sorting_group_idx == (int)i);
|
||||
if (ImGui::Selectable(m_subtitle_db.m_subtitle_groups->m_group_order[i].c_str(),
|
||||
isSelected)) {
|
||||
// Remove from current group
|
||||
m_subtitle_db.m_subtitle_groups->remove_scene(scene.m_sorting_group, scene.m_name);
|
||||
// Add to new group
|
||||
scene.m_sorting_group_idx = i;
|
||||
scene.m_sorting_group = m_subtitle_db.m_subtitle_groups->m_group_order.at(i);
|
||||
m_subtitle_db.m_subtitle_groups->add_scene(scene.m_sorting_group, scene.m_name);
|
||||
}
|
||||
if (isSelected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (current_scene) {
|
||||
draw_new_cutscene_line_form();
|
||||
}
|
||||
for (size_t i = 0; i < scene.m_lines.size(); i++) {
|
||||
auto& subtitleLine = scene.m_lines.at(i);
|
||||
std::string summary;
|
||||
if (subtitleLine.line_utf8.empty()) {
|
||||
summary = fmt::format("[{}] Clear Screen", subtitleLine.frame);
|
||||
} else {
|
||||
summary = fmt::format("[{}] {} - '{}...'", subtitleLine.frame, subtitleLine.speaker_utf8,
|
||||
subtitleLine.line_utf8.substr(0, 30));
|
||||
}
|
||||
if (subtitleLine.line_utf8.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
|
||||
} else if (subtitleLine.offscreen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_offscreen_text_color);
|
||||
}
|
||||
if (ImGui::TreeNode(fmt::format("{}", i).c_str(), "%s", summary.c_str())) {
|
||||
if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::InputInt("Starting Frame", &subtitleLine.frame,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::InputText("Speaker", &subtitleLine.speaker_utf8);
|
||||
ImGui::InputText("Text", &subtitleLine.line_utf8);
|
||||
ImGui::Checkbox("Offscreen?", &subtitleLine.offscreen);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, m_warning_color);
|
||||
if (ImGui::Button("Remove Line")) {
|
||||
scene.m_lines.erase(scene.m_lines.begin() + i);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::TreePop();
|
||||
} else if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SubtitleEditor::draw_new_cutscene_line_form() {
|
||||
ImGui::InputInt("Frame Number", &m_current_scene_frame,
|
||||
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
|
||||
ImGui::InputText("Text", &m_current_scene_text);
|
||||
ImGui::InputText("Speaker", &m_current_scene_speaker);
|
||||
ImGui::Checkbox("Offscreen", &m_current_scene_offscreen);
|
||||
bool rendered_text_entry_btn = false;
|
||||
if (m_current_scene_frame < 0 || m_current_scene_text.empty() ||
|
||||
m_current_scene_speaker.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("Can't add a new text entry with the current fields!");
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
rendered_text_entry_btn = true;
|
||||
if (ImGui::Button("Add Text Entry")) {
|
||||
m_current_scene->add_line(m_current_scene_frame, "", m_current_scene_text, "",
|
||||
m_current_scene_speaker, m_current_scene_offscreen);
|
||||
}
|
||||
}
|
||||
if (m_current_scene_frame < 0) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
|
||||
ImGui::Text("Can't add a clear screen entry with the current fields!");
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
if (rendered_text_entry_btn) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Add Clear Screen Entry")) {
|
||||
m_current_scene->add_line(m_current_scene_frame, "", "", "", "", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,10 @@ class SubtitleEditor {
|
||||
|
||||
void draw_all_cutscene_groups();
|
||||
void draw_all_scenes(std::string group_name, bool base_cutscenes = false);
|
||||
void draw_current_cutscene();
|
||||
void draw_subtitle_options(GameSubtitleSceneInfo& scene, bool current_scene = false);
|
||||
void draw_new_cutscene_line_form();
|
||||
void draw_all_hint_groups();
|
||||
void draw_all_hints(std::string group_name, bool base_cutscenes);
|
||||
|
||||
GameSubtitleDB m_subtitle_db;
|
||||
std::map<std::string, SubtitleEditorDB::Entry> m_db = {};
|
||||
@@ -50,6 +53,7 @@ class SubtitleEditor {
|
||||
|
||||
std::string m_new_scene_name = "";
|
||||
std::string m_new_scene_group = "";
|
||||
std::string m_new_scene_id = "0";
|
||||
|
||||
std::string m_new_scene_group_name = "";
|
||||
|
||||
@@ -79,6 +83,7 @@ class SubtitleEditor {
|
||||
const std::string_view& process_name);
|
||||
void repl_execute_cutscene_code(const SubtitleEditorDB::Entry& entry);
|
||||
void repl_rebuild_text();
|
||||
void repl_play_hint(const std::string_view& hint_name);
|
||||
|
||||
bool is_scene_in_current_lang(const std::string& scene_name);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user