fix tech disk stacking on 11/2000
This commit is contained in:
+4
-4
@@ -987,7 +987,7 @@ bool ItemCreator::shop_does_not_contain_duplicate_or_too_many_similar_weapons(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ItemCreator::shop_does_not_contain_duplicate_item_by_primary_identifier(
|
||||
bool ItemCreator::shop_does_not_contain_duplicate_item_by_data1_0_1_2(
|
||||
const vector<ItemData>& shop, const ItemData& item) {
|
||||
for (const auto& shop_item : shop) {
|
||||
if ((shop_item.data1[0] == item.data1[0]) &&
|
||||
@@ -1080,7 +1080,7 @@ void ItemCreator::generate_armor_shop_shields(vector<ItemData>& shop, size_t pla
|
||||
}
|
||||
}
|
||||
|
||||
if (this->shop_does_not_contain_duplicate_item_by_primary_identifier(shop, item)) {
|
||||
if (this->shop_does_not_contain_duplicate_item_by_data1_0_1_2(shop, item)) {
|
||||
shop.emplace_back(std::move(item));
|
||||
items_generated++;
|
||||
}
|
||||
@@ -1114,7 +1114,7 @@ void ItemCreator::generate_armor_shop_units(vector<ItemData>& shop, size_t playe
|
||||
item.data1[0] = 1;
|
||||
item.data1[1] = 3;
|
||||
item.data1[2] = pt.pop();
|
||||
if (this->shop_does_not_contain_duplicate_item_by_primary_identifier(shop, item)) {
|
||||
if (this->shop_does_not_contain_duplicate_item_by_data1_0_1_2(shop, item)) {
|
||||
shop.emplace_back(std::move(item));
|
||||
items_generated++;
|
||||
}
|
||||
@@ -1225,7 +1225,7 @@ void ItemCreator::generate_rare_tool_shop_recovery_items(
|
||||
item.data1[0] = 3;
|
||||
item.data1[1] = tool_item_defs[type].first;
|
||||
item.data1[2] = tool_item_defs[type].second;
|
||||
if (this->shop_does_not_contain_duplicate_item_by_primary_identifier(shop, item)) {
|
||||
if (this->shop_does_not_contain_duplicate_item_by_data1_0_1_2(shop, item)) {
|
||||
shop.emplace_back(std::move(item));
|
||||
items_generated++;
|
||||
}
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ private:
|
||||
const std::vector<ItemData>& shop, const ItemData& item);
|
||||
static bool shop_does_not_contain_duplicate_or_too_many_similar_weapons(
|
||||
const std::vector<ItemData>& shop, const ItemData& item);
|
||||
static bool shop_does_not_contain_duplicate_item_by_primary_identifier(
|
||||
static bool shop_does_not_contain_duplicate_item_by_data1_0_1_2(
|
||||
const std::vector<ItemData>& shop, const ItemData& item);
|
||||
void generate_armor_shop_armors(
|
||||
std::vector<ItemData>& shop, size_t player_level);
|
||||
|
||||
+26
-9
@@ -71,16 +71,17 @@ uint32_t ItemData::primary_identifier() const {
|
||||
// The game treats any item starting with 04 as Meseta, and ignores the rest
|
||||
// of data1 (the value is in data2)
|
||||
if (this->data1[0] == 0x04) {
|
||||
return 0x040000;
|
||||
return 0x04000000;
|
||||
}
|
||||
if (this->data1[0] == 0x03 && this->data1[1] == 0x02) {
|
||||
return 0x030200; // Tech disk (data1[2] is level, so omit it)
|
||||
// Tech disk (tech ID is data1[4], not [2])
|
||||
return 0x03020000 | (this->data1[4] << 8) | this->data1[2];
|
||||
} else if (this->data1[0] == 0x02) {
|
||||
return 0x020000 | (this->data1[1] << 8); // Mag
|
||||
return 0x02000000 | (this->data1[1] << 16); // Mag
|
||||
} else if (this->is_s_rank_weapon()) {
|
||||
return (this->data1[0] << 16) | (this->data1[1] << 8);
|
||||
return (this->data1[0] << 24) | (this->data1[1] << 16);
|
||||
} else {
|
||||
return (this->data1[0] << 16) | (this->data1[1] << 8) | this->data1[2];
|
||||
return (this->data1[0] << 24) | (this->data1[1] << 16) | (this->data1[2] << 8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,10 +165,9 @@ void ItemData::enforce_min_stack_size(Version version) {
|
||||
}
|
||||
|
||||
bool ItemData::is_common_consumable(uint32_t primary_identifier) {
|
||||
if (primary_identifier == 0x030200) {
|
||||
return false;
|
||||
}
|
||||
return (primary_identifier >= 0x030000) && (primary_identifier < 0x030A00);
|
||||
return (primary_identifier >= 0x03000000) &&
|
||||
(primary_identifier < 0x030A0000) &&
|
||||
((primary_identifier & 0xFFFF0000) != 0x03020000);
|
||||
}
|
||||
|
||||
bool ItemData::is_common_consumable() const {
|
||||
@@ -667,6 +667,23 @@ ItemData ItemData::from_data(const string& data) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ItemData ItemData::from_primary_identifier(Version version, uint32_t primary_identifier) {
|
||||
ItemData ret;
|
||||
if (primary_identifier > 0x04000000) {
|
||||
throw runtime_error("invalid item class");
|
||||
}
|
||||
ret.data1[0] = (primary_identifier >> 24) & 0xFF;
|
||||
ret.data1[1] = (primary_identifier >> 16) & 0xFF;
|
||||
if ((primary_identifier & 0xFFFF0000) == 0x03020000) {
|
||||
ret.data1[4] = (primary_identifier >> 8) & 0xFF;
|
||||
ret.data1[2] = primary_identifier & 0xFF;
|
||||
} else {
|
||||
ret.data1[2] = (primary_identifier >> 8) & 0xFF;
|
||||
}
|
||||
ret.set_tool_item_amount(version, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string ItemData::hex() const {
|
||||
return string_printf("%02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX (%08" PRIX32 ") %02hhX%02hhX%02hhX%02hhX",
|
||||
this->data1[0], this->data1[1], this->data1[2], this->data1[3],
|
||||
|
||||
+1
-2
@@ -6,8 +6,6 @@
|
||||
#include "Text.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
constexpr uint32_t MESETA_IDENTIFIER = 0x040000;
|
||||
|
||||
class ItemParameterTable;
|
||||
|
||||
enum class EquipSlot {
|
||||
@@ -126,6 +124,7 @@ struct ItemData { // 0x14 bytes
|
||||
void clear();
|
||||
|
||||
static ItemData from_data(const std::string& data);
|
||||
static ItemData from_primary_identifier(Version version, uint32_t primary_identifier);
|
||||
std::string hex() const;
|
||||
uint32_t primary_identifier() const;
|
||||
|
||||
|
||||
+12
-27
@@ -4,22 +4,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
// class ItemNameIndex {
|
||||
// public:
|
||||
// ItemNameIndex(std::shared_ptr<const ItemParameterTable> pmt, const std::vector<std::string>& name_coll);
|
||||
// std::string describe_item(const ItemData& item, bool include_color_escapes = false) const;
|
||||
// ItemData parse_item_description(const std::string& description) const;
|
||||
// private:
|
||||
// ItemData parse_item_description_phase(const std::string& description, bool skip_special) const;
|
||||
// std::shared_ptr<const ItemParameterTable> item_parameter_table;
|
||||
// struct ItemMetadata {
|
||||
// uint32_t primary_identifier;
|
||||
// std::string name;
|
||||
// };
|
||||
// std::unordered_map<uint32_t, std::shared_ptr<ItemMetadata>> primary_identifier_indexes;
|
||||
// std::map<std::string, std::shared_ptr<ItemMetadata>> name_indexes;
|
||||
// };
|
||||
|
||||
ItemNameIndex::ItemNameIndex(
|
||||
Version version,
|
||||
std::shared_ptr<const ItemParameterTable> item_parameter_table,
|
||||
@@ -55,7 +39,9 @@ ItemNameIndex::ItemNameIndex(
|
||||
};
|
||||
auto find_items_2d = [&](uint64_t data1) {
|
||||
for (size_t x = 0; x < 0x100; x++) {
|
||||
if (find_items_1d(data1 | (static_cast<uint64_t>(x) << 48), 2) == 0) {
|
||||
size_t effective_data1 = data1 | (static_cast<uint64_t>(x) << 48);
|
||||
size_t data2_position = (effective_data1 == 0x0302000000000000) ? 4 : 2;
|
||||
if (find_items_1d(effective_data1, data2_position) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -182,17 +168,15 @@ std::string ItemNameIndex::describe_item(
|
||||
ret_tokens.emplace_back("Wrapped");
|
||||
}
|
||||
|
||||
// Add the item name. Technique disks are special because the level is part of
|
||||
// the primary identifier, so we manually generate the name instead of looking
|
||||
// it up.
|
||||
// Add the item name
|
||||
uint32_t primary_identifier = item.primary_identifier();
|
||||
if ((primary_identifier & 0xFFFFFF00) == 0x00030200) {
|
||||
if ((primary_identifier & 0xFFFF0000) == 0x03020000) {
|
||||
string technique_name;
|
||||
try {
|
||||
technique_name = tech_id_to_name.at(item.data1[4]);
|
||||
technique_name[0] = toupper(technique_name[0]);
|
||||
} catch (const out_of_range&) {
|
||||
technique_name = string_printf("!TECH:%02hhX", item.data1[4]);
|
||||
technique_name = string_printf("!TD:%02hhX", item.data1[4]);
|
||||
}
|
||||
// Hide the level for Reverser and Ryuker, unless the level isn't 1
|
||||
if ((item.data1[2] == 0) && ((item.data1[4] == 0x0E) || (item.data1[4] == 0x11))) {
|
||||
@@ -204,9 +188,8 @@ std::string ItemNameIndex::describe_item(
|
||||
try {
|
||||
auto meta = this->primary_identifier_index.at(primary_identifier);
|
||||
ret_tokens.emplace_back(meta->name);
|
||||
|
||||
} catch (const out_of_range&) {
|
||||
ret_tokens.emplace_back(string_printf("!ID:%06" PRIX32, primary_identifier));
|
||||
ret_tokens.emplace_back(string_printf("!ID:%08" PRIX32, primary_identifier));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,10 +475,12 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
|
||||
desc = desc.substr(1);
|
||||
}
|
||||
|
||||
// Tech disks should have already been handled above, so we don't need to
|
||||
// special-case 0302xxxx identifiers here.
|
||||
uint32_t primary_identifier = name_it->second->primary_identifier;
|
||||
ret.data1[0] = (primary_identifier >> 16) & 0xFF;
|
||||
ret.data1[1] = (primary_identifier >> 8) & 0xFF;
|
||||
ret.data1[2] = primary_identifier & 0xFF;
|
||||
ret.data1[0] = (primary_identifier >> 24) & 0xFF;
|
||||
ret.data1[1] = (primary_identifier >> 16) & 0xFF;
|
||||
ret.data1[2] = (primary_identifier >> 8) & 0xFF;
|
||||
|
||||
if (ret.data1[0] == 0x00) {
|
||||
// Weapons: add special, grind and percentages (or name, if S-rank)
|
||||
|
||||
+16
-16
@@ -17,12 +17,12 @@ void player_use_item(shared_ptr<Client> c, size_t item_index, shared_ptr<PSOLFGE
|
||||
|
||||
auto player = c->character();
|
||||
auto& item = player->inventory.items[item_index];
|
||||
uint32_t item_identifier = item.data.primary_identifier();
|
||||
uint32_t primary_identifier = item.data.primary_identifier();
|
||||
|
||||
if (item.data.is_common_consumable()) { // Monomate, etc.
|
||||
// Nothing to do (it should be deleted)
|
||||
|
||||
} else if (item_identifier == 0x030200) { // Technique disk
|
||||
} else if ((primary_identifier & 0xFFFF0000) == 0x03020000) { // Technique disk
|
||||
auto item_parameter_table = s->item_parameter_table(c->version());
|
||||
uint8_t max_level = item_parameter_table->get_max_tech_level(player->disp.visual.char_class, item.data.data1[4]);
|
||||
if (item.data.data1[2] > max_level) {
|
||||
@@ -30,7 +30,7 @@ void player_use_item(shared_ptr<Client> c, size_t item_index, shared_ptr<PSOLFGE
|
||||
}
|
||||
player->set_technique_level(item.data.data1[4], item.data.data1[2]);
|
||||
|
||||
} else if ((item_identifier & 0xFFFF00) == 0x030A00) { // Grinder
|
||||
} else if ((primary_identifier & 0xFFFF00) == 0x030A0000) { // Grinder
|
||||
if (item.data.data1[2] > 2) {
|
||||
throw runtime_error("incorrect grinder value");
|
||||
}
|
||||
@@ -51,7 +51,7 @@ void player_use_item(shared_ptr<Client> c, size_t item_index, shared_ptr<PSOLFGE
|
||||
}
|
||||
weapon.data.data1[3] += (item.data.data1[2] + 1);
|
||||
|
||||
} else if ((item_identifier & 0xFFFF00) == 0x030B00) { // Material
|
||||
} else if ((primary_identifier & 0xFFFF0000) == 0x030B0000) { // Material
|
||||
auto p = c->character();
|
||||
|
||||
using Type = PSOBBCharacterFile::MaterialType;
|
||||
@@ -104,7 +104,7 @@ void player_use_item(shared_ptr<Client> c, size_t item_index, shared_ptr<PSOLFGE
|
||||
p->set_material_usage(type, p->get_material_usage(type) + 1);
|
||||
}
|
||||
|
||||
} else if ((item_identifier & 0xFFFF00) == 0x030F00) { // AddSlot
|
||||
} else if ((primary_identifier & 0xFFFF0000) == 0x030F0000) { // AddSlot
|
||||
auto& armor = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::ARMOR)];
|
||||
if (armor.data.data1[5] >= 4) {
|
||||
throw runtime_error("armor already at maximum slot count");
|
||||
@@ -116,57 +116,57 @@ void player_use_item(shared_ptr<Client> c, size_t item_index, shared_ptr<PSOLFGE
|
||||
item.data.unwrap(c->version());
|
||||
should_delete_item = false;
|
||||
|
||||
} else if (item_identifier == 0x003300) {
|
||||
} else if (primary_identifier == 0x00330000) {
|
||||
// Unseal Sealed J-Sword => Tsumikiri J-Sword
|
||||
item.data.data1[1] = 0x32;
|
||||
should_delete_item = false;
|
||||
|
||||
} else if (item_identifier == 0x00AB00) {
|
||||
} else if (primary_identifier == 0x00AB0000) {
|
||||
// Unseal Lame d'Argent => Excalibur
|
||||
item.data.data1[1] = 0xAC;
|
||||
should_delete_item = false;
|
||||
|
||||
} else if (item_identifier == 0x01034D) {
|
||||
} else if (primary_identifier == 0x01034D00) {
|
||||
// Unseal Limiter => Adept
|
||||
item.data.data1[2] = 0x4E;
|
||||
should_delete_item = false;
|
||||
|
||||
} else if (item_identifier == 0x01034F) {
|
||||
} else if (primary_identifier == 0x01034F00) {
|
||||
// Unseal Swordsman Lore => Proof of Sword-Saint
|
||||
item.data.data1[2] = 0x50;
|
||||
should_delete_item = false;
|
||||
|
||||
} else if (item_identifier == 0x030C00) {
|
||||
} else if (primary_identifier == 0x030C0000) {
|
||||
// Cell of MAG 502
|
||||
auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)];
|
||||
mag.data.data1[1] = (player->disp.visual.section_id & 1) ? 0x1D : 0x21;
|
||||
|
||||
} else if (item_identifier == 0x030C01) {
|
||||
} else if (primary_identifier == 0x030C0100) {
|
||||
// Cell of MAG 213
|
||||
auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)];
|
||||
mag.data.data1[1] = (player->disp.visual.section_id & 1) ? 0x27 : 0x22;
|
||||
|
||||
} else if (item_identifier == 0x030C02) {
|
||||
} else if (primary_identifier == 0x030C0200) {
|
||||
// Parts of RoboChao
|
||||
auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)];
|
||||
mag.data.data1[1] = 0x28;
|
||||
|
||||
} else if (item_identifier == 0x030C03) {
|
||||
} else if (primary_identifier == 0x030C0300) {
|
||||
// Heart of Opa Opa
|
||||
auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)];
|
||||
mag.data.data1[1] = 0x29;
|
||||
|
||||
} else if (item_identifier == 0x030C04) {
|
||||
} else if (primary_identifier == 0x030C0400) {
|
||||
// Heart of Pian
|
||||
auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)];
|
||||
mag.data.data1[1] = 0x2A;
|
||||
|
||||
} else if (item_identifier == 0x030C05) {
|
||||
} else if (primary_identifier == 0x030C0500) {
|
||||
// Heart of Chao
|
||||
auto& mag = player->inventory.items[player->inventory.find_equipped_item(EquipSlot::MAG)];
|
||||
mag.data.data1[1] = 0x2B;
|
||||
|
||||
} else if ((item_identifier & 0xFFFF00) == 0x031500) {
|
||||
} else if ((primary_identifier & 0xFFFF0000) == 0x03150000) {
|
||||
// Christmas Present, etc. - use unwrap_table + probabilities therein
|
||||
auto item_parameter_table = s->item_parameter_table(c->version());
|
||||
auto table = item_parameter_table->get_event_items(item.data.data1[2]);
|
||||
|
||||
+3
-2
@@ -1472,11 +1472,12 @@ Action a_name_all_items(
|
||||
fputc('\n', stderr);
|
||||
|
||||
for (uint32_t primary_identifier : all_primary_identifiers) {
|
||||
fprintf(stderr, "%06" PRIX32 ":", primary_identifier);
|
||||
fprintf(stderr, "%08" PRIX32 ":", primary_identifier);
|
||||
for (size_t v_s = 0; v_s < NUM_VERSIONS; v_s++) {
|
||||
const auto& index = s.item_name_indexes.at(v_s);
|
||||
if (index) {
|
||||
ItemData item(static_cast<uint64_t>(primary_identifier) << 40);
|
||||
Version version = static_cast<Version>(v_s);
|
||||
ItemData item = ItemData::from_primary_identifier(version, primary_identifier);
|
||||
string name = index->describe_item(item);
|
||||
fprintf(stderr, " %30s", name.c_str());
|
||||
}
|
||||
|
||||
@@ -451,9 +451,9 @@ PlayerRecordsBB_Challenge::operator PlayerRecordsV3_Challenge<false>() const {
|
||||
}
|
||||
|
||||
void PlayerBank::add_item(const ItemData& item, Version version) {
|
||||
uint32_t pid = item.primary_identifier();
|
||||
uint32_t primary_identifier = item.primary_identifier();
|
||||
|
||||
if (pid == MESETA_IDENTIFIER) {
|
||||
if (primary_identifier == 0x04000000) {
|
||||
this->meseta += item.data2d;
|
||||
if (this->meseta > 999999) {
|
||||
this->meseta = 999999;
|
||||
@@ -465,7 +465,7 @@ void PlayerBank::add_item(const ItemData& item, Version version) {
|
||||
if (combine_max > 1) {
|
||||
size_t y;
|
||||
for (y = 0; y < this->num_items; y++) {
|
||||
if (this->items[y].data.primary_identifier() == item.primary_identifier()) {
|
||||
if (this->items[y].data.primary_identifier() == primary_identifier) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -446,13 +446,13 @@ std::string RareItemSet::serialize_json(shared_ptr<const ItemNameIndex> name_ind
|
||||
}
|
||||
|
||||
for (const auto& spec : this->get_enemy_specs(GameMode::NORMAL, episode, difficulty, section_id, rt_index)) {
|
||||
uint32_t primary_identifier = (spec.item_code[0] << 16) | (spec.item_code[1] << 8) | spec.item_code[2];
|
||||
if (primary_identifier == 0) {
|
||||
uint32_t data1_0_1_2 = (spec.item_code[0] << 16) | (spec.item_code[1] << 8) | spec.item_code[2];
|
||||
if (data1_0_1_2 == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000);
|
||||
auto spec_json = JSON::list({string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second), primary_identifier});
|
||||
auto spec_json = JSON::list({string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second), data1_0_1_2});
|
||||
if (name_index) {
|
||||
ItemData data;
|
||||
data.data1[0] = spec.item_code[0];
|
||||
@@ -473,13 +473,13 @@ std::string RareItemSet::serialize_json(shared_ptr<const ItemNameIndex> name_ind
|
||||
auto area_list = JSON::list();
|
||||
|
||||
for (const auto& spec : this->get_box_specs(GameMode::NORMAL, episode, difficulty, section_id, area)) {
|
||||
uint32_t primary_identifier = (spec.item_code[0] << 16) | (spec.item_code[1] << 8) | spec.item_code[2];
|
||||
if (primary_identifier == 0) {
|
||||
uint32_t data1_0_1_2 = (spec.item_code[0] << 16) | (spec.item_code[1] << 8) | spec.item_code[2];
|
||||
if (data1_0_1_2 == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000);
|
||||
area_list.emplace_back(JSON::list({string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second), std::move(primary_identifier)}));
|
||||
area_list.emplace_back(JSON::list({string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second), data1_0_1_2}));
|
||||
if (name_index) {
|
||||
ItemData data;
|
||||
data.data1[0] = spec.item_code[0];
|
||||
|
||||
@@ -3118,7 +3118,7 @@ static void on_photon_drop_exchange_for_item_bb(shared_ptr<Client> c, uint8_t, u
|
||||
try {
|
||||
auto p = c->character();
|
||||
|
||||
size_t found_index = p->inventory.find_item_by_primary_identifier(0x031000);
|
||||
size_t found_index = p->inventory.find_item_by_primary_identifier(0x03100000);
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 0, c->version());
|
||||
send_destroy_item_to_lobby(c, found_item.id, found_item.stack_size(c->version()));
|
||||
|
||||
@@ -3150,7 +3150,7 @@ static void on_photon_drop_exchange_for_s_rank_special_bb(shared_ptr<Client> c,
|
||||
static const array<uint8_t, 0x10> costs({60, 60, 20, 20, 30, 30, 30, 50, 40, 50, 40, 40, 50, 40, 40, 40});
|
||||
uint8_t cost = costs.at(cmd.special_type);
|
||||
|
||||
size_t payment_item_index = p->inventory.find_item_by_primary_identifier(0x031000);
|
||||
size_t payment_item_index = p->inventory.find_item_by_primary_identifier(0x03100000);
|
||||
// Ensure weapon exists before removing PDs, so inventory state will be
|
||||
// consistent in case of error
|
||||
p->inventory.find_item(cmd.item_id);
|
||||
@@ -3186,7 +3186,7 @@ static void on_secret_lottery_ticket_exchange_bb(shared_ptr<Client> c, uint8_t,
|
||||
auto p = c->character();
|
||||
ssize_t slt_index = -1;
|
||||
try {
|
||||
slt_index = p->inventory.find_item_by_primary_identifier(0x031003); // Secret Lottery Ticket
|
||||
slt_index = p->inventory.find_item_by_primary_identifier(0x03100300); // Secret Lottery Ticket
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
@@ -3234,7 +3234,7 @@ static void on_photon_crystal_exchange_bb(shared_ptr<Client> c, uint8_t, uint8_t
|
||||
if (l->is_game() && (l->base_version == Version::BB_V4) && l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS)) {
|
||||
check_size_t<G_ExchangePhotonCrystals_BB_6xDF>(data, size);
|
||||
auto p = c->character();
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x031002);
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x03100200);
|
||||
auto item = p->remove_item(p->inventory.items[index].data.id, 1, c->version());
|
||||
send_destroy_item_to_lobby(c, item.id, 1);
|
||||
}
|
||||
@@ -3284,7 +3284,7 @@ static void on_quest_F95F_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
|
||||
throw runtime_error("invalid result index");
|
||||
}
|
||||
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x031004); // Photon Ticket
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x03100400); // Photon Ticket
|
||||
auto ticket_item = p->remove_item(p->inventory.items[index].data.id, result.first, c->version());
|
||||
// TODO: Shouldn't we send a 6x29 here? Check if this causes desync in an
|
||||
// actual game
|
||||
@@ -3417,7 +3417,7 @@ static void on_upgrade_weapon_attribute_bb(shared_ptr<Client> c, uint8_t, uint8_
|
||||
size_t item_index = p->inventory.find_item(cmd.item_id);
|
||||
auto& item = p->inventory.items[item_index].data;
|
||||
|
||||
uint32_t payment_primary_identifier = cmd.payment_type ? 0x031001 : 0x031000;
|
||||
uint32_t payment_primary_identifier = cmd.payment_type ? 0x03100100 : 0x03100000;
|
||||
size_t payment_index = p->inventory.find_item_by_primary_identifier(payment_primary_identifier);
|
||||
auto& payment_item = p->inventory.items[payment_index].data;
|
||||
if (payment_item.stack_size(c->version()) < cmd.payment_count) {
|
||||
|
||||
@@ -397,11 +397,11 @@ PSOBBCharacterFile::SymbolChatEntry PSOBBCharacterFile::DefaultSymbolChatEntry::
|
||||
// TODO: Eliminate duplication between this function and the parallel function
|
||||
// in PlayerBank
|
||||
void PSOBBCharacterFile::add_item(const ItemData& item, Version version) {
|
||||
uint32_t pid = item.primary_identifier();
|
||||
uint32_t primary_identifier = item.primary_identifier();
|
||||
|
||||
// Annoyingly, meseta is in the disp data, not in the inventory struct. If the
|
||||
// item is meseta, we have to modify disp instead.
|
||||
if (pid == MESETA_IDENTIFIER) {
|
||||
if (primary_identifier == 0x04000000) {
|
||||
this->add_meseta(item.data2d);
|
||||
return;
|
||||
}
|
||||
@@ -413,7 +413,7 @@ void PSOBBCharacterFile::add_item(const ItemData& item, Version version) {
|
||||
// player's inventory
|
||||
size_t y;
|
||||
for (y = 0; y < this->inventory.num_items; y++) {
|
||||
if (this->inventory.items[y].data.primary_identifier() == item.primary_identifier()) {
|
||||
if (this->inventory.items[y].data.primary_identifier() == primary_identifier) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user