Skip to content

Commit

Permalink
Add "Bosses only" option to Enemy Soul Shuffle (#737)
Browse files Browse the repository at this point in the history
* Mention Iron Knuckle in Gerudo Soul messages

* Add "Bosses only" option for Enemy Souls

* Formatting
  • Loading branch information
HylianFreddy authored Jun 26, 2024
1 parent e2012dc commit 97eb227
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 96 deletions.
25 changes: 14 additions & 11 deletions code/src/actor.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,23 +324,26 @@ void HyperActors_UpdateAgain(Actor* thisx) {
hyperActors_ExtraUpdate = 0;
}

s32 Actor_IsBoss(Actor* actor) {
return (actor->id == 0x28) || // Gohma
(actor->id == 0x27 || actor->id == 0x30) || // King Dodongo + Fire Breath
(actor->id == 0xBA && actor->params == -1) || // Barinade
(actor->id == 0x52 || actor->id == 0x67 || actor->id == 0x6D) || // Phantom Ganon + Horse + Lightning
(actor->id == 0x96 || actor->id == 0xA2 || actor->id == 0xAD) || // Volvagia + Rock Attack
(actor->id == 0xC4) || // Morpha
(actor->id == 0xE9 && actor->params == -1) || // Bongo Bongo
(actor->id == 0xDC) || // Twinrova
(actor->id == 0xE8) || // Ganondorf
(actor->id == 0x17A); // Ganon
}

void HyperActors_Main(Actor* thisx, GlobalContext* globalCtx) {
if (!IsInGame() || thisx->update == NULL || (PLAYER != NULL && Player_InBlockingCsMode(globalCtx, PLAYER))) {
return;
}

if (gSettingsContext.hyperBosses == ON) {
if ((thisx->id == 0x28) || // Gohma
(thisx->id == 0x27 || thisx->id == 0x30) || // King Dodongo + Fire Breath
(thisx->id == 0xBA && thisx->params == -1) || // Barinade
(thisx->id == 0x52 || thisx->id == 0x67 || thisx->id == 0x6D) || // Phantom Ganon + Horse + Lightning
(thisx->id == 0x96 || thisx->id == 0xA2 || thisx->id == 0xAD) || // Volvagia + Rock Attack
(thisx->id == 0xC4) || // Morpha
(thisx->id == 0xE9 && thisx->params == -1) || // Bongo Bongo
(thisx->id == 0xDC) || // Twinrova
(thisx->id == 0xE8) || // Ganondorf
(thisx->id == 0x17A)) { // Ganon

if (Actor_IsBoss(thisx)) {
// Special case to update in order for Barinade and Bongo Bongo
if (thisx->id == 0xBA || thisx->id == 0xE9) {
for (Actor* actor = gGlobalContext->actorCtx.actorList[ACTORTYPE_BOSS].first; actor != NULL;
Expand Down
1 change: 1 addition & 0 deletions code/src/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
void Actor_Init();
void ActorSetup_Extra();
s32 Actor_CollisionATvsAC(Collider* at, Collider* ac);
s32 Actor_IsBoss(Actor* actor);

#endif //_ACTOR_H_
2 changes: 1 addition & 1 deletion code/src/actors/shabom.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "enemy_souls.h"

u16 Shabom_CheckEnemySoul(void) {
return gSettingsContext.shuffleEnemySouls == OFF || EnemySouls_GetSoulFlag(SOUL_SHABOM);
return gSettingsContext.shuffleEnemySouls != SHUFFLEENEMYSOULS_ALL || EnemySouls_GetSoulFlag(SOUL_SHABOM);
}

// This is currently useless because soulless enemies are invisible
Expand Down
4 changes: 3 additions & 1 deletion code/src/enemy_souls.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "savefile.h"
#include "settings.h"
#include "armos.h"
#include "actor.h"

// clang-format off
static EnemySoulId EnemySouls_GetSoulId(s16 actorId) {
Expand Down Expand Up @@ -96,7 +97,8 @@ void EnemySouls_SetSoulFlag(EnemySoulId soulId) {
}

u8 EnemySouls_CheckSoulForActor(Actor* actor) {
if ((gSettingsContext.shuffleEnemySouls == OFF) ||
if ((gSettingsContext.shuffleEnemySouls == SHUFFLEENEMYSOULS_OFF) ||
(gSettingsContext.shuffleEnemySouls == SHUFFLEENEMYSOULS_BOSSES && !Actor_IsBoss(actor)) ||
(actor->id == 0x054 && ((EnAm*)actor)->textureBlend == 0 /* Armos, statue or asleep */)) {
return TRUE;
}
Expand Down
5 changes: 3 additions & 2 deletions code/src/enemy_souls.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ typedef enum EnemySoulId {
typedef struct SoulMenuInfo {
EnemySoulId soulId;
const char* name;
const char* altName;
} SoulMenuInfo;

extern SoulMenuInfo SoulMenuNames[SOUL_MAX];
Expand Down Expand Up @@ -107,8 +108,8 @@ SoulMenuInfo SoulMenuNames[SOUL_MAX] = {
{ SOUL_WALLMASTER, "Wallmaster, Floormaster" },
{ SOUL_WOLFOS, "Wolfos (all)" },
// Bosses
{ SOUL_GOHMA, "Gohma, Gohma Larva" },
{ SOUL_DODONGO, "Dodongo (all)" },
{ SOUL_GOHMA, "Gohma, Gohma Larva", "Queen Gohma" },
{ SOUL_DODONGO, "Dodongo (all)", "King Dodongo" },
{ SOUL_BARINADE, "Barinade" },
{ SOUL_PHANTOM_GANON, "Phantom Ganon" },
{ SOUL_VOLVAGIA, "Volvagia" },
Expand Down
22 changes: 17 additions & 5 deletions code/src/gfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ static void Gfx_DrawButtonPrompts(void) {
Draw_DrawIcon(offsetX, promptY, COLOR_BUTTON_A, ICON_BUTTON_A);
offsetX += buttonSpacing;
Draw_DrawString(offsetX, textY, COLOR_TITLE, "Toggle Legend");
} else if (curMenuIdx == PAGE_ENEMYSOULS) {
} else if (curMenuIdx == PAGE_ENEMYSOULS && gSettingsContext.shuffleEnemySouls == SHUFFLEENEMYSOULS_ALL) {
Draw_DrawIcon(offsetX, promptY, COLOR_WHITE, ICON_BUTTON_DPAD);
offsetX += buttonSpacing;
nextStr = "Scroll";
Expand Down Expand Up @@ -536,17 +536,29 @@ static void Gfx_DrawDungeonItems(void) {
static void Gfx_DrawEnemySouls(void) {
Draw_DrawString(10, 16, COLOR_TITLE, "Enemy Souls Obtained");

u8 startIndex = soulsScroll <= 0 ? 0 : 32;
u8 endIndex = soulsScroll <= 0 ? 32 : ARRAY_SIZE(SoulMenuNames);
const s32 bossesOnly = gSettingsContext.shuffleEnemySouls == SHUFFLEENEMYSOULS_BOSSES;
u8 startIndex, endIndex;

if (bossesOnly) {
startIndex = ARRAY_SIZE(SoulMenuNames) - 9;
endIndex = ARRAY_SIZE(SoulMenuNames);
} else if (soulsScroll == 0) {
startIndex = 0;
endIndex = 32;
} else {
startIndex = 32;
endIndex = ARRAY_SIZE(SoulMenuNames);
}

for (u8 i = startIndex; i < endIndex; i++) {
u16 posX = 10 + (((i % 32) / 16) * (SPACING_X * 25));
u16 posY = 30 + (SPACING_Y * (i % 16));
u16 posY = 30 + (SPACING_Y * ((i - (bossesOnly ? startIndex : 0)) % 16));
SoulMenuInfo info = SoulMenuNames[i];
const char* name = (bossesOnly && info.altName != NULL) ? info.altName : info.name;

Draw_DrawRect(posX, posY, 9, 9, COLOR_WHITE);
Draw_DrawRect(posX + 1, posY + 1, 7, 7, EnemySouls_GetSoulFlag(info.soulId) ? COLOR_GREEN : COLOR_BLACK);
Draw_DrawString(posX + SPACING_X * 2, posY, COLOR_WHITE, info.name);
Draw_DrawString(posX + SPACING_X * 2, posY, COLOR_WHITE, name);
}
}

Expand Down
6 changes: 6 additions & 0 deletions code/src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ typedef enum {
SHUFFLECHESTMINIGAME_PACK,
} ShuffleChestMinigameSetting;

typedef enum {
SHUFFLEENEMYSOULS_OFF,
SHUFFLEENEMYSOULS_ALL,
SHUFFLEENEMYSOULS_BOSSES,
} ShuffleEnemySoulsSetting;

typedef enum {
MAPSANDCOMPASSES_START_WITH,
MAPSANDCOMPASSES_VANILLA,
Expand Down
2 changes: 1 addition & 1 deletion source/hint_list/hint_list_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2292,7 +2292,7 @@ void HintTable_Init_Item() {

hintTable[SOUL_ITEM_GERUDO] = HintText::Item({
// obscure text
Text{"the Gerudo Soul", /*french*/"l'Essence de Voleuse Gerudo", /*spanish*/"el alma de Gerudo", /*italian*/"l'anima di Gerudo", /*german*/"die Seele von Gerudos"},
Text{"the Gerudo and Iron Knuckle Soul", /*french*/"l'Essence de Voleuse Gerudo et de Hache-Viande", /*spanish*/"el alma de Gerudo y Nudillo de hierro", /*italian*/"l'anima di Gerudo e Guerriero d'acciaio", /*german*/"die Seele von Gerudos und Eisenprinzen"},
}, {
// ambiguous text
Text{"a Soul", /*french*/"une Essence", /*spanish*/"un alma", /*italian*/"un'anima", /*german*/"eine Seele"},
Expand Down
2 changes: 1 addition & 1 deletion source/item_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ void ItemTable_Init() { //Item Type
itemTable[SOUL_ITEM_DARK_LINK] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DARK_LINK, true, &SoulDarkLink, SOUL_ITEM_DARK_LINK, Text{"Dark Link Soul", "Essence de l'ombre de Link", "Alma de Link Oscuro", "Anima di Link Oscuro", "Seele von schwarzen Link"});
itemTable[SOUL_ITEM_FLARE_DANCER] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_FLARE_DANCER, true, &SoulFlareDancer, SOUL_ITEM_FLARE_DANCER, Text{"Flare Dancer Soul", "Essence de Danse-Flamme", "Alma de Bailafuego", "Anima di Fiammerino", "Seele von Flammenderwischen"});
itemTable[SOUL_ITEM_DEAD_HAND] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DEAD_HAND, true, &SoulDeadHand, SOUL_ITEM_DEAD_HAND, Text{"Dead Hand Soul", "Essence de Poigneur", "Alma de Mano Muerta", "Anima di Smaniosso", "Seele von Hirnsaugern"});
itemTable[SOUL_ITEM_GERUDO] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_GERUDO, true, &SoulGerudo, SOUL_ITEM_GERUDO, Text{"Gerudo Soul", "Essence de Voleuse Gerudo", "Alma de Gerudo", "Anima di Gerudo", "Seele von Gerudos"});
itemTable[SOUL_ITEM_GERUDO] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_GERUDO, true, &SoulGerudo, SOUL_ITEM_GERUDO, Text{"Gerudo and Iron Knuckle Soul", "Essence de Voleuse Gerudo et Hache-Viande","Alma de Gerudo y Nudillo de hierro", "Anima di Gerudo e Guerriero d'acciaio", "Seele von Gerudos und Eisenprinzen"});
itemTable[SOUL_ITEM_GOHMA] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_GOHMA, true, &SoulGohma, SOUL_ITEM_GOHMA, Text{"Gohma Soul", "Essence de Gohma", "Alma de Gohma", "Anima di Gohma", "Seele von Gohma"});
itemTable[SOUL_ITEM_DODONGO] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_DODONGO, true, &SoulDodongo, SOUL_ITEM_DODONGO, Text{"Dodongo Soul", "Essence de Dodongo", "Alma de Dodongo", "Anima di Dodongo", "Seele von Dodongos"});
itemTable[SOUL_ITEM_BARINADE] = Item(ITEMTYPE_ENEMY_SOUL, GI_SOUL_BARINADE, true, &SoulBarinade, SOUL_ITEM_BARINADE, Text{"Barinade Soul", "Essence de Barinade", "Alma de Barinade", "Anima di Cnidade", "Seele von Barinade"});
Expand Down
11 changes: 10 additions & 1 deletion source/item_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ const std::array<ItemKey, 47> enemySouls = {
SOUL_ITEM_BARINADE, SOUL_ITEM_PHANTOM_GANON, SOUL_ITEM_VOLVAGIA, SOUL_ITEM_MORPHA, SOUL_ITEM_BONGO_BONGO,
SOUL_ITEM_TWINROVA, SOUL_ITEM_GANON,
};
const std::array<ItemKey, 9> bossSouls = {
SOUL_ITEM_GOHMA, SOUL_ITEM_DODONGO, SOUL_ITEM_BARINADE, SOUL_ITEM_PHANTOM_GANON, SOUL_ITEM_VOLVAGIA,
SOUL_ITEM_MORPHA, SOUL_ITEM_BONGO_BONGO, SOUL_ITEM_TWINROVA, SOUL_ITEM_GANON,
};
const std::array<ItemKey, 5> ocarinaNoteButtons = {
OCA_BUTTON_ITEM_L, OCA_BUTTON_ITEM_R, OCA_BUTTON_ITEM_X, OCA_BUTTON_ITEM_Y, OCA_BUTTON_ITEM_A,
};
Expand Down Expand Up @@ -1030,11 +1034,16 @@ void GenerateItemPool() {
IceTrapModels.push_back(GI_SWORD_BGS);
}

if (ShuffleEnemySouls) {
if (ShuffleEnemySouls.Is(SHUFFLEENEMYSOULS_ALL)) {
AddItemsToPool(ItemPool, enemySouls);
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
AddItemsToPool(PendingJunkPool, enemySouls);
}
} else if (ShuffleEnemySouls.Is(SHUFFLEENEMYSOULS_BOSSES)) {
AddItemsToPool(ItemPool, bossSouls);
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
AddItemsToPool(PendingJunkPool, bossSouls);
}
}

if (ShuffleOcarinaButtons) {
Expand Down
67 changes: 34 additions & 33 deletions source/location_access/locacc_dodongos_cavern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,39 +124,40 @@ void AreaTable_Init_DodongosCavern() {
Entrance(DODONGOS_CAVERN_DODONGO_ROOM, { [] { return true; } }),
});

areaTable[DODONGOS_CAVERN_SE_CORRIDOR] = Area(
"Dodongos Cavern SE Corridor", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {},
{
// Locations
LocationAccess(DODONGOS_CAVERN_GS_SCARECROW,
{ [] {
return CanUse(SCARECROW) || (IsAdult && CanUse(LONGSHOT)) ||
(LogicDCScarecrowGS && (CanAdultAttack || CanChildAttack));
},
/*Glitched*/
[] {
return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) ||
(CanUse(LONGSHOT) &&
CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));
} }),
},
{
// Exits
Entrance(DODONGOS_CAVERN_LOBBY, { [] { return true; } }),
Entrance(DODONGOS_CAVERN_SE_ROOM, { [] {
return Here(DODONGOS_CAVERN_SE_CORRIDOR, [] {
return CanBlastOrSmash ||
(SoulDodongo && (CanAdultAttack || CanChildAttack ||
(CanTakeDamage && CanShield)));
});
},
/*Glitched*/
[] {
return Here(DODONGOS_CAVERN_SE_CORRIDOR,
[] { return (GlitchBlueFireWall && BlueFire); });
} }),
Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, { [] { return true; } }),
});
areaTable[DODONGOS_CAVERN_SE_CORRIDOR] =
Area("Dodongos Cavern SE Corridor", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {},
{
// Locations
LocationAccess(DODONGOS_CAVERN_GS_SCARECROW,
{ [] {
return CanUse(SCARECROW) || (IsAdult && CanUse(LONGSHOT)) ||
(LogicDCScarecrowGS && (CanAdultAttack || CanChildAttack));
},
/*Glitched*/
[] {
return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) ||
(CanUse(LONGSHOT) &&
CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));
} }),
},
{
// Exits
Entrance(DODONGOS_CAVERN_LOBBY, { [] { return true; } }),
Entrance(DODONGOS_CAVERN_SE_ROOM,
{ [] {
return Here(DODONGOS_CAVERN_SE_CORRIDOR, [] {
return CanBlastOrSmash ||
((SoulDodongo || ShuffleEnemySouls.IsNot(SHUFFLEENEMYSOULS_ALL)) &&
(CanAdultAttack || CanChildAttack || (CanTakeDamage && CanShield)));
});
},
/*Glitched*/
[] {
return Here(DODONGOS_CAVERN_SE_CORRIDOR,
[] { return (GlitchBlueFireWall && BlueFire); });
} }),
Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, { [] { return true; } }),
});

areaTable[DODONGOS_CAVERN_SE_ROOM] =
Area("Dodongos Cavern SE Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {},
Expand Down
Loading

0 comments on commit 97eb227

Please sign in to comment.