implement bb shops incompletely
This commit is contained in:
@@ -281,7 +281,7 @@ int32_t CommonItemCreator::decide_item_type(bool is_box) const {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemData CommonItemCreator::create_item(bool is_box, uint8_t episode,
|
ItemData CommonItemCreator::create_drop_item(bool is_box, uint8_t episode,
|
||||||
uint8_t difficulty, uint8_t area, uint8_t section_id) const {
|
uint8_t difficulty, uint8_t area, uint8_t section_id) const {
|
||||||
// change the area if it's invalid (data for the bosses are actually in other areas)
|
// change the area if it's invalid (data for the bosses are actually in other areas)
|
||||||
if (area > 10) {
|
if (area > 10) {
|
||||||
@@ -465,3 +465,124 @@ ItemData CommonItemCreator::create_item(bool is_box, uint8_t episode,
|
|||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ItemData CommonItemCreator::create_shop_item(uint8_t difficulty,
|
||||||
|
uint8_t item_type) const {
|
||||||
|
static const uint8_t max_percentages[4] = {20, 35, 45, 50};
|
||||||
|
static const uint8_t max_quantity[4] = { 1, 1, 2, 2};
|
||||||
|
static const uint8_t max_tech_level[4] = { 8, 15, 23, 30};
|
||||||
|
static const uint8_t max_anti_level[4] = { 2, 4, 6, 7};
|
||||||
|
|
||||||
|
ItemData item;
|
||||||
|
memset(&item, 0, sizeof(item));
|
||||||
|
|
||||||
|
item.item_data1[0] = item_type;
|
||||||
|
while (item.item_data1[0] == 2) {
|
||||||
|
item.item_data1[0] = rand() % 3;
|
||||||
|
}
|
||||||
|
switch (item.item_data1[0]) {
|
||||||
|
case 0: { // weapon
|
||||||
|
item.item_data1[1] = (rand() % 12) + 1;
|
||||||
|
if (item.item_data1[1] > 9) {
|
||||||
|
item.item_data1[2] = difficulty;
|
||||||
|
} else {
|
||||||
|
item.item_data1[2] = (rand() & 1) + difficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.item_data1[3] = rand() % 11;
|
||||||
|
item.item_data1[4] = rand() % 11;
|
||||||
|
|
||||||
|
size_t num_percentages = 0;
|
||||||
|
for (size_t x = 0; (x < 5) && (num_percentages < 3); x++) {
|
||||||
|
if ((rand() % 4) == 1) {
|
||||||
|
item.item_data1[(num_percentages * 2) + 6] = x;
|
||||||
|
item.item_data1[(num_percentages * 2) + 7] = rand() % (max_percentages[difficulty] + 1);
|
||||||
|
num_percentages++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1: // armor
|
||||||
|
item.item_data1[1] = 0;
|
||||||
|
while (item.item_data1[1] == 0) {
|
||||||
|
item.item_data1[1] = rand() & 3;
|
||||||
|
}
|
||||||
|
switch (item.item_data1[1]) {
|
||||||
|
case 1:
|
||||||
|
item.item_data1[2] = (rand() % 6) + (difficulty * 6);
|
||||||
|
item.item_data1[5] = rand() % 5;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
item.item_data2[2] = (rand() % 6) + (difficulty * 5);
|
||||||
|
*reinterpret_cast<short*>(&item.item_data1[6]) = (rand() % 9) - 4;
|
||||||
|
*reinterpret_cast<short*>(&item.item_data1[9]) = (rand() % 9) - 4;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
item.item_data2[2] = rand() % 0x3B;
|
||||||
|
*reinterpret_cast<short*>(&item.item_data1[7]) = (rand() % 5) - 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // tool
|
||||||
|
item.item_data1[1] = rand() % 12;
|
||||||
|
switch (item.item_data1[1]) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
if (difficulty == 0) {
|
||||||
|
item.item_data1[2] = 0;
|
||||||
|
} else if (difficulty == 1) {
|
||||||
|
item.item_data1[2] = rand() % 2;
|
||||||
|
} else if (difficulty == 2) {
|
||||||
|
item.item_data1[2] = (rand() % 2) + 1;
|
||||||
|
} else if (difficulty == 3) {
|
||||||
|
item.item_data1[2] = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
item.item_data1[2] = rand() % 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10:
|
||||||
|
item.item_data1[2] = rand() % 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
item.item_data1[2] = rand() % 7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (item.item_data1[1]) {
|
||||||
|
case 2:
|
||||||
|
item.item_data1[4] = rand() % 19;
|
||||||
|
switch (item.item_data1[4]) {
|
||||||
|
case 14:
|
||||||
|
case 17:
|
||||||
|
item.item_data1[2] = 0; // reverser & ryuker always level 1
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
item.item_data1[2] = rand() % max_anti_level[difficulty];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
item.item_data1[2] = rand() % max_tech_level[difficulty];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 16:
|
||||||
|
item.item_data1[5] = rand() % (max_quantity[difficulty] + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ struct CommonItemCreator {
|
|||||||
const std::vector<std::vector<uint8_t>>& unit_types);
|
const std::vector<std::vector<uint8_t>>& unit_types);
|
||||||
|
|
||||||
int32_t decide_item_type(bool is_box) const;
|
int32_t decide_item_type(bool is_box) const;
|
||||||
ItemData create_item(bool is_box, uint8_t episode, uint8_t difficulty,
|
ItemData create_drop_item(bool is_box, uint8_t episode, uint8_t difficulty,
|
||||||
uint8_t area, uint8_t section_id) const;
|
uint8_t area, uint8_t section_id) const;
|
||||||
|
ItemData create_shop_item(uint8_t difficulty, uint8_t shop_type) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ void Lobby::remove_item(uint32_t item_id, PlayerInventoryItem* item) {
|
|||||||
this->item_id_to_floor_item.erase(item_it);
|
this->item_id_to_floor_item.erase(item_it);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Lobby::generate_item_id(uint32_t client_id) {
|
uint32_t Lobby::generate_item_id(uint8_t client_id) {
|
||||||
if (client_id < this->max_clients) {
|
if (client_id < this->max_clients) {
|
||||||
return this->next_item_id[client_id]++;
|
return this->next_item_id[client_id]++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ struct Lobby {
|
|||||||
void add_item(const PlayerInventoryItem& item);
|
void add_item(const PlayerInventoryItem& item);
|
||||||
void remove_item(uint32_t item_id, PlayerInventoryItem* item);
|
void remove_item(uint32_t item_id, PlayerInventoryItem* item);
|
||||||
size_t find_item(uint32_t item_id);
|
size_t find_item(uint32_t item_id);
|
||||||
uint32_t generate_item_id(uint32_t client_id);
|
uint32_t generate_item_id(uint8_t client_id);
|
||||||
|
|
||||||
void assign_item_ids_for_player(uint32_t client_id, PlayerInventory& inv);
|
void assign_item_ids_for_player(uint32_t client_id, PlayerInventory& inv);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Version.hh"
|
#include "Version.hh"
|
||||||
|
|
||||||
@@ -329,9 +330,9 @@ struct PlayerBB {
|
|||||||
uint8_t quest_data1[0x0208]; // 04F0 // player
|
uint8_t quest_data1[0x0208]; // 04F0 // player
|
||||||
PlayerBank bank; // 06F8 // player
|
PlayerBank bank; // 06F8 // player
|
||||||
uint32_t serial_number; // 19C0 // player
|
uint32_t serial_number; // 19C0 // player
|
||||||
char16_t name[0x18]; // 19C4 // player
|
char16_t name[0x18]; // 19C4 // player
|
||||||
char16_t team_name[0x10]; // 19C4 // player
|
char16_t team_name[0x10]; // 19C4 // player
|
||||||
char16_t guild_card_desc[0x58]; // 1A14 // player
|
char16_t guild_card_desc[0x58]; // 1A14 // player
|
||||||
uint8_t reserved1; // 1AC4 // player
|
uint8_t reserved1; // 1AC4 // player
|
||||||
uint8_t reserved2; // 1AC5 // player
|
uint8_t reserved2; // 1AC5 // player
|
||||||
uint8_t section_id; // 1AC6 // player
|
uint8_t section_id; // 1AC6 // player
|
||||||
@@ -339,8 +340,8 @@ struct PlayerBB {
|
|||||||
uint32_t unknown3; // 1AC8 //
|
uint32_t unknown3; // 1AC8 //
|
||||||
uint8_t symbol_chats[0x04E0]; // 1ACC // account
|
uint8_t symbol_chats[0x04E0]; // 1ACC // account
|
||||||
uint8_t shortcuts[0x0A40]; // 1FAC // account
|
uint8_t shortcuts[0x0A40]; // 1FAC // account
|
||||||
char16_t auto_reply[0x00AC]; // 29EC // player
|
char16_t auto_reply[0x00AC]; // 29EC // player
|
||||||
char16_t info_board[0x00AC]; // 2B44 // player
|
char16_t info_board[0x00AC]; // 2B44 // player
|
||||||
uint8_t unknown5[0x001C]; // 2C9C //
|
uint8_t unknown5[0x001C]; // 2C9C //
|
||||||
uint8_t challenge_data[0x0140]; // 2CB8 // player
|
uint8_t challenge_data[0x0140]; // 2CB8 // player
|
||||||
uint8_t tech_menu_config[0x0028]; // 2DF8 // player
|
uint8_t tech_menu_config[0x0028]; // 2DF8 // player
|
||||||
@@ -399,6 +400,7 @@ struct Player {
|
|||||||
uint8_t quest_data1[0x0208]; // player
|
uint8_t quest_data1[0x0208]; // player
|
||||||
uint8_t quest_data2[0x0058]; // player
|
uint8_t quest_data2[0x0058]; // player
|
||||||
uint32_t serial_number;
|
uint32_t serial_number;
|
||||||
|
std::vector<ItemData> current_shop_contents;
|
||||||
uint8_t shortcuts[0x0A40]; // account
|
uint8_t shortcuts[0x0A40]; // account
|
||||||
uint8_t symbol_chats[0x04E0]; // account
|
uint8_t symbol_chats[0x04E0]; // account
|
||||||
char16_t team_name[0x0010]; // account
|
char16_t team_name[0x0010]; // account
|
||||||
|
|||||||
+35
-6
@@ -357,6 +357,35 @@ static void process_subcommand_use_item(shared_ptr<ServerState> s,
|
|||||||
forward_subcommand(l, c, command, flag, p, count);
|
forward_subcommand(l, c, command, flag, p, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void process_subcommand_open_shop(shared_ptr<ServerState> s,
|
||||||
|
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||||
|
const PSOSubcommand* p, size_t count) {
|
||||||
|
check_size(count, 2);
|
||||||
|
uint32_t shop_type = p[1].dword;
|
||||||
|
|
||||||
|
if ((l->version == GameVersion::BB) && l->is_game()) {
|
||||||
|
size_t num_items = (rand() % 4) + 9;
|
||||||
|
c->player.current_shop_contents.clear();
|
||||||
|
while (c->player.current_shop_contents.size() < num_items) {
|
||||||
|
ItemData item_data;
|
||||||
|
if (shop_type == 0) { // tool shop
|
||||||
|
item_data = s->common_item_creator->create_shop_item(l->difficulty, 3);
|
||||||
|
} else if (shop_type == 1) { // weapon shop
|
||||||
|
item_data = s->common_item_creator->create_shop_item(l->difficulty, 0);
|
||||||
|
} else if (shop_type == 2) { // guards shop
|
||||||
|
item_data = s->common_item_creator->create_shop_item(l->difficulty, 1);
|
||||||
|
} else { // unknown shop... just leave it blank I guess
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
item_data.item_id = l->generate_item_id(c->lobby_client_id);
|
||||||
|
c->player.current_shop_contents.emplace_back(item_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_shop(c, shop_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void process_subcommand_open_bank(shared_ptr<ServerState> s,
|
static void process_subcommand_open_bank(shared_ptr<ServerState> s,
|
||||||
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||||
const PSOSubcommand* p, size_t count) {
|
const PSOSubcommand* p, size_t count) {
|
||||||
@@ -418,7 +447,7 @@ static void process_subcommand_bank_action(shared_ptr<ServerState> s,
|
|||||||
PlayerBankItem bank_item;
|
PlayerBankItem bank_item;
|
||||||
c->player.bank.remove_item(cmd->item_id, cmd->item_amount, &bank_item);
|
c->player.bank.remove_item(cmd->item_id, cmd->item_amount, &bank_item);
|
||||||
PlayerInventoryItem item = bank_item.to_inventory_item();
|
PlayerInventoryItem item = bank_item.to_inventory_item();
|
||||||
item.data.item_id = l->generate_item_id(0xFFFFFFFF);
|
item.data.item_id = l->generate_item_id(0xFF);
|
||||||
c->player.add_item(item);
|
c->player.add_item(item);
|
||||||
send_create_inventory_item(l, c, item.data);
|
send_create_inventory_item(l, c, item.data);
|
||||||
}
|
}
|
||||||
@@ -514,7 +543,7 @@ static void process_subcommand_enemy_drop_item(shared_ptr<ServerState> s,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
item.data = s->common_item_creator->create_item(false, l->episode,
|
item.data = s->common_item_creator->create_drop_item(false, l->episode,
|
||||||
l->difficulty, cmd->area, l->section_id);
|
l->difficulty, cmd->area, l->section_id);
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
// create_common_item throws this when it doesn't want to make an item
|
// create_common_item throws this when it doesn't want to make an item
|
||||||
@@ -522,7 +551,7 @@ static void process_subcommand_enemy_drop_item(shared_ptr<ServerState> s,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item.data.item_id = l->generate_item_id(0xFFFFFFFF);
|
item.data.item_id = l->generate_item_id(0xFF);
|
||||||
|
|
||||||
l->add_item(item);
|
l->add_item(item);
|
||||||
send_drop_item(l, item.data, false, cmd->area, cmd->x, cmd->y,
|
send_drop_item(l, item.data, false, cmd->area, cmd->x, cmd->y,
|
||||||
@@ -586,7 +615,7 @@ static void process_subcommand_box_drop_item(shared_ptr<ServerState> s,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
item.data = s->common_item_creator->create_item(true, l->episode,
|
item.data = s->common_item_creator->create_drop_item(true, l->episode,
|
||||||
l->difficulty, cmd->area, l->section_id);
|
l->difficulty, cmd->area, l->section_id);
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
// create_common_item throws this when it doesn't want to make an item
|
// create_common_item throws this when it doesn't want to make an item
|
||||||
@@ -594,7 +623,7 @@ static void process_subcommand_box_drop_item(shared_ptr<ServerState> s,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item.data.item_id = l->generate_item_id(0xFFFFFFFF);
|
item.data.item_id = l->generate_item_id(0xFF);
|
||||||
|
|
||||||
l->add_item(item);
|
l->add_item(item);
|
||||||
send_drop_item(l, item.data, false, cmd->area, cmd->x, cmd->y,
|
send_drop_item(l, item.data, false, cmd->area, cmd->x, cmd->y,
|
||||||
@@ -1067,7 +1096,7 @@ subcommand_handler_t subcommand_handlers[0x100] = {
|
|||||||
process_subcommand_unimplemented,
|
process_subcommand_unimplemented,
|
||||||
process_subcommand_unimplemented,
|
process_subcommand_unimplemented,
|
||||||
process_subcommand_unimplemented,
|
process_subcommand_unimplemented,
|
||||||
process_subcommand_unimplemented,
|
process_subcommand_open_shop,
|
||||||
process_subcommand_unimplemented,
|
process_subcommand_unimplemented,
|
||||||
process_subcommand_unimplemented,
|
process_subcommand_unimplemented,
|
||||||
process_subcommand_identify_item,
|
process_subcommand_identify_item,
|
||||||
|
|||||||
@@ -1936,6 +1936,37 @@ void send_bank(shared_ptr<Client> c) {
|
|||||||
send_command(c, 0x6C, 0x00, cmd, items);
|
send_command(c, 0x6C, 0x00, cmd, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sends the player a shop's contents
|
||||||
|
void send_shop(shared_ptr<Client> c, uint8_t shop_type) {
|
||||||
|
struct {
|
||||||
|
uint8_t subcommand; // B6
|
||||||
|
uint8_t size; // 2C regardless of the number of items??
|
||||||
|
uint16_t params; // 037F
|
||||||
|
uint8_t shop_type;
|
||||||
|
uint8_t num_items;
|
||||||
|
uint16_t unused;
|
||||||
|
ItemData entries[20];
|
||||||
|
} cmd = {
|
||||||
|
0xB6,
|
||||||
|
0x2C,
|
||||||
|
0x037F,
|
||||||
|
shop_type,
|
||||||
|
static_cast<uint8_t>(c->player.current_shop_contents.size()),
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t count = c->player.current_shop_contents.size();
|
||||||
|
if (count > sizeof(cmd.entries) / sizeof(cmd.entries[0])) {
|
||||||
|
throw logic_error("too many items in shop");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t x = 0; x < count; x++) {
|
||||||
|
cmd.entries[x] = c->player.current_shop_contents[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
send_command(c, 0x6C, 0x00, &cmd, sizeof(cmd) - sizeof(cmd.entries[0]) * (20 - count));
|
||||||
|
}
|
||||||
|
|
||||||
// notifies players about a level up
|
// notifies players about a level up
|
||||||
void send_level_up(shared_ptr<Lobby> l, shared_ptr<Client> c) {
|
void send_level_up(shared_ptr<Lobby> l, shared_ptr<Client> c) {
|
||||||
PlayerStats stats = c->player.disp.stats;
|
PlayerStats stats = c->player.disp.stats;
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ void send_create_inventory_item(std::shared_ptr<Lobby> l, std::shared_ptr<Client
|
|||||||
void send_destroy_item(std::shared_ptr<Lobby> l, std::shared_ptr<Client> c,
|
void send_destroy_item(std::shared_ptr<Lobby> l, std::shared_ptr<Client> c,
|
||||||
uint32_t item_id, uint32_t amount);
|
uint32_t item_id, uint32_t amount);
|
||||||
void send_bank(std::shared_ptr<Client> c);
|
void send_bank(std::shared_ptr<Client> c);
|
||||||
|
void send_shop(std::shared_ptr<Client> c, uint8_t shop_type);
|
||||||
void send_level_up(std::shared_ptr<Lobby> l, std::shared_ptr<Client> c);
|
void send_level_up(std::shared_ptr<Lobby> l, std::shared_ptr<Client> c);
|
||||||
void send_give_experience(std::shared_ptr<Lobby> l, std::shared_ptr<Client> c,
|
void send_give_experience(std::shared_ptr<Lobby> l, std::shared_ptr<Client> c,
|
||||||
uint32_t amount);
|
uint32_t amount);
|
||||||
|
|||||||
Reference in New Issue
Block a user