Allow for User Selected Enemies for Enemizer (#4236)

* Allow for User Selected Enemies for Enemizer

* Updated CVar Entry List

* ImGui Cvar Updates

* GetSelectedEnemies Cvar Update

* Populate List if empty and if menu selection changes for Enemy Randomizer/Enemy List

* for loop for Menu Bar cvars, added enemyNameList table to get actor names

* Update variable for macOS/Linux

* Alphabetical Order you say?
This commit is contained in:
Caladius 2024-10-10 19:11:35 -04:00 committed by GitHub
parent a6110dbc51
commit 6d8480c16a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 151 additions and 45 deletions

View File

@ -13,56 +13,100 @@ extern "C" {
extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
const char* enemyCVarList[] = {
CVAR_ENHANCEMENT("RandomizedEnemyList.Armos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Arwing"),
CVAR_ENHANCEMENT("RandomizedEnemyList.BabyDodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.Bari"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Beamos"), CVAR_ENHANCEMENT("RandomizedEnemyList.BigSkulltula"),
CVAR_ENHANCEMENT("RandomizedEnemyList.BigStalchild"), CVAR_ENHANCEMENT("RandomizedEnemyList.Biri"),
CVAR_ENHANCEMENT("RandomizedEnemyList.BlackKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.BlueTektite"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Bubble"), CVAR_ENHANCEMENT("RandomizedEnemyList.ClubMoblin"),
CVAR_ENHANCEMENT("RandomizedEnemyList.DarkLink"), CVAR_ENHANCEMENT("RandomizedEnemyList.Dinolfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Dodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.FireKeese"),
CVAR_ENHANCEMENT("RandomizedEnemyList.FloorTile"), CVAR_ENHANCEMENT("RandomizedEnemyList.Floormaster"),
CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPeahat"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPot"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Freezard"), CVAR_ENHANCEMENT("RandomizedEnemyList.Gibdo"),
CVAR_ENHANCEMENT("RandomizedEnemyList.GohmaLarva"), CVAR_ENHANCEMENT("RandomizedEnemyList.Guay"),
CVAR_ENHANCEMENT("RandomizedEnemyList.IceKeese"), CVAR_ENHANCEMENT("RandomizedEnemyList.InvisSkulltula"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Keese"), CVAR_ENHANCEMENT("RandomizedEnemyList.LargeBaba"),
CVAR_ENHANCEMENT("RandomizedEnemyList.LikeLike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Lizalfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.MadScrub"), CVAR_ENHANCEMENT("RandomizedEnemyList.NormalWolfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.PeahatLarva"), CVAR_ENHANCEMENT("RandomizedEnemyList.Redead"),
CVAR_ENHANCEMENT("RandomizedEnemyList.RedTektite"), CVAR_ENHANCEMENT("RandomizedEnemyList.Shabom"),
CVAR_ENHANCEMENT("RandomizedEnemyList.ShellBlade"), CVAR_ENHANCEMENT("RandomizedEnemyList.Skulltula"),
CVAR_ENHANCEMENT("RandomizedEnemyList.SmallBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.SmallStalchild"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Spike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stalfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Stinger"), CVAR_ENHANCEMENT("RandomizedEnemyList.Tailparasan"),
CVAR_ENHANCEMENT("RandomizedEnemyList.TorchSlug"), CVAR_ENHANCEMENT("RandomizedEnemyList.Wallmaster"),
CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteWolfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.WitheredBaba"),
};
const char* enemyNameList[] = {
"Armos", "Arwing", "Baby Dodongo", "Bari",
"Beamos", "Big Skulltula", "Stalchild (Big)", "Biri",
"Iron Knuckle (Black)", "Blue Tektite", "Bubble", "Club Moblin",
"Dark Link", "Dinolfos", "Dodongo", "Fire Keese",
"Floor Tile", "Floormaster", "Flying Peahat", "Flying Pot",
"Freezard", "Gibdo", "Gohma Larva", "Guay",
"Ice Keese", "Invisible Skulltula", "Keese", "Large Deku Baba",
"Like-Like", "Lizalfos", "Mad Scrub", "Wolfos (Normal)",
"Peahat Larva", "Redead", "Red Tektite", "Shabom",
"ShellBlade", "Skulltula", "Small Deku Baba", "Stalchild (Small)",
"Spike", "Stalfos", "Stinger", "Tailparasan",
"Torch Slug", "Wallmaster", "Iron Knuckle (White)", "Wolfos (White)",
"Withered Deku Baba",
};
static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = { static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
{ ACTOR_EN_FIREFLY, 2 }, // Regular Keese { ACTOR_EN_AM, -1 }, // Armos
{ ACTOR_EN_FIREFLY, 1 }, // Fire Keese { ACTOR_EN_CLEAR_TAG, 1 }, // Arwing
{ ACTOR_EN_FIREFLY, 4 }, // Ice Keese
{ ACTOR_EN_TEST, 2 }, // Stalfos
{ ACTOR_EN_TITE, -1 }, // Tektite (red)
{ ACTOR_EN_TITE, -2 }, // Tektite (blue)
{ ACTOR_EN_WALLMAS, 1 }, // Wallmaster
{ ACTOR_EN_DODONGO, -1 }, // Dodongo
{ ACTOR_EN_PEEHAT, -1 }, // Flying Peahat (big grounded, doesn't spawn larva)
{ ACTOR_EN_PEEHAT, 1 }, // Flying Peahat Larva
{ ACTOR_EN_ZF, -1 }, // Lizalfos
{ ACTOR_EN_ZF, -2 }, // Dinolfos
{ ACTOR_EN_GOMA, 7 }, // Gohma larva (non-gohma rooms)
{ ACTOR_EN_BUBBLE, 0 }, // Shabom (bubble)
{ ACTOR_EN_DODOJR, 0 }, // Baby Dodongo { ACTOR_EN_DODOJR, 0 }, // Baby Dodongo
{ ACTOR_EN_TORCH2, 0 }, // Dark Link
{ ACTOR_EN_BILI, 0 }, // Biri (jellyfish)
{ ACTOR_EN_TP, -1 }, // Electric Tailparasan
{ ACTOR_EN_ST, 0 }, // Skulltula (normal)
{ ACTOR_EN_ST, 1 }, // Skulltula (big)
{ ACTOR_EN_ST, 2 }, // Skulltula (invisible)
{ ACTOR_EN_BW, 0 }, // Torch Slug
{ ACTOR_EN_EIYER, 10 }, // Stinger (land) (One in formation, sink under floor and do not activate)
{ ACTOR_EN_MB, 0 }, // Moblins (Club)
{ ACTOR_EN_DEKUBABA, 0 }, // Deku Baba (small)
{ ACTOR_EN_DEKUBABA, 1 }, // Deku Baba (large)
{ ACTOR_EN_AM, -1 }, // Armos (enemy variant)
{ ACTOR_EN_DEKUNUTS, 768 }, // Mad Scrub (triple attack) (projectiles don't work)
{ ACTOR_EN_VALI, -1 }, // Bari (big jellyfish) { ACTOR_EN_VALI, -1 }, // Bari (big jellyfish)
{ ACTOR_EN_BB, -1 }, // Bubble (flying skull enemy) (blue)
{ ACTOR_EN_YUKABYUN, 0 }, // Flying Floor Tile
{ ACTOR_EN_VM, 1280 }, // Beamos { ACTOR_EN_VM, 1280 }, // Beamos
{ ACTOR_EN_FLOORMAS, 0 }, // Floormaster { ACTOR_EN_ST, 1 }, // Skulltula (big)
{ ACTOR_EN_RD, 1 }, // Redead (standing) { ACTOR_EN_SKB, 20 }, // Stalchild (big)
{ ACTOR_EN_RD, 32766 }, // Gibdo (standing) { ACTOR_EN_BILI, 0 }, // Biri (jellyfish)
{ ACTOR_EN_SB, 0 }, // Shell Blade
{ ACTOR_EN_KAREBABA, 0 }, // Withered Deku Baba
{ ACTOR_EN_RR, 0 }, // Like-Like
{ ACTOR_EN_NY, 0 }, // Spike (rolling enemy)
{ ACTOR_EN_IK, 2 }, // Iron Knuckle (black, standing) { ACTOR_EN_IK, 2 }, // Iron Knuckle (black, standing)
{ ACTOR_EN_IK, 3 }, // Iron Knuckle (white, standing) { ACTOR_EN_TITE, -2 }, // Tektite (blue)
{ ACTOR_EN_BB, -1 }, // Bubble (flying skull enemy) (blue)
{ ACTOR_EN_MB, 0 }, // Moblins (Club)
{ ACTOR_EN_TORCH2, 0 }, // Dark Link
{ ACTOR_EN_ZF, -2 }, // Dinolfos
{ ACTOR_EN_DODONGO, -1 }, // Dodongo
{ ACTOR_EN_FIREFLY, 1 }, // Fire Keese
{ ACTOR_EN_YUKABYUN, 0 }, // Flying Floor Tile
{ ACTOR_EN_FLOORMAS, 0 }, // Floormaster
{ ACTOR_EN_PEEHAT, -1 }, // Flying Peahat (big grounded, doesn't spawn larva)
{ ACTOR_EN_TUBO_TRAP, 0 }, // Flying pot { ACTOR_EN_TUBO_TRAP, 0 }, // Flying pot
{ ACTOR_EN_FZ, 0 }, // Freezard { ACTOR_EN_FZ, 0 }, // Freezard
{ ACTOR_EN_CLEAR_TAG, 1 }, // Arwing { ACTOR_EN_RD, 32766 }, // Gibdo (standing)
{ ACTOR_EN_GOMA, 7 }, // Gohma larva (non-gohma rooms)
{ ACTOR_EN_CROW, 0 }, // Guay
{ ACTOR_EN_FIREFLY, 4 }, // Ice Keese
{ ACTOR_EN_ST, 2 }, // Skulltula (invisible)
{ ACTOR_EN_IK, 3 }, // Iron Knuckle (white, standing)
{ ACTOR_EN_FIREFLY, 2 }, // Regular Keese
{ ACTOR_EN_DEKUBABA, 1 }, // Deku Baba (large)
{ ACTOR_EN_RR, 0 }, // Like-Like
{ ACTOR_EN_ZF, -1 }, // Lizalfos
{ ACTOR_EN_DEKUNUTS, 768 }, // Mad Scrub (triple attack) (projectiles don't work)
{ ACTOR_EN_WF, 0 }, // Wolfos (normal) { ACTOR_EN_WF, 0 }, // Wolfos (normal)
{ ACTOR_EN_WF, 1 }, // Wolfos (white) { ACTOR_EN_PEEHAT, 1 }, // Flying Peahat Larva
{ ACTOR_EN_RD, 1 }, // Redead (standing)
{ ACTOR_EN_TITE, -1 }, // Tektite (red)
{ ACTOR_EN_BUBBLE, 0 }, // Shabom (bubble)
{ ACTOR_EN_SB, 0 }, // Shell Blade
{ ACTOR_EN_ST, 0 }, // Skulltula (normal)
{ ACTOR_EN_DEKUBABA, 0 }, // Deku Baba (small)
{ ACTOR_EN_SKB, 1 }, // Stalchild (small) { ACTOR_EN_SKB, 1 }, // Stalchild (small)
{ ACTOR_EN_SKB, 20 }, // Stalchild (big) { ACTOR_EN_NY, 0 }, // Spike (rolling enemy)
{ ACTOR_EN_CROW, 0 } // Guay { ACTOR_EN_TEST, 2 }, // Stalfos
{ ACTOR_EN_EIYER, 10 }, // Stinger (land) (One in formation, sink under floor and do not activate)
{ ACTOR_EN_TP, -1 }, // Electric Tailparasan
{ ACTOR_EN_BW, 0 }, // Torch Slug
{ ACTOR_EN_WALLMAS, 1 }, // Wallmaster
{ ACTOR_EN_WF, 1 }, // Wolfos (white)
{ ACTOR_EN_KAREBABA, 0 }, // Withered Deku Baba
// Doesn't work {ACTOR_EN_POH, 0}, // Poe (Seems to rely on other objects?) // Doesn't work {ACTOR_EN_POH, 0}, // Poe (Seems to rely on other objects?)
// Doesn't work {ACTOR_EN_POH, 2}, // Poe (composer Sharp) (Seems to rely on other objects?) // Doesn't work {ACTOR_EN_POH, 2}, // Poe (composer Sharp) (Seems to rely on other objects?)
@ -234,14 +278,41 @@ extern "C" uint8_t GetRandomizedEnemy(PlayState* play, int16_t *actorId, f32 *po
return 1; return 1;
} }
std::vector<EnemyEntry> selectedEnemyList;
void GetSelectedEnemies() {
selectedEnemyList.clear();
if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), ENEMY_RANDOMIZER_OFF) == ENEMY_RANDOMIZER_RANDOM) {
for (int i = 0; i < 49; i++) {
if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0)) {
selectedEnemyList.push_back(randomizedEnemySpawnTable[i]);
} else if (CVarGetInteger(enemyCVarList[i], 0)) {
selectedEnemyList.push_back(randomizedEnemySpawnTable[i]);
}
}
if (selectedEnemyList.size() == 0) {
selectedEnemyList.push_back(randomizedEnemySpawnTable[0]);
}
} else {
for (int i = 0; i < 49; i++) {
selectedEnemyList.push_back(randomizedEnemySpawnTable[i]);
}
}
}
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed) { EnemyEntry GetRandomizedEnemyEntry(uint32_t seed) {
if (selectedEnemyList.size() == 0) {
GetSelectedEnemies();
}
if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), ENEMY_RANDOMIZER_OFF) == ENEMY_RANDOMIZER_RANDOM_SEEDED) { if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), ENEMY_RANDOMIZER_OFF) == ENEMY_RANDOMIZER_RANDOM_SEEDED) {
uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.sohStats.fileCreatedAt); uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.sohStats.fileCreatedAt);
Random_Init(finalSeed); Random_Init(finalSeed);
}
uint32_t randomNumber = Random(0, RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE); uint32_t randomNumber = Random(0, RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE);
return randomizedEnemySpawnTable[randomNumber]; return selectedEnemyList[randomNumber];
} else {
uint32_t randomSelectedEnemy = Random(0, selectedEnemyList.size());
return selectedEnemyList[randomSelectedEnemy];
}
} }
bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, int16_t params, float posX) { bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, int16_t params, float posX) {

View File

@ -13,6 +13,10 @@ bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId,
bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy); bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy);
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed); EnemyEntry GetRandomizedEnemyEntry(uint32_t seed);
extern const char* enemyCVarList[];
extern const char* enemyNameList[];
extern void GetSelectedEnemies();
#ifndef __cplusplus #ifndef __cplusplus
uint8_t GetRandomizedEnemy(PlayState* play, int16_t *actorId, f32 *posX, f32 *posY, f32 *posZ, int16_t *rotX, int16_t *rotY, int16_t *rotZ, int16_t *params); uint8_t GetRandomizedEnemy(PlayState* play, int16_t *actorId, f32 *posX, f32 *posY, f32 *posZ, int16_t *rotX, int16_t *rotY, int16_t *rotZ, int16_t *params);
#endif #endif

View File

@ -38,6 +38,7 @@
#include "Enhancements/randomizer/randomizer_item_tracker.h" #include "Enhancements/randomizer/randomizer_item_tracker.h"
#include "Enhancements/randomizer/randomizer_settings_window.h" #include "Enhancements/randomizer/randomizer_settings_window.h"
#include "Enhancements/resolution-editor/ResolutionEditor.h" #include "Enhancements/resolution-editor/ResolutionEditor.h"
#include "Enhancements/enemyrandomizer.h"
// FA icons are kind of wonky, if they worked how I expected them to the "+ 2.0f" wouldn't be needed, but // FA icons are kind of wonky, if they worked how I expected them to the "+ 2.0f" wouldn't be needed, but
// they don't work how I expect them to so I added that because it looked good when I eyeballed it // they don't work how I expect them to so I added that because it looked good when I eyeballed it
@ -1447,13 +1448,43 @@ void DrawEnhancementsMenu() {
); );
UIWidgets::PaddedText("Enemy Randomizer", true, false); UIWidgets::PaddedText("Enemy Randomizer", true, false);
UIWidgets::EnhancementCombobox(CVAR_ENHANCEMENT("RandomizedEnemies"), enemyRandomizerModes, ENEMY_RANDOMIZER_OFF); if (UIWidgets::EnhancementCombobox(CVAR_ENHANCEMENT("RandomizedEnemies"), enemyRandomizerModes, ENEMY_RANDOMIZER_OFF)) {
GetSelectedEnemies();
}
UIWidgets::Tooltip( UIWidgets::Tooltip(
"Replaces fixed enemies throughout the game with a random enemy. Bosses, mini-bosses and a few specific regular enemies are excluded.\n" "Replaces fixed enemies throughout the game with a random enemy. Bosses, mini-bosses and a few specific regular enemies are excluded.\n"
"Enemies that need more than Deku Nuts + either Deku Sticks or a sword to kill are excluded from spawning in \"clear enemy\" rooms.\n\n" "Enemies that need more than Deku Nuts + either Deku Sticks or a sword to kill are excluded from spawning in \"clear enemy\" rooms.\n\n"
"- Random: Enemies are randomized every time you load a room\n" "- Random: Enemies are randomized every time you load a room\n"
"- Random (Seeded): Enemies are randomized based on the current randomizer seed/file\n" "- Random (Seeded): Enemies are randomized based on the current randomizer seed/file\n"
); );
if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0) == ENEMY_RANDOMIZER_RANDOM) {
ImGui::Separator();
if (ImGui::BeginMenu("Enemy List")) {
UIWidgets::PaddedEnhancementCheckbox("Select All Enemies", CVAR_ENHANCEMENT("RandomizedEnemyList.All"), true, false);
bool disabledEnemyList = CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0);
ImGui::Separator();
ImGui::BeginDisabled(CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0));
ImGui::BeginTable("Enemy Table", 2);
ImGui::TableNextColumn();
for (int i = 0; i < RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE; i++) {
if (UIWidgets::PaddedEnhancementCheckbox(enemyNameList[i], enemyCVarList[i], true, false, disabledEnemyList,
"These options are disabled because \"Select All Enemies\" is enabled.",
UIWidgets::CheckboxGraphics::Checkmark)) {
GetSelectedEnemies();
}
if (i == RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE / 2) {
ImGui::TableNextColumn();
}
}
ImGui::EndTable();
ImGui::EndDisabled();
ImGui::EndMenu();
}
};
ImGui::Separator();
UIWidgets::PaddedEnhancementCheckbox("Randomized Enemy Sizes", CVAR_ENHANCEMENT("RandomizedEnemySizes"), true, false); UIWidgets::PaddedEnhancementCheckbox("Randomized Enemy Sizes", CVAR_ENHANCEMENT("RandomizedEnemySizes"), true, false);
UIWidgets::Tooltip("Enemies and Bosses spawn with random sizes."); UIWidgets::Tooltip("Enemies and Bosses spawn with random sizes.");