4#include "DialogFactory.h"
6#include "spdlog/spdlog.h"
7#include <binarytools/BinaryReader.h>
8#include <binarytools/BinaryWriter.h>
9#include <factories/BaseFactory.h>
20constexpr int kQuestionOptionCount = 3;
23inline void WriteEscapedChars(std::ostream& write,
const std::string& str) {
26 write <<
", 0x" << FORMAT_HEX((uint32_t)c, 2);
27 }
else if (c ==
'\'') {
28 write <<
", \'\\" << c <<
"\'";
30 write <<
", \'" << c <<
"\'";
36inline void WriteDialogStringArray(std::ostream& write,
const std::vector<DialogString>& entries) {
37 write << fourSpaceTab << entries.size() <<
",\n";
38 for (
const auto& [cmd, str] : entries) {
39 write << fourSpaceTab <<
"0x" << FORMAT_HEX((uint32_t)cmd, 2) <<
", " << str.length();
40 WriteEscapedChars(write, str);
46inline void WriteDialogStrings(LUS::BinaryWriter& writer,
const std::vector<DialogString>& entries) {
47 writer.Write((uint32_t)entries.size());
48 for (
const auto& entry : entries) {
49 writer.Write(entry.cmd);
50 writer.Write((uint32_t)entry.str.length());
52 writer.Write((
char*)entry.str.data(), entry.str.size());
57inline void EmitDialogStringSeq(YAML::Emitter& out,
const std::vector<DialogString>& entries) {
58 out << YAML::BeginSeq;
59 for (
const auto& [cmd, str] : entries) {
61 out << YAML::BeginSeq;
62 out << YAML_HEX((uint32_t)cmd);
70inline bool HasBytes(LUS::BinaryReader& reader,
size_t count) {
71 return reader.GetBaseAddress() + count <= reader.GetLength();
74inline std::vector<DialogString> ReadDialogStrings(LUS::BinaryReader& reader,
int count,
const std::string& symbol,
76 std::vector<DialogString> entries;
77 for (
int i = 0; i < count; i++) {
78 if (!HasBytes(reader, 2)) {
79 SPDLOG_WARN(
"[BK64] {} {}: entry {} of {} runs past the end of the blob; dropping the rest.", kind, symbol,
85 entry.cmd = reader.ReadUByte();
86 const auto strLen = reader.ReadUByte();
88 if (!HasBytes(reader, strLen)) {
89 SPDLOG_WARN(
"[BK64] {} {}: entry {} of {} claims {} bytes the blob doesn't hold; dropping the rest.", kind,
90 symbol, i + 1, count, strLen);
94 entry.str = reader.ReadString(strLen);
95 entries.push_back(entry);
102inline std::vector<DialogString> ReadModdingDialogSeq(
const YAML::Node& seq) {
103 std::vector<DialogString> entries;
104 for (YAML::const_iterator it = seq.begin(); it != seq.end(); ++it) {
106 entry.cmd = (*it)[0].as<uint32_t>();
107 entry.str = DecodeText((*it)[1].as<std::string>());
109 entries.push_back(entry);
114inline constexpr const char* kPalExtraLangs[] = {
"French",
"German" };
115inline std::vector<YAML::Node> ReadPalExtraLangs(
const YAML::Node& info,
const std::string& symbol,
const char* kind) {
116 const bool french =
static_cast<bool>(info[kPalExtraLangs[0]]);
117 const bool german =
static_cast<bool>(info[kPalExtraLangs[1]]);
118 if (french != german) {
119 throw std::runtime_error(fmt::format(
"BK64 {}: {} has {} but no {}; give it both or neither", kind, symbol,
120 kPalExtraLangs[french ? 0 : 1], kPalExtraLangs[french ? 1 : 0]));
125 return { info[kPalExtraLangs[0]], info[kPalExtraLangs[1]] };
135inline std::optional<std::vector<uint16_t>> SeekQuestionBlock(LUS::BinaryReader& reader,
const std::string& symbol,
136 const char* kind,
const int8_t (&usHeader)[3],
137 const int8_t (&palHeader)[3]) {
138 const auto header1 = reader.ReadInt8();
139 const auto header2 = reader.ReadInt8();
140 const auto header3 = reader.ReadInt8();
142 if (header1 == usHeader[0] && header2 == usHeader[1] && header3 == usHeader[2]) {
145 return std::vector<uint16_t>{};
148 if (header1 == palHeader[0] && header2 == palHeader[1] && header3 == palHeader[2]) {
149 std::vector<uint16_t> extraOffsets;
150 for (
int i = 0; i < header1; i++) {
151 const uint16_t offset = reader.ReadUByte() | (reader.ReadUByte() << 8);
153 extraOffsets.push_back(offset);
159 SPDLOG_ERROR(
"Invalid Header For BK64 {} {}: {:02X} {:02X} {:02X}", kind, symbol, header1, header2, header3);
Definition DialogFactory.h:8