Add Anubis, Flare Dancer, Skull Kid & Spear Moblin to enemy randomizer (#5483)

* Add Anubis, Flare Dancer, Skull Kid & Spear Moblin

* Include spear moblins and exclude flare dancer in clear rooms

* Exclude anubis from clear rooms

* Fix skull kill issues

* Clang format

* Address review

* Use hook

* Update z_en_mb.c
This commit is contained in:
Pepe20129 2025-06-05 03:07:57 +02:00 committed by GitHub
parent 5b2c30edb0
commit abb0a93945
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 162 additions and 123 deletions

View file

@ -13,15 +13,29 @@ extern "C" {
#include <z64.h> #include <z64.h>
} }
const char* enemyCVarList[] = { #define CVAR_ENEMY_RANDOMIZER_NAME CVAR_ENHANCEMENT("RandomizedEnemies")
CVAR_ENHANCEMENT("RandomizedEnemyList.Armos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Arwing"), #define CVAR_ENEMY_RANDOMIZER_DEFAULT ENEMY_RANDOMIZER_OFF
CVAR_ENHANCEMENT("RandomizedEnemyList.BabyDodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.Bari"), #define CVAR_ENEMY_RANDOMIZER_VALUE CVarGetInteger(CVAR_ENEMY_RANDOMIZER_NAME, CVAR_ENEMY_RANDOMIZER_DEFAULT)
CVAR_ENHANCEMENT("RandomizedEnemyList.Beamos"), CVAR_ENHANCEMENT("RandomizedEnemyList.BigSkulltula"),
CVAR_ENHANCEMENT("RandomizedEnemyList.BigStalchild"), CVAR_ENHANCEMENT("RandomizedEnemyList.Biri"), typedef struct EnemyEntry {
CVAR_ENHANCEMENT("RandomizedEnemyList.BlackKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.BlueTektite"), int16_t id;
CVAR_ENHANCEMENT("RandomizedEnemyList.Bubble"), CVAR_ENHANCEMENT("RandomizedEnemyList.ClubMoblin"), int16_t params;
CVAR_ENHANCEMENT("RandomizedEnemyList.DarkLink"), CVAR_ENHANCEMENT("RandomizedEnemyList.Dinolfos"), } EnemyEntry;
CVAR_ENHANCEMENT("RandomizedEnemyList.Dodongo"), CVAR_ENHANCEMENT("RandomizedEnemyList.FireKeese"),
bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, int16_t params, float posX);
bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy);
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed);
const char* enemyCVarList[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
CVAR_ENHANCEMENT("RandomizedEnemyList.Anubis"), 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.FlareDancer"),*/
CVAR_ENHANCEMENT("RandomizedEnemyList.FloorTile"), CVAR_ENHANCEMENT("RandomizedEnemyList.Floormaster"), CVAR_ENHANCEMENT("RandomizedEnemyList.FloorTile"), CVAR_ENHANCEMENT("RandomizedEnemyList.Floormaster"),
CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPeahat"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPot"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPeahat"), CVAR_ENHANCEMENT("RandomizedEnemyList.FlyingPot"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Freezard"), CVAR_ENHANCEMENT("RandomizedEnemyList.Gibdo"), CVAR_ENHANCEMENT("RandomizedEnemyList.Freezard"), CVAR_ENHANCEMENT("RandomizedEnemyList.Gibdo"),
@ -30,18 +44,20 @@ const char* enemyCVarList[] = {
CVAR_ENHANCEMENT("RandomizedEnemyList.Keese"), CVAR_ENHANCEMENT("RandomizedEnemyList.LargeBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.Keese"), CVAR_ENHANCEMENT("RandomizedEnemyList.LargeBaba"),
CVAR_ENHANCEMENT("RandomizedEnemyList.LikeLike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Lizalfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.LikeLike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Lizalfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.MadScrub"), CVAR_ENHANCEMENT("RandomizedEnemyList.NormalWolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.MadScrub"), CVAR_ENHANCEMENT("RandomizedEnemyList.NormalWolfos"),
CVAR_ENHANCEMENT("RandomizedEnemyList.PeahatLarva"), CVAR_ENHANCEMENT("RandomizedEnemyList.Redead"), CVAR_ENHANCEMENT("RandomizedEnemyList.PeahatLarva"), /*CVAR_ENHANCEMENT("RandomizedEnemyList.Poe"),*/
CVAR_ENHANCEMENT("RandomizedEnemyList.RedTektite"), CVAR_ENHANCEMENT("RandomizedEnemyList.Shabom"), CVAR_ENHANCEMENT("RandomizedEnemyList.Redead"), CVAR_ENHANCEMENT("RandomizedEnemyList.RedTektite"),
CVAR_ENHANCEMENT("RandomizedEnemyList.ShellBlade"), CVAR_ENHANCEMENT("RandomizedEnemyList.Skulltula"), CVAR_ENHANCEMENT("RandomizedEnemyList.Shabom"), CVAR_ENHANCEMENT("RandomizedEnemyList.ShellBlade"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Skulltula"), CVAR_ENHANCEMENT("RandomizedEnemyList.SkullKid"),
CVAR_ENHANCEMENT("RandomizedEnemyList.SmallBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.SmallStalchild"), CVAR_ENHANCEMENT("RandomizedEnemyList.SmallBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.SmallStalchild"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Spike"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stalfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.SpearMoblin"), CVAR_ENHANCEMENT("RandomizedEnemyList.Spike"),
CVAR_ENHANCEMENT("RandomizedEnemyList.Stinger"), CVAR_ENHANCEMENT("RandomizedEnemyList.Tailparasan"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stalfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Stinger"),
CVAR_ENHANCEMENT("RandomizedEnemyList.TorchSlug"), CVAR_ENHANCEMENT("RandomizedEnemyList.Wallmaster"), CVAR_ENHANCEMENT("RandomizedEnemyList.Tailparasan"), CVAR_ENHANCEMENT("RandomizedEnemyList.TorchSlug"),
CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteKnuckle"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteWolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.Wallmaster"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteKnuckle"),
CVAR_ENHANCEMENT("RandomizedEnemyList.WitheredBaba"), CVAR_ENHANCEMENT("RandomizedEnemyList.WhiteWolfos"), CVAR_ENHANCEMENT("RandomizedEnemyList.WitheredBaba"),
}; };
const char* enemyNameList[] = { const char* enemyNameList[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
"Anubis",
"Armos", "Armos",
"Arwing", "Arwing",
"Baby Dodongo", "Baby Dodongo",
@ -58,6 +74,7 @@ const char* enemyNameList[] = {
"Dinolfos", "Dinolfos",
"Dodongo", "Dodongo",
"Fire Keese", "Fire Keese",
//"Flare Dancer",
"Floor Tile", "Floor Tile",
"Floormaster", "Floormaster",
"Flying Peahat", "Flying Peahat",
@ -75,13 +92,16 @@ const char* enemyNameList[] = {
"Mad Scrub", "Mad Scrub",
"Wolfos (Normal)", "Wolfos (Normal)",
"Peahat Larva", "Peahat Larva",
//"Poe",
"Redead", "Redead",
"Red Tektite", "Red Tektite",
"Shabom", "Shabom",
"Shell Blade", "Shell Blade",
"Skulltula", "Skulltula",
"Skull Kid",
"Small Deku Baba", "Small Deku Baba",
"Stalchild (Small)", "Stalchild (Small)",
"Spear Moblin",
"Spike", "Spike",
"Stalfos", "Stalfos",
"Stinger", "Stinger",
@ -94,98 +114,105 @@ const char* enemyNameList[] = {
}; };
static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = { static EnemyEntry randomizedEnemySpawnTable[RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE] = {
{ ACTOR_EN_AM, -1 }, // Armos { ACTOR_EN_ANUBICE_TAG, 1 }, // Anubis
{ ACTOR_EN_CLEAR_TAG, 1 }, // Arwing { ACTOR_EN_AM, -1 }, // Armos
{ ACTOR_EN_DODOJR, 0 }, // Baby Dodongo { ACTOR_EN_CLEAR_TAG, 1 }, // Arwing
{ ACTOR_EN_VALI, -1 }, // Bari (big jellyfish) { ACTOR_EN_DODOJR, 0 }, // Baby Dodongo
{ ACTOR_EN_VM, 1280 }, // Beamos { ACTOR_EN_VALI, -1 }, // Bari (big jellyfish)
{ ACTOR_EN_ST, 1 }, // Skulltula (big) { ACTOR_EN_VM, 1280 }, // Beamos
{ ACTOR_EN_SKB, 20 }, // Stalchild (big) { ACTOR_EN_ST, 1 }, // Skulltula (big)
{ ACTOR_EN_BILI, 0 }, // Biri (jellyfish) { ACTOR_EN_SKB, 20 }, // Stalchild (big)
{ ACTOR_EN_IK, 2 }, // Iron Knuckle (black, standing) { ACTOR_EN_BILI, 0 }, // Biri (jellyfish)
{ ACTOR_EN_TITE, -2 }, // Tektite (blue) { ACTOR_EN_IK, 2 }, // Iron Knuckle (black, standing)
{ ACTOR_EN_BB, -1 }, // Bubble (flying skull enemy) (blue) { ACTOR_EN_TITE, -2 }, // Tektite (blue)
{ ACTOR_EN_MB, 0 }, // Moblins (Club) { ACTOR_EN_BB, -1 }, // Bubble (flying skull enemy) (blue)
{ ACTOR_EN_TORCH2, 0 }, // Dark Link { ACTOR_EN_MB, 0 }, // Club Moblin
{ ACTOR_EN_ZF, -2 }, // Dinolfos { ACTOR_EN_TORCH2, 0 }, // Dark Link
{ ACTOR_EN_DODONGO, -1 }, // Dodongo { ACTOR_EN_ZF, -2 }, // Dinolfos
{ ACTOR_EN_FIREFLY, 1 }, // Fire Keese { ACTOR_EN_DODONGO, -1 }, // Dodongo
{ ACTOR_EN_YUKABYUN, 0 }, // Flying Floor Tile { ACTOR_EN_FIREFLY, 1 }, // Fire Keese
{ ACTOR_EN_FLOORMAS, 0 }, // Floormaster // { ACTOR_EN_FD, 0 }, // Flare Dancer (possible cause of crashes because of spawning flame actors on
{ ACTOR_EN_PEEHAT, -1 }, // Flying Peahat (big grounded, doesn't spawn larva) // sloped ground)
{ ACTOR_EN_TUBO_TRAP, 0 }, // Flying pot { ACTOR_EN_YUKABYUN, 0 }, // Flying Floor Tile
{ ACTOR_EN_FZ, 0 }, // Freezard { ACTOR_EN_FLOORMAS, 0 }, // Floormaster
{ ACTOR_EN_RD, 32766 }, // Gibdo (standing) { ACTOR_EN_PEEHAT, -1 }, // Flying Peahat (big grounded, doesn't spawn larva)
{ ACTOR_EN_GOMA, 7 }, // Gohma Larva (Non-Gohma rooms) { ACTOR_EN_TUBO_TRAP, 0 }, // Flying pot
{ ACTOR_EN_CROW, 0 }, // Guay { ACTOR_EN_FZ, 0 }, // Freezard
{ ACTOR_EN_FIREFLY, 4 }, // Ice Keese { ACTOR_EN_RD, 32766 }, // Gibdo (standing)
{ ACTOR_EN_ST, 2 }, // Skulltula (invisible) { ACTOR_EN_GOMA, 7 }, // Gohma Larva (Non-Gohma rooms)
{ ACTOR_EN_FIREFLY, 2 }, // Regular Keese { ACTOR_EN_CROW, 0 }, // Guay
{ ACTOR_EN_DEKUBABA, 1 }, // Deku Baba (large) { ACTOR_EN_FIREFLY, 4 }, // Ice Keese
{ ACTOR_EN_ST, 2 }, // Skulltula (invisible)
{ ACTOR_EN_FIREFLY, 2 }, // Regular Keese
{ ACTOR_EN_DEKUBABA, 1 }, // Deku Baba (large)
// Doesn't work (reliant on surface and also normally used in tandem with a leever spawner, kills itself too quickly
// otherwise) { ACTOR_EN_REEBA, 0 }, // Leever
{ ACTOR_EN_RR, 0 }, // Like-Like { ACTOR_EN_RR, 0 }, // Like-Like
{ ACTOR_EN_ZF, -1 }, // Lizalfos { ACTOR_EN_ZF, -1 }, // Lizalfos
{ ACTOR_EN_DEKUNUTS, 768 }, // Mad Scrub (triple attack) (projectiles don't work) { 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_PEEHAT, 1 }, // Flying Peahat Larva // Doesn't work (actor directly uses water box collision to handle hiding/popping up)
{ ACTOR_EN_RD, 1 }, // Redead (standing) // { ACTOR_EN_OKUTA, 0 }, // Octorok
{ ACTOR_EN_TITE, -1 }, // Tektite (red) { ACTOR_EN_PEEHAT, 1 }, // Flying Peahat Larva
{ ACTOR_EN_BUBBLE, 0 }, // Shabom (bubble) // Doesn't work (Seems to rely on other objects?)
{ ACTOR_EN_SB, 0 }, // Shell Blade // { ACTOR_EN_POH, 0 }, // Poe
{ ACTOR_EN_ST, 0 }, // Skulltula (normal) // Doesn't work (Seems to rely on other objects?)
{ ACTOR_EN_DEKUBABA, 0 }, // Deku Baba (small) // { ACTOR_EN_POH, 2 }, // Poe (composer Sharp)
{ ACTOR_EN_SKB, 1 }, // Stalchild (small) // Doesn't work (Seems to rely on other objects?)
{ ACTOR_EN_NY, 0 }, // Spike (rolling enemy) // { ACTOR_EN_POH, 3 }, // Poe (composer Flat)
{ ACTOR_EN_TEST, 2 }, // Stalfos { ACTOR_EN_RD, 1 }, // Redead (standing)
{ ACTOR_EN_EIYER, 10 }, // Stinger (land) (One in formation, sink under floor and do not activate) { ACTOR_EN_TITE, -1 }, // Tektite (red)
{ ACTOR_EN_TP, -1 }, // Electric Tailpasaran { ACTOR_EN_BUBBLE, 0 }, // Shabom (bubble)
{ ACTOR_EN_BW, 0 }, // Torch Slug { ACTOR_EN_SB, 0 }, // Shell Blade
{ ACTOR_EN_WALLMAS, 1 }, // Wallmaster { ACTOR_EN_ST, 0 }, // Skulltula (normal)
{ ACTOR_EN_IK, 3 }, // Iron Knuckle (white, standing) { ACTOR_EN_SKJ, 4159 }, // Skull Kid
{ ACTOR_EN_WF, 1 }, // Wolfos (white) { ACTOR_EN_DEKUBABA, 0 }, // Deku Baba (small)
{ ACTOR_EN_KAREBABA, 0 }, // Withered Deku Baba { ACTOR_EN_SKB, 1 }, // Stalchild (small)
{ ACTOR_EN_MB, -1 }, // Spear Moblin
// Doesn't work {ACTOR_EN_POH, 0}, // Poe (Seems to rely on other objects?) { ACTOR_EN_NY, 0 }, // Spike (rolling enemy)
// Doesn't work {ACTOR_EN_POH, 2}, // Poe (composer Sharp) (Seems to rely on other objects?) { ACTOR_EN_TEST, 2 }, // Stalfos
// Doesn't work {ACTOR_EN_POH, 3}, // Poe (composer Flat) (Seems to rely on other objects?) { ACTOR_EN_EIYER, 10 }, // Stinger (land) (One in formation, sink under floor and do not activate)
// Doesn't work {ACTOR_EN_OKUTA, 0}, // Octorok (actor directly uses water box collision to handle hiding/popping { ACTOR_EN_TP, -1 }, // Electric Tailpasaran
// up) Doesn't work {ACTOR_EN_REEBA, 0}, // Leever (reliant on surface and also normally used in tandem with a { ACTOR_EN_BW, 0 }, // Torch Slug
// leever spawner, kills itself too quickly otherwise) Kinda doesn't work { ACTOR_EN_FD, 0 }, // Flare Dancer (jumps { ACTOR_EN_WALLMAS, 1 }, // Wallmaster
// out of bounds a lot, and possible cause of crashes because of spawning a ton of flame actors) { ACTOR_EN_IK, 3 }, // Iron Knuckle (white, standing)
{ ACTOR_EN_WF, 1 }, // Wolfos (white)
{ ACTOR_EN_KAREBABA, 0 }, // Withered Deku Baba
}; };
static int enemiesToRandomize[] = { static int enemiesToRandomize[] = {
ACTOR_EN_FIREFLY, // Keese (including fire/ice) ACTOR_EN_ANUBICE_TAG, // Anubis
ACTOR_EN_TEST, // Stalfos ACTOR_EN_FIREFLY, // Keese (including fire/ice)
ACTOR_EN_TITE, // Tektite ACTOR_EN_TEST, // Stalfos
ACTOR_EN_POH, // Poe (normal, blue rupee, composers) ACTOR_EN_TITE, // Tektite
ACTOR_EN_OKUTA, // Octorok ACTOR_EN_POH, // Poe (normal, blue rupee, composers)
ACTOR_EN_WALLMAS, // Wallmaster ACTOR_EN_OKUTA, // Octorok
ACTOR_EN_DODONGO, // Dodongo ACTOR_EN_WALLMAS, // Wallmaster
// ACTOR_EN_REEBA, // Leever (reliant on spawner (z_e_encount1.c) ACTOR_EN_DODONGO, // Dodongo
ACTOR_EN_PEEHAT, // Flying Peahat, big one spawning larva, larva // ACTOR_EN_REEBA, // Leever (reliant on spawner (z_en_encount1.c))
ACTOR_EN_ZF, // Lizalfos, Dinolfos ACTOR_EN_PEEHAT, // Flying Peahat, big one spawning larva, larva
ACTOR_EN_GOMA, // Gohma Larva (normal, eggs, gohma eggs) ACTOR_EN_ZF, // Lizalfos, Dinolfos
ACTOR_EN_BUBBLE, // Shabom (bubble) ACTOR_EN_GOMA, // Gohma Larva (normal, eggs, gohma eggs)
ACTOR_EN_DODOJR, // Baby Dodongo ACTOR_EN_BUBBLE, // Shabom (bubble)
ACTOR_EN_TORCH2, // Dark Link ACTOR_EN_DODOJR, // Baby Dodongo
ACTOR_EN_BILI, // Biri (small jellyfish) ACTOR_EN_TORCH2, // Dark Link
ACTOR_EN_TP, // Electric Tailpasaran ACTOR_EN_BILI, // Biri (small jellyfish)
ACTOR_EN_ST, // Skulltula (normal, big, invisible) ACTOR_EN_TP, // Electric Tailpasaran
ACTOR_EN_BW, // Torch Slug ACTOR_EN_ST, // Skulltula (normal, big, invisible)
ACTOR_EN_EIYER, // Stinger (land) ACTOR_EN_BW, // Torch Slug
ACTOR_EN_MB, // Moblins (Club, spear) ACTOR_EN_EIYER, // Stinger (land)
ACTOR_EN_DEKUBABA, // Deku Baba (small, large) ACTOR_EN_MB, // Moblins (Club, spear)
ACTOR_EN_AM, // Armos (enemy variant) ACTOR_EN_DEKUBABA, // Deku Baba (small, large)
ACTOR_EN_DEKUNUTS, // Mad Scrub (single attack, triple attack) ACTOR_EN_AM, // Armos (enemy variant)
ACTOR_EN_VALI, // Bari (big jellyfish) (spawns very high up) ACTOR_EN_DEKUNUTS, // Mad Scrub (single attack, triple attack)
ACTOR_EN_BB, // Bubble (flying skull enemy) (all colors) ACTOR_EN_VALI, // Bari (big jellyfish) (spawns very high up)
ACTOR_EN_YUKABYUN, // Flying Floor Tile ACTOR_EN_BB, // Bubble (flying skull enemy) (all colors)
ACTOR_EN_VM, // Beamos ACTOR_EN_YUKABYUN, // Flying Floor Tile
ACTOR_EN_FLOORMAS, // Floormaster ACTOR_EN_VM, // Beamos
ACTOR_EN_RD, // Redead, Gibdo ACTOR_EN_FLOORMAS, // Floormaster
ACTOR_EN_SW, // Skullwalltula ACTOR_EN_RD, // Redead, Gibdo
// ACTOR_EN_FD, // Flare Dancer (can be randomized, but not randomized to, so keeping it in vanilla locations ACTOR_EN_SW, // Skullwalltula
// means it at least shows up in the game) ACTOR_EN_FD, // Flare Dancer
ACTOR_EN_SB, // Shell Blade ACTOR_EN_SB, // Shell Blade
ACTOR_EN_KAREBABA, // Withered Deku Baba ACTOR_EN_KAREBABA, // Withered Deku Baba
ACTOR_EN_RR, // Like-Like ACTOR_EN_RR, // Like-Like
@ -198,6 +225,7 @@ static int enemiesToRandomize[] = {
ACTOR_EN_WF, // Wolfos ACTOR_EN_WF, // Wolfos
ACTOR_EN_SKB, // Stalchild ACTOR_EN_SKB, // Stalchild
ACTOR_EN_CROW, // Guay ACTOR_EN_CROW, // Guay
ACTOR_EN_SKJ, // Skull Kid
}; };
extern "C" uint8_t GetRandomizedEnemy(PlayState* play, int16_t* actorId, f32* posX, f32* posY, f32* posZ, int16_t* rotX, extern "C" uint8_t GetRandomizedEnemy(PlayState* play, int16_t* actorId, f32* posX, f32* posY, f32* posZ, int16_t* rotX,
@ -322,7 +350,7 @@ static std::vector<EnemyEntry> selectedEnemyList;
void GetSelectedEnemies() { void GetSelectedEnemies() {
selectedEnemyList.clear(); selectedEnemyList.clear();
for (int i = 0; i < 49; i++) { for (int i = 0; i < RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE; i++) {
if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0)) { if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0)) {
selectedEnemyList.push_back(randomizedEnemySpawnTable[i]); selectedEnemyList.push_back(randomizedEnemySpawnTable[i]);
} else if (CVarGetInteger(enemyCVarList[i], 1)) { } else if (CVarGetInteger(enemyCVarList[i], 1)) {
@ -408,6 +436,8 @@ bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId,
case ACTOR_EN_SB: case ACTOR_EN_SB:
case ACTOR_EN_NY: case ACTOR_EN_NY:
return (!(!isMQ && sceneNum == SCENE_WATER_TEMPLE && roomNum == 2)); return (!(!isMQ && sceneNum == SCENE_WATER_TEMPLE && roomNum == 2));
case ACTOR_EN_SKJ:
return !(sceneNum == SCENE_LOST_WOODS && LINK_IS_CHILD);
default: default:
return 1; return 1;
} }
@ -419,19 +449,19 @@ 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) {
uint32_t isMQ = ResourceMgr_IsSceneMasterQuest(sceneNum); uint32_t isMQ = ResourceMgr_IsSceneMasterQuest(sceneNum);
// Freezard - Child Link can only kill this with jump slash Deku Sticks or other equipment like bombs. // Freezard - Child Link can only kill this with jump slash Deku Sticks or other equipment like bombs.
// Beamos - Needs bombs. // Beamos - Needs bombs.
// Anubis - Needs fire.
// Shell Blade & Spike - Child Link can't kill these with sword or Deku Stick. // Shell Blade & Spike - Child Link can't kill these with sword or Deku Stick.
// Arwing & Dark Link - Both go out of bounds way too easily, softlocking the player. // Flare dancer, Arwing & Dark Link - Both go out of bounds way too easily, softlocking the player.
// Wallmaster - Not easily visible, often makes players think they're softlocked and that there's no enemies left. // Wallmaster - Not easily visible, often makes players think they're softlocked and that there's no enemies left.
// Club Moblin - Many issues with them falling or placing out of bounds. Maybe fixable in the future? // Club Moblin - Many issues with them falling or placing out of bounds. Maybe fixable in the future?
bool enemiesToExcludeClearRooms = enemy.id == ACTOR_EN_FZ || enemy.id == ACTOR_EN_VM || enemy.id == ACTOR_EN_SB || bool enemiesToExcludeClearRooms =
enemy.id == ACTOR_EN_NY || enemy.id == ACTOR_EN_CLEAR_TAG || enemy.id == ACTOR_EN_FZ || enemy.id == ACTOR_EN_VM || enemy.id == ACTOR_EN_SB || enemy.id == ACTOR_EN_NY ||
enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2 || enemy.id == ACTOR_EN_CLEAR_TAG || enemy.id == ACTOR_EN_WALLMAS || enemy.id == ACTOR_EN_TORCH2 ||
enemy.id == ACTOR_EN_MB; (enemy.id == ACTOR_EN_MB && enemy.params == 0) || enemy.id == ACTOR_EN_FD || enemy.id == ACTOR_EN_ANUBICE_TAG;
// Bari - Spawns 3 more enemies, potentially extremely difficult in timed rooms. // Bari - Spawns 3 more enemies, potentially extremely difficult in timed rooms.
bool enemiesToExcludeTimedRooms = enemiesToExcludeClearRooms || enemy.id == ACTOR_EN_VALI; bool enemiesToExcludeTimedRooms = enemiesToExcludeClearRooms || enemy.id == ACTOR_EN_VALI;
@ -532,3 +562,16 @@ bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy) {
return 1; return 1;
} }
} }
void FixClubMoblinScale(void* ptr) {
Actor* actor = (Actor*)ptr;
if (actor->params == -1) {
Actor_SetScale(actor, 0.014f);
}
}
void RegisterEnemyRandomizer() {
COND_ID_HOOK(OnActorInit, ACTOR_EN_MB, CVAR_ENEMY_RANDOMIZER_VALUE, FixClubMoblinScale);
}
static RegisterShipInitFunc initFunc(RegisterEnemyRandomizer, { CVAR_ENEMY_RANDOMIZER_NAME });

View file

@ -1,23 +1,16 @@
#pragma once #pragma once
#include <libultraship/bridge.h> #include <libultraship/libultra/types.h>
typedef struct EnemyEntry { #define RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE 52
int16_t id;
int16_t params;
} EnemyEntry;
#define RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE 49
bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, int16_t params, float posX);
bool IsEnemyAllowedToSpawn(int16_t sceneNum, int8_t roomNum, EnemyEntry enemy);
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed);
extern const char* enemyCVarList[]; extern const char* enemyCVarList[];
extern const char* enemyNameList[]; extern const char* enemyNameList[];
extern void GetSelectedEnemies(); extern void GetSelectedEnemies();
#ifndef __cplusplus #ifndef __cplusplus
uint8_t GetRandomizedEnemy(PlayState* play, int16_t* actorId, f32* posX, f32* posY, f32* posZ, int16_t* rotX, struct PlayState;
uint8_t GetRandomizedEnemy(struct PlayState* play, int16_t* actorId, f32* posX, f32* posY, f32* posZ, int16_t* rotX,
int16_t* rotY, int16_t* rotZ, int16_t* params); int16_t* rotY, int16_t* rotZ, int16_t* params);
#endif #endif

View file

@ -1,6 +1,7 @@
#include "z_en_skj.h" #include "z_en_skj.h"
#include "overlays/actors/ovl_En_Skjneedle/z_en_skjneedle.h" #include "overlays/actors/ovl_En_Skjneedle/z_en_skjneedle.h"
#include "objects/object_skj/object_skj.h" #include "objects/object_skj/object_skj.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h" #include "soh/ResourceManagerHelpers.h"
@ -404,7 +405,9 @@ void EnSkj_Init(Actor* thisx, PlayState* play2) {
default: default:
this->actor.params = type; this->actor.params = type;
if (((this->actor.params != 0) && (this->actor.params != 1)) && (this->actor.params != 2)) { if (((this->actor.params != 0) && (this->actor.params != 1)) && (this->actor.params != 2)) {
if (INV_CONTENT(ITEM_TRADE_ADULT) < ITEM_SAW) { if (INV_CONTENT(ITEM_TRADE_ADULT) < ITEM_SAW &&
CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), ENEMY_RANDOMIZER_OFF) ==
ENEMY_RANDOMIZER_OFF) {
Actor_Kill(&this->actor); Actor_Kill(&this->actor);
return; return;
} }