make it possible to disable item tracking
This commit is contained in:
+24
-21
@@ -590,28 +590,31 @@ static void command_what(shared_ptr<ServerState>, shared_ptr<Lobby> l,
|
||||
if (!l->episode || (l->episode > 3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float min_dist2 = 0.0f;
|
||||
uint32_t nearest_item_id = 0xFFFFFFFF;
|
||||
for (const auto& it : l->item_id_to_floor_item) {
|
||||
if (it.second.area != c->area) {
|
||||
continue;
|
||||
}
|
||||
float dx = it.second.x - c->x;
|
||||
float dz = it.second.z - c->z;
|
||||
float dist2 = (dx * dx) + (dz * dz);
|
||||
if ((nearest_item_id == 0xFFFFFFFF) || (dist2 < min_dist2)) {
|
||||
nearest_item_id = it.first;
|
||||
min_dist2 = dist2;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest_item_id == 0xFFFFFFFF) {
|
||||
send_text_message(c, u"No items are near you");
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
send_text_message(c, u"$C4Item tracking is off");
|
||||
} else {
|
||||
const auto& item = l->item_id_to_floor_item.at(nearest_item_id);
|
||||
string name = name_for_item(item.inv_item.data, true);
|
||||
send_text_message(c, decode_sjis(name));
|
||||
float min_dist2 = 0.0f;
|
||||
uint32_t nearest_item_id = 0xFFFFFFFF;
|
||||
for (const auto& it : l->item_id_to_floor_item) {
|
||||
if (it.second.area != c->area) {
|
||||
continue;
|
||||
}
|
||||
float dx = it.second.x - c->x;
|
||||
float dz = it.second.z - c->z;
|
||||
float dist2 = (dx * dx) + (dz * dz);
|
||||
if ((nearest_item_id == 0xFFFFFFFF) || (dist2 < min_dist2)) {
|
||||
nearest_item_id = it.first;
|
||||
min_dist2 = dist2;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest_item_id == 0xFFFFFFFF) {
|
||||
send_text_message(c, u"$C4No items are near you");
|
||||
} else {
|
||||
const auto& item = l->item_id_to_floor_item.at(nearest_item_id);
|
||||
string name = name_for_item(item.inv_item.data, true);
|
||||
send_text_message(c, decode_sjis(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -96,8 +96,9 @@ void Lobby::add_client(shared_ptr<Client> c) {
|
||||
}
|
||||
}
|
||||
|
||||
// If the lobby is a game, assign the inventory's item IDs
|
||||
if (this->is_game()) {
|
||||
// If the lobby is a game and item tracking is enabled, assign the inventory's
|
||||
// item IDs
|
||||
if (this->is_game() && (this->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
auto& inv = c->game_data.player()->inventory;
|
||||
size_t count = min<uint8_t>(inv.num_items, 30);
|
||||
for (size_t x = 0; x < count; x++) {
|
||||
|
||||
+13
-8
@@ -18,14 +18,19 @@
|
||||
|
||||
struct Lobby {
|
||||
enum Flag {
|
||||
GAME = 0x01,
|
||||
CHEATS_ENABLED = 0x02, // game only
|
||||
PUBLIC = 0x04, // lobby only
|
||||
EPISODE_3_ONLY = 0x08, // lobby & game
|
||||
QUEST_IN_PROGRESS = 0x10, // game only
|
||||
JOINABLE_QUEST_IN_PROGRESS = 0x20, // game only
|
||||
DEFAULT = 0x40, // lobby only; not set for games and private lobbies
|
||||
PERSISTENT = 0x80, // if not set, lobby is deleted when empty
|
||||
GAME = 0x00000001,
|
||||
EPISODE_3_ONLY = 0x00000002,
|
||||
|
||||
// Flags used only for games
|
||||
CHEATS_ENABLED = 0x00000100,
|
||||
QUEST_IN_PROGRESS = 0x00000200,
|
||||
JOINABLE_QUEST_IN_PROGRESS = 0x00000400,
|
||||
ITEM_TRACKING_ENABLED = 0x00000800,
|
||||
|
||||
// Flags used only for lobbies
|
||||
PUBLIC = 0x00010000,
|
||||
DEFAULT = 0x00020000,
|
||||
PERSISTENT = 0x00040000,
|
||||
};
|
||||
|
||||
uint32_t lobby_id;
|
||||
|
||||
@@ -128,6 +128,12 @@ void populate_state_from_config(shared_ptr<ServerState> s,
|
||||
s->allow_unregistered_users = true;
|
||||
}
|
||||
|
||||
try {
|
||||
s->item_tracking_enabled = d.at("EnableItemTracking")->as_bool();
|
||||
} catch (const out_of_range&) {
|
||||
s->item_tracking_enabled = true;
|
||||
}
|
||||
|
||||
for (const string& filename : list_directory("system/blueburst/keys")) {
|
||||
if (!ends_with(filename, ".nsk")) {
|
||||
continue;
|
||||
|
||||
@@ -1767,6 +1767,8 @@ shared_ptr<Lobby> create_game_generic(shared_ptr<ServerState> s,
|
||||
throw invalid_argument("level too low for difficulty");
|
||||
}
|
||||
|
||||
bool item_tracking_enabled = (c->version == GameVersion::BB) | s->item_tracking_enabled;
|
||||
|
||||
shared_ptr<Lobby> game(new Lobby());
|
||||
game->name = name;
|
||||
game->password = password;
|
||||
@@ -1787,7 +1789,10 @@ shared_ptr<Lobby> create_game_generic(shared_ptr<ServerState> s,
|
||||
game->event = Lobby::game_event_for_lobby_event(current_lobby->event);
|
||||
game->block = 0xFF;
|
||||
game->max_clients = 4;
|
||||
game->flags = (is_ep3 ? Lobby::Flag::EPISODE_3_ONLY : 0) | Lobby::Flag::GAME;
|
||||
game->flags =
|
||||
(is_ep3 ? Lobby::Flag::EPISODE_3_ONLY : 0) |
|
||||
(item_tracking_enabled ? Lobby::Flag::ITEM_TRACKING_ENABLED : 0) |
|
||||
Lobby::Flag::GAME;
|
||||
game->min_level = min_level;
|
||||
game->max_level = 0xFFFFFFFF;
|
||||
|
||||
|
||||
+104
-53
@@ -273,12 +273,14 @@ static void process_subcommand_player_drop_item(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
l->add_item(c->game_data.player()->remove_item(cmd->item_id, 0),
|
||||
cmd->area, cmd->x, cmd->z);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
l->add_item(c->game_data.player()->remove_item(cmd->item_id, 0),
|
||||
cmd->area, cmd->x, cmd->z);
|
||||
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu dropped item %08" PRIX32 " at %hu:(%g, %g)",
|
||||
l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu dropped item %08" PRIX32 " at %hu:(%g, %g)",
|
||||
l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
}
|
||||
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
@@ -297,16 +299,18 @@ static void process_subcommand_create_inventory_item(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInventoryItem item;
|
||||
item.equip_flags = 0; // TODO: Use the right default flags here
|
||||
item.tech_flag = 0;
|
||||
item.game_flags = 0;
|
||||
item.data = cmd->item;
|
||||
c->game_data.player()->add_item(item);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
PlayerInventoryItem item;
|
||||
item.equip_flags = 0; // TODO: Use the right default flags here
|
||||
item.tech_flag = 0;
|
||||
item.game_flags = 0;
|
||||
item.data = cmd->item;
|
||||
c->game_data.player()->add_item(item);
|
||||
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu created inventory item %08" PRIX32,
|
||||
l->lobby_id, cmd->client_id, cmd->item.id.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu created inventory item %08" PRIX32,
|
||||
l->lobby_id, cmd->client_id, cmd->item.id.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
}
|
||||
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
@@ -324,18 +328,20 @@ static void process_subcommand_drop_partial_stack(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Should we delete anything from the inventory here? Does the client
|
||||
// send an appropriate 6x29 alongside this?
|
||||
PlayerInventoryItem item;
|
||||
item.equip_flags = 0; // TODO: Use the right default flags here
|
||||
item.tech_flag = 0;
|
||||
item.game_flags = 0;
|
||||
item.data = cmd->data;
|
||||
l->add_item(item, cmd->area, cmd->x, cmd->z);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
// TODO: Should we delete anything from the inventory here? Does the client
|
||||
// send an appropriate 6x29 alongside this?
|
||||
PlayerInventoryItem item;
|
||||
item.equip_flags = 0; // TODO: Use the right default flags here
|
||||
item.tech_flag = 0;
|
||||
item.game_flags = 0;
|
||||
item.data = cmd->data;
|
||||
l->add_item(item, cmd->area, cmd->x, cmd->z);
|
||||
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu split stack to create ground item %08" PRIX32 " at %hu:(%g, %g)",
|
||||
l->lobby_id, cmd->client_id, item.data.id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu split stack to create ground item %08" PRIX32 " at %hu:(%g, %g)",
|
||||
l->lobby_id, cmd->client_id, item.data.id.load(), cmd->area.load(), cmd->x.load(), cmd->z.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
}
|
||||
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
@@ -350,6 +356,10 @@ static void process_subcommand_drop_partial_stack_bb(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
auto item = c->game_data.player()->remove_item(cmd->item_id, cmd->amount);
|
||||
|
||||
// if a stack was split, the original item still exists, so the dropped item
|
||||
@@ -389,16 +399,18 @@ static void process_subcommand_buy_shop_item(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInventoryItem item;
|
||||
item.equip_flags = 0; // TODO: Use the right default flags here
|
||||
item.tech_flag = 0;
|
||||
item.game_flags = 0;
|
||||
item.data = cmd->item;
|
||||
c->game_data.player()->add_item(item);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
PlayerInventoryItem item;
|
||||
item.equip_flags = 0; // TODO: Use the right default flags here
|
||||
item.tech_flag = 0;
|
||||
item.game_flags = 0;
|
||||
item.data = cmd->item;
|
||||
c->game_data.player()->add_item(item);
|
||||
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu bought item %08" PRIX32 " from shop",
|
||||
l->lobby_id, cmd->client_id, item.data.id.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hhu bought item %08" PRIX32 " from shop",
|
||||
l->lobby_id, cmd->client_id, item.data.id.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
}
|
||||
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
@@ -447,10 +459,12 @@ static void process_subcommand_pick_up_item(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
effective_c->game_data.player()->add_item(l->remove_item(cmd->item_id));
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hu picked up %08" PRIX32,
|
||||
l->lobby_id, cmd->client_id.load(), cmd->item_id.load());
|
||||
effective_c->game_data.player()->print_inventory(stderr);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
effective_c->game_data.player()->add_item(l->remove_item(cmd->item_id));
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player %hu picked up %08" PRIX32,
|
||||
l->lobby_id, cmd->client_id.load(), cmd->item_id.load());
|
||||
effective_c->game_data.player()->print_inventory(stderr);
|
||||
}
|
||||
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
@@ -466,6 +480,10 @@ static void process_subcommand_pick_up_item_request(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
c->game_data.player()->add_item(l->remove_item(cmd->item_id));
|
||||
|
||||
log(INFO, "[Items/%08" PRIX32 "/BB] Player %hhu picked up %08" PRIX32,
|
||||
@@ -482,7 +500,7 @@ static void process_subcommand_pick_up_item_request(shared_ptr<ServerState>,
|
||||
static void process_subcommand_equip_unequip_item(shared_ptr<ServerState>,
|
||||
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||
const string& data) {
|
||||
// We don't track equip state on non-BB versions
|
||||
// TODO: We should track equip state on non-BB versions
|
||||
if (l->version == GameVersion::BB) {
|
||||
const auto* cmd = check_size_sc<G_ItemSubcommand>(data);
|
||||
|
||||
@@ -490,6 +508,10 @@ static void process_subcommand_equip_unequip_item(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
size_t index = c->game_data.player()->inventory.find_item(cmd->item_id);
|
||||
if (cmd->command == 0x25) {
|
||||
c->game_data.player()->inventory.items[index].game_flags |= 0x00000008; // equip
|
||||
@@ -511,12 +533,14 @@ static void process_subcommand_use_item(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
size_t index = c->game_data.player()->inventory.find_item(cmd->item_id);
|
||||
player_use_item(c, index);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
size_t index = c->game_data.player()->inventory.find_item(cmd->item_id);
|
||||
player_use_item(c, index);
|
||||
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player used item %hhu:%08" PRIX32,
|
||||
l->lobby_id, cmd->client_id, cmd->item_id.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Player used item %hhu:%08" PRIX32,
|
||||
l->lobby_id, cmd->client_id, cmd->item_id.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
}
|
||||
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
@@ -572,6 +596,10 @@ static void process_subcommand_bank_action_bb(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
if (cmd->action == 0) { // deposit
|
||||
if (cmd->item_id == 0xFFFFFFFF) { // meseta
|
||||
if (cmd->meseta_amount > c->game_data.player()->disp.meseta) {
|
||||
@@ -615,6 +643,10 @@ static void process_subcommand_sort_inventory_bb(shared_ptr<ServerState>,
|
||||
if (l->version == GameVersion::BB) {
|
||||
const auto* cmd = check_size_sc<G_SortInventory_6xC4>(data);
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
PlayerInventory sorted;
|
||||
|
||||
for (size_t x = 0; x < 30; x++) {
|
||||
@@ -647,6 +679,10 @@ static void process_subcommand_enemy_drop_item_request(shared_ptr<ServerState> s
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
PlayerInventoryItem item;
|
||||
|
||||
// TODO: Deduplicate this code with the box drop item request handler
|
||||
@@ -701,6 +737,10 @@ static void process_subcommand_box_drop_item_request(shared_ptr<ServerState> s,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
PlayerInventoryItem item;
|
||||
|
||||
bool is_rare = false;
|
||||
@@ -891,11 +931,13 @@ static void process_subcommand_destroy_inventory_item(shared_ptr<ServerState>,
|
||||
if (cmd->client_id != c->lobby_client_id) {
|
||||
return;
|
||||
}
|
||||
c->game_data.player()->remove_item(cmd->item_id, cmd->amount);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Inventory item %hhu:%08" PRIX32 " destroyed (%" PRIX32 " of them)",
|
||||
l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->amount.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
c->game_data.player()->remove_item(cmd->item_id, cmd->amount);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Inventory item %hhu:%08" PRIX32 " destroyed (%" PRIX32 " of them)",
|
||||
l->lobby_id, cmd->client_id, cmd->item_id.load(), cmd->amount.load());
|
||||
c->game_data.player()->print_inventory(stderr);
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_subcommand_destroy_ground_item(shared_ptr<ServerState>,
|
||||
@@ -905,10 +947,12 @@ static void process_subcommand_destroy_ground_item(shared_ptr<ServerState>,
|
||||
if (!l->is_game()) {
|
||||
return;
|
||||
}
|
||||
l->remove_item(cmd->item_id);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Ground item %08" PRIX32 " destroyed (%" PRIX32 " of them)",
|
||||
l->lobby_id, cmd->item_id.load(), cmd->amount.load());
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) {
|
||||
l->remove_item(cmd->item_id);
|
||||
log(INFO, "[Items/%08" PRIX32 "] Ground item %08" PRIX32 " destroyed (%" PRIX32 " of them)",
|
||||
l->lobby_id, cmd->item_id.load(), cmd->amount.load());
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_subcommand_identify_item_bb(shared_ptr<ServerState>,
|
||||
@@ -920,6 +964,10 @@ static void process_subcommand_identify_item_bb(shared_ptr<ServerState>,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw logic_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
size_t x = c->game_data.player()->inventory.find_item(cmd->item_id);
|
||||
if (c->game_data.player()->inventory.items[x].data.data1[0] != 0) {
|
||||
return; // only weapons can be identified
|
||||
@@ -956,6 +1004,9 @@ static void process_subcommand_identify_item_bb(shared_ptr<ServerState>,
|
||||
// if (cmd->client_id != c->lobby_client_id) {
|
||||
// return;
|
||||
// }
|
||||
// if (!(l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
// throw logic_error("item tracking not enabled in BB game");
|
||||
// }
|
||||
//
|
||||
// size_t x = c->game_data.player()->inventory.find_item(cmd->item_id);
|
||||
// c->game_data.player()->inventory.items[x] = c->game_data.player()->identify_result;
|
||||
|
||||
@@ -18,6 +18,7 @@ ServerState::ServerState()
|
||||
: dns_server_port(0),
|
||||
ip_stack_debug(false),
|
||||
allow_unregistered_users(false),
|
||||
item_tracking_enabled(true),
|
||||
run_shell_behavior(RunShellBehavior::DEFAULT), next_lobby_id(1),
|
||||
pre_lobby_event(0),
|
||||
ep3_menu_song(-1) {
|
||||
|
||||
@@ -46,6 +46,7 @@ struct ServerState {
|
||||
std::vector<std::string> ip_stack_addresses;
|
||||
bool ip_stack_debug;
|
||||
bool allow_unregistered_users;
|
||||
bool item_tracking_enabled;
|
||||
RunShellBehavior run_shell_behavior;
|
||||
std::vector<std::shared_ptr<const PSOBBEncryption::KeyFile>> bb_private_keys;
|
||||
std::shared_ptr<const FunctionCodeIndex> function_code_index;
|
||||
|
||||
@@ -1468,6 +1468,8 @@ string name_for_item(const ItemData& item, bool include_color_codes) {
|
||||
|
||||
// For weapons, specials appear before the weapon name
|
||||
if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00)) {
|
||||
// 0x80 is the unidentified flag, but we always return the identified name
|
||||
// of the item here, so we ignore it
|
||||
bool is_present = item.data1[4] & 0x40;
|
||||
uint8_t special_id = item.data1[4] & 0x3F;
|
||||
if (is_present) {
|
||||
|
||||
@@ -128,6 +128,14 @@
|
||||
// BB users.
|
||||
"WelcomeMessage": "",
|
||||
|
||||
// By default, the server keeps track of items in all games, even for versions
|
||||
// other than Blue Burst. This enables use of the $what command, as well as
|
||||
// protection against item duplication cheats (the cheater is disconnected
|
||||
// instead of the other players). If item tracking causes any issues, it can
|
||||
// be turned off here. This option has no effect on Blue Burst games - item
|
||||
// tracking is always enabled for them.
|
||||
"EnableItemTracking": true,
|
||||
|
||||
// Item drop rates for non-rare items in BB games. For each type (boxes or
|
||||
// enemies), all the categories must add up to a number less than 0x100000000.
|
||||
// Each number is a probability (out of 0x100000000) that the given item type
|
||||
|
||||
Reference in New Issue
Block a user