4#include "DialogFactory.h"
6#include "spdlog/spdlog.h"
7#include <binarytools/BinaryReader.h>
8#include <binarytools/BinaryWriter.h>
9#include <factories/BaseFactory.h>
19constexpr int kQuestionOptionCount = 3;
22inline void WriteEscapedChars(std::ostream& write,
const std::string& str) {
25 write <<
", 0x" << FORMAT_HEX((uint32_t)c, 2);
26 }
else if (c ==
'\'') {
27 write <<
", \'\\" << c <<
"\'";
29 write <<
", \'" << c <<
"\'";
35inline void WriteDialogStringArray(std::ostream& write,
const std::vector<DialogString>& entries) {
36 write << fourSpaceTab << entries.size() <<
",\n";
37 for (
const auto& [cmd, str] : entries) {
38 write << fourSpaceTab <<
"0x" << FORMAT_HEX((uint32_t)cmd, 2) <<
", " << str.length();
39 WriteEscapedChars(write, str);
45inline void WriteDialogStrings(LUS::BinaryWriter& writer,
const std::vector<DialogString>& entries) {
46 writer.Write((uint32_t)entries.size());
47 for (
const auto& entry : entries) {
48 writer.Write(entry.cmd);
49 writer.Write((uint32_t)entry.str.length());
51 writer.Write((
char*)entry.str.data(), entry.str.size());
56inline void EmitDialogStringSeq(YAML::Emitter& out,
const std::vector<DialogString>& entries) {
57 out << YAML::BeginSeq;
58 for (
const auto& [cmd, str] : entries) {
60 out << YAML::BeginSeq;
61 out << YAML_HEX((uint32_t)cmd);
69inline bool HasBytes(LUS::BinaryReader& reader,
size_t count) {
70 return reader.GetBaseAddress() + count <= reader.GetLength();
73inline std::vector<DialogString> ReadDialogStrings(LUS::BinaryReader& reader,
int count,
const std::string& symbol,
75 std::vector<DialogString> entries;
76 for (
int i = 0; i < count; i++) {
77 if (!HasBytes(reader, 2)) {
78 SPDLOG_WARN(
"[BK64] {} {}: entry {} of {} runs past the end of the blob; dropping the rest.", kind, symbol,
84 entry.cmd = reader.ReadUByte();
85 const auto strLen = reader.ReadUByte();
87 if (!HasBytes(reader, strLen)) {
88 SPDLOG_WARN(
"[BK64] {} {}: entry {} of {} claims {} bytes the blob doesn't hold; dropping the rest.", kind,
89 symbol, i + 1, count, strLen);
93 entry.str = reader.ReadString(strLen);
94 entries.push_back(entry);
101inline std::vector<DialogString> ReadModdingDialogSeq(
const YAML::Node& seq) {
102 std::vector<DialogString> entries;
103 for (YAML::const_iterator it = seq.begin(); it != seq.end(); ++it) {
105 entry.cmd = (*it)[0].as<uint32_t>();
106 entry.str = DecodeText((*it)[1].as<std::string>());
108 entries.push_back(entry);
114inline std::optional<YAML::Node> LoadModdingRoot(
const std::vector<uint8_t>& buffer) {
116 std::string text((
char*)buffer.data(), buffer.size());
117 YAML::Node assetNode = YAML::Load(text.c_str());
118 return assetNode.begin()->second;
119 }
catch (YAML::ParserException& e) {
120 SPDLOG_ERROR(
"Failed to parse message data: {}", e.what());
121 SPDLOG_ERROR(
"{}", (
char*)buffer.data());
132inline std::optional<std::vector<uint16_t>> SeekQuestionBlock(LUS::BinaryReader& reader,
const std::string& symbol,
133 const char* kind,
const int8_t (&usHeader)[3],
134 const int8_t (&palHeader)[3]) {
135 const auto header1 = reader.ReadInt8();
136 const auto header2 = reader.ReadInt8();
137 const auto header3 = reader.ReadInt8();
139 if (header1 == usHeader[0] && header2 == usHeader[1] && header3 == usHeader[2]) {
142 return std::vector<uint16_t>{};
145 if (header1 == palHeader[0] && header2 == palHeader[1] && header3 == palHeader[2]) {
146 std::vector<uint16_t> extraOffsets;
147 for (
int i = 0; i < header1; i++) {
148 const uint16_t offset = reader.ReadUByte() | (reader.ReadUByte() << 8);
150 extraOffsets.push_back(offset);
156 SPDLOG_ERROR(
"Invalid Header For BK64 {} {}: {:02X} {:02X} {:02X}", kind, symbol, header1, header2, header3);
Definition DialogFactory.h:8