34 return std::unexpected(
"Stats property is outside the board");
36 city =
static_cast<int>(catalog.language()) - 2;
37 const auto id = 1001ULL + 42ULL *
static_cast<unsigned>(std::max(city, 0)) + square;
38 if (
id > std::numeric_limits<std::uint32_t>::max())
39 return std::unexpected(
"Stats city name offset overflows LANG IDs");
40 auto text = catalog.lookup(
static_cast<std::uint32_t
>(
id));
41 if (!
text)
return std::unexpected(
text.error().detail);
42 if (!*
text)
return std::unexpected(
"Stats property name is missing from LANG");
43 if (!(**text)->empty() && (**text)->front() == u
'*')
45 text = catalog.lookup(1001U +
static_cast<unsigned>(square));
46 if (!
text)
return std::unexpected(
text.error().detail);
47 if (!*
text)
return std::unexpected(
"Stats base property name is missing from LANG");
119 if (state_.
turn == 0)
121 if (path_.empty())
return std::unexpected(
"account history path is not configured");
122 std::ofstream
output(path_, std::ios::binary | std::ios::trunc);
123 if (!
output)
return std::unexpected(
"cannot reset account history for first turn");
127 if (state_.
turn == std::numeric_limits<std::uint32_t>::max())
128 return std::unexpected(
"account history turn overflow");
136 return std::unexpected(
"account history notification has invalid square");
137 const int square =
static_cast<int>(message.
numberA);
138 auto player = iBarPlayer;
145 return std::unexpected(
"account history notification has invalid player");
146 const auto language = resources.language();
147 if (!language || !language->catalog)
148 return std::unexpected(
"account history has no LANG catalog");
149 const auto edition = resources.context().board;
153 const auto before =
previous.squares[
static_cast<std::size_t
>(square)].houses;
157 return std::unexpected(
"retail European house-history text IDs are absent from the source catalog");
158 row.description =
sold ? (
hotel ? u
"Sold a hotel. " : u
"Sold a house. ") :
159 (
hotel ? u
"Purchased a hotel. " : u
"Purchased a house. ");
163 const auto property =
statsPropertyName(*language->catalog, edition, city, square);
164 if (!property)
return std::unexpected(property.error());
168 u
"Purchased property " : message.
numberB ? u
"Mortgaged property " : u
"Unmortgaged property ";
169 row.description += *
property + u
". ";
174 return std::unexpected(
"retail European mortgage-history text IDs are absent from the source catalog");
175 const auto pattern = language->catalog->lookup(3178);
177 if (!*
pattern)
return std::unexpected(
"account purchase history is missing LANG ID 3178");
178 for (std::size_t
i = 0;
i < (***pattern).size(); ++
i)
180 const auto unit = (***pattern)[
i];
181 if (
unit == u
'^' &&
i + 1 < (***pattern).size() &&
183 {
row.description += *property; ++
i; }
184 else row.description.push_back(
unit);
188 if (path_.empty())
return std::unexpected(
"account history path is not configured");
189 if (
row.description.size() >= 500)
191 row.description.resize(499);
192 if (
row.description.back() >= 0xD800 &&
row.description.back() <= 0xDBFF)
193 row.description.pop_back();
195 std::array<unsigned char, RecordBytes>
bytes{};
198 for (std::size_t
i = 0;
i <
row.description.size(); ++
i)
200 bytes[8 +
i * 2] =
static_cast<unsigned char>(
row.description[
i]);
201 bytes[9 +
i * 2] =
static_cast<unsigned char>(
row.description[
i] >> 8);
203 std::ofstream
output(path_, std::ios::binary | std::ios::app);
205 return std::unexpected(
"cannot append account history");
207 if (!
output)
return std::unexpected(
"cannot flush account history");
std::vector< std::byte > bytes
std::expected< void, std::string > processRuleMessage(const actions::Message &message, const rules::GameState &previous, rules::PlayerNumber iBarPlayer, int city, const data::ResourceSnapshot &resources)
std::u16string description