restrict rare notifs to items generated from ItemRT
This commit is contained in:
+49
-42
@@ -134,46 +134,49 @@ uint8_t ItemCreator::normalize_area_number(uint8_t area) const {
|
||||
}
|
||||
}
|
||||
|
||||
ItemData ItemCreator::on_box_item_drop(uint16_t entity_id, uint8_t area) {
|
||||
ItemCreator::DropResult ItemCreator::on_box_item_drop(uint16_t entity_id, uint8_t area) {
|
||||
return this->destroyed_boxes.count(entity_id)
|
||||
? ItemData()
|
||||
? DropResult()
|
||||
: this->on_box_item_drop_with_area_norm(this->normalize_area_number(area));
|
||||
}
|
||||
|
||||
ItemData ItemCreator::on_monster_item_drop(uint16_t entity_id, uint32_t enemy_type, uint8_t area) {
|
||||
ItemCreator::DropResult ItemCreator::on_monster_item_drop(uint16_t entity_id, uint32_t enemy_type, uint8_t area) {
|
||||
return this->destroyed_monsters.count(entity_id)
|
||||
? ItemData()
|
||||
? DropResult()
|
||||
: this->on_monster_item_drop_with_area_norm(enemy_type, this->normalize_area_number(area));
|
||||
}
|
||||
|
||||
ItemData ItemCreator::on_box_item_drop_with_area_norm(uint8_t area_norm) {
|
||||
ItemCreator::DropResult ItemCreator::on_box_item_drop_with_area_norm(uint8_t area_norm) {
|
||||
this->log.info("Box drop checks for area_norm %02hhX; random state: %08" PRIX32 " %08" PRIX32,
|
||||
area_norm, this->random_crypt.seed(), this->random_crypt.absolute_offset());
|
||||
ItemData item = this->check_rare_specs_and_create_rare_box_item(area_norm);
|
||||
if (item.empty()) {
|
||||
DropResult res;
|
||||
res.item = this->check_rare_specs_and_create_rare_box_item(area_norm);
|
||||
if (!res.item.empty()) {
|
||||
res.is_from_rare_table = true;
|
||||
} else {
|
||||
uint8_t item_class = this->get_rand_from_weighted_tables_2d_vertical(this->pt->box_item_class_prob_table, area_norm);
|
||||
this->log.info("Item class is %02hhX", item_class);
|
||||
switch (item_class) {
|
||||
case 0: // Weapon
|
||||
item.data1[0] = 0;
|
||||
res.item.data1[0] = 0;
|
||||
break;
|
||||
case 1: // Armor
|
||||
item.data1[0] = 1;
|
||||
item.data1[1] = 1;
|
||||
res.item.data1[0] = 1;
|
||||
res.item.data1[1] = 1;
|
||||
break;
|
||||
case 2: // Shield
|
||||
item.data1[0] = 1;
|
||||
item.data1[1] = 2;
|
||||
res.item.data1[0] = 1;
|
||||
res.item.data1[1] = 2;
|
||||
break;
|
||||
case 3: // Unit
|
||||
item.data1[0] = 1;
|
||||
item.data1[1] = 3;
|
||||
res.item.data1[0] = 1;
|
||||
res.item.data1[1] = 3;
|
||||
break;
|
||||
case 4: // Tool
|
||||
item.data1[0] = 3;
|
||||
res.item.data1[0] = 3;
|
||||
break;
|
||||
case 5: // Meseta
|
||||
item.data1[0] = 4;
|
||||
res.item.data1[0] = 4;
|
||||
break;
|
||||
case 6: // Nothing
|
||||
break;
|
||||
@@ -181,16 +184,16 @@ ItemData ItemCreator::on_box_item_drop_with_area_norm(uint8_t area_norm) {
|
||||
throw logic_error("this should be impossible");
|
||||
}
|
||||
if (item_class < 6) {
|
||||
this->generate_common_item_variances(area_norm, item);
|
||||
this->generate_common_item_variances(area_norm, res.item);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
return res;
|
||||
}
|
||||
|
||||
ItemData ItemCreator::on_monster_item_drop_with_area_norm(uint32_t enemy_type, uint8_t area_norm) {
|
||||
ItemCreator::DropResult ItemCreator::on_monster_item_drop_with_area_norm(uint32_t enemy_type, uint8_t area_norm) {
|
||||
if (enemy_type > 0x58) {
|
||||
this->log.warning("Invalid enemy type: %" PRIX32, enemy_type);
|
||||
return ItemData();
|
||||
return DropResult();
|
||||
}
|
||||
this->log.info("Enemy type: %" PRIX32 "; random state: %08" PRIX32 " %08" PRIX32, enemy_type, this->random_crypt.seed(), this->random_crypt.absolute_offset());
|
||||
|
||||
@@ -198,13 +201,16 @@ ItemData ItemCreator::on_monster_item_drop_with_area_norm(uint32_t enemy_type, u
|
||||
uint8_t drop_sample = this->rand_int(100);
|
||||
if (drop_sample >= type_drop_prob) {
|
||||
this->log.info("Drop not chosen (%hhu >= %hhu)", drop_sample, type_drop_prob);
|
||||
return ItemData();
|
||||
return DropResult();
|
||||
} else {
|
||||
this->log.info("Drop chosen (%hhu < %hhu)", drop_sample, type_drop_prob);
|
||||
}
|
||||
|
||||
ItemData item = this->check_rare_spec_and_create_rare_enemy_item(enemy_type, area_norm);
|
||||
if (item.empty()) {
|
||||
DropResult res;
|
||||
res.item = this->check_rare_spec_and_create_rare_enemy_item(enemy_type, area_norm);
|
||||
if (!res.item.empty()) {
|
||||
res.is_from_rare_table = true;
|
||||
} else {
|
||||
uint32_t item_class_determinant =
|
||||
this->should_allow_meseta_drops()
|
||||
? this->rand_int(3)
|
||||
@@ -229,34 +235,34 @@ ItemData ItemCreator::on_monster_item_drop_with_area_norm(uint32_t enemy_type, u
|
||||
|
||||
switch (item_class) {
|
||||
case 0: // Weapon
|
||||
item.data1[0] = 0x00;
|
||||
res.item.data1[0] = 0x00;
|
||||
break;
|
||||
case 1: // Armor
|
||||
item.data1w[0] = 0x0101;
|
||||
res.item.data1w[0] = 0x0101;
|
||||
break;
|
||||
case 2: // Shield
|
||||
item.data1w[0] = 0x0201;
|
||||
res.item.data1w[0] = 0x0201;
|
||||
break;
|
||||
case 3: // Unit
|
||||
item.data1w[0] = 0x0301;
|
||||
res.item.data1w[0] = 0x0301;
|
||||
break;
|
||||
case 4: // Tool
|
||||
item.data1[0] = 0x03;
|
||||
res.item.data1[0] = 0x03;
|
||||
break;
|
||||
case 5: // Meseta
|
||||
item.data1[0] = 0x04;
|
||||
item.data2d = this->choose_meseta_amount(this->pt->enemy_meseta_ranges, enemy_type) & 0xFFFF;
|
||||
res.item.data1[0] = 0x04;
|
||||
res.item.data2d = this->choose_meseta_amount(this->pt->enemy_meseta_ranges, enemy_type) & 0xFFFF;
|
||||
break;
|
||||
default:
|
||||
return item;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (item.data1[0] != 0x04) {
|
||||
this->generate_common_item_variances(area_norm, item);
|
||||
if (res.item.data1[0] != 0x04) {
|
||||
this->generate_common_item_variances(area_norm, res.item);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
return res;
|
||||
}
|
||||
|
||||
ItemData ItemCreator::check_rare_specs_and_create_rare_box_item(uint8_t area_norm) {
|
||||
@@ -1663,20 +1669,21 @@ void ItemCreator::generate_weapon_shop_item_bonus2(ItemData& item, size_t player
|
||||
}
|
||||
}
|
||||
|
||||
ItemData ItemCreator::on_specialized_box_item_drop(
|
||||
ItemCreator::DropResult ItemCreator::on_specialized_box_item_drop(
|
||||
uint16_t entity_id, uint8_t area, float def_z, uint32_t def0, uint32_t def1, uint32_t def2) {
|
||||
if (this->destroyed_boxes.count(entity_id)) {
|
||||
return ItemData();
|
||||
return DropResult();
|
||||
}
|
||||
|
||||
ItemData item = this->base_item_for_specialized_box(def0, def1, def2);
|
||||
DropResult res;
|
||||
res.item = this->base_item_for_specialized_box(def0, def1, def2);
|
||||
if (def_z == 0.0f) {
|
||||
uint16_t type = item.data1w[0];
|
||||
item.clear();
|
||||
item.data1w[0] = type;
|
||||
this->generate_common_item_variances(this->normalize_area_number(area), item);
|
||||
uint16_t type = res.item.data1w[0];
|
||||
res.item.clear();
|
||||
res.item.data1w[0] = type;
|
||||
this->generate_common_item_variances(this->normalize_area_number(area), res.item);
|
||||
}
|
||||
return item;
|
||||
return res;
|
||||
}
|
||||
|
||||
ItemData ItemCreator::base_item_for_specialized_box(uint32_t def0, uint32_t def1, uint32_t def2) {
|
||||
|
||||
+10
-5
@@ -31,9 +31,14 @@ public:
|
||||
void set_random_state(uint32_t seed, uint32_t absolute_offset);
|
||||
void clear_destroyed_entities();
|
||||
|
||||
ItemData on_monster_item_drop(uint16_t entity_id, uint32_t enemy_type, uint8_t area);
|
||||
ItemData on_box_item_drop(uint16_t entity_id, uint8_t area);
|
||||
ItemData on_specialized_box_item_drop(uint16_t entity_id, uint8_t area, float def_z, uint32_t def0, uint32_t def1, uint32_t def2);
|
||||
struct DropResult {
|
||||
ItemData item;
|
||||
bool is_from_rare_table = false;
|
||||
};
|
||||
|
||||
DropResult on_monster_item_drop(uint16_t entity_id, uint32_t enemy_type, uint8_t area);
|
||||
DropResult on_box_item_drop(uint16_t entity_id, uint8_t area);
|
||||
DropResult on_specialized_box_item_drop(uint16_t entity_id, uint8_t area, float def_z, uint32_t def0, uint32_t def1, uint32_t def2);
|
||||
|
||||
void set_monster_destroyed(uint16_t entity_id);
|
||||
void set_box_destroyed(uint16_t entity_id);
|
||||
@@ -87,8 +92,8 @@ private:
|
||||
bool are_rare_drops_allowed() const;
|
||||
uint8_t normalize_area_number(uint8_t area) const;
|
||||
|
||||
ItemData on_monster_item_drop_with_area_norm(uint32_t enemy_type, uint8_t area_norm);
|
||||
ItemData on_box_item_drop_with_area_norm(uint8_t area_norm);
|
||||
DropResult on_monster_item_drop_with_area_norm(uint32_t enemy_type, uint8_t area_norm);
|
||||
DropResult on_box_item_drop_with_area_norm(uint8_t area_norm);
|
||||
|
||||
uint32_t rand_int(uint64_t max);
|
||||
float rand_float_0_1_from_crypt();
|
||||
|
||||
+30
-24
@@ -2113,7 +2113,7 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
cmd.effective_area = in_cmd.floor;
|
||||
}
|
||||
|
||||
auto generate_item = [&]() -> ItemData {
|
||||
auto generate_item = [&]() -> ItemCreator::DropResult {
|
||||
if (cmd.rt_index == 0x30) {
|
||||
if (l->map) {
|
||||
auto& object = l->map->objects.at(cmd.entity_id);
|
||||
@@ -2177,33 +2177,37 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
case Lobby::DropMode::SERVER_DUPLICATE: {
|
||||
// TODO: In SERVER_DUPLICATE mode, should we reduce the rates for rare
|
||||
// items? Maybe by a factor of l->count_clients()?
|
||||
auto item = generate_item();
|
||||
if (item.empty()) {
|
||||
auto res = generate_item();
|
||||
if (res.item.empty()) {
|
||||
l->log.info("No item was created");
|
||||
} else {
|
||||
string name = s->describe_item(l->base_version, item, false);
|
||||
string name = s->describe_item(l->base_version, res.item, false);
|
||||
l->log.info("Entity %04hX (area %02hX) created item %s", cmd.entity_id.load(), cmd.effective_area, name.c_str());
|
||||
if (l->drop_mode == Lobby::DropMode::SERVER_DUPLICATE) {
|
||||
for (const auto& lc : l->clients) {
|
||||
if (lc && ((cmd.rt_index == 0x30) || (lc->floor == cmd.floor))) {
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
res.item.id = l->generate_item_id(0xFF);
|
||||
l->log.info("Creating item %08" PRIX32 " at %02hhX:%g,%g for %s",
|
||||
item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load(), lc->channel.name.c_str());
|
||||
l->add_item(cmd.floor, item, cmd.x, cmd.z, (1 << lc->lobby_client_id));
|
||||
send_drop_item_to_channel(s, lc->channel, item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
|
||||
send_rare_notification_if_needed(lc, item);
|
||||
res.item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load(), lc->channel.name.c_str());
|
||||
l->add_item(cmd.floor, res.item, cmd.x, cmd.z, (1 << lc->lobby_client_id));
|
||||
send_drop_item_to_channel(s, lc->channel, res.item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
|
||||
if (res.is_from_rare_table) {
|
||||
send_rare_notification_if_needed(lc, res.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
res.item.id = l->generate_item_id(0xFF);
|
||||
l->log.info("Creating item %08" PRIX32 " at %02hhX:%g,%g for all clients",
|
||||
item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load());
|
||||
l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F);
|
||||
send_drop_item_to_lobby(l, item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
|
||||
for (auto lc : l->clients) {
|
||||
if (lc) {
|
||||
send_rare_notification_if_needed(lc, item);
|
||||
res.item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load());
|
||||
l->add_item(cmd.floor, res.item, cmd.x, cmd.z, 0x00F);
|
||||
send_drop_item_to_lobby(l, res.item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
|
||||
if (res.is_from_rare_table) {
|
||||
for (auto lc : l->clients) {
|
||||
if (lc) {
|
||||
send_rare_notification_if_needed(lc, res.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2213,18 +2217,20 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
case Lobby::DropMode::SERVER_PRIVATE: {
|
||||
for (const auto& lc : l->clients) {
|
||||
if (lc && ((cmd.rt_index == 0x30) || (lc->floor == cmd.floor))) {
|
||||
auto item = generate_item();
|
||||
if (item.empty()) {
|
||||
auto res = generate_item();
|
||||
if (res.item.empty()) {
|
||||
l->log.info("No item was created for %s", lc->channel.name.c_str());
|
||||
} else {
|
||||
string name = s->describe_item(l->base_version, item, false);
|
||||
string name = s->describe_item(l->base_version, res.item, false);
|
||||
l->log.info("Entity %04hX (area %02hX) created item %s", cmd.entity_id.load(), cmd.effective_area, name.c_str());
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
res.item.id = l->generate_item_id(0xFF);
|
||||
l->log.info("Creating item %08" PRIX32 " at %02hhX:%g,%g for %s",
|
||||
item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load(), lc->channel.name.c_str());
|
||||
l->add_item(cmd.floor, item, cmd.x, cmd.z, (1 << lc->lobby_client_id));
|
||||
send_drop_item_to_channel(s, lc->channel, item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
|
||||
send_rare_notification_if_needed(lc, item);
|
||||
res.item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load(), lc->channel.name.c_str());
|
||||
l->add_item(cmd.floor, res.item, cmd.x, cmd.z, (1 << lc->lobby_client_id));
|
||||
send_drop_item_to_channel(s, lc->channel, res.item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
|
||||
if (res.is_from_rare_table) {
|
||||
send_rare_notification_if_needed(lc, res.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user