diff --git a/src/Map.cc b/src/Map.cc index a464883d..9c2aefbc 100644 --- a/src/Map.cc +++ b/src/Map.cc @@ -6307,6 +6307,32 @@ uint16_t MapState::index_for_event_state(Version version, shared_ptrfloor_config(ev_st->super_ev->floor).base_indexes_for_version(version).base_event_index); } +shared_ptr MapState::object_state_for_index(Version version, uint16_t object_index) { + size_t dynamic_obj_base_index = this->dynamic_obj_base_index_for_version.at(static_cast(version)); + if (object_index < dynamic_obj_base_index) { + int8_t floor; + for (floor = this->floor_config_entries.size() - 1; floor >= 0; floor--) { + const auto& fc = this->floor_config_entries[floor]; + size_t base_object_index = fc.base_indexes_for_version(version).base_object_index; + if (object_index >= base_object_index) { + if (!fc.super_map) { + throw out_of_range("there are no objects on the specified floor"); + } + const auto& obj = fc.super_map->version(version).objects.at(object_index - base_object_index); + return this->object_states.at(fc.base_super_ids.base_object_index + obj->super_id); + } + } + throw out_of_range("the specified enemy does not exist"); + + } else { + size_t k_id_delta = object_index - dynamic_obj_base_index; + auto obj_st = make_shared(); + obj_st->k_id = this->dynamic_obj_base_k_id + k_id_delta; + obj_st->super_obj = nullptr; + return obj_st; + } +} + shared_ptr MapState::object_state_for_index(Version version, uint8_t floor, uint16_t object_index) { size_t dynamic_obj_base_index = this->dynamic_obj_base_index_for_version.at(static_cast(version)); if (object_index < dynamic_obj_base_index) { @@ -6354,6 +6380,22 @@ vector> MapState::door_states_for_switch_flag( return ret; } +shared_ptr MapState::enemy_state_for_index(Version version, uint16_t enemy_index) { + int8_t floor; + for (floor = this->floor_config_entries.size() - 1; floor >= 0; floor--) { + const auto& fc = this->floor_config_entries[floor]; + size_t base_enemy_index = fc.base_indexes_for_version(version).base_enemy_index; + if (enemy_index >= base_enemy_index) { + if (!fc.super_map) { + throw out_of_range("there are no enemies on the specified floor"); + } + const auto& ene = fc.super_map->version(version).enemies.at(enemy_index - base_enemy_index); + return this->enemy_states.at(fc.base_super_ids.base_enemy_index + ene->super_id); + } + } + throw out_of_range("the specified enemy does not exist"); +} + shared_ptr MapState::enemy_state_for_index(Version version, uint8_t floor, uint16_t enemy_index) { const auto& fc = this->floor_config(floor); size_t base_enemy_index = fc.base_indexes_for_version(version).base_enemy_index; diff --git a/src/Map.hh b/src/Map.hh index d7a7e4c5..a749c060 100644 --- a/src/Map.hh +++ b/src/Map.hh @@ -945,12 +945,14 @@ public: uint16_t set_index_for_enemy_state(Version version, std::shared_ptr ene_st) const; uint16_t index_for_event_state(Version version, std::shared_ptr evt_st) const; + std::shared_ptr object_state_for_index(Version version, uint16_t object_index); std::shared_ptr object_state_for_index(Version version, uint8_t floor, uint16_t object_index); std::vector> object_states_for_floor_room_group( Version version, uint8_t floor, uint16_t room, uint16_t group); std::vector> door_states_for_switch_flag( Version version, uint8_t floor, uint8_t switch_flag); + std::shared_ptr enemy_state_for_index(Version version, uint16_t enemy_index); std::shared_ptr enemy_state_for_index(Version version, uint8_t floor, uint16_t enemy_index); std::shared_ptr enemy_state_for_set_index(Version version, uint8_t floor, uint16_t enemy_set_index); std::shared_ptr enemy_state_for_floor_type(Version version, uint8_t floor, EnemyType type); diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 73667b95..acb1b625 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -1005,7 +1005,7 @@ static asio::awaitable S_6x(shared_ptr c, Channel::Messag if (c->proxy_session->map_state) { shared_ptr obj_st; try { - obj_st = c->proxy_session->map_state->object_state_for_index(c->version(), c->floor, cmd.header.entity_id - 0x4000); + obj_st = c->proxy_session->map_state->object_state_for_index(c->version(), cmd.header.entity_id - 0x4000); } catch (const exception& e) { c->log.warning_f("Invalid object reference ({})", e.what()); } diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 99e42d09..7aa5e145 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -381,9 +381,9 @@ asio::awaitable forward_subcommand_with_entity_id_transcode_t(shared_ptr ene_st; shared_ptr obj_st; if ((cmd_entity_id >= 0x1000) && (cmd_entity_id < 0x4000)) { - ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd_entity_id - 0x1000); + ene_st = l->map_state->enemy_state_for_index(c->version(), cmd_entity_id - 0x1000); } else if ((cmd_entity_id >= 0x4000) && (cmd_entity_id < 0xFFFF)) { - obj_st = l->map_state->object_state_for_index(c->version(), c->floor, cmd_entity_id - 0x4000); + obj_st = l->map_state->object_state_for_index(c->version(), cmd_entity_id - 0x4000); } for (auto& lc : l->clients) { @@ -446,9 +446,9 @@ asio::awaitable forward_subcommand_with_entity_targets_transcode_t(shared_ for (size_t z = 0; z < header.target_count; z++) { auto& res = resolutions.emplace_back(TargetResolution{nullptr, nullptr, targets[z].entity_id}); if ((res.entity_id >= 0x1000) && (res.entity_id < 0x4000)) { - res.ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, res.entity_id - 0x1000); + res.ene_st = l->map_state->enemy_state_for_index(c->version(), res.entity_id - 0x1000); } else if ((res.entity_id >= 0x4000) && (res.entity_id < 0xFFFF)) { - res.obj_st = l->map_state->object_state_for_index(c->version(), c->floor, res.entity_id - 0x4000); + res.obj_st = l->map_state->object_state_for_index(c->version(), res.entity_id - 0x4000); } } @@ -3451,7 +3451,7 @@ static asio::awaitable on_update_enemy_state(shared_ptr c, Subcomm if ((cmd.enemy_index & 0xF000) || (cmd.header.entity_id != (cmd.enemy_index | 0x1000))) { throw runtime_error("mismatched enemy id/index"); } - auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.enemy_index); + auto ene_st = l->map_state->enemy_state_for_index(c->version(), cmd.enemy_index); uint32_t src_flags = is_big_endian(c->version()) ? bswap32(cmd.game_flags) : cmd.game_flags.load(); if (l->difficulty == Difficulty::ULTIMATE) { src_flags = (src_flags & 0xFFFFFFC0) | (ene_st->game_flags & 0x0000003F); @@ -3493,7 +3493,7 @@ static asio::awaitable on_incr_enemy_damage(shared_ptr c, Subcomma if (cmd.header.entity_id < 0x1000 || cmd.header.entity_id >= 0x4000) { throw runtime_error("6xE4 received for non-enemy entity"); } - auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id & 0x0FFF); + auto ene_st = l->map_state->enemy_state_for_index(c->version(), cmd.header.entity_id & 0x0FFF); c->log.info_f("E-{:03X} damage incremented by {} with factor {}; before hit, damage was {} (cmd) or {} (ene_st) and HP was {}/{}", ene_st->e_id, @@ -3523,7 +3523,7 @@ static asio::awaitable on_set_enemy_low_game_flags_ultimate(shared_ptrmap_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id - 0x1000); + auto ene_st = l->map_state->enemy_state_for_index(c->version(), cmd.header.entity_id - 0x1000); if (!(ene_st->game_flags & cmd.low_game_flags)) { ene_st->game_flags |= cmd.low_game_flags; l->log.info_f("E-{:03X} updated to game_flags={:08X}", ene_st->e_id, ene_st->game_flags); @@ -3544,7 +3544,7 @@ static asio::awaitable on_update_object_state_t(shared_ptr c, Subc co_return; } - auto obj_st = l->map_state->object_state_for_index(c->version(), c->floor, cmd.object_index); + auto obj_st = l->map_state->object_state_for_index(c->version(), cmd.object_index); obj_st->game_flags = cmd.flags; l->log.info_f("K-{:03X} updated with game_flags={:08X}", obj_st->k_id, obj_st->game_flags); @@ -3647,7 +3647,7 @@ static asio::awaitable on_dragon_actions_6x12(shared_ptr c, Subcom co_return; } - auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id - 0x1000); + auto ene_st = l->map_state->enemy_state_for_index(c->version(), cmd.header.entity_id - 0x1000); if (ene_st->super_ene->type != EnemyType::DRAGON) { throw runtime_error("6x12 command sent for incorrect enemy type"); } @@ -3683,7 +3683,7 @@ static asio::awaitable on_gol_dragon_actions(shared_ptr c, Subcomm co_return; } - auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id - 0x1000); + auto ene_st = l->map_state->enemy_state_for_index(c->version(), cmd.header.entity_id - 0x1000); if (ene_st->super_ene->type != EnemyType::GOL_DRAGON) { throw runtime_error("6xA8 command sent for incorrect enemy type"); } @@ -3786,7 +3786,7 @@ static asio::awaitable on_set_boss_warp_flags_6x6A(shared_ptr c, S throw runtime_error("6x6A sent for non-object entity"); } - auto obj_st = l->map_state->object_state_for_index(c->version(), c->floor, cmd.header.entity_id - 0x4000); + auto obj_st = l->map_state->object_state_for_index(c->version(), cmd.header.entity_id - 0x4000); if (!obj_st->super_obj) { throw runtime_error("missing object for 6x6A command"); } @@ -3981,7 +3981,7 @@ static asio::awaitable on_steal_exp_bb(shared_ptr c, SubcommandMes co_return; } - const auto& ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.enemy_index); + const auto& ene_st = l->map_state->enemy_state_for_index(c->version(), cmd.enemy_index); if (ene_st->super_ene->floor != c->floor) { throw runtime_error("enemy is on a different floor"); } @@ -4035,7 +4035,7 @@ static asio::awaitable on_enemy_exp_request_bb(shared_ptr c, Subco throw runtime_error("client ID is too large"); } - auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.enemy_index); + auto ene_st = l->map_state->enemy_state_for_index(c->version(), cmd.enemy_index); string ene_str = ene_st->super_ene->str(); c->log.info_f("EXP requested for E-{:03X}: {}", ene_st->e_id, ene_str);