fix enemy type conditions to match what the client does

This commit is contained in:
Martin Michelsen
2025-02-23 11:24:43 -08:00
parent f9cac45996
commit 52bca977c3
3 changed files with 44 additions and 46 deletions
+1
View File
@@ -16,6 +16,7 @@ static constexpr uint8_t RARE = EnemyTypeDefinition::Flag::IS_RARE;
static const vector<EnemyTypeDefinition> type_defs{ static const vector<EnemyTypeDefinition> type_defs{
// clang-format off // clang-format off
// TYPE FLAGS RT BP ENUM NAME IN-GAME NAME ULTIMATE NAME
{EnemyType::UNKNOWN, 0, 0xFF, 0xFF, "UNKNOWN", "__UNKNOWN__", nullptr}, {EnemyType::UNKNOWN, 0, 0xFF, 0xFF, "UNKNOWN", "__UNKNOWN__", nullptr},
{EnemyType::NONE, 0, 0xFF, 0xFF, "NONE", "__NONE__", nullptr}, {EnemyType::NONE, 0, 0xFF, 0xFF, "NONE", "__NONE__", nullptr},
{EnemyType::NON_ENEMY_NPC, EP1 | EP2 | EP4, 0xFF, 0xFF, "NON_ENEMY_NPC", "__NPC__", nullptr}, {EnemyType::NON_ENEMY_NPC, EP1 | EP2 | EP4, 0xFF, 0xFF, "NON_ENEMY_NPC", "__NPC__", nullptr},
+38 -41
View File
@@ -1055,8 +1055,8 @@ string MapFile::EnemySetEntry::str() const {
this->fparam3.load(), this->fparam3.load(),
this->fparam4.load(), this->fparam4.load(),
this->fparam5.load(), this->fparam5.load(),
this->uparam1.load(), this->iparam1.load(),
this->uparam2.load(), this->iparam2.load(),
this->unused.load()); this->unused.load());
} }
@@ -1073,8 +1073,8 @@ uint64_t MapFile::EnemySetEntry::semantic_hash(uint8_t floor) const {
ret = phosg::fnv1a64(&this->fparam3, sizeof(this->fparam3), ret); ret = phosg::fnv1a64(&this->fparam3, sizeof(this->fparam3), ret);
ret = phosg::fnv1a64(&this->fparam4, sizeof(this->fparam4), ret); ret = phosg::fnv1a64(&this->fparam4, sizeof(this->fparam4), ret);
ret = phosg::fnv1a64(&this->fparam5, sizeof(this->fparam5), ret); ret = phosg::fnv1a64(&this->fparam5, sizeof(this->fparam5), ret);
ret = phosg::fnv1a64(&this->uparam1, sizeof(this->uparam1), ret); ret = phosg::fnv1a64(&this->iparam1, sizeof(this->iparam1), ret);
ret = phosg::fnv1a64(&this->uparam2, sizeof(this->uparam2), ret); ret = phosg::fnv1a64(&this->iparam2, sizeof(this->iparam2), ret);
ret = phosg::fnv1a64(&floor, sizeof(floor), ret); ret = phosg::fnv1a64(&floor, sizeof(floor), ret);
return ret; return ret;
} }
@@ -1132,8 +1132,8 @@ string MapFile::RandomEnemyDefinition::str() const {
this->fparam3.load(), this->fparam3.load(),
this->fparam4.load(), this->fparam4.load(),
this->fparam5.load(), this->fparam5.load(),
this->uparam1.load(), this->iparam1.load(),
this->uparam2.load(), this->iparam2.load(),
this->entry_num.load(), this->entry_num.load(),
this->min_children.load(), this->min_children.load(),
this->max_children.load()); this->max_children.load());
@@ -1496,8 +1496,8 @@ std::shared_ptr<MapFile> MapFile::materialize_random_sections(uint32_t random_se
e.fparam3 = def.fparam3; e.fparam3 = def.fparam3;
e.fparam4 = def.fparam4; e.fparam4 = def.fparam4;
e.fparam5 = def.fparam5; e.fparam5 = def.fparam5;
e.uparam1 = def.uparam1; e.iparam1 = def.iparam1;
e.uparam2 = def.uparam2; e.iparam2 = def.iparam2;
e.num_children = random_state.rand_int_biased(def.min_children, def.max_children); e.num_children = random_state.rand_int_biased(def.min_children, def.max_children);
} else { } else {
throw runtime_error("random enemy definition not found"); throw runtime_error("random enemy definition not found");
@@ -2078,13 +2078,13 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
add(EnemyType::NON_ENEMY_NPC); add(EnemyType::NON_ENEMY_NPC);
break; break;
case 0x0040: { // TObjEneMoja case 0x0040: { // TObjEneMoja
bool is_rare = (static_cast<int16_t>(set_entry->uparam1.load()) >= 1); bool is_rare = (set_entry->iparam1.load() >= 1);
add(EnemyType::HILDEBEAR, is_rare, is_rare); add(EnemyType::HILDEBEAR, is_rare, is_rare);
break; break;
} }
case 0x0041: { // TObjEneLappy case 0x0041: { // TObjEneLappy
bool is_rare_v123 = (set_entry->uparam1 != 0); bool is_rare_v123 = (set_entry->iparam1 != 0);
bool is_rare_bb = (set_entry->uparam1 & 1); bool is_rare_bb = (set_entry->iparam1 & 1);
switch (this->episode) { switch (this->episode) {
case Episode::EP1: case Episode::EP1:
case Episode::EP2: case Episode::EP2:
@@ -2104,11 +2104,11 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
default_num_children = 30; default_num_children = 30;
break; break;
case 0x0043: // TObjEneBm5Wolf case 0x0043: // TObjEneBm5Wolf
add(set_entry->fparam2 ? EnemyType::BARBAROUS_WOLF : EnemyType::SAVAGE_WOLF); add((set_entry->fparam2 >= 1) ? EnemyType::BARBAROUS_WOLF : EnemyType::SAVAGE_WOLF);
break; break;
case 0x0044: { // TObjEneBeast case 0x0044: { // TObjEneBeast
static const EnemyType types[3] = {EnemyType::BOOMA, EnemyType::GOBOOMA, EnemyType::GIGOBOOMA}; static const EnemyType types[3] = {EnemyType::BOOMA, EnemyType::GOBOOMA, EnemyType::GIGOBOOMA};
add(types[set_entry->uparam1 % 3]); add(types[clamp<int16_t>(set_entry->iparam1, 0, 2)]);
break; break;
} }
case 0x0060: // TObjGrass case 0x0060: // TObjGrass
@@ -2122,13 +2122,13 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
break; break;
case 0x0063: { // TObjEneShark case 0x0063: { // TObjEneShark
static const EnemyType types[3] = {EnemyType::EVIL_SHARK, EnemyType::PAL_SHARK, EnemyType::GUIL_SHARK}; static const EnemyType types[3] = {EnemyType::EVIL_SHARK, EnemyType::PAL_SHARK, EnemyType::GUIL_SHARK};
add(types[set_entry->uparam1 % 3]); add(types[clamp<int16_t>(set_entry->iparam1, 0, 2)]);
break; break;
} }
case 0x0064: { // TObjEneSlime case 0x0064: { // TObjEneSlime
// Unlike all other versions, BB doesn't have a way to force slimes to be // Unlike all other versions, BB doesn't have a way to force slimes to be
// rare via constructor args // rare via constructor args
bool is_rare_v123 = (set_entry->uparam2 & 1); bool is_rare_v123 = (set_entry->iparam2 & 1);
default_num_children = -1; // Skip adding children later (because we do it here) default_num_children = -1; // Skip adding children later (because we do it here)
size_t num_children = set_entry->num_children ? set_entry->num_children.load() : 4; size_t num_children = set_entry->num_children ? set_entry->num_children.load() : 4;
for (size_t z = 0; z < num_children + 1; z++) { for (size_t z = 0; z < num_children + 1; z++) {
@@ -2146,13 +2146,13 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
add(EnemyType::MIGIUM); add(EnemyType::MIGIUM);
break; break;
case 0x0080: // TObjEneDubchik case 0x0080: // TObjEneDubchik
add((set_entry->uparam1 & 0x01) ? EnemyType::GILLCHIC : EnemyType::DUBCHIC); add((set_entry->iparam1 != 0) ? EnemyType::GILLCHIC : EnemyType::DUBCHIC);
break; break;
case 0x0081: // TObjEneGyaranzo case 0x0081: // TObjEneGyaranzo
add(EnemyType::GARANZ); add(EnemyType::GARANZ);
break; break;
case 0x0082: // TObjEneMe3ShinowaReal case 0x0082: // TObjEneMe3ShinowaReal
add(set_entry->fparam2 ? EnemyType::SINOW_GOLD : EnemyType::SINOW_BEAT); add((set_entry->fparam2 >= 1) ? EnemyType::SINOW_GOLD : EnemyType::SINOW_BEAT);
default_num_children = 4; default_num_children = 4;
break; break;
case 0x0083: // TObjEneMe1Canadin case 0x0083: // TObjEneMe1Canadin
@@ -2192,7 +2192,7 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
break; break;
case 0x00A6: { // TObjEneDimedian case 0x00A6: { // TObjEneDimedian
static const EnemyType types[3] = {EnemyType::DIMENIAN, EnemyType::LA_DIMENIAN, EnemyType::SO_DIMENIAN}; static const EnemyType types[3] = {EnemyType::DIMENIAN, EnemyType::LA_DIMENIAN, EnemyType::SO_DIMENIAN};
add(types[set_entry->uparam1 % 3]); add(types[clamp<int16_t>(set_entry->iparam1, 0, 2)]);
break; break;
} }
case 0x00A7: // TObjEneBalClawBody case 0x00A7: // TObjEneBalClawBody
@@ -2277,14 +2277,14 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
default_num_children = 5; default_num_children = 5;
break; break;
case 0x00D4: // TObjEneMe3StelthReal case 0x00D4: // TObjEneMe3StelthReal
add((set_entry->uparam1 & 1) ? EnemyType::SINOW_SPIGELL : EnemyType::SINOW_BERILL); add((set_entry->iparam1 > 0) ? EnemyType::SINOW_SPIGELL : EnemyType::SINOW_BERILL);
default_num_children = 4; default_num_children = 4;
break; break;
case 0x00D5: // TObjEneMerillLia case 0x00D5: // TObjEneMerillLia
add((set_entry->uparam1 & 1) ? EnemyType::MERILTAS : EnemyType::MERILLIA); add((set_entry->iparam1 > 0) ? EnemyType::MERILTAS : EnemyType::MERILLIA);
break; break;
case 0x00D6: { // TObjEneBm9Mericarol case 0x00D6: { // TObjEneBm9Mericarol
switch (set_entry->uparam1) { switch (set_entry->iparam1) {
case 0: case 0:
add(EnemyType::MERICAROL); add(EnemyType::MERICAROL);
break; break;
@@ -2300,7 +2300,7 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
break; break;
} }
case 0x00D7: // TObjEneBm5GibonU case 0x00D7: // TObjEneBm5GibonU
add((set_entry->uparam1 & 0x01) ? EnemyType::ZOL_GIBBON : EnemyType::UL_GIBBON); add((set_entry->iparam1 > 0) ? EnemyType::ZOL_GIBBON : EnemyType::UL_GIBBON);
break; break;
case 0x00D8: // TObjEneGibbles case 0x00D8: // TObjEneGibbles
add(EnemyType::GIBBLES); add(EnemyType::GIBBLES);
@@ -2318,7 +2318,7 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
add(EnemyType::DELBITER); add(EnemyType::DELBITER);
break; break;
case 0x00DD: // TObjEneDolmOlm case 0x00DD: // TObjEneDolmOlm
add(set_entry->uparam1 ? EnemyType::DOLMDARL : EnemyType::DOLMOLM); add((set_entry->iparam1 > 0) ? EnemyType::DOLMDARL : EnemyType::DOLMOLM);
break; break;
case 0x00DE: // TObjEneMorfos case 0x00DE: // TObjEneMorfos
add(EnemyType::MORFOS); add(EnemyType::MORFOS);
@@ -2333,7 +2333,7 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
default_num_children = 4; default_num_children = 4;
child_type = EnemyType::EPSIGARD; child_type = EnemyType::EPSIGARD;
} else { } else {
add((set_entry->uparam1 & 0x01) ? EnemyType::SINOW_ZELE : EnemyType::SINOW_ZOA); add((set_entry->iparam1 > 0) ? EnemyType::SINOW_ZELE : EnemyType::SINOW_ZOA);
} }
break; break;
case 0x00E1: // TObjEneIllGill case 0x00E1: // TObjEneIllGill
@@ -2350,7 +2350,7 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
} }
break; break;
case 0x0112: { case 0x0112: {
bool is_rare = (set_entry->uparam1 & 0x01); bool is_rare = (set_entry->iparam1 & 1);
add(EnemyType::MERISSA_A, is_rare, is_rare); add(EnemyType::MERISSA_A, is_rare, is_rare);
break; break;
} }
@@ -2358,34 +2358,31 @@ shared_ptr<SuperMap::Enemy> SuperMap::add_enemy_and_children(
add(EnemyType::GIRTABLULU); add(EnemyType::GIRTABLULU);
break; break;
case 0x0114: { case 0x0114: {
bool is_rare = (set_entry->uparam1 & 0x01); bool is_rare = (set_entry->iparam1 & 1);
add((floor > 0x05) ? EnemyType::ZU_DESERT : EnemyType::ZU_CRATER, is_rare, is_rare); add((floor > 0x05) ? EnemyType::ZU_DESERT : EnemyType::ZU_CRATER, is_rare, is_rare);
break; break;
} }
case 0x0115: case 0x0115: {
if (set_entry->uparam1 & 2) { static const EnemyType types[3] = {EnemyType::BOOTA, EnemyType::ZE_BOOTA, EnemyType::BA_BOOTA};
add(EnemyType::BA_BOOTA); add(types[clamp<int16_t>(set_entry->iparam1, 0, 2)]);
} else {
add((set_entry->uparam1 & 1) ? EnemyType::ZE_BOOTA : EnemyType::BOOTA);
}
break; break;
}
case 0x0116: { case 0x0116: {
bool is_rare = (set_entry->uparam1 & 0x01); bool is_rare = (set_entry->iparam1 & 1);
add(EnemyType::DORPHON, is_rare, is_rare); add(EnemyType::DORPHON, is_rare, is_rare);
break; break;
} }
case 0x0117: { case 0x0117: {
static const EnemyType types[3] = {EnemyType::GORAN, EnemyType::PYRO_GORAN, EnemyType::GORAN_DETONATOR}; static const EnemyType types[3] = {EnemyType::GORAN, EnemyType::PYRO_GORAN, EnemyType::GORAN_DETONATOR};
add(types[set_entry->uparam1 % 3]); add(types[clamp<int16_t>(set_entry->iparam1, 0, 2)]);
break; break;
} }
case 0x0119: { case 0x0119:
// TODO: It appears BB doesn't have a way to force Kondrieu to appear via // There isn't a way to force the Episode 4 boss to be rare via
// constructor args. Is this true? // constructor args
add((set_entry->uparam1 & 1) ? EnemyType::SHAMBERTIN : EnemyType::SAINT_MILION); add((set_entry->iparam1 & 1) ? EnemyType::SHAMBERTIN : EnemyType::SAINT_MILION);
default_num_children = 0x18; default_num_children = 0x18;
break; break;
}
case 0x00C3: // TBoss3VoloptP01 case 0x00C3: // TBoss3VoloptP01
case 0x00C4: // TBoss3VoloptCore or subclass case 0x00C4: // TBoss3VoloptCore or subclass
@@ -2762,8 +2759,8 @@ static double enemy_set_edit_cost(const MapFile::EnemySetEntry& prev, const MapF
((prev.fparam3 != current.fparam3) * 10.0) + ((prev.fparam3 != current.fparam3) * 10.0) +
((prev.fparam4 != current.fparam4) * 10.0) + ((prev.fparam4 != current.fparam4) * 10.0) +
((prev.fparam5 != current.fparam5) * 10.0) + ((prev.fparam5 != current.fparam5) * 10.0) +
((prev.uparam1 != current.uparam1) * 10.0) + ((prev.iparam1 != current.iparam1) * 10.0) +
((prev.uparam2 != current.uparam2) * 10.0)); ((prev.iparam2 != current.iparam2) * 10.0));
} }
static double event_add_cost(const MapFile::Event1Entry&) { static double event_add_cost(const MapFile::Event1Entry&) {
+5 -5
View File
@@ -206,8 +206,8 @@ public:
/* 34 */ le_float fparam3 = 0.0f; /* 34 */ le_float fparam3 = 0.0f;
/* 38 */ le_float fparam4 = 0.0f; /* 38 */ le_float fparam4 = 0.0f;
/* 3C */ le_float fparam5 = 0.0f; /* 3C */ le_float fparam5 = 0.0f;
/* 40 */ le_uint16_t uparam1 = 0; /* 40 */ le_int16_t iparam1 = 0;
/* 42 */ le_uint16_t uparam2 = 0; /* 42 */ le_int16_t iparam2 = 0;
/* 44 */ le_uint32_t unused = 0; // Reserved for pointer in client's memory; unused by server /* 44 */ le_uint32_t unused = 0; // Reserved for pointer in client's memory; unused by server
/* 48 */ /* 48 */
@@ -296,14 +296,14 @@ public:
struct RandomEnemyDefinition { // Section type 5 (RANDOM_ENEMY_DEFINITIONS) struct RandomEnemyDefinition { // Section type 5 (RANDOM_ENEMY_DEFINITIONS)
// All fields through entry_num map to the corresponding fields in // All fields through entry_num map to the corresponding fields in
// EnemySetEntry. Note that the order of the uparam fields is switched! // EnemySetEntry. Note that the order of the iparam fields is switched!
/* 00 */ le_float fparam1; /* 00 */ le_float fparam1;
/* 04 */ le_float fparam2; /* 04 */ le_float fparam2;
/* 08 */ le_float fparam3; /* 08 */ le_float fparam3;
/* 0C */ le_float fparam4; /* 0C */ le_float fparam4;
/* 10 */ le_float fparam5; /* 10 */ le_float fparam5;
/* 14 */ le_uint16_t uparam2; /* 14 */ le_int16_t iparam2;
/* 16 */ le_uint16_t uparam1; /* 16 */ le_int16_t iparam1;
/* 18 */ le_uint32_t entry_num; /* 18 */ le_uint32_t entry_num;
/* 1C */ le_uint16_t min_children; /* 1C */ le_uint16_t min_children;
/* 1E */ le_uint16_t max_children; /* 1E */ le_uint16_t max_children;