implement server drop tables
This commit is contained in:
@@ -1236,6 +1236,21 @@ static void server_command_drop(shared_ptr<Client> c, const std::u16string&) {
|
||||
send_text_message_printf(l, "Drops %s", (l->flags & Lobby::Flag::DROPS_ENABLED) ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
static void server_command_raretable(shared_ptr<Client> c, const std::u16string&) {
|
||||
auto l = c->require_lobby();
|
||||
check_is_game(l, true);
|
||||
check_is_leader(l, c);
|
||||
if (l->base_version == GameVersion::BB) {
|
||||
send_text_message_printf(c, "Cannot use client\nrare table on BB");
|
||||
} else if (l->item_creator) {
|
||||
l->item_creator.reset();
|
||||
send_text_message_printf(l, "Game switched to\nclient rare tables");
|
||||
} else {
|
||||
l->create_item_creator();
|
||||
send_text_message_printf(l, "Game switched to\nserver rare tables");
|
||||
}
|
||||
}
|
||||
|
||||
static void server_command_item(shared_ptr<Client> c, const std::u16string& args) {
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
@@ -1566,6 +1581,7 @@ static const unordered_map<u16string, ChatCommandDefinition> chat_commands({
|
||||
{u"$persist", {server_command_persist, nullptr}},
|
||||
{u"$playrec", {server_command_playrec, nullptr}},
|
||||
{u"$rand", {server_command_rand, proxy_command_rand}},
|
||||
{u"$raretable", {server_command_raretable, nullptr}},
|
||||
{u"$saverec", {server_command_saverec, nullptr}},
|
||||
{u"$sc", {server_command_send_client, proxy_command_send_client}},
|
||||
{u"$secid", {server_command_secid, proxy_command_secid}},
|
||||
|
||||
@@ -87,6 +87,7 @@ Client::Client(
|
||||
card_battle_table_seat_state(0),
|
||||
next_exp_value(0),
|
||||
can_chat(true),
|
||||
use_server_rare_tables(false),
|
||||
pending_bb_save_player_index(0),
|
||||
dol_base_addr(0) {
|
||||
this->last_switch_enabled_command.header.subcommand = 0;
|
||||
|
||||
@@ -172,6 +172,7 @@ struct Client : public std::enable_shared_from_this<Client> {
|
||||
uint32_t next_exp_value; // next EXP value to give
|
||||
G_SwitchStateChanged_6x05 last_switch_enabled_command;
|
||||
bool can_chat;
|
||||
bool use_server_rare_tables;
|
||||
std::string pending_bb_save_username;
|
||||
uint8_t pending_bb_save_player_index;
|
||||
std::deque<std::function<void(uint32_t, uint32_t)>> function_call_response_queue;
|
||||
|
||||
@@ -43,6 +43,33 @@ shared_ptr<ServerState> Lobby::require_server_state() const {
|
||||
return s;
|
||||
}
|
||||
|
||||
void Lobby::create_item_creator() {
|
||||
auto s = this->require_server_state();
|
||||
|
||||
shared_ptr<const RareItemSet> rare_item_set;
|
||||
if (this->base_version == GameVersion::BB) {
|
||||
rare_item_set = s->rare_item_sets.at("default-v4");
|
||||
} else if (this->base_version == GameVersion::GC || this->base_version == GameVersion::XB) {
|
||||
rare_item_set = s->rare_item_sets.at("default-v3");
|
||||
} else {
|
||||
// TODO: SHould there be a separate table for V1 eventually?
|
||||
rare_item_set = s->rare_item_sets.at("default-v2");
|
||||
}
|
||||
this->item_creator.reset(new ItemCreator(
|
||||
s->common_item_set,
|
||||
rare_item_set,
|
||||
s->armor_random_set,
|
||||
s->tool_random_set,
|
||||
s->weapon_random_sets.at(this->difficulty),
|
||||
s->tekker_adjustment_set,
|
||||
s->item_parameter_table,
|
||||
this->episode,
|
||||
(this->mode == GameMode::SOLO) ? GameMode::NORMAL : this->mode,
|
||||
this->difficulty,
|
||||
this->section_id,
|
||||
this->random_seed));
|
||||
}
|
||||
|
||||
void Lobby::create_ep3_server() {
|
||||
auto s = this->require_server_state();
|
||||
if (!this->ep3_server) {
|
||||
|
||||
+2
-1
@@ -18,7 +18,6 @@
|
||||
#include "Map.hh"
|
||||
#include "Player.hh"
|
||||
#include "Quest.hh"
|
||||
#include "RareItemSet.hh"
|
||||
#include "StaticGameData.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
@@ -40,6 +39,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
START_BATTLE_PLAYER_IMMEDIATELY = 0x00008000,
|
||||
DROPS_ENABLED = 0x00010000, // Does not affect BB
|
||||
IS_EP3_TRIAL = 0x00020000,
|
||||
USE_SERVER_RARE_TABLE = 0x00040000, // Does not affect BB
|
||||
|
||||
// Flags used only for lobbies
|
||||
PUBLIC = 0x01000000,
|
||||
@@ -124,6 +124,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
Lobby& operator=(Lobby&&) = delete;
|
||||
|
||||
std::shared_ptr<ServerState> require_server_state() const;
|
||||
void create_item_creator();
|
||||
void create_ep3_server();
|
||||
|
||||
inline bool is_game() const {
|
||||
|
||||
+3
-15
@@ -3349,21 +3349,9 @@ shared_ptr<Lobby> create_game_generic(
|
||||
game->battle_player = battle_player;
|
||||
battle_player->set_lobby(game);
|
||||
}
|
||||
if (game->base_version == GameVersion::BB) {
|
||||
if ((game->base_version == GameVersion::BB) || (c->use_server_rare_tables)) {
|
||||
// TODO: Use appropriate restrictions here if in battle mode
|
||||
game->item_creator.reset(new ItemCreator(
|
||||
s->common_item_set,
|
||||
s->rare_item_set,
|
||||
s->armor_random_set,
|
||||
s->tool_random_set,
|
||||
s->weapon_random_sets.at(game->difficulty),
|
||||
s->tekker_adjustment_set,
|
||||
s->item_parameter_table,
|
||||
game->episode,
|
||||
(game->mode == GameMode::SOLO) ? GameMode::NORMAL : game->mode,
|
||||
game->difficulty,
|
||||
game->section_id,
|
||||
game->random_seed));
|
||||
game->create_item_creator();
|
||||
}
|
||||
game->event = Lobby::game_event_for_lobby_event(current_lobby->event);
|
||||
game->block = 0xFF;
|
||||
@@ -3461,7 +3449,7 @@ static void on_0C_C1_E7_EC(shared_ptr<Client> c, uint16_t command, uint32_t, con
|
||||
const auto& cmd = check_size_t<C_CreateGame_DCNTE<char>>(data);
|
||||
u16string name = decode_sjis(cmd.name);
|
||||
u16string password = decode_sjis(cmd.password);
|
||||
game = create_game_generic(s, c, name, password);
|
||||
game = create_game_generic(s, c, name, password, Episode::EP1, GameMode::NORMAL, 0, 0, true);
|
||||
|
||||
} else {
|
||||
const auto& cmd = check_size_t<C_CreateGame_DC_V3_0C_C1_Ep3_EC>(data);
|
||||
|
||||
+11
-16
@@ -1185,9 +1185,9 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
return;
|
||||
}
|
||||
|
||||
// If the game is not BB, forward the request to the leader (if drops are
|
||||
// enabled, or just ignore it) instead of generating the item drop command
|
||||
if (l->base_version != GameVersion::BB) {
|
||||
// If there is no item creator (that is, the game is BB or has server rare
|
||||
// tables disabled), then forward the request to the leader
|
||||
if (!l->item_creator) {
|
||||
if (l->flags & Lobby::Flag::DROPS_ENABLED) {
|
||||
forward_subcommand(c, command, flag, data, size);
|
||||
}
|
||||
@@ -1208,10 +1208,6 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
cmd.ignore_def = true;
|
||||
}
|
||||
|
||||
if (!l->item_creator.get()) {
|
||||
throw runtime_error("received box drop subcommand without item creator present");
|
||||
}
|
||||
|
||||
ItemData item;
|
||||
if (cmd.rt_index == 0x30) {
|
||||
if (cmd.ignore_def) {
|
||||
@@ -1220,16 +1216,15 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
item = l->item_creator->on_specialized_box_item_drop(cmd.def[0], cmd.def[1], cmd.def[2]);
|
||||
}
|
||||
} else {
|
||||
if (!l->map) {
|
||||
throw runtime_error("game does not have a map loaded");
|
||||
if (l->map) {
|
||||
const auto& enemy = l->map->enemies.at(cmd.entity_id);
|
||||
uint32_t expected_rt_index = rare_table_index_for_enemy_type(enemy.type);
|
||||
if (cmd.rt_index != expected_rt_index) {
|
||||
c->log.warning("rt_index %02hhX from command does not match entity\'s expected index %02" PRIX32,
|
||||
cmd.rt_index, expected_rt_index);
|
||||
}
|
||||
}
|
||||
const auto& enemy = l->map->enemies.at(cmd.entity_id);
|
||||
uint32_t expected_rt_index = rare_table_index_for_enemy_type(enemy.type);
|
||||
if (cmd.rt_index != expected_rt_index) {
|
||||
c->log.warning("rt_index %02hhX from command does not match entity\'s expected index %02" PRIX32,
|
||||
cmd.rt_index, expected_rt_index);
|
||||
}
|
||||
item = l->item_creator->on_monster_item_drop(expected_rt_index, cmd.area);
|
||||
item = l->item_creator->on_monster_item_drop(cmd.rt_index, cmd.area);
|
||||
}
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
|
||||
|
||||
+35
-9
@@ -861,15 +861,41 @@ void ServerState::load_level_table() {
|
||||
}
|
||||
|
||||
void ServerState::load_item_tables() {
|
||||
try {
|
||||
config_log.info("Loading JSON rare item table");
|
||||
auto json = JSON::parse(load_file("system/blueburst/rare-table.json"));
|
||||
this->rare_item_set.reset(new JSONRareItemSet(json));
|
||||
} catch (const exception& e) {
|
||||
config_log.info("Failed to load JSON rare item table: %s", e.what());
|
||||
config_log.info("Loading REL rare item table");
|
||||
this->rare_item_set.reset(new RELRareItemSet(
|
||||
this->load_bb_file("ItemRT.rel")));
|
||||
config_log.info("Loading rare item sets");
|
||||
for (const auto& filename : list_directory_sorted("system/rare-tables")) {
|
||||
string path = "system/rare-tables/" + filename;
|
||||
size_t ext_offset = filename.rfind('.');
|
||||
string basename = (ext_offset == string::npos) ? filename : filename.substr(0, ext_offset);
|
||||
|
||||
if (ends_with(filename, ".json")) {
|
||||
config_log.info("Loading JSON rare item table %s", filename.c_str());
|
||||
this->rare_item_sets.emplace(basename, new JSONRareItemSet(JSON::parse(load_file(path))));
|
||||
|
||||
} else if (ends_with(filename, ".afs")) {
|
||||
config_log.info("Loading AFS rare item table %s", filename.c_str());
|
||||
shared_ptr<string> data(new string(load_file(path)));
|
||||
this->rare_item_sets.emplace(basename, new AFSRareItemSet(data));
|
||||
|
||||
} else if (ends_with(filename, ".gsl")) {
|
||||
config_log.info("Loading GSL rare item table %s", filename.c_str());
|
||||
shared_ptr<string> data(new string(load_file(path)));
|
||||
this->rare_item_sets.emplace(basename, new GSLRareItemSet(data, false));
|
||||
|
||||
} else if (ends_with(filename, ".gslb")) {
|
||||
config_log.info("Loading GSL rare item table %s", filename.c_str());
|
||||
shared_ptr<string> data(new string(load_file(path)));
|
||||
this->rare_item_sets.emplace(basename, new GSLRareItemSet(data, true));
|
||||
|
||||
} else if (ends_with(filename, ".reg")) {
|
||||
config_log.info("Loading REL rare item table %s", filename.c_str());
|
||||
shared_ptr<string> data(new string(load_file(path)));
|
||||
this->rare_item_sets.emplace(basename, new RELRareItemSet(data));
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->rare_item_sets.count("default-v4")) {
|
||||
config_log.info("default-v4 rare item set is not available; loading from BB data");
|
||||
this->rare_item_sets.emplace("default-v4", new RELRareItemSet(this->load_bb_file("ItemRT.rel")));
|
||||
}
|
||||
|
||||
// Note: These files don't exist in BB, so we use the GC versions of them
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::shared_ptr<const LevelTable> level_table;
|
||||
std::shared_ptr<const BattleParamsIndex> battle_params;
|
||||
std::shared_ptr<const GSLArchive> bb_data_gsl;
|
||||
std::shared_ptr<const RareItemSet> rare_item_set;
|
||||
std::unordered_map<std::string, std::shared_ptr<const RareItemSet>> rare_item_sets;
|
||||
std::shared_ptr<const CommonItemSet> common_item_set;
|
||||
std::shared_ptr<const ArmorRandomSet> armor_random_set;
|
||||
std::shared_ptr<const ToolRandomSet> tool_random_set;
|
||||
|
||||
Reference in New Issue
Block a user