make $killcount work for units too
This commit is contained in:
+30
-20
@@ -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);
|
send_text_message(a.c, "$C7Item created:\n" + name);
|
||||||
co_return;
|
co_return;
|
||||||
});
|
});
|
||||||
@@ -1364,28 +1364,38 @@ ChatCommandDefinition cc_killcount(
|
|||||||
a.check_is_proxy(false);
|
a.check_is_proxy(false);
|
||||||
|
|
||||||
auto p = a.c->character();
|
auto p = a.c->character();
|
||||||
size_t item_index;
|
vector<size_t> item_indexes;
|
||||||
try {
|
for (size_t z = 0; z < p->inventory.num_items; z++) {
|
||||||
item_index = p->inventory.find_equipped_item(EquipSlot::WEAPON);
|
const auto& item = p->inventory.items[z];
|
||||||
} catch (const out_of_range&) {
|
if (item.is_equipped() && item.data.has_kill_count()) {
|
||||||
throw precondition_failed("No weapon equipped");
|
item_indexes.emplace_back(z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& item = p->inventory.items.at(item_index);
|
if (item_indexes.empty()) {
|
||||||
if (!item.data.has_kill_count()) {
|
throw precondition_failed("No equipped items\nhave kill counts");
|
||||||
throw precondition_failed("Weapon does not\nhave a 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_fmt(a.c, "{} kills", item.data.get_kill_count());
|
|
||||||
} else {
|
} 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;
|
co_return;
|
||||||
});
|
});
|
||||||
@@ -2768,7 +2778,7 @@ ChatCommandDefinition cc_what(
|
|||||||
throw precondition_failed("$C4No items are near you");
|
throw precondition_failed("$C4No items are near you");
|
||||||
} else {
|
} else {
|
||||||
auto s = a.c->require_server_state();
|
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);
|
send_text_message(a.c, name);
|
||||||
}
|
}
|
||||||
co_return;
|
co_return;
|
||||||
|
|||||||
+2
-2
@@ -1058,7 +1058,7 @@ void Client::print_inventory() const {
|
|||||||
for (size_t x = 0; x < p->inventory.num_items; x++) {
|
for (size_t x = 0; x < p->inventory.num_items; x++) {
|
||||||
const auto& item = p->inventory.items[x];
|
const auto& item = p->inventory.items[x];
|
||||||
auto hex = item.data.hex();
|
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);
|
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 auto& item = bank.items[x];
|
||||||
const char* present_token = item.present ? "" : " (missing present flag)";
|
const char* present_token = item.present ? "" : " (missing present flag)";
|
||||||
auto hex = item.data.hex();
|
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);
|
this->log.info_f("[PlayerBank] {:3}: {} ({}) (x{}){}", x, hex, name, item.amount, present_token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -193,7 +193,7 @@ std::shared_ptr<phosg::JSON> HTTPServer::generate_client_json(
|
|||||||
{"ItemID", item.data.id.load()},
|
{"ItemID", item.data.id.load()},
|
||||||
});
|
});
|
||||||
if (item_name_index) {
|
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));
|
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()},
|
{"ItemID", item->data.id.load()},
|
||||||
});
|
});
|
||||||
if (item_name_index) {
|
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));
|
floor_items_json.emplace_back(std::move(item_dict));
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-15
@@ -97,7 +97,10 @@ const array<const char*, 0x11> name_for_s_rank_special = {
|
|||||||
"King\'s",
|
"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) {
|
if (item.data1[0] == 0x04) {
|
||||||
return std::format("{}{} Meseta", include_color_escapes ? "$C7" : "", item.data2d);
|
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;
|
bool is_unidentified = false;
|
||||||
if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00) && !item.is_s_rank_weapon()) {
|
if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00) && !item.is_s_rank_weapon()) {
|
||||||
is_unidentified = item.data1[4] & 0x80;
|
is_unidentified = item.data1[4] & 0x80;
|
||||||
bool is_present = item.data1[4] & 0x40;
|
|
||||||
uint8_t special_id = item.data1[4] & 0x3F;
|
uint8_t special_id = item.data1[4] & 0x3F;
|
||||||
if (is_present) {
|
if (!name_only) {
|
||||||
ret_tokens.emplace_back("Wrapped");
|
if (item.data1[4] & 0x40) {
|
||||||
}
|
ret_tokens.emplace_back("Wrapped");
|
||||||
if (is_unidentified) {
|
}
|
||||||
ret_tokens.emplace_back("????");
|
if (is_unidentified) {
|
||||||
|
ret_tokens.emplace_back("????");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (special_id) {
|
if (special_id) {
|
||||||
try {
|
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 {
|
try {
|
||||||
ret_tokens.emplace_back(name_for_s_rank_special.at(item.data1[2]));
|
ret_tokens.emplace_back(name_for_s_rank_special.at(item.data1[2]));
|
||||||
} catch (const out_of_range&) {
|
} 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
|
// 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
|
// non-stackable tools (0x03). However, each of these item classes has its
|
||||||
// flags in a different location.
|
// flags in a different location.
|
||||||
if (((item.data1[0] == 0x01) && (item.data1[4] & 0x40)) ||
|
if (!name_only &&
|
||||||
((item.data1[0] == 0x02) && (item.data2[2] & 0x40)) ||
|
(((item.data1[0] == 0x01) && (item.data1[4] & 0x40)) ||
|
||||||
((item.data1[0] == 0x03) && !item.is_stackable(*this->limits) && (item.data1[3] & 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");
|
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) {
|
if (item.data1[0] == 0x00) {
|
||||||
// For weapons, add the grind and bonuses, or S-rank name if applicable
|
// 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]));
|
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);
|
parray<int8_t, 5> bonuses(0);
|
||||||
for (size_t x = 0; x < 3; x++) {
|
for (size_t x = 0; x < 3; x++) {
|
||||||
uint8_t which = item.data1[6 + 2 * 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));
|
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] > 0) {
|
||||||
if (item.data1[5] == 1) {
|
if (item.data1[5] == 1) {
|
||||||
ret_tokens.emplace_back("(1 slot)");
|
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
|
// For mags, add tons of info
|
||||||
ret_tokens.emplace_back(std::format("LV{}", item.data1[2]));
|
ret_tokens.emplace_back(std::format("LV{}", item.data1[2]));
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,12 @@ public:
|
|||||||
inline bool exists(const ItemData& item) const {
|
inline bool exists(const ItemData& item) const {
|
||||||
return this->primary_identifier_index.count(item.primary_identifier());
|
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;
|
ItemData parse_item_description(const std::string& description) const;
|
||||||
|
|
||||||
void print_table(FILE* stream) const;
|
void print_table(FILE* stream) const;
|
||||||
|
|||||||
+1
-1
@@ -2158,7 +2158,7 @@ Action a_describe_item(
|
|||||||
}
|
}
|
||||||
|
|
||||||
string desc = name_index->describe_item(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}",
|
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],
|
item.data1[0], item.data1[1], item.data1[2], item.data1[3],
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ struct PlayerInventoryItemT {
|
|||||||
ret.data.id.store_raw(phosg::bswap32(ret.data.id.load_raw()));
|
ret.data.id.store_raw(phosg::bswap32(ret.data.id.load_raw()));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_equipped() const {
|
||||||
|
return (this->flags & 8);
|
||||||
|
}
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
using PlayerInventoryItem = PlayerInventoryItemT<false>;
|
using PlayerInventoryItem = PlayerInventoryItemT<false>;
|
||||||
using PlayerInventoryItemBE = PlayerInventoryItemT<true>;
|
using PlayerInventoryItemBE = PlayerInventoryItemT<true>;
|
||||||
|
|||||||
@@ -884,7 +884,7 @@ static asio::awaitable<HandlerResult> SC_6x60_6xA2(shared_ptr<Client> c, Channel
|
|||||||
c->log.info_f("No item was created");
|
c->log.info_f("No item was created");
|
||||||
} else {
|
} else {
|
||||||
auto s = c->require_server_state();
|
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);
|
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++;
|
res.item.id = c->proxy_session->next_item_id++;
|
||||||
c->log.info_f("Creating item {:08X} at {:02X}:{:g},{:g} for all clients",
|
c->log.info_f("Creating item {:08X} at {:02X}:{:g},{:g} for all clients",
|
||||||
|
|||||||
+1
-1
@@ -722,7 +722,7 @@ string RareItemSet::serialize_html(
|
|||||||
}
|
}
|
||||||
|
|
||||||
string hex = example_item.short_hex();
|
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));
|
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);
|
float denom = static_cast<float>(frac.second) / static_cast<double>(frac.first);
|
||||||
|
|||||||
@@ -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;
|
award_state.rank_award_flags |= cmd.rank_bitmask;
|
||||||
p->add_item(cmd.item, *s->item_stack_limits(c->version()));
|
p->add_item(cmd.item, *s->item_stack_limits(c->version()));
|
||||||
l->on_item_id_generated_externally(cmd.item.id);
|
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);
|
l->log.info_f("(Challenge mode) Item awarded to player {}: {}", c->lobby_client_id, desc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-28
@@ -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)) {
|
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
||||||
auto s = c->require_server_state();
|
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})",
|
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);
|
cmd.header.client_id, cmd.item_id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
|
||||||
c->print_inventory();
|
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)) {
|
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);
|
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()));
|
c->character()->add_item(item, *s->item_stack_limits(c->version()));
|
||||||
|
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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);
|
l->log.info_f("Player {} created inventory item {:08X} ({})", c->lobby_client_id, item.id, name);
|
||||||
c->print_inventory();
|
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)) {
|
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
||||||
auto s = c->require_server_state();
|
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})",
|
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);
|
cmd.header.client_id, item.id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
|
||||||
c->print_inventory();
|
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)) {
|
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
||||||
auto s = c->require_server_state();
|
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})",
|
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);
|
cmd.header.client_id, cmd.item_id, name, cmd.floor, cmd.pos.x, cmd.pos.z);
|
||||||
c->print_inventory();
|
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);
|
p->remove_meseta(price, c->version() != Version::BB_V4);
|
||||||
|
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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)",
|
l->log.info_f("Player {} bought item {:08X} ({}) from shop ({} Meseta)",
|
||||||
cmd.header.client_id, item.id, name, price);
|
cmd.header.client_id, item.id, name, price);
|
||||||
c->print_inventory();
|
c->print_inventory();
|
||||||
@@ -2156,7 +2156,7 @@ void send_item_notification_if_needed(shared_ptr<Client> c, const ItemData& item
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (should_notify) {
|
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" : "");
|
const char* rare_header = (should_include_rare_header ? "$C6Rare item dropped:\n" : "");
|
||||||
send_text_message_fmt(c, "{}{}", rare_header, name);
|
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->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);
|
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->log.info_f("Player {} (leader) created floor item {:08X} ({}){} at {}:({:g}, {:g})",
|
||||||
l->leader_id,
|
l->leader_id,
|
||||||
item.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)) {
|
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
||||||
auto s = c->require_server_state();
|
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);
|
l->log.info_f("Player {} picked up {:08X} ({})", client_id, item_id, name);
|
||||||
c->print_inventory();
|
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) {
|
if (should_send_game_notif || should_send_global_notif) {
|
||||||
string p_name = p->disp.name.decode();
|
string p_name = p->disp.name.decode();
|
||||||
string desc_ingame = s->describe_item(c->version(), fi->data, true);
|
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, false);
|
string desc_http = s->describe_item(c->version(), fi->data);
|
||||||
|
|
||||||
if (s->http_server) {
|
if (s->http_server) {
|
||||||
auto message = make_shared<phosg::JSON>(phosg::JSON::dict({
|
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
|
// Note: We do this weird scoping thing because player_use_item will
|
||||||
// likely delete the item, which will break the reference here.
|
// likely delete the item, which will break the reference here.
|
||||||
const auto& item = p->inventory.items[index].data;
|
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);
|
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
|
// Note: We do this weird scoping thing because player_feed_mag will
|
||||||
// likely delete the items, which will break the references here.
|
// likely delete the items, which will break the references here.
|
||||||
const auto& fed_item = p->inventory.items[fed_index].data;
|
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;
|
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);
|
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);
|
send_destroy_item_to_lobby(c, cmd.item_id, cmd.item_amount, true);
|
||||||
|
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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",
|
l->log.info_f("Player {} deposited item {:08X} (x{}) ({}) in the bank",
|
||||||
c->lobby_client_id, cmd.item_id, cmd.item_amount, name);
|
c->lobby_client_id, cmd.item_id, cmd.item_amount, name);
|
||||||
c->print_inventory();
|
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);
|
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||||
|
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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",
|
l->log.info_f("Player {} withdrew item {:08X} (x{}) ({}) from the bank",
|
||||||
c->lobby_client_id, item.id, cmd.item_amount, name);
|
c->lobby_client_id, item.id, cmd.item_amount, name);
|
||||||
c->print_inventory();
|
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()) {
|
if (res.item.empty()) {
|
||||||
l->log.info_f("No item was created");
|
l->log.info_f("No item was created");
|
||||||
} else {
|
} 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);
|
l->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
|
||||||
if (drop_mode == Lobby::DropMode::SERVER_DUPLICATE) {
|
if (drop_mode == Lobby::DropMode::SERVER_DUPLICATE) {
|
||||||
for (const auto& lc : l->clients) {
|
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()) {
|
if (res.item.empty()) {
|
||||||
l->log.info_f("No item was created for {}", lc->channel->name);
|
l->log.info_f("No item was created for {}", lc->channel->name);
|
||||||
} else {
|
} 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);
|
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);
|
res.item.id = l->generate_item_id(0xFF);
|
||||||
l->log.info_f("Creating item {:08X} at {:02X}:{:g},{:g} for {}",
|
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);
|
c->character()->add_item(item, limits);
|
||||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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",
|
l->log.info_f("Player {} created inventory item {:08X} ({}) via quest command",
|
||||||
c->lobby_client_id, item.id, name);
|
c->lobby_client_id, item.id, name);
|
||||||
c->print_inventory();
|
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&) {
|
} catch (const out_of_range&) {
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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",
|
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);
|
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);
|
auto item = p->remove_item(cmd.item_id, cmd.amount, limits);
|
||||||
|
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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}",
|
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->lobby_client_id, cmd.header.client_id, cmd.item_id, name, cmd.amount, cmd.target_guild_card_number);
|
||||||
c->print_inventory();
|
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);
|
s->team_index->add_member_points(c->login->account->account_id, points);
|
||||||
|
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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",
|
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->lobby_client_id, cmd.header.client_id, cmd.item_id, name, points);
|
||||||
c->print_inventory();
|
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()));
|
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)) {
|
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} ({})",
|
l->log.info_f("Player {} destroyed inventory item {}:{:08X} ({})",
|
||||||
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name);
|
c->lobby_client_id, cmd.header.client_id, cmd.item_id, name);
|
||||||
c->print_inventory();
|
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);
|
c->lobby_client_id, cmd.item_id);
|
||||||
|
|
||||||
} else {
|
} 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);
|
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
|
// 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);
|
p->add_meseta(price);
|
||||||
|
|
||||||
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
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",
|
l->log.info_f("Player {} sold inventory item {:08X} ({}) for {} Meseta",
|
||||||
c->lobby_client_id, cmd.item_id, name, price);
|
c->lobby_client_id, cmd.item_id, name, price);
|
||||||
c->print_inventory();
|
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)) {
|
if (l->log.should_log(phosg::LogLevel::L_INFO)) {
|
||||||
auto s = c->require_server_state();
|
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",
|
l->log.info_f("Player {} purchased item {:08X} ({}) for {} meseta",
|
||||||
c->lobby_client_id, item.id, name, price);
|
c->lobby_client_id, item.id, name, price);
|
||||||
c->print_inventory();
|
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()));
|
p->add_item(item, *s->item_stack_limits(c->version()));
|
||||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||||
if (c->log.should_log(phosg::LogLevel::L_INFO)) {
|
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);
|
c->log.info_f("Awarded item {}", name);
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
if (c->log.should_log(phosg::LogLevel::L_INFO)) {
|
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);
|
c->log.info_f("Attempted to award item {}, but inventory was full", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -501,13 +501,13 @@ shared_ptr<const ItemNameIndex> ServerState::item_name_index(Version version) co
|
|||||||
return ret;
|
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)) {
|
if (is_v1(version)) {
|
||||||
ItemData encoded = item;
|
ItemData encoded = item;
|
||||||
encoded.encode_for_version(version, this->item_parameter_table(version));
|
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 {
|
} 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
@@ -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 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_opt(Version version) const; // Returns null if missing
|
||||||
std::shared_ptr<const ItemNameIndex> item_name_index(Version version) const; // Throws 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;
|
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;
|
const std::vector<uint32_t>& public_lobby_search_order(Version version, bool is_client_customization) const;
|
||||||
|
|||||||
@@ -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->channel, item, c->floor, c->pos);
|
||||||
send_drop_stacked_item_to_channel(args.s, c->proxy_session->server_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);
|
send_text_message(c->channel, "$C7Item created:\n" + name);
|
||||||
co_return deque<string>{};
|
co_return deque<string>{};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user