make $killcount work for units too

This commit is contained in:
Martin Michelsen
2025-06-07 09:53:56 -07:00
parent c1a2742617
commit d4bc880018
14 changed files with 101 additions and 77 deletions
+30 -20
View File
@@ -1302,7 +1302,7 @@ ChatCommandDefinition cc_item(
}
}
string name = s->describe_item(a.c->version(), item, true);
string name = s->describe_item(a.c->version(), item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
send_text_message(a.c, "$C7Item created:\n" + name);
co_return;
});
@@ -1364,28 +1364,38 @@ ChatCommandDefinition cc_killcount(
a.check_is_proxy(false);
auto p = a.c->character();
size_t item_index;
try {
item_index = p->inventory.find_equipped_item(EquipSlot::WEAPON);
} catch (const out_of_range&) {
throw precondition_failed("No weapon equipped");
vector<size_t> item_indexes;
for (size_t z = 0; z < p->inventory.num_items; z++) {
const auto& item = p->inventory.items[z];
if (item.is_equipped() && item.data.has_kill_count()) {
item_indexes.emplace_back(z);
}
}
const auto& item = p->inventory.items.at(item_index);
if (!item.data.has_kill_count()) {
throw precondition_failed("Weapon does not\nhave a kill count");
}
if (item_indexes.empty()) {
throw precondition_failed("No equipped items\nhave kill counts");
// Kill counts are only accurate on the server side at all times on BB. On
// other versions, we update the server's view of the client's inventory
// during games, but we can't track kills because the client doesn't inform
// the server whether it counted a kill for any individual enemy. So, on
// non-BB versions, the kill count is accurate at all times in the lobby
// (since kills can't occur there), or at the beginning of a game.
if ((a.c->version() == Version::BB_V4) || !a.c->require_lobby()->is_game()) {
send_text_message_fmt(a.c, "{} kills", item.data.get_kill_count());
} else {
send_text_message_fmt(a.c, "{} kills as of\ngame join", item.data.get_kill_count());
// Kill counts are only accurate on the server side at all times on BB.
// On other versions, we update the server's view of the client's
// inventory during games, but we can't track kills because the client
// doesn't inform the server whether it counted a kill for any
// individual enemy. So, on non-BB versions, the kill count is accurate
// at all times in the lobby (since kills can't occur there), or at the
// beginning of a game.
if ((a.c->version() == Version::BB_V4) || !a.c->require_lobby()->is_game()) {
send_text_message(a.c, "As of now:");
} else {
send_text_message(a.c, "As of game join:");
}
auto s = a.c->require_server_state();
for (size_t z : item_indexes) {
const auto& item = p->inventory.items[z];
string name = s->describe_item(
a.c->version(), item.data, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES | ItemNameIndex::Flag::NAME_ONLY);
send_text_message_fmt(a.c, "{}$C7: {} kills", name, item.data.get_kill_count());
}
}
co_return;
});
@@ -2768,7 +2778,7 @@ ChatCommandDefinition cc_what(
throw precondition_failed("$C4No items are near you");
} else {
auto s = a.c->require_server_state();
string name = s->describe_item(a.c->version(), nearest_fi->data, true);
string name = s->describe_item(a.c->version(), nearest_fi->data, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
send_text_message(a.c, name);
}
co_return;
+2 -2
View File
@@ -1058,7 +1058,7 @@ void Client::print_inventory() const {
for (size_t x = 0; x < p->inventory.num_items; x++) {
const auto& item = p->inventory.items[x];
auto hex = item.data.hex();
auto name = s->describe_item(this->version(), item.data, false);
auto name = s->describe_item(this->version(), item.data);
this->log.info_f("[PlayerInventory] {:2}: [+{:08X}] {} ({})", x, item.flags, hex, name);
}
}
@@ -1072,7 +1072,7 @@ void Client::print_bank() const {
const auto& item = bank.items[x];
const char* present_token = item.present ? "" : " (missing present flag)";
auto hex = item.data.hex();
auto name = s->describe_item(this->version(), item.data, false);
auto name = s->describe_item(this->version(), item.data);
this->log.info_f("[PlayerBank] {:3}: {} ({}) (x{}){}", x, hex, name, item.amount, present_token);
}
}
+2 -2
View File
@@ -193,7 +193,7 @@ std::shared_ptr<phosg::JSON> HTTPServer::generate_client_json(
{"ItemID", item.data.id.load()},
});
if (item_name_index) {
item_dict.emplace("Description", item_name_index->describe_item(item.data, false));
item_dict.emplace("Description", item_name_index->describe_item(item.data));
}
items_json.emplace_back(std::move(item_dict));
}
@@ -431,7 +431,7 @@ std::shared_ptr<phosg::JSON> HTTPServer::generate_lobby_json(
{"ItemID", item->data.id.load()},
});
if (item_name_index) {
item_dict.emplace("Description", item_name_index->describe_item(item->data, false));
item_dict.emplace("Description", item_name_index->describe_item(item->data));
}
floor_items_json.emplace_back(std::move(item_dict));
}
+20 -15
View File
@@ -97,7 +97,10 @@ const array<const char*, 0x11> name_for_s_rank_special = {
"King\'s",
};
std::string ItemNameIndex::describe_item(const ItemData& item, bool include_color_escapes, bool hide_mag_stats) const {
std::string ItemNameIndex::describe_item(const ItemData& item, uint8_t flags) const {
bool include_color_escapes = flags & ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES;
bool name_only = flags & ItemNameIndex::Flag::NAME_ONLY;
if (item.data1[0] == 0x04) {
return std::format("{}{} Meseta", include_color_escapes ? "$C7" : "", item.data2d);
}
@@ -108,13 +111,14 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
bool is_unidentified = false;
if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00) && !item.is_s_rank_weapon()) {
is_unidentified = item.data1[4] & 0x80;
bool is_present = item.data1[4] & 0x40;
uint8_t special_id = item.data1[4] & 0x3F;
if (is_present) {
ret_tokens.emplace_back("Wrapped");
}
if (is_unidentified) {
ret_tokens.emplace_back("????");
if (!name_only) {
if (item.data1[4] & 0x40) {
ret_tokens.emplace_back("Wrapped");
}
if (is_unidentified) {
ret_tokens.emplace_back("????");
}
}
if (special_id) {
try {
@@ -124,7 +128,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
}
}
}
if ((item.data1[0] == 0x00) && (item.data1[2] != 0x00) && item.is_s_rank_weapon()) {
if (!name_only && (item.data1[0] == 0x00) && (item.data1[2] != 0x00) && item.is_s_rank_weapon()) {
try {
ret_tokens.emplace_back(name_for_s_rank_special.at(item.data1[2]));
} catch (const out_of_range&) {
@@ -135,9 +139,10 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
// Armors, shields, and units (0x01) can be wrapped, as can mags (0x02) and
// non-stackable tools (0x03). However, each of these item classes has its
// flags in a different location.
if (((item.data1[0] == 0x01) && (item.data1[4] & 0x40)) ||
((item.data1[0] == 0x02) && (item.data2[2] & 0x40)) ||
((item.data1[0] == 0x03) && !item.is_stackable(*this->limits) && (item.data1[3] & 0x40))) {
if (!name_only &&
(((item.data1[0] == 0x01) && (item.data1[4] & 0x40)) ||
((item.data1[0] == 0x02) && (item.data2[2] & 0x40)) ||
((item.data1[0] == 0x03) && !item.is_stackable(*this->limits) && (item.data1[3] & 0x40)))) {
ret_tokens.emplace_back("Wrapped");
}
@@ -168,7 +173,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
if (item.data1[0] == 0x00) {
// For weapons, add the grind and bonuses, or S-rank name if applicable
if (item.data1[3] > 0) {
if (!name_only && item.data1[3] > 0) {
ret_tokens.emplace_back(std::format("+{}", item.data1[3]));
}
@@ -210,7 +215,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
}
}
} else { // Not S-rank (extended name bits not set)
} else if (!name_only) { // Not S-rank (extended name bits not set)
parray<int8_t, 5> bonuses(0);
for (size_t x = 0; x < 3; x++) {
uint8_t which = item.data1[6 + 2 * x];
@@ -258,7 +263,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
ret_tokens.emplace_back(std::format("!MD:{:04X}", modifier));
}
} else { // Armor/shields
} else if (!name_only) { // Armor/shields
if (item.data1[5] > 0) {
if (item.data1[5] == 1) {
ret_tokens.emplace_back("(1 slot)");
@@ -276,7 +281,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
}
}
} else if (!hide_mag_stats && (item.data1[0] == 0x02)) {
} else if (!name_only && (item.data1[0] == 0x02)) {
// For mags, add tons of info
ret_tokens.emplace_back(std::format("LV{}", item.data1[2]));
+6 -1
View File
@@ -38,7 +38,12 @@ public:
inline bool exists(const ItemData& item) const {
return this->primary_identifier_index.count(item.primary_identifier());
}
std::string describe_item(const ItemData& item, bool include_color_escapes = false, bool hide_mag_stats = false) const;
enum Flag : uint8_t {
INCLUDE_PSO_COLOR_ESCAPES = 0x01,
NAME_ONLY = 0x02,
};
std::string describe_item(const ItemData& item, uint8_t flags = 0) const;
ItemData parse_item_description(const std::string& description) const;
void print_table(FILE* stream) const;
+1 -1
View File
@@ -2158,7 +2158,7 @@ Action a_describe_item(
}
string desc = name_index->describe_item(item);
string desc_colored = name_index->describe_item(item, true);
string desc_colored = name_index->describe_item(item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
phosg::log_info_f("Data (decoded): {:02X}{:02X}{:02X}{:02X} {:02X}{:02X}{:02X}{:02X} {:02X}{:02X}{:02X}{:02X} -------- {:02X}{:02X}{:02X}{:02X}",
item.data1[0], item.data1[1], item.data1[2], item.data1[3],
+4
View File
@@ -77,6 +77,10 @@ struct PlayerInventoryItemT {
ret.data.id.store_raw(phosg::bswap32(ret.data.id.load_raw()));
return ret;
}
bool is_equipped() const {
return (this->flags & 8);
}
} __attribute__((packed));
using PlayerInventoryItem = PlayerInventoryItemT<false>;
using PlayerInventoryItemBE = PlayerInventoryItemT<true>;
+1 -1
View File
@@ -884,7 +884,7 @@ static asio::awaitable<HandlerResult> SC_6x60_6xA2(shared_ptr<Client> c, Channel
c->log.info_f("No item was created");
} else {
auto s = c->require_server_state();
string name = s->describe_item(c->version(), res.item, false);
string name = s->describe_item(c->version(), res.item);
c->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
res.item.id = c->proxy_session->next_item_id++;
c->log.info_f("Creating item {:08X} at {:02X}:{:g},{:g} for all clients",
+1 -1
View File
@@ -722,7 +722,7 @@ string RareItemSet::serialize_html(
}
string hex = example_item.short_hex();
string desc = name_index->describe_item(example_item, false, true);
string desc = name_index->describe_item(example_item, ItemNameIndex::Flag::NAME_ONLY);
tokens.emplace_back(std::format("<span class=\"item\" title=\"Hex: {}\">{}</span>", hex, desc));
float denom = static_cast<float>(frac.second) / static_cast<double>(frac.first);
+1 -1
View File
@@ -4088,7 +4088,7 @@ static asio::awaitable<void> on_DF_BB(shared_ptr<Client> c, Channel::Message& ms
award_state.rank_award_flags |= cmd.rank_bitmask;
p->add_item(cmd.item, *s->item_stack_limits(c->version()));
l->on_item_id_generated_externally(cmd.item.id);
string desc = s->describe_item(Version::BB_V4, cmd.item, false);
string desc = s->describe_item(Version::BB_V4, cmd.item);
l->log.info_f("(Challenge mode) Item awarded to player {}: {}", c->lobby_client_id, desc);
break;
}
+28 -28
View File
@@ -1947,7 +1947,7 @@ static asio::awaitable<void> on_player_drop_item(shared_ptr<Client> c, Subcomman
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} dropped item {:08X} ({}) at {}:({:g}, {:g})",
cmd.header.client_id, cmd.item_id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
c->print_inventory();
@@ -1985,7 +1985,7 @@ static asio::awaitable<void> on_create_inventory_item_t(shared_ptr<Client> c, Su
}
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} created inventory item {:08X} ({}) in inventory of NPC {:02X}; ignoring", c->lobby_client_id, item.id, name, cmd.header.client_id);
}
@@ -1993,7 +1993,7 @@ static asio::awaitable<void> on_create_inventory_item_t(shared_ptr<Client> c, Su
c->character()->add_item(item, *s->item_stack_limits(c->version()));
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} created inventory item {:08X} ({})", c->lobby_client_id, item.id, name);
c->print_inventory();
}
@@ -2036,7 +2036,7 @@ static void on_drop_partial_stack_t(shared_ptr<Client> c, SubcommandMessage& msg
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} split stack to create floor item {:08X} ({}) at {}:({:g},{:g})",
cmd.header.client_id, item.id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
c->print_inventory();
@@ -2091,7 +2091,7 @@ static asio::awaitable<void> on_drop_partial_stack_bb(shared_ptr<Client> c, Subc
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} split stack {:08X} (removed: {}) at {}:({:g}, {:g})",
cmd.header.client_id, cmd.item_id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
c->print_inventory();
@@ -2124,7 +2124,7 @@ static asio::awaitable<void> on_buy_shop_item(shared_ptr<Client> c, SubcommandMe
p->remove_meseta(price, c->version() != Version::BB_V4);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} bought item {:08X} ({}) from shop ({} Meseta)",
cmd.header.client_id, item.id, name, price);
c->print_inventory();
@@ -2156,7 +2156,7 @@ void send_item_notification_if_needed(shared_ptr<Client> c, const ItemData& item
}
if (should_notify) {
string name = s->describe_item(c->version(), item, true);
string name = s->describe_item(c->version(), item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
const char* rare_header = (should_include_rare_header ? "$C6Rare item dropped:\n" : "");
send_text_message_fmt(c, "{}{}", rare_header, name);
}
@@ -2199,7 +2199,7 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, SubcommandMessage&
l->on_item_id_generated_externally(item.id);
l->add_item(cmd.item.floor, item, cmd.item.pos, obj_st, ene_st, should_notify ? 0x100F : 0x000F);
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} (leader) created floor item {:08X} ({}){} at {}:({:g}, {:g})",
l->leader_id,
item.id,
@@ -2279,7 +2279,7 @@ static asio::awaitable<void> on_pick_up_item_generic(
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), fi->data, false);
auto name = s->describe_item(c->version(), fi->data);
l->log.info_f("Player {} picked up {:08X} ({})", client_id, item_id, name);
c->print_inventory();
}
@@ -2313,8 +2313,8 @@ static asio::awaitable<void> on_pick_up_item_generic(
if (should_send_game_notif || should_send_global_notif) {
string p_name = p->disp.name.decode();
string desc_ingame = s->describe_item(c->version(), fi->data, true);
string desc_http = s->describe_item(c->version(), fi->data, false);
string desc_ingame = s->describe_item(c->version(), fi->data, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
string desc_http = s->describe_item(c->version(), fi->data);
if (s->http_server) {
auto message = make_shared<phosg::JSON>(phosg::JSON::dict({
@@ -2407,7 +2407,7 @@ static asio::awaitable<void> on_use_item(shared_ptr<Client> c, SubcommandMessage
// Note: We do this weird scoping thing because player_use_item will
// likely delete the item, which will break the reference here.
const auto& item = p->inventory.items[index].data;
name = s->describe_item(c->version(), item, false);
name = s->describe_item(c->version(), item);
}
player_use_item(c, index, l->rand_crypt);
@@ -2438,9 +2438,9 @@ static asio::awaitable<void> on_feed_mag(shared_ptr<Client> c, SubcommandMessage
// Note: We do this weird scoping thing because player_feed_mag will
// likely delete the items, which will break the references here.
const auto& fed_item = p->inventory.items[fed_index].data;
fed_name = s->describe_item(c->version(), fed_item, false);
fed_name = s->describe_item(c->version(), fed_item);
const auto& mag_item = p->inventory.items[mag_index].data;
mag_name = s->describe_item(c->version(), mag_item, false);
mag_name = s->describe_item(c->version(), mag_item);
}
player_feed_mag(c, mag_index, fed_index);
@@ -2699,7 +2699,7 @@ static asio::awaitable<void> on_ep3_private_word_select_bb_bank_action(
send_destroy_item_to_lobby(c, cmd.item_id, cmd.item_amount, true);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(Version::BB_V4, item, false);
string name = s->describe_item(Version::BB_V4, item);
l->log.info_f("Player {} deposited item {:08X} (x{}) ({}) in the bank",
c->lobby_client_id, cmd.item_id, cmd.item_amount, name);
c->print_inventory();
@@ -2729,7 +2729,7 @@ static asio::awaitable<void> on_ep3_private_word_select_bb_bank_action(
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(Version::BB_V4, item, false);
string name = s->describe_item(Version::BB_V4, item);
l->log.info_f("Player {} withdrew item {:08X} (x{}) ({}) from the bank",
c->lobby_client_id, item.id, cmd.item_amount, name);
c->print_inventory();
@@ -3024,7 +3024,7 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
if (res.item.empty()) {
l->log.info_f("No item was created");
} else {
string name = s->describe_item(c->version(), res.item, false);
string name = s->describe_item(c->version(), res.item);
l->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
if (drop_mode == Lobby::DropMode::SERVER_DUPLICATE) {
for (const auto& lc : l->clients) {
@@ -3062,7 +3062,7 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
if (res.item.empty()) {
l->log.info_f("No item was created for {}", lc->channel->name);
} else {
string name = s->describe_item(lc->version(), res.item, false);
string name = s->describe_item(lc->version(), res.item);
l->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
res.item.id = l->generate_item_id(0xFF);
l->log.info_f("Creating item {:08X} at {:02X}:{:g},{:g} for {}",
@@ -4045,7 +4045,7 @@ static asio::awaitable<void> on_item_reward_request_bb(shared_ptr<Client> c, Sub
c->character()->add_item(item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} created inventory item {:08X} ({}) via quest command",
c->lobby_client_id, item.id, name);
c->print_inventory();
@@ -4053,7 +4053,7 @@ static asio::awaitable<void> on_item_reward_request_bb(shared_ptr<Client> c, Sub
} catch (const out_of_range&) {
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} attempted to create inventory item {:08X} ({}) via quest command, but it cannot be placed in their inventory",
c->lobby_client_id, item.id, name);
}
@@ -4084,7 +4084,7 @@ asio::awaitable<void> on_transfer_item_via_mail_message_bb(shared_ptr<Client> c,
auto item = p->remove_item(cmd.item_id, cmd.amount, limits);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} sent inventory item {}:{:08X} ({}) x{} to player {:08X}",
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name, cmd.amount, cmd.target_guild_card_number);
c->print_inventory();
@@ -4151,7 +4151,7 @@ static asio::awaitable<void> on_exchange_item_for_team_points_bb(shared_ptr<Clie
s->team_index->add_member_points(c->login->account->account_id, points);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} exchanged inventory item {}:{:08X} ({}) for {} team points",
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name, points);
c->print_inventory();
@@ -4184,7 +4184,7 @@ static asio::awaitable<void> on_destroy_inventory_item(shared_ptr<Client> c, Sub
auto item = p->remove_item(cmd.item_id, cmd.amount, *s->item_stack_limits(c->version()));
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} destroyed inventory item {}:{:08X} ({})",
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name);
c->print_inventory();
@@ -4236,7 +4236,7 @@ static asio::awaitable<void> on_destroy_floor_item(shared_ptr<Client> c, Subcomm
c->lobby_client_id, cmd.item_id);
} else {
auto name = s->describe_item(c->version(), fi->data, false);
auto name = s->describe_item(c->version(), fi->data);
l->log.info_f("Player {} destroyed floor item {:08X} ({})", c->lobby_client_id, cmd.item_id, name);
// Only forward to players for whom the item was visible
@@ -4342,7 +4342,7 @@ static asio::awaitable<void> on_sell_item_at_shop_bb(shared_ptr<Client> c, Subco
p->add_meseta(price);
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} sold inventory item {:08X} ({}) for {} Meseta",
c->lobby_client_id, cmd.item_id, name, price);
c->print_inventory();
@@ -4385,7 +4385,7 @@ static asio::awaitable<void> on_buy_shop_item_bb(shared_ptr<Client> c, Subcomman
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
auto name = s->describe_item(c->version(), item);
l->log.info_f("Player {} purchased item {:08X} ({}) for {} meseta",
c->lobby_client_id, item.id, name, price);
c->print_inventory();
@@ -5048,12 +5048,12 @@ static asio::awaitable<void> on_quest_F960_result_bb(shared_ptr<Client> c, Subco
p->add_item(item, *s->item_stack_limits(c->version()));
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (c->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(c->version(), item, false);
string name = s->describe_item(c->version(), item);
c->log.info_f("Awarded item {}", name);
}
} catch (const out_of_range&) {
if (c->log.should_log(phosg::LogLevel::L_INFO)) {
string name = s->describe_item(c->version(), item, false);
string name = s->describe_item(c->version(), item);
c->log.info_f("Attempted to award item {}, but inventory was full", name);
}
}
+3 -3
View File
@@ -501,13 +501,13 @@ shared_ptr<const ItemNameIndex> ServerState::item_name_index(Version version) co
return ret;
}
string ServerState::describe_item(Version version, const ItemData& item, bool include_color_codes) const {
string ServerState::describe_item(Version version, const ItemData& item, uint8_t flags) const {
if (is_v1(version)) {
ItemData encoded = item;
encoded.encode_for_version(version, this->item_parameter_table(version));
return this->item_name_index(version)->describe_item(encoded, include_color_codes);
return this->item_name_index(version)->describe_item(encoded, flags);
} else {
return this->item_name_index(version)->describe_item(item, include_color_codes);
return this->item_name_index(version)->describe_item(item, flags);
}
}
+1 -1
View File
@@ -351,7 +351,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::shared_ptr<const ItemData::StackLimits> item_stack_limits(Version version) const;
std::shared_ptr<const ItemNameIndex> item_name_index_opt(Version version) const; // Returns null if missing
std::shared_ptr<const ItemNameIndex> item_name_index(Version version) const; // Throws if missing
std::string describe_item(Version version, const ItemData& item, bool include_color_codes) const;
std::string describe_item(Version version, const ItemData& item, uint8_t flags = 0) const;
ItemData parse_item_description(Version version, const std::string& description) const;
const std::vector<uint32_t>& public_lobby_search_order(Version version, bool is_client_customization) const;
+1 -1
View File
@@ -1072,7 +1072,7 @@ ShellCommand c_create_item(
send_drop_stacked_item_to_channel(args.s, c->channel, item, c->floor, c->pos);
send_drop_stacked_item_to_channel(args.s, c->proxy_session->server_channel, item, c->floor, c->pos);
string name = args.s->describe_item(c->version(), item, true);
string name = args.s->describe_item(c->version(), item, ItemNameIndex::Flag::INCLUDE_PSO_COLOR_ESCAPES);
send_text_message(c->channel, "$C7Item created:\n" + name);
co_return deque<string>{};
});