rename area -> floor in most places

This commit is contained in:
Martin Michelsen
2023-11-13 17:25:16 -08:00
parent 8d4c9ca93a
commit 1ca0e928a4
21 changed files with 285 additions and 283 deletions
+20 -20
View File
@@ -396,7 +396,7 @@ static void server_command_exit(shared_ptr<Client> c, const std::string&) {
} else if (l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS) || l->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS)) {
G_UnusedHeader cmd = {0x73, 0x01, 0x0000};
c->channel.send(0x60, 0x00, cmd);
c->area = 0;
c->floor = 0;
} else {
send_text_message(c, "$C6You must return to\nthe lobby first");
}
@@ -1081,23 +1081,23 @@ static void server_command_warp(shared_ptr<Client> c, const std::string& args, b
check_is_game(l, true);
check_cheats_enabled(l);
uint32_t area = stoul(args, nullptr, 0);
if (c->area == area) {
uint32_t floor = stoul(args, nullptr, 0);
if (c->floor == floor) {
return;
}
size_t limit = area_limit_for_episode(l->episode);
size_t limit = floor_limit_for_episode(l->episode);
if (limit == 0) {
return;
} else if (area > limit) {
} else if (floor > limit) {
send_text_message_printf(c, "$C6Area numbers must\nbe %zu or less.", limit);
return;
}
if (is_warpall) {
send_warp(l, area, false);
send_warp(l, floor, false);
} else {
send_warp(c, area, true);
send_warp(c, floor, true);
}
}
@@ -1116,12 +1116,12 @@ static void proxy_command_warp(shared_ptr<ProxyServer::LinkedSession> ses, const
send_text_message(ses->client_channel, "$C6You must be in a\ngame to use this\ncommand");
return;
}
uint32_t area = stoul(args, nullptr, 0);
send_warp(ses->client_channel, ses->lobby_client_id, area, !is_warpall);
uint32_t floor = stoul(args, nullptr, 0);
send_warp(ses->client_channel, ses->lobby_client_id, floor, !is_warpall);
if (is_warpall) {
send_warp(ses->server_channel, ses->lobby_client_id, area, false);
send_warp(ses->server_channel, ses->lobby_client_id, floor, false);
}
ses->area = area;
ses->floor = floor;
}
static void proxy_command_warpme(shared_ptr<ProxyServer::LinkedSession> ses, const std::string& args) {
@@ -1138,11 +1138,11 @@ static void server_command_next(shared_ptr<Client> c, const std::string&) {
check_is_game(l, true);
check_cheats_enabled(l);
size_t limit = area_limit_for_episode(l->episode);
size_t limit = floor_limit_for_episode(l->episode);
if (limit == 0) {
return;
}
send_warp(c, (c->area + 1) % limit, true);
send_warp(c, (c->floor + 1) % limit, true);
}
static void proxy_command_next(shared_ptr<ProxyServer::LinkedSession> ses, const std::string&) {
@@ -1153,8 +1153,8 @@ static void proxy_command_next(shared_ptr<ProxyServer::LinkedSession> ses, const
return;
}
ses->area++;
send_warp(ses->client_channel, ses->lobby_client_id, ses->area, true);
ses->floor++;
send_warp(ses->client_channel, ses->lobby_client_id, ses->floor, true);
}
static void server_command_what(shared_ptr<Client> c, const std::string&) {
@@ -1170,7 +1170,7 @@ static void server_command_what(shared_ptr<Client> c, const std::string&) {
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) {
if (it.second.floor != c->floor) {
continue;
}
float dx = it.second.x - c->x;
@@ -1305,8 +1305,8 @@ static void server_command_item(shared_ptr<Client> c, const std::string& args) {
ItemData item = s->item_name_index->parse_item_description(c->version(), args);
item.id = l->generate_item_id(c->lobby_client_id);
l->add_item(item, c->area, c->x, c->z);
send_drop_stacked_item(l, item, c->area, c->x, c->z);
l->add_item(item, c->floor, c->x, c->z);
send_drop_stacked_item(l, item, c->floor, c->x, c->z);
string name = s->describe_item(c->version(), item, true);
send_text_message(c, "$C7Item created:\n" + name);
@@ -1340,8 +1340,8 @@ static void proxy_command_item(shared_ptr<ProxyServer::LinkedSession> ses, const
send_text_message(ses->client_channel, "$C7Next drop:\n" + name);
} else {
send_drop_stacked_item(s, ses->client_channel, item, ses->area, ses->x, ses->z);
send_drop_stacked_item(s, ses->server_channel, item, ses->area, ses->x, ses->z);
send_drop_stacked_item(s, ses->client_channel, item, ses->floor, ses->x, ses->z);
send_drop_stacked_item(s, ses->server_channel, item, ses->floor, ses->x, ses->z);
string name = s->describe_item(ses->version(), item, true);
send_text_message(ses->client_channel, "$C7Item created:\n" + name);
+1 -1
View File
@@ -146,7 +146,7 @@ Client::Client(
sub_version(-1),
x(0.0f),
z(0.0f),
area(0),
floor(0),
lobby_client_id(0),
lobby_arrow_color(0),
preferred_lobby_id(-1),
+1 -1
View File
@@ -176,7 +176,7 @@ struct Client : public std::enable_shared_from_this<Client> {
int32_t sub_version;
float x;
float z;
uint32_t area;
uint32_t floor;
std::weak_ptr<Lobby> lobby;
uint8_t lobby_client_id;
uint8_t lobby_arrow_color;
+29 -29
View File
@@ -3679,7 +3679,7 @@ struct G_SwitchStateChanged_6x05 {
parray<uint8_t, 2> unknown_a1;
le_uint16_t unknown_a2 = 0;
parray<uint8_t, 2> unknown_a3;
uint8_t area = 0;
uint8_t floor = 0;
uint8_t flags = 0; // Bit field, with 2 lowest bits having meaning
} __packed__;
@@ -3870,11 +3870,11 @@ struct G_DestroyNPC_6x1C {
// 6x1D: Invalid subcommand
// 6x1E: Invalid subcommand
// 6x1F: Set player area
// 6x1F: Set player floor
struct G_SetPlayerArea_6x1F {
G_ClientIDHeader header;
le_uint32_t area = 0;
le_uint32_t floor = 0;
} __packed__;
// 6x20: Set position
@@ -3883,7 +3883,7 @@ struct G_SetPlayerArea_6x1F {
struct G_SetPosition_6x20 {
G_ClientIDHeader header;
le_uint32_t area = 0;
le_uint32_t floor = 0;
le_float x = 0.0f;
le_float y = 0.0f;
le_float z = 0.0f;
@@ -3894,12 +3894,12 @@ struct G_SetPosition_6x20 {
struct G_InterLevelWarp_6x21 {
G_ClientIDHeader header;
le_uint32_t area = 0;
le_uint32_t floor = 0;
} __packed__;
// 6x22: Set player invisible
// 6x23: Set player visible
// These are generally used while a player is in the process of changing areas.
// These are generally used while a player is in the process of changing floors.
struct G_SetPlayerVisibility_6x22_6x23 {
G_ClientIDHeader header;
@@ -3954,7 +3954,7 @@ struct G_DeleteInventoryItem_6x29 {
struct G_DropItem_6x2A {
G_ClientIDHeader header;
le_uint16_t unknown_a1 = 0; // Should be 1... maybe amount?
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint32_t item_id = 0;
le_float x = 0.0f;
le_float y = 0.0f;
@@ -4093,7 +4093,7 @@ struct G_StopAtPosition_6x3E {
G_ClientIDHeader header;
le_uint16_t unknown_a1 = 0;
le_uint16_t unknown_a2 = 0;
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint16_t unknown_a3 = 0;
le_float x = 0.0f;
le_float y = 0.0f;
@@ -4106,7 +4106,7 @@ struct G_SetPosition_6x3F {
G_ClientIDHeader header;
le_uint16_t unknown_a1 = 0;
le_uint16_t angle = 0;
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint16_t room = 0;
le_float x = 0.0f;
le_float y = 0.0f;
@@ -4309,7 +4309,7 @@ struct G_LobbyAnimation_6x58 {
struct G_PickUpItem_6x59 {
G_ClientIDHeader header;
le_uint16_t client_id2 = 0;
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint32_t item_id = 0;
} __packed__;
@@ -4318,7 +4318,7 @@ struct G_PickUpItem_6x59 {
struct G_PickUpItemRequest_6x5A {
G_ClientIDHeader header;
le_uint32_t item_id = 0;
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint16_t unused = 0;
} __packed__;
@@ -4336,7 +4336,7 @@ struct G_Unknown_6x5C {
struct G_DropStackedItem_DC_6x5D {
G_ClientIDHeader header;
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint16_t unknown_a2 = 0; // Corresponds to FloorItem::unknown_a2
le_float x = 0.0f;
le_float z = 0.0f;
@@ -4357,15 +4357,15 @@ struct G_BuyShopItem_6x5E {
// 6x5F: Drop item from box/enemy
struct FloorItem {
uint8_t area = 0;
uint8_t floor = 0;
uint8_t from_enemy = 0;
le_uint16_t entity_id = 0; // < 0x0B50 if from_enemy != 0; otherwise < 0x0BA0
le_float x = 0.0f;
le_float z = 0.0f;
le_uint16_t unknown_a2 = 0;
// The drop number is scoped to the area and increments by 1 each time an
// item is dropped. The last item dropped in each area has drop_number equal
// to total_items_dropped_per_area[area - 1] - 1.
// The drop number is scoped to the floor and increments by 1 each time an
// item is dropped. The last item dropped in each floor has drop_number equal
// to total_items_dropped_per_floor[floor - 1] - 1.
le_uint16_t drop_number = 0;
ItemData item;
} __packed__;
@@ -4383,7 +4383,7 @@ struct G_DropItem_PC_V3_BB_6x5F : G_DropItem_DC_6x5F {
struct G_StandardDropItemRequest_DC_6x60 {
G_UnusedHeader header;
uint8_t area = 0;
uint8_t floor = 0;
uint8_t rt_index = 0;
le_uint16_t entity_id = 0;
le_float x = 0.0f;
@@ -4413,7 +4413,7 @@ struct G_ActivateMagEffect_6x61 {
struct G_DestroyGroundItem_6x63 {
G_UnusedHeader header;
le_uint32_t item_id = 0;
le_uint32_t area = 0;
le_uint32_t floor = 0;
} __packed__;
// 6x64: Unknown (not valid on Episode 3)
@@ -4433,7 +4433,7 @@ struct G_UseStarAtomizer_6x66 {
struct G_CreateEnemySet_6x67 {
G_UnusedHeader header;
// unused1 could be area; the client checks this againset a global but the
// unused1 could be floor; the client checks this against a global but the
// logic is the same in both branches
le_uint32_t unused1 = 0;
le_uint32_t unknown_a1 = 0;
@@ -4510,16 +4510,16 @@ struct G_SyncItemState_6x6D_Decompressed {
// TODO: Verify this format on DC and PC. It appears correct for GC and BB.
// Note: 16 vs. 15 is not a bug here - there really is an extra field in the
// total drop count vs. the floor item count. Despite this, Pioneer 2 or Lab
// (area 0) isn't included in total_items_dropped_per_area (so Forest 1 is [0]
// in that array) but it is included in floor_item_count_per_area (so Forest 1
// is [1] there).
parray<le_uint16_t, 16> total_items_dropped_per_area;
// (floor 0) isn't included in total_items_dropped_per_floor (so Forest 1 is
// [0] in that array) but it is included in floor_item_count_per_floor (so
// Forest 1 is [1] there).
parray<le_uint16_t, 16> total_items_dropped_per_floor;
// Only [0]-[3] in this array are ever actually used in normal gameplay, but
// the client fills in all 12 of these with reasonable values.
parray<le_uint32_t, 12> next_item_id_per_player;
parray<le_uint32_t, 15> floor_item_count_per_area;
parray<le_uint32_t, 15> floor_item_count_per_floor;
// Variable-length field:
// FloorItem items[sum(floor_item_count_per_area)];
// FloorItem items[sum(floor_item_count_per_floor)];
} __packed__;
// 6x6E: Sync flag state (used while loading into game)
@@ -4886,7 +4886,7 @@ struct G_Unknown_6x92 {
struct G_ActivateTimedSwitch_6x93 {
G_UnusedHeader header;
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint16_t switch_id = 0;
uint8_t unknown_a1 = 0; // Logic is different if this is 1 vs. any other value
parray<uint8_t, 3> unused;
@@ -4896,7 +4896,7 @@ struct G_ActivateTimedSwitch_6x93 {
struct G_InterLevelWarp_6x94 {
G_UnusedHeader header;
le_uint16_t area = 0;
le_uint16_t floor = 0;
parray<uint8_t, 2> unused;
} __packed__;
@@ -5141,7 +5141,7 @@ struct G_MoveLobbyChair_6xB0 {
struct G_Unknown_6xB2 {
G_UnusedHeader header;
uint8_t area = 0;
uint8_t floor = 0;
uint8_t unused = 0;
le_uint16_t client_id = 0;
le_uint32_t unknown_a3 = 0; // PSO GC puts 0x00051720 (333600) here
@@ -5427,7 +5427,7 @@ struct G_TeamInvitationAction_BB_6xC1_6xC2_6xCD_6xCE {
struct G_SplitStackedItem_BB_6xC3 {
G_ClientIDHeader header;
le_uint16_t area = 0;
le_uint16_t floor = 0;
le_uint16_t unused2 = 0;
le_float x = 0.0f;
le_float z = 0.0f;
+4 -8
View File
@@ -78,8 +78,7 @@ private:
bool are_rare_drops_allowed() const;
uint8_t normalize_area_number(uint8_t area) const;
ItemData on_monster_item_drop_with_norm_area(
uint32_t enemy_type, uint8_t norm_area);
ItemData on_monster_item_drop_with_norm_area(uint32_t enemy_type, uint8_t norm_area);
ItemData on_box_item_drop_with_norm_area(uint8_t area_norm);
uint32_t rand_int(uint64_t max);
@@ -105,22 +104,19 @@ private:
void generate_common_item_variances(uint32_t norm_area, ItemData& item);
void generate_common_armor_slots_and_bonuses(ItemData& item);
void generate_common_armor_slot_count(ItemData& item);
void generate_common_armor_or_shield_type_and_variances(
char area_norm, ItemData& item);
void generate_common_armor_or_shield_type_and_variances(char area_norm, ItemData& item);
void generate_common_tool_variances(uint32_t area_norm, ItemData& item);
uint8_t generate_tech_disk_level(uint32_t tech_num, uint32_t area_norm);
void generate_common_tool_type(uint8_t tool_class, ItemData& item) const;
void generate_common_mag_variances(ItemData& item) const;
void generate_common_weapon_variances(uint8_t area_norm, ItemData& item);
void generate_common_weapon_grind(ItemData& item,
uint8_t offset_within_subtype_range);
void generate_common_weapon_grind(ItemData& item, uint8_t offset_within_subtype_range);
void generate_common_weapon_bonuses(ItemData& item, uint8_t area_norm);
void generate_common_weapon_special(ItemData& item, uint8_t area_norm);
uint8_t choose_weapon_special(uint8_t det);
void generate_unit_weights_tables();
void generate_common_unit_variances(uint8_t det, ItemData& item);
void choose_tech_disk_level_for_tool_shop(
ItemData& item, size_t player_level, uint8_t tech_num_index);
void choose_tech_disk_level_for_tool_shop(ItemData& item, size_t player_level, uint8_t tech_num_index);
static void clear_tool_item_if_invalid(ItemData& item);
void clear_item_if_restricted(ItemData& item) const;
+2 -2
View File
@@ -336,10 +336,10 @@ const Lobby::FloorItem& Lobby::find_item(uint32_t item_id) const {
return this->item_id_to_floor_item.at(item_id);
}
void Lobby::add_item(const ItemData& data, uint8_t area, float x, float z) {
void Lobby::add_item(const ItemData& data, uint8_t floor, float x, float z) {
auto& fi = this->item_id_to_floor_item[data.id];
fi.data = data;
fi.area = area;
fi.floor = floor;
fi.x = x;
fi.z = z;
}
+2 -2
View File
@@ -64,7 +64,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
ItemData data;
float x;
float z;
uint8_t area;
uint8_t floor;
};
std::shared_ptr<Map> map;
std::array<uint32_t, 12> next_item_id;
@@ -188,7 +188,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
bool item_exists(uint32_t item_id) const;
const FloorItem& find_item(uint32_t item_id) const;
void add_item(const ItemData& item, uint8_t area, float x, float z);
void add_item(const ItemData& item, uint8_t floor, float x, float z);
ItemData remove_item(uint32_t item_id);
uint32_t generate_item_id(uint8_t client_id);
void on_item_id_generated_externally(uint32_t item_id);
+105 -104
View File
@@ -13,8 +13,9 @@ using namespace std;
static constexpr float UINT32_MAX_AS_FLOAT = 4294967296.0f;
Map::Enemy::Enemy(EnemyType type)
Map::Enemy::Enemy(uint8_t floor, EnemyType type)
: type(type),
floor(floor),
flags(0),
last_hit_by_client_id(0) {
}
@@ -52,9 +53,9 @@ bool Map::check_and_log_rare_enemy(bool default_is_rare, uint32_t rare_rate) {
return false;
}
void Map::add_enemy(EnemyType type) {
static_game_data_log.info("Adding enemy E-%zX => %s", this->enemies.size(), name_for_enum(type));
this->enemies.emplace_back(type);
void Map::add_enemy(uint8_t floor, EnemyType type) {
static_game_data_log.info("Adding enemy %02hhX:E-%zX => %s", floor, this->enemies.size(), name_for_enum(type));
this->enemies.emplace_back(floor, type);
}
void Map::add_enemy(
@@ -67,39 +68,39 @@ void Map::add_enemy(
switch (e.base_type) {
case 0x40: {
bool is_rare = this->check_and_log_rare_enemy(e.uparam1 & 0x01, rare_rates.hildeblue);
this->add_enemy(is_rare ? EnemyType::HILDEBLUE : EnemyType::HILDEBEAR);
this->add_enemy(e.floor, is_rare ? EnemyType::HILDEBLUE : EnemyType::HILDEBEAR);
break;
}
case 0x41: {
bool is_rare = this->check_and_log_rare_enemy(e.uparam1 & 0x01, rare_rates.rappy);
switch (episode) {
case Episode::EP1:
this->add_enemy(is_rare ? EnemyType::AL_RAPPY : EnemyType::RAG_RAPPY);
this->add_enemy(e.floor, is_rare ? EnemyType::AL_RAPPY : EnemyType::RAG_RAPPY);
break;
case Episode::EP2:
if (is_rare) {
switch (event) {
case 0x01:
this->add_enemy(EnemyType::SAINT_RAPPY);
this->add_enemy(e.floor, EnemyType::SAINT_RAPPY);
break;
case 0x04:
this->add_enemy(EnemyType::EGG_RAPPY);
this->add_enemy(e.floor, EnemyType::EGG_RAPPY);
break;
case 0x05:
this->add_enemy(EnemyType::HALLO_RAPPY);
this->add_enemy(e.floor, EnemyType::HALLO_RAPPY);
break;
default:
this->add_enemy(EnemyType::LOVE_RAPPY);
this->add_enemy(e.floor, EnemyType::LOVE_RAPPY);
}
} else {
this->add_enemy(EnemyType::RAG_RAPPY);
this->add_enemy(e.floor, EnemyType::RAG_RAPPY);
}
break;
case Episode::EP4:
if (e.floor > 0x05) {
this->add_enemy(is_rare ? EnemyType::DEL_RAPPY_ALT : EnemyType::SAND_RAPPY_ALT);
this->add_enemy(e.floor, is_rare ? EnemyType::DEL_RAPPY_ALT : EnemyType::SAND_RAPPY_ALT);
} else {
this->add_enemy(is_rare ? EnemyType::DEL_RAPPY : EnemyType::SAND_RAPPY);
this->add_enemy(e.floor, is_rare ? EnemyType::DEL_RAPPY : EnemyType::SAND_RAPPY);
}
break;
default:
@@ -108,292 +109,292 @@ void Map::add_enemy(
break;
}
case 0x42: {
this->add_enemy(EnemyType::MONEST);
this->add_enemy(e.floor, EnemyType::MONEST);
for (size_t x = 0; x < 30; x++) {
this->add_enemy(EnemyType::MOTHMANT);
this->add_enemy(e.floor, EnemyType::MOTHMANT);
}
break;
}
case 0x43: {
this->add_enemy(e.fparam2 ? EnemyType::BARBAROUS_WOLF : EnemyType::SAVAGE_WOLF);
this->add_enemy(e.floor, e.fparam2 ? EnemyType::BARBAROUS_WOLF : EnemyType::SAVAGE_WOLF);
break;
}
case 0x44:
static const EnemyType types[3] = {EnemyType::BOOMA, EnemyType::GOBOOMA, EnemyType::GIGOBOOMA};
this->add_enemy(types[e.uparam1 % 3]);
this->add_enemy(e.floor, types[e.uparam1 % 3]);
break;
case 0x60:
this->add_enemy(EnemyType::GRASS_ASSASSIN);
this->add_enemy(e.floor, EnemyType::GRASS_ASSASSIN);
break;
case 0x61:
if ((episode == Episode::EP2) && (e.floor > 0x0F)) {
this->add_enemy(EnemyType::DEL_LILY);
this->add_enemy(e.floor, EnemyType::DEL_LILY);
} else {
bool is_rare = this->check_and_log_rare_enemy(e.uparam1 & 0x01, rare_rates.nar_lily);
this->add_enemy(is_rare ? EnemyType::NAR_LILY : EnemyType::POISON_LILY);
this->add_enemy(e.floor, is_rare ? EnemyType::NAR_LILY : EnemyType::POISON_LILY);
}
break;
case 0x62:
this->add_enemy(EnemyType::NANO_DRAGON);
this->add_enemy(e.floor, EnemyType::NANO_DRAGON);
break;
case 0x63: {
static const EnemyType types[3] = {EnemyType::EVIL_SHARK, EnemyType::PAL_SHARK, EnemyType::GUIL_SHARK};
this->add_enemy(types[e.uparam1 % 3]);
this->add_enemy(e.floor, types[e.uparam1 % 3]);
break;
}
case 0x64: {
bool is_rare = this->check_and_log_rare_enemy(e.uparam1 & 0x01, rare_rates.pouilly_slime);
for (size_t x = 0; x < 5; x++) { // Main slime + 4 clones
this->add_enemy(is_rare ? EnemyType::POFUILLY_SLIME : EnemyType::POUILLY_SLIME);
this->add_enemy(e.floor, is_rare ? EnemyType::POFUILLY_SLIME : EnemyType::POUILLY_SLIME);
}
break;
}
case 0x65:
this->add_enemy(EnemyType::PAN_ARMS);
this->add_enemy(EnemyType::HIDOOM);
this->add_enemy(EnemyType::MIGIUM);
this->add_enemy(e.floor, EnemyType::PAN_ARMS);
this->add_enemy(e.floor, EnemyType::HIDOOM);
this->add_enemy(e.floor, EnemyType::MIGIUM);
break;
case 0x80:
this->add_enemy((e.uparam1 & 0x01) ? EnemyType::GILLCHIC : EnemyType::DUBCHIC);
this->add_enemy(e.floor, (e.uparam1 & 0x01) ? EnemyType::GILLCHIC : EnemyType::DUBCHIC);
break;
case 0x81:
this->add_enemy(EnemyType::GARANZ);
this->add_enemy(e.floor, EnemyType::GARANZ);
break;
case 0x82: {
EnemyType type = e.fparam2 ? EnemyType::SINOW_GOLD : EnemyType::SINOW_BEAT;
size_t count = (e.num_children == 0) ? 5 : (e.num_children + 1);
for (size_t z = 0; z < count; z++) {
this->add_enemy(type);
this->add_enemy(e.floor, type);
}
break;
}
case 0x83:
this->add_enemy(EnemyType::CANADINE);
this->add_enemy(e.floor, EnemyType::CANADINE);
break;
case 0x84:
this->add_enemy(EnemyType::CANANE);
this->add_enemy(e.floor, EnemyType::CANANE);
for (size_t x = 0; x < 8; x++) {
this->add_enemy(EnemyType::CANADINE_GROUP);
this->add_enemy(e.floor, EnemyType::CANADINE_GROUP);
}
break;
case 0x85:
this->add_enemy(EnemyType::DUBWITCH);
this->add_enemy(e.floor, EnemyType::DUBWITCH);
break;
case 0xA0:
this->add_enemy(EnemyType::DELSABER);
this->add_enemy(e.floor, EnemyType::DELSABER);
break;
case 0xA1:
this->add_enemy(EnemyType::CHAOS_SORCERER);
this->add_enemy(EnemyType::BEE_R);
this->add_enemy(EnemyType::BEE_L);
this->add_enemy(e.floor, EnemyType::CHAOS_SORCERER);
this->add_enemy(e.floor, EnemyType::BEE_R);
this->add_enemy(e.floor, EnemyType::BEE_L);
break;
case 0xA2:
this->add_enemy(EnemyType::DARK_GUNNER);
this->add_enemy(e.floor, EnemyType::DARK_GUNNER);
break;
case 0xA3:
this->add_enemy(EnemyType::DEATH_GUNNER);
this->add_enemy(e.floor, EnemyType::DEATH_GUNNER);
break;
case 0xA4:
this->add_enemy(EnemyType::CHAOS_BRINGER);
this->add_enemy(e.floor, EnemyType::CHAOS_BRINGER);
break;
case 0xA5:
this->add_enemy(EnemyType::DARK_BELRA);
this->add_enemy(e.floor, EnemyType::DARK_BELRA);
break;
case 0xA6: {
static const EnemyType types[3] = {EnemyType::DIMENIAN, EnemyType::LA_DIMENIAN, EnemyType::SO_DIMENIAN};
this->add_enemy(types[e.uparam1 % 3]);
this->add_enemy(e.floor, types[e.uparam1 % 3]);
break;
}
case 0xA7:
this->add_enemy(EnemyType::BULCLAW);
this->add_enemy(e.floor, EnemyType::BULCLAW);
for (size_t x = 0; x < 4; x++) {
this->add_enemy(EnemyType::CLAW);
this->add_enemy(e.floor, EnemyType::CLAW);
}
break;
case 0xA8:
this->add_enemy(EnemyType::CLAW);
this->add_enemy(e.floor, EnemyType::CLAW);
break;
case 0xC0:
if (episode == Episode::EP1) {
this->add_enemy(EnemyType::DRAGON);
this->add_enemy(e.floor, EnemyType::DRAGON);
} else if (episode == Episode::EP2) {
this->add_enemy(EnemyType::GAL_GRYPHON);
this->add_enemy(e.floor, EnemyType::GAL_GRYPHON);
} else {
throw runtime_error("DRAGON-type enemy placed outside of Episodes 1 or 2");
}
break;
case 0xC1:
this->add_enemy(EnemyType::DE_ROL_LE);
this->add_enemy(e.floor, EnemyType::DE_ROL_LE);
for (size_t z = 0; z < 0x0A; z++) {
this->add_enemy(EnemyType::DE_ROL_LE_BODY);
this->add_enemy(e.floor, EnemyType::DE_ROL_LE_BODY);
}
for (size_t z = 0; z < 0x09; z++) {
this->add_enemy(EnemyType::DE_ROL_LE_MINE);
this->add_enemy(e.floor, EnemyType::DE_ROL_LE_MINE);
}
break;
case 0xC2:
this->add_enemy(EnemyType::VOL_OPT_1);
this->add_enemy(e.floor, EnemyType::VOL_OPT_1);
for (size_t z = 0; z < 6; z++) {
this->add_enemy(EnemyType::VOL_OPT_PILLAR);
this->add_enemy(e.floor, EnemyType::VOL_OPT_PILLAR);
}
for (size_t z = 0; z < 24; z++) {
this->add_enemy(EnemyType::VOL_OPT_MONITOR);
this->add_enemy(e.floor, EnemyType::VOL_OPT_MONITOR);
}
for (size_t z = 0; z < 2; z++) {
this->add_enemy(EnemyType::NONE);
this->add_enemy(e.floor, EnemyType::NONE);
}
this->add_enemy(EnemyType::VOL_OPT_AMP);
this->add_enemy(EnemyType::VOL_OPT_CORE);
this->add_enemy(EnemyType::NONE);
this->add_enemy(e.floor, EnemyType::VOL_OPT_AMP);
this->add_enemy(e.floor, EnemyType::VOL_OPT_CORE);
this->add_enemy(e.floor, EnemyType::NONE);
break;
case 0xC5:
this->add_enemy(EnemyType::VOL_OPT_2);
this->add_enemy(e.floor, EnemyType::VOL_OPT_2);
break;
case 0xC8:
if (difficulty) {
this->add_enemy(EnemyType::DARK_FALZ_3);
this->add_enemy(e.floor, EnemyType::DARK_FALZ_3);
} else {
this->add_enemy(EnemyType::DARK_FALZ_2);
this->add_enemy(e.floor, EnemyType::DARK_FALZ_2);
}
for (size_t x = 0; x < 0x1FD; x++) {
this->add_enemy(difficulty == 3 ? EnemyType::DARVANT_ULTIMATE : EnemyType::DARVANT);
this->add_enemy(e.floor, difficulty == 3 ? EnemyType::DARVANT_ULTIMATE : EnemyType::DARVANT);
}
this->add_enemy(EnemyType::DARK_FALZ_3);
this->add_enemy(EnemyType::DARK_FALZ_2);
this->add_enemy(EnemyType::DARK_FALZ_1);
this->add_enemy(e.floor, EnemyType::DARK_FALZ_3);
this->add_enemy(e.floor, EnemyType::DARK_FALZ_2);
this->add_enemy(e.floor, EnemyType::DARK_FALZ_1);
break;
case 0xCA:
for (size_t z = 0; z < 0x201; z++) {
this->add_enemy(EnemyType::OLGA_FLOW_2);
this->add_enemy(e.floor, EnemyType::OLGA_FLOW_2);
}
break;
case 0xCB:
this->add_enemy(EnemyType::BARBA_RAY);
this->add_enemy(e.floor, EnemyType::BARBA_RAY);
for (size_t z = 0; z < 0x2F; z++) {
this->add_enemy(EnemyType::PIG_RAY);
this->add_enemy(e.floor, EnemyType::PIG_RAY);
}
break;
case 0xCC:
for (size_t z = 0; z < 6; z++) {
this->add_enemy(EnemyType::GOL_DRAGON);
this->add_enemy(e.floor, EnemyType::GOL_DRAGON);
}
break;
case 0xD4: {
EnemyType type = (e.uparam1 & 1) ? EnemyType::SINOW_SPIGELL : EnemyType::SINOW_BERILL;
for (size_t z = 0; z < 5; z++) {
this->add_enemy(type);
this->add_enemy(e.floor, type);
}
break;
}
case 0xD5:
this->add_enemy((e.uparam1 & 0x01) ? EnemyType::MERILTAS : EnemyType::MERILLIA);
this->add_enemy(e.floor, (e.uparam1 & 0x01) ? EnemyType::MERILTAS : EnemyType::MERILLIA);
break;
case 0xD6:
if (e.uparam1 == 0) {
this->add_enemy(EnemyType::MERICAROL);
this->add_enemy(e.floor, EnemyType::MERICAROL);
} else {
this->add_enemy(((e.uparam1 % 3) == 2) ? EnemyType::MERICUS : EnemyType::MERIKLE);
this->add_enemy(e.floor, ((e.uparam1 % 3) == 2) ? EnemyType::MERICUS : EnemyType::MERIKLE);
}
break;
case 0xD7:
this->add_enemy((e.uparam1 & 0x01) ? EnemyType::ZOL_GIBBON : EnemyType::UL_GIBBON);
this->add_enemy(e.floor, (e.uparam1 & 0x01) ? EnemyType::ZOL_GIBBON : EnemyType::UL_GIBBON);
break;
case 0xD8:
this->add_enemy(EnemyType::GIBBLES);
this->add_enemy(e.floor, EnemyType::GIBBLES);
break;
case 0xD9:
this->add_enemy(EnemyType::GEE);
this->add_enemy(e.floor, EnemyType::GEE);
break;
case 0xDA:
this->add_enemy(EnemyType::GI_GUE);
this->add_enemy(e.floor, EnemyType::GI_GUE);
break;
case 0xDB:
this->add_enemy(EnemyType::DELDEPTH);
this->add_enemy(e.floor, EnemyType::DELDEPTH);
break;
case 0xDC:
this->add_enemy(EnemyType::DELBITER);
this->add_enemy(e.floor, EnemyType::DELBITER);
break;
case 0xDD:
this->add_enemy((e.uparam1 & 0x01) ? EnemyType::DOLMDARL : EnemyType::DOLMOLM);
this->add_enemy(e.floor, (e.uparam1 & 0x01) ? EnemyType::DOLMDARL : EnemyType::DOLMOLM);
break;
case 0xDE:
this->add_enemy(EnemyType::MORFOS);
this->add_enemy(e.floor, EnemyType::MORFOS);
break;
case 0xDF:
this->add_enemy(EnemyType::RECOBOX);
this->add_enemy(e.floor, EnemyType::RECOBOX);
for (size_t x = 0; x < e.num_children; x++) {
this->add_enemy(EnemyType::RECON);
this->add_enemy(e.floor, EnemyType::RECON);
}
break;
case 0xE0:
if ((episode == Episode::EP2) && (e.floor > 0x0F)) {
this->add_enemy(EnemyType::EPSILON);
this->add_enemy(e.floor, EnemyType::EPSILON);
for (size_t z = 0; z < 4; z++) {
this->add_enemy(EnemyType::EPSIGUARD);
this->add_enemy(e.floor, EnemyType::EPSIGUARD);
}
} else {
this->add_enemy((e.uparam1 & 0x01) ? EnemyType::SINOW_ZELE : EnemyType::SINOW_ZOA);
this->add_enemy(e.floor, (e.uparam1 & 0x01) ? EnemyType::SINOW_ZELE : EnemyType::SINOW_ZOA);
}
break;
case 0xE1:
this->add_enemy(EnemyType::ILL_GILL);
this->add_enemy(e.floor, EnemyType::ILL_GILL);
break;
case 0x0110:
this->add_enemy(EnemyType::ASTARK);
this->add_enemy(e.floor, EnemyType::ASTARK);
break;
case 0x0111:
if (e.floor > 0x05) {
this->add_enemy(e.fparam2 ? EnemyType::YOWIE_ALT : EnemyType::SATELLITE_LIZARD_ALT);
this->add_enemy(e.floor, e.fparam2 ? EnemyType::YOWIE_ALT : EnemyType::SATELLITE_LIZARD_ALT);
} else {
this->add_enemy(e.fparam2 ? EnemyType::YOWIE : EnemyType::SATELLITE_LIZARD);
this->add_enemy(e.floor, e.fparam2 ? EnemyType::YOWIE : EnemyType::SATELLITE_LIZARD);
}
break;
case 0x0112: {
bool is_rare = this->check_and_log_rare_enemy(e.uparam1 & 0x01, rare_rates.merissa_aa);
this->add_enemy(is_rare ? EnemyType::MERISSA_AA : EnemyType::MERISSA_A);
this->add_enemy(e.floor, is_rare ? EnemyType::MERISSA_AA : EnemyType::MERISSA_A);
break;
}
case 0x0113:
this->add_enemy(EnemyType::GIRTABLULU);
this->add_enemy(e.floor, EnemyType::GIRTABLULU);
break;
case 0x0114: {
bool is_rare = this->check_and_log_rare_enemy(e.uparam1 & 0x01, rare_rates.pazuzu);
if (e.floor > 0x05) {
this->add_enemy(is_rare ? EnemyType::PAZUZU_ALT : EnemyType::ZU_ALT);
this->add_enemy(e.floor, is_rare ? EnemyType::PAZUZU_ALT : EnemyType::ZU_ALT);
} else {
this->add_enemy(is_rare ? EnemyType::PAZUZU : EnemyType::ZU);
this->add_enemy(e.floor, is_rare ? EnemyType::PAZUZU : EnemyType::ZU);
}
break;
}
case 0x0115:
if (e.uparam1 & 2) {
this->add_enemy(EnemyType::BA_BOOTA);
this->add_enemy(e.floor, EnemyType::BA_BOOTA);
} else {
this->add_enemy((e.uparam1 & 1) ? EnemyType::ZE_BOOTA : EnemyType::BOOTA);
this->add_enemy(e.floor, (e.uparam1 & 1) ? EnemyType::ZE_BOOTA : EnemyType::BOOTA);
}
break;
case 0x0116: {
bool is_rare = this->check_and_log_rare_enemy(e.uparam1 & 0x01, rare_rates.dorphon_eclair);
this->add_enemy(is_rare ? EnemyType::DORPHON_ECLAIR : EnemyType::DORPHON);
this->add_enemy(e.floor, is_rare ? EnemyType::DORPHON_ECLAIR : EnemyType::DORPHON);
break;
}
case 0x0117: {
static const EnemyType types[3] = {EnemyType::GORAN, EnemyType::PYRO_GORAN, EnemyType::GORAN_DETONATOR};
this->add_enemy(types[e.uparam1 % 3]);
this->add_enemy(e.floor, types[e.uparam1 % 3]);
break;
}
case 0x0119: {
bool is_rare = this->check_and_log_rare_enemy((e.fparam2 != 0.0f), rare_rates.kondrieu);
if (is_rare) {
this->add_enemy(EnemyType::KONDRIEU);
this->add_enemy(e.floor, EnemyType::KONDRIEU);
} else {
this->add_enemy((e.uparam1 & 1) ? EnemyType::SHAMBERTIN : EnemyType::SAINT_MILLION);
this->add_enemy(e.floor, (e.uparam1 & 1) ? EnemyType::SHAMBERTIN : EnemyType::SAINT_MILLION);
}
break;
}
default:
for (size_t z = 0; z < static_cast<size_t>(e.num_children + 1); z++) {
this->add_enemy(EnemyType::UNKNOWN);
this->add_enemy(e.floor, EnemyType::UNKNOWN);
}
static_game_data_log.warning(
"(Entry %zu, offset %zX in file) Unknown enemy type %04hX",
@@ -844,7 +845,7 @@ struct AreaMapFileIndex {
variation2_values(variation2_values) {}
};
// These are indexed as [episode][is_solo][area], where episode is 0-2
// These are indexed as [episode][is_solo][floor], where episode is 0-2
static const vector<vector<vector<AreaMapFileIndex>>> map_file_info = {
{
// Episode 1
@@ -1009,7 +1010,7 @@ void generate_variations(
}
vector<string> map_filenames_for_variation(
Episode episode, bool is_solo, uint8_t area, uint32_t var1, uint32_t var2, bool is_enemies) {
Episode episode, bool is_solo, uint8_t floor, uint32_t var1, uint32_t var2, bool is_enemies) {
// Map filenames are like map_<name_token>[_VV][_VV][_off]<e|o>[_s].dat
// name_token comes from AreaMapFileIndex
// _VV are the values from the variation<1|2>_values vector (in contrast to
@@ -1020,10 +1021,10 @@ vector<string> map_filenames_for_variation(
const auto& ep_index = map_file_info_for_episode(episode);
const AreaMapFileIndex* a = nullptr;
if (is_solo) {
a = &ep_index.at(true).at(area);
a = &ep_index.at(true).at(floor);
}
if (!a || !a->name_token) {
a = &ep_index.at(false).at(area);
a = &ep_index.at(false).at(floor);
}
if (!a->name_token) {
return vector<string>();
+6 -5
View File
@@ -202,10 +202,11 @@ struct Map {
ITEM_DROPPED = 0x20,
};
EnemyType type;
uint8_t floor;
uint8_t flags;
uint8_t last_hit_by_client_id;
explicit Enemy(EnemyType type);
Enemy(uint8_t floor, EnemyType type);
std::string str() const;
} __attribute__((packed));
@@ -216,7 +217,7 @@ struct Map {
void clear();
void add_objects_from_map_data(const void* data, size_t size);
bool check_and_log_rare_enemy(bool default_is_rare, uint32_t rare_rate);
void add_enemy(EnemyType type);
void add_enemy(uint8_t floor, EnemyType type);
void add_enemy(
Episode episode,
uint8_t difficulty,
@@ -274,8 +275,8 @@ private:
template <bool IsBigEndian>
void load_table_t(std::shared_ptr<const std::string> data);
// Indexes are [area_id][variation1][variation2]
// area_id is cumulative per episode, so Ep2 starts at area_id=18.
// Indexes are [floor][variation1][variation2]
// floor is cumulative per episode, so Ep2 starts at floor=18.
std::vector<std::vector<std::vector<SetEntry>>> entries;
};
@@ -285,5 +286,5 @@ void generate_variations(
Episode episode,
bool is_solo);
std::vector<std::string> map_filenames_for_variation(
Episode episode, bool is_solo, uint8_t area, uint32_t var1, uint32_t var2, bool is_enemies);
Episode episode, bool is_solo, uint8_t floor, uint32_t var1, uint32_t var2, bool is_enemies);
void load_map_files();
+9 -9
View File
@@ -996,8 +996,8 @@ static HandlerResult S_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
const auto& cmd = check_size_t<G_StandardDropItemRequest_DC_6x60>(
data, sizeof(G_StandardDropItemRequest_PC_V3_BB_6x60));
ses->next_drop_item.id = ses->next_item_id++;
send_drop_item(s, ses->server_channel, ses->next_drop_item, true, cmd.area, cmd.x, cmd.z, cmd.entity_id);
send_drop_item(s, ses->client_channel, ses->next_drop_item, true, cmd.area, cmd.x, cmd.z, cmd.entity_id);
send_drop_item(s, ses->server_channel, ses->next_drop_item, true, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
send_drop_item(s, ses->client_channel, ses->next_drop_item, true, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
ses->next_drop_item.clear();
return HandlerResult::Type::SUPPRESS;
@@ -1008,8 +1008,8 @@ static HandlerResult S_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
} else if ((static_cast<uint8_t>(data[0]) == 0xA2) && ses->next_drop_item.data1d[0] && (ses->version() != GameVersion::BB)) {
const auto& cmd = check_size_t<G_SpecializableItemDropRequest_6xA2>(data);
ses->next_drop_item.id = ses->next_item_id++;
send_drop_item(s, ses->server_channel, ses->next_drop_item, false, cmd.area, cmd.x, cmd.z, cmd.entity_id);
send_drop_item(s, ses->client_channel, ses->next_drop_item, false, cmd.area, cmd.x, cmd.z, cmd.entity_id);
send_drop_item(s, ses->server_channel, ses->next_drop_item, false, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
send_drop_item(s, ses->client_channel, ses->next_drop_item, false, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
ses->next_drop_item.clear();
return HandlerResult::Type::SUPPRESS;
@@ -1344,7 +1344,7 @@ static HandlerResult S_65_67_68_EB(shared_ptr<ProxyServer::LinkedSession> ses, u
ses->clear_lobby_players(12);
ses->is_in_game = false;
ses->is_in_quest = false;
ses->area = 0x0F;
ses->floor = 0x0F;
// This command can cause the client to no longer send D6 responses when
// 1A/D5 large message boxes are closed. newserv keeps track of this
@@ -1423,7 +1423,7 @@ static HandlerResult S_64(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
}
ses->clear_lobby_players(4);
ses->area = 0;
ses->floor = 0;
ses->is_in_game = true;
ses->is_in_quest = false;
@@ -1477,7 +1477,7 @@ static HandlerResult S_E8(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
auto& cmd = check_size_t<S_JoinSpectatorTeam_GC_Ep3_E8>(data);
ses->clear_lobby_players(12);
ses->area = 0;
ses->floor = 0;
ses->is_in_game = true;
ses->is_in_quest = false;
@@ -1555,7 +1555,7 @@ static HandlerResult S_66_69_E9(shared_ptr<ProxyServer::LinkedSession> ses, uint
}
static HandlerResult C_98(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t command, uint32_t flag, string& data) {
ses->area = 0x0F;
ses->floor = 0x0F;
ses->is_in_game = false;
ses->is_in_quest = false;
if (ses->version() == GameVersion::GC ||
@@ -1681,7 +1681,7 @@ static HandlerResult C_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t c
if (!data.empty()) {
if (data[0] == 0x21) {
const auto& cmd = check_size_t<G_InterLevelWarp_6x21>(data);
ses->area = cmd.area;
ses->floor = cmd.floor;
} else if (data[0] == 0x2F || data[0] == 0x4B || data[0] == 0x4C) {
if (ses->config.check_flag(Client::Flag::INFINITE_HP_ENABLED)) {
+1 -1
View File
@@ -489,7 +489,7 @@ ProxyServer::LinkedSession::LinkedSession(
lobby_players(12),
lobby_client_id(0),
leader_client_id(0),
area(0),
floor(0),
x(0.0),
z(0.0),
is_in_game(false),
+1 -1
View File
@@ -86,7 +86,7 @@ public:
std::vector<LobbyPlayer> lobby_players;
size_t lobby_client_id;
size_t leader_client_id;
uint16_t area;
uint16_t floor;
float x;
float z;
bool is_in_game;
+2 -2
View File
@@ -319,7 +319,7 @@ RareItemSet::RareItemSet(const JSON& json, GameVersion version, shared_ptr<const
for (const auto& item_it : section_id_it.second->as_dict()) {
vector<ExpandedDrop>* target;
if (starts_with(item_it.first, "Box-")) {
uint8_t area = area_for_name(item_it.first.substr(4));
uint8_t area = floor_for_name(item_it.first.substr(4));
if (collection.box_area_to_specs.size() <= area) {
collection.box_area_to_specs.resize(area + 1);
}
@@ -484,7 +484,7 @@ std::string RareItemSet::serialize_json(GameVersion version, shared_ptr<const It
if (!area_list.empty()) {
collection_dict.emplace(
string_printf("Box-%s", name_for_area(episode, area)),
string_printf("Box-%s", name_for_floor(episode, area)),
std::move(area_list));
}
}
+9 -9
View File
@@ -3720,19 +3720,19 @@ shared_ptr<Lobby> create_game_generic(
if (game->base_version == GameVersion::BB) {
game->map.reset(new Map());
for (size_t area = 0; area < 0x10; area++) {
for (size_t floor = 0; floor < 0x10; floor++) {
c->log.info("[Map/%zu] Using variations %" PRIX32 ", %" PRIX32,
area, game->variations[area * 2].load(), game->variations[area * 2 + 1].load());
floor, game->variations[floor * 2].load(), game->variations[floor * 2 + 1].load());
auto enemy_filenames = map_filenames_for_variation(
game->episode,
is_solo,
area,
game->variations[area * 2],
game->variations[area * 2 + 1],
floor,
game->variations[floor * 2],
game->variations[floor * 2 + 1],
true);
if (enemy_filenames.empty()) {
c->log.info("[Map/%zu:e] No file to load", area);
c->log.info("[Map/%zu:e] No file to load", floor);
} else {
bool any_map_loaded = false;
for (const string& filename : enemy_filenames) {
@@ -3743,7 +3743,7 @@ shared_ptr<Lobby> create_game_generic(
game->episode, game->difficulty, game->event, map_data->data(), map_data->size());
size_t entries_loaded = game->map->enemies.size() - start_offset;
c->log.info("[Map/%zu:e] Loaded %s (%zu entries)",
area, filename.c_str(), entries_loaded);
floor, filename.c_str(), entries_loaded);
for (size_t z = start_offset; z < game->map->enemies.size(); z++) {
string e_str = game->map->enemies[z].str();
static_game_data_log.info("(Entry %zX) %s", z, e_str.c_str());
@@ -3751,11 +3751,11 @@ shared_ptr<Lobby> create_game_generic(
any_map_loaded = true;
break;
} catch (const exception& e) {
c->log.info("[Map/%zu:e] Failed to load %s: %s", area, filename.c_str(), e.what());
c->log.info("[Map/%zu:e] Failed to load %s: %s", floor, filename.c_str(), e.what());
}
}
if (!any_map_loaded) {
throw runtime_error(string_printf("no enemy maps loaded for area %zu", area));
throw runtime_error(string_printf("no enemy maps loaded for floor %zu", floor));
}
}
}
+38 -34
View File
@@ -206,8 +206,8 @@ static void on_sync_joining_player_item_state(shared_ptr<Client> c, uint8_t comm
auto* decompressed_cmd = reinterpret_cast<G_SyncItemState_6x6D_Decompressed*>(decompressed.data());
size_t num_floor_items = 0;
for (size_t z = 0; z < decompressed_cmd->floor_item_count_per_area.size(); z++) {
num_floor_items += decompressed_cmd->floor_item_count_per_area[z];
for (size_t z = 0; z < decompressed_cmd->floor_item_count_per_floor.size(); z++) {
num_floor_items += decompressed_cmd->floor_item_count_per_floor[z];
}
size_t required_size = sizeof(G_SyncItemState_6x6D_Decompressed) + num_floor_items * sizeof(FloorItem);
@@ -559,9 +559,9 @@ static void on_set_player_visibility(shared_ptr<Client> c, uint8_t command, uint
// Game commands used by cheat mechanisms
template <typename CmdT>
static void on_change_area(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
static void on_change_floor(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
const auto& cmd = check_size_t<CmdT>(data, size);
c->area = cmd.area;
c->floor = cmd.floor;
forward_subcommand(c, command, flag, data, size);
}
@@ -684,7 +684,7 @@ void on_movement(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void
}
template <typename CmdT>
void on_movement_with_area(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
void on_movement_with_floor(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
const auto& cmd = check_size_t<CmdT>(data, size);
if (cmd.header.client_id != c->lobby_client_id) {
return;
@@ -692,7 +692,7 @@ void on_movement_with_area(shared_ptr<Client> c, uint8_t command, uint8_t flag,
c->x = cmd.x;
c->z = cmd.z;
c->area = cmd.area;
c->floor = cmd.floor;
forward_subcommand(c, command, flag, data, size);
}
@@ -711,12 +711,12 @@ static void on_player_drop_item(shared_ptr<Client> c, uint8_t command, uint8_t f
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto p = c->game_data.character();
auto item = p->remove_item(cmd.item_id, 0, c->version() != GameVersion::BB);
l->add_item(item, cmd.area, cmd.x, cmd.z);
l->add_item(item, cmd.floor, cmd.x, cmd.z);
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu dropped item %08" PRIX32 " (%s) at %hu:(%g, %g)",
cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), cmd.area.load(), cmd.x.load(), cmd.z.load());
cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), cmd.floor.load(), cmd.x.load(), cmd.z.load());
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
auto name = s->describe_item(c->version(), item, true);
send_text_message_printf(c, "$C5DROP %08" PRIX32 "\n%s",
@@ -816,13 +816,13 @@ static void on_drop_partial_stack_t(shared_ptr<Client> c, uint8_t command, uint8
ItemData item = cmd.item_data;
item.decode_for_version(c->version());
l->on_item_id_generated_externally(item.id);
l->add_item(item, cmd.area, cmd.x, cmd.z);
l->add_item(item, cmd.floor, cmd.x, cmd.z);
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu split stack to create floor item %08" PRIX32 " (%s) at %hu:(%g, %g)",
cmd.header.client_id.load(), item.id.load(), name.c_str(),
cmd.area.load(), cmd.x.load(), cmd.z.load());
cmd.floor.load(), cmd.x.load(), cmd.z.load());
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
string name = s->describe_item(c->version(), item, true);
send_text_message_printf(c, "$C5SPLIT %08" PRIX32 "\n%s", item.id.load(), name.c_str());
@@ -871,13 +871,13 @@ static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint
// removed again by the 6x29 handler)
p->add_item(item);
l->add_item(item, cmd.area, cmd.x, cmd.z);
l->add_item(item, cmd.floor, cmd.x, cmd.z);
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu split stack %08" PRIX32 " (removed: %s) at %hu:(%g, %g)",
cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(),
cmd.area.load(), cmd.x.load(), cmd.z.load());
cmd.floor.load(), cmd.x.load(), cmd.z.load());
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
auto name = s->describe_item(c->version(), item, true);
send_text_message_printf(c, "$C5SPLIT/BB %08" PRIX32 "\n%s",
@@ -885,7 +885,7 @@ static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint
}
p->print_inventory(stderr, c->version(), s->item_name_index);
send_drop_stacked_item(l, item, cmd.area, cmd.x, cmd.z);
send_drop_stacked_item(l, item, cmd.floor, cmd.x, cmd.z);
} else {
forward_subcommand(c, command, flag, data, size);
@@ -950,12 +950,12 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, uint8_t command, u
ItemData item = cmd.item.item;
item.decode_for_version(c->version());
l->on_item_id_generated_externally(item.id);
l->add_item(item, cmd.item.area, cmd.item.x, cmd.item.z);
l->add_item(item, cmd.item.floor, cmd.item.x, cmd.item.z);
auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hhu (leader) created floor item %08" PRIX32 " (%s) at %hhu:(%g, %g)",
l->leader_id, item.id.load(), name.c_str(), cmd.item.area, cmd.item.x.load(), cmd.item.z.load());
l->leader_id, item.id.load(), name.c_str(), cmd.item.floor, cmd.item.x.load(), cmd.item.z.load());
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
string name = s->describe_item(c->version(), item, true);
send_text_message_printf(c, "$C5DROP %08" PRIX32 "\n%s", item.id.load(), name.c_str());
@@ -1087,7 +1087,7 @@ static void on_pick_up_item_request(shared_ptr<Client> c, uint8_t command, uint8
}
p->print_inventory(stderr, c->version(), s->item_name_index);
send_pick_up_item(c, cmd.item_id, cmd.area);
send_pick_up_item(c, cmd.item_id, cmd.floor);
} else if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED) && !l->item_exists(cmd.item_id)) {
l->log.warning("Player %hu requests to pick up %08" PRIX32 ", but the item does not exist; dropping command",
@@ -1414,7 +1414,7 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
throw runtime_error("item drop request has incorrect subcommand");
}
cmd.entity_id = in_cmd.entity_id;
cmd.area = in_cmd.area;
cmd.floor = in_cmd.floor;
cmd.rt_index = in_cmd.rt_index;
cmd.x = in_cmd.x;
cmd.z = in_cmd.z;
@@ -1426,12 +1426,12 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
throw runtime_error("item drop request has incorrect subcommand");
}
cmd.entity_id = in_cmd.entity_id;
cmd.area = in_cmd.area;
cmd.floor = in_cmd.floor;
cmd.rt_index = in_cmd.rt_index;
cmd.x = in_cmd.x;
cmd.z = in_cmd.z;
cmd.ignore_def = true;
cmd.effective_area = in_cmd.area;
cmd.effective_area = in_cmd.floor;
}
ItemData item;
@@ -1453,6 +1453,10 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
c->log.warning("rt_index %02hhX from command does not match entity\'s expected index %02" PRIX32,
cmd.rt_index, expected_rt_index);
}
if (cmd.floor != enemy.floor) {
c->log.warning("Floor %02hhX from command does not match entity\'s expected floor %02hhX",
cmd.floor, enemy.floor);
}
}
item = l->item_creator->on_monster_item_drop(cmd.entity_id, cmd.rt_index, cmd.effective_area);
}
@@ -1463,11 +1467,11 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
item.id = l->generate_item_id(0xFF);
string name = s->item_name_index->describe_item(l->base_version, item);
l->log.info("Entity %04hX (area %02hX) created item %s", cmd.entity_id.load(), cmd.effective_area, name.c_str());
l->log.info("Creating item %08" PRIX32 " at %02hhX:%g,%g", item.id.load(), cmd.area, cmd.x.load(), cmd.z.load());
l->log.info("Creating item %08" PRIX32 " at %02hhX:%g,%g", item.id.load(), cmd.floor, cmd.x.load(), cmd.z.load());
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
l->add_item(item, cmd.area, cmd.x, cmd.z);
l->add_item(item, cmd.floor, cmd.x, cmd.z);
}
send_drop_item(l, item, cmd.rt_index != 0x30, cmd.area, cmd.x, cmd.z, cmd.entity_id);
send_drop_item(l, item, cmd.rt_index != 0x30, cmd.floor, cmd.x, cmd.z, cmd.entity_id);
}
}
@@ -1512,7 +1516,7 @@ static void on_set_quest_flag(shared_ptr<Client> c, uint8_t command, uint8_t fla
if (c->version() == GameVersion::GC) {
bool should_send_boss_drop_req = false;
bool is_ep2 = (l->episode == Episode::EP2);
if ((l->episode == Episode::EP1) && (c->area == 0x0E)) {
if ((l->episode == Episode::EP1) && (c->floor == 0x0E)) {
// On Normal, Dark Falz does not have a third phase, so send the drop
// request after the end of the second phase. On all other difficulty
// levels, send it after the third phase.
@@ -1520,7 +1524,7 @@ static void on_set_quest_flag(shared_ptr<Client> c, uint8_t command, uint8_t fla
((difficulty != 0) && (flag_index == 0x0037))) {
should_send_boss_drop_req = true;
}
} else if (is_ep2 && (flag_index == 0x0057) && (c->area == 0x0D)) {
} else if (is_ep2 && (flag_index == 0x0057) && (c->floor == 0x0D)) {
should_send_boss_drop_req = true;
}
@@ -1530,7 +1534,7 @@ static void on_set_quest_flag(shared_ptr<Client> c, uint8_t command, uint8_t fla
G_StandardDropItemRequest_PC_V3_BB_6x60 req = {
{
{0x60, 0x06, 0x0000},
static_cast<uint8_t>(c->area),
static_cast<uint8_t>(c->floor),
static_cast<uint8_t>(is_ep2 ? 0x4E : 0x2F),
0x0B4F,
is_ep2 ? -9999.0f : 10160.58984375f,
@@ -1755,7 +1759,7 @@ static void on_steal_exp_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void*
add_player_exp(c, stolen_exp);
}
static void on_enemy_killed_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
static void on_enemy_killed_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void* data, size_t size) {
auto s = c->require_server_state();
auto l = c->require_lobby();
@@ -1763,8 +1767,6 @@ static void on_enemy_killed_bb(shared_ptr<Client> c, uint8_t command, uint8_t fl
throw runtime_error("BB-only command sent in non-BB game");
}
forward_subcommand(c, command, flag, data, size);
const auto& cmd = check_size_t<G_EnemyKilled_BB_6xC8>(data, size);
if (!l->is_game()) {
@@ -1806,11 +1808,13 @@ static void on_enemy_killed_bb(shared_ptr<Client> c, uint8_t command, uint8_t fl
if (!((e.flags >> x) & 1)) {
continue; // Player did not hit this enemy
}
auto other_c = l->clients[x];
if (!other_c) {
continue; // No player
}
if (other_c->floor != e.floor) {
continue;
}
if (experience != 0xFFFFFFFF) {
// Killer gets full experience, others get 77%
@@ -2307,9 +2311,9 @@ subcommand_handler_t subcommand_handlers[0x100] = {
/* 6x1C */ on_forward_check_size_game,
/* 6x1D */ nullptr,
/* 6x1E */ nullptr,
/* 6x1F */ on_change_area<G_SetPlayerArea_6x1F>,
/* 6x20 */ on_movement_with_area<G_SetPosition_6x20>,
/* 6x21 */ on_change_area<G_InterLevelWarp_6x21>,
/* 6x1F */ on_change_floor<G_SetPlayerArea_6x1F>,
/* 6x20 */ on_movement_with_floor<G_SetPosition_6x20>,
/* 6x21 */ on_change_floor<G_InterLevelWarp_6x21>,
/* 6x22 */ on_forward_check_size_client,
/* 6x23 */ on_set_player_visibility,
/* 6x24 */ on_forward_check_size_game,
@@ -2338,8 +2342,8 @@ subcommand_handler_t subcommand_handlers[0x100] = {
/* 6x3B */ on_forward_check_size,
/* 6x3C */ nullptr,
/* 6x3D */ nullptr,
/* 6x3E */ on_movement_with_area<G_StopAtPosition_6x3E>,
/* 6x3F */ on_movement_with_area<G_SetPosition_6x3F>,
/* 6x3E */ on_movement_with_floor<G_StopAtPosition_6x3E>,
/* 6x3F */ on_movement_with_floor<G_SetPosition_6x3F>,
/* 6x40 */ on_movement<G_WalkToPosition_6x40>,
/* 6x41 */ nullptr,
/* 6x42 */ on_movement<G_RunToPosition_6x42>,
+17 -17
View File
@@ -2100,20 +2100,20 @@ void send_player_stats_change(Channel& ch, uint16_t client_id, PlayerStatsChange
send_command_vt(ch, (subs.size() > 0x400 / sizeof(G_UpdatePlayerStat_6x9A)) ? 0x6C : 0x60, 0x00, subs);
}
void send_warp(Channel& ch, uint8_t client_id, uint32_t area, bool is_private) {
G_InterLevelWarp_6x94 cmd = {{0x94, 0x02, 0}, area, {}};
void send_warp(Channel& ch, uint8_t client_id, uint32_t floor, bool is_private) {
G_InterLevelWarp_6x94 cmd = {{0x94, 0x02, 0}, floor, {}};
ch.send(is_private ? 0x62 : 0x60, client_id, &cmd, sizeof(cmd));
}
void send_warp(shared_ptr<Client> c, uint32_t area, bool is_private) {
send_warp(c->channel, c->lobby_client_id, area, is_private);
c->area = area;
void send_warp(shared_ptr<Client> c, uint32_t floor, bool is_private) {
send_warp(c->channel, c->lobby_client_id, floor, is_private);
c->floor = floor;
}
void send_warp(shared_ptr<Lobby> l, uint32_t area, bool is_private) {
void send_warp(shared_ptr<Lobby> l, uint32_t floor, bool is_private) {
for (const auto& c : l->clients) {
if (c) {
send_warp(c, area, is_private);
send_warp(c, floor, is_private);
}
}
}
@@ -2135,44 +2135,44 @@ void send_set_player_visibility(shared_ptr<Lobby> l, shared_ptr<Client> c,
// BB game commands
void send_drop_item(shared_ptr<ServerState> s, Channel& ch, const ItemData& item,
bool from_enemy, uint8_t area, float x, float z, uint16_t entity_id) {
bool from_enemy, uint8_t floor, float x, float z, uint16_t entity_id) {
G_DropItem_PC_V3_BB_6x5F cmd = {
{{0x5F, 0x0B, 0x0000}, {area, from_enemy, entity_id, x, z, 0, 0, item}}, 0};
{{0x5F, 0x0B, 0x0000}, {floor, from_enemy, entity_id, x, z, 0, 0, item}}, 0};
cmd.item.item.encode_for_version(ch.version, s->item_parameter_table_for_version(ch.version));
ch.send(0x60, 0x00, &cmd, sizeof(cmd));
}
void send_drop_item(shared_ptr<Lobby> l, const ItemData& item,
bool from_enemy, uint8_t area, float x, float z, uint16_t entity_id) {
bool from_enemy, uint8_t floor, float x, float z, uint16_t entity_id) {
auto s = l->require_server_state();
for (auto& c : l->clients) {
if (!c) {
continue;
}
send_drop_item(s, c->channel, item, from_enemy, area, x, z, entity_id);
send_drop_item(s, c->channel, item, from_enemy, floor, x, z, entity_id);
}
}
void send_drop_stacked_item(shared_ptr<ServerState> s, Channel& ch, const ItemData& item, uint8_t area, float x, float z) {
G_DropStackedItem_PC_V3_BB_6x5D cmd = {{{0x5D, 0x0A, 0x0000}, area, 0, x, z, item}, 0};
void send_drop_stacked_item(shared_ptr<ServerState> s, Channel& ch, const ItemData& item, uint8_t floor, float x, float z) {
G_DropStackedItem_PC_V3_BB_6x5D cmd = {{{0x5D, 0x0A, 0x0000}, floor, 0, x, z, item}, 0};
cmd.item_data.encode_for_version(ch.version, s->item_parameter_table_for_version(ch.version));
ch.send(0x60, 0x00, &cmd, sizeof(cmd));
}
void send_drop_stacked_item(shared_ptr<Lobby> l, const ItemData& item, uint8_t area, float x, float z) {
void send_drop_stacked_item(shared_ptr<Lobby> l, const ItemData& item, uint8_t floor, float x, float z) {
auto s = l->require_server_state();
for (auto& c : l->clients) {
if (!c) {
continue;
}
send_drop_stacked_item(s, c->channel, item, area, x, z);
send_drop_stacked_item(s, c->channel, item, floor, x, z);
}
}
void send_pick_up_item(shared_ptr<Client> c, uint32_t item_id, uint8_t area) {
void send_pick_up_item(shared_ptr<Client> c, uint32_t item_id, uint8_t floor) {
auto l = c->require_lobby();
uint16_t client_id = c->lobby_client_id;
G_PickUpItem_6x59 cmd = {{0x59, 0x03, client_id}, client_id, area, item_id};
G_PickUpItem_6x59 cmd = {{0x59, 0x03, client_id}, client_id, floor, item_id};
send_command_t(l, 0x60, 0x00, cmd);
}
+8 -8
View File
@@ -284,23 +284,23 @@ enum PlayerStatsChange {
void send_player_stats_change(std::shared_ptr<Client> c, PlayerStatsChange stat, uint32_t amount);
void send_player_stats_change(
Channel& ch, uint16_t client_id, PlayerStatsChange stat, uint32_t amount);
void send_warp(Channel& ch, uint8_t client_id, uint32_t area, bool is_private);
void send_warp(std::shared_ptr<Client> c, uint32_t area, bool is_private);
void send_warp(std::shared_ptr<Lobby> l, uint32_t area, bool is_private);
void send_warp(Channel& ch, uint8_t client_id, uint32_t floor, bool is_private);
void send_warp(std::shared_ptr<Client> c, uint32_t floor, bool is_private);
void send_warp(std::shared_ptr<Lobby> l, uint32_t floor, bool is_private);
void send_ep3_change_music(Channel& ch, uint32_t song);
void send_set_player_visibility(std::shared_ptr<Client> c, bool visible);
void send_revive_player(std::shared_ptr<Client> c);
void send_drop_item(std::shared_ptr<ServerState> s, Channel& ch, const ItemData& item,
bool from_enemy, uint8_t area, float x, float z, uint16_t request_id);
bool from_enemy, uint8_t floor, float x, float z, uint16_t request_id);
void send_drop_item(std::shared_ptr<Lobby> l, const ItemData& item,
bool from_enemy, uint8_t area, float x, float z, uint16_t request_id);
bool from_enemy, uint8_t floor, float x, float z, uint16_t request_id);
void send_drop_stacked_item(std::shared_ptr<ServerState> s, Channel& ch, const ItemData& item,
uint8_t area, float x, float z);
uint8_t floor, float x, float z);
void send_drop_stacked_item(std::shared_ptr<Lobby> l, const ItemData& item,
uint8_t area, float x, float z);
void send_pick_up_item(std::shared_ptr<Client> c, uint32_t id, uint8_t area);
uint8_t floor, float x, float z);
void send_pick_up_item(std::shared_ptr<Client> c, uint32_t id, uint8_t floor);
void send_create_inventory_item(std::shared_ptr<Client> c, const ItemData& item);
void send_destroy_item(std::shared_ptr<Client> c, uint32_t item_id, uint32_t amount);
void send_item_identify_result(std::shared_ptr<Client> c);
+9 -9
View File
@@ -230,9 +230,9 @@ Proxy session commands:\n\
Change your lobby marker color.\n\
warp AREA-ID\n\
warpme AREA-ID\n\
Send yourself to a specific area.\n\
Send yourself to a specific floor.\n\
warpall AREA-ID\n\
Send everyone to a specific area.\n\
Send everyone to a specific floor.\n\
set-override-section-id [SECTION-ID]\n\
Override the section ID for games you create or join. This affects the\n\
active drop chart if you are the leader of the game and the server doesn't\n\
@@ -706,15 +706,15 @@ Proxy session commands:\n\
} else if ((command_name == "warp") || (command_name == "warpme")) {
auto ses = this->get_proxy_session(session_name);
uint8_t area = stoul(command_args);
send_warp(ses->client_channel, ses->lobby_client_id, area, true);
uint8_t floor = stoul(command_args);
send_warp(ses->client_channel, ses->lobby_client_id, floor, true);
} else if (command_name == "warpall") {
auto ses = this->get_proxy_session(session_name);
uint8_t area = stoul(command_args);
send_warp(ses->client_channel, ses->lobby_client_id, area, false);
send_warp(ses->server_channel, ses->lobby_client_id, area, false);
uint8_t floor = stoul(command_args);
send_warp(ses->client_channel, ses->lobby_client_id, floor, false);
send_warp(ses->server_channel, ses->lobby_client_id, floor, false);
} else if ((command_name == "info-board") || (command_name == "info-board-data")) {
auto ses = this->get_proxy_session(session_name);
@@ -815,8 +815,8 @@ Proxy session commands:\n\
send_text_message(ses->client_channel, "$C7Next drop:\n" + name);
} else {
send_drop_stacked_item(s, ses->client_channel, item, ses->area, ses->x, ses->z);
send_drop_stacked_item(s, ses->server_channel, item, ses->area, ses->x, ses->z);
send_drop_stacked_item(s, ses->client_channel, item, ses->floor, ses->x, ses->z);
send_drop_stacked_item(s, ses->server_channel, item, ses->floor, ses->x, ses->z);
string name = s->describe_item(ses->version(), ses->next_drop_item, true);
send_text_message(ses->client_channel, "$C7Item created:\n" + name);
+15 -15
View File
@@ -583,8 +583,8 @@ const unordered_map<string, uint8_t> mag_color_for_name({
{"costume-color", 0x12},
});
uint8_t area_for_name(const std::string& name) {
static const unordered_map<string, uint8_t> areas({
uint8_t floor_for_name(const std::string& name) {
static const unordered_map<string, uint8_t> floors({
{"pioneer2", 0x00},
{"p2", 0x00},
{"forest1", 0x01},
@@ -669,10 +669,10 @@ uint8_t area_for_name(const std::string& name) {
{"saintmillion", 0x09},
{"purgatory", 0x0A},
});
return areas.at(tolower(name));
return floors.at(tolower(name));
}
static const array<const char*, 0x12> ep1_area_names = {
static const array<const char*, 0x12> ep1_floor_names = {
"Pioneer2",
"Forest1",
"Forest2",
@@ -693,7 +693,7 @@ static const array<const char*, 0x12> ep1_area_names = {
"Battle2",
};
static const array<const char*, 0x12> ep2_area_names = {
static const array<const char*, 0x12> ep2_floor_names = {
"Pioneer2",
"VRTempleAlpha",
"VRTempleBeta",
@@ -714,7 +714,7 @@ static const array<const char*, 0x12> ep2_area_names = {
"Tower",
};
static const array<const char*, 0x0B> ep4_area_names = {
static const array<const char*, 0x0B> ep4_floor_names = {
"Pioneer2",
"CraterEast",
"CraterWest",
@@ -728,29 +728,29 @@ static const array<const char*, 0x0B> ep4_area_names = {
"Purgatory",
};
size_t area_limit_for_episode(Episode ep) {
size_t floor_limit_for_episode(Episode ep) {
switch (ep) {
case Episode::EP1:
return ep1_area_names.size() - 1;
return ep1_floor_names.size() - 1;
case Episode::EP2:
return ep2_area_names.size() - 1;
return ep2_floor_names.size() - 1;
case Episode::EP4:
return ep4_area_names.size() - 1;
return ep4_floor_names.size() - 1;
default:
return 0;
}
}
const char* name_for_area(Episode episode, uint8_t area) {
const char* name_for_floor(Episode episode, uint8_t floor) {
switch (episode) {
case Episode::EP1:
return ep1_area_names.at(area);
return ep1_floor_names.at(floor);
case Episode::EP2:
return ep2_area_names.at(area);
return ep2_floor_names.at(floor);
case Episode::EP4:
return ep4_area_names.at(area);
return ep4_floor_names.at(floor);
default:
throw logic_error("invalid episode for drop area");
throw logic_error("invalid episode for drop floor");
}
}
+3 -3
View File
@@ -71,9 +71,9 @@ uint8_t language_code_for_char(char language_char);
extern const std::vector<const char*> name_for_mag_color;
extern const std::unordered_map<std::string, uint8_t> mag_color_for_name;
size_t area_limit_for_episode(Episode ep);
uint8_t area_for_name(const std::string& name);
const char* name_for_area(Episode episode, uint8_t area);
size_t floor_limit_for_episode(Episode ep);
uint8_t floor_for_name(const std::string& name);
const char* name_for_floor(Episode episode, uint8_t floor);
uint32_t class_flags_for_class(uint8_t char_class);