Add ganon dating sim PoC (#4510)

This commit is contained in:
Garrett Cox 2024-11-02 11:38:17 -05:00 committed by GitHub
parent 8d4adb0f50
commit 5c98cdacde
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 152 additions and 2 deletions

View File

@ -0,0 +1,146 @@
#include "Holiday.hpp"
#include <libultraship/libultraship.h>
#include "soh/UIWidgets.hpp"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/custom-message/CustomMessageManager.h"
#include "include/message_data_fmt.h"
extern "C" {
#include "macros.h"
#include "functions.h"
#include "variables.h"
extern PlayState* gPlayState;
}
#define AUTHOR "NotProxySaw"
#define CVAR(v) "gHoliday." AUTHOR "." v
int dialogIndex = 0;
int affection = 0;
int TARGET_AFFECTION = 10;
struct DialogOption {
std::string text;
int affectionChange;
int nextDialogIndex;
};
struct Dialog {
std::string ganonText;
std::vector<DialogOption> options;
};
const std::vector<Dialog> dialogs = {
{ // 0
"Think you can defeat me? Foolish!",
{
{"You're lonely. You don't have to be.", 3, 1},
{"I'm here to end this... peacefully.", 1, 2},
{"I respect a man with ambition.", -1, 3},
}
},
{ // 1
"Lonely? Power's my only ally.",
{
{"There's more to you than that.", 3, 4},
{"I get it more than you think.", 5, 4},
{"Why not let someone in?", 2, 4},
}
},
{ // 2
"Peace? It's meaningless here.",
{
{"Maybe you've forgotten peace.", 2, 4},
{"Power isn't everything.", 4, 4},
{"Ally, not enemy.. that's my goal.", 1, 4},
}
},
{ // 3
"Respect? From you?",
{
{"We're not so different.", 3, 4},
{"Maybe I admire your strength.", 5, 4},
{"True power must be earned.", -1, 4},
}
},
{ // 4
"You're... different than I thought.",
{
{"Together, we'd be unstoppable.", 5, 5},
{"Power won't bring fulfillment.", 3, 5},
{"Let's change the world.", 4, 5},
}
},
{ // 5
"What if I trusted you with power?",
{
{"I'll protect it. And you.", 10, -1},
{"Together, we're unstoppable.", 5, -1},
{"Our way. Our history.", -3, -1},
}
}
};
static void ConfigurationChanged() {
COND_ID_HOOK(OnActorInit, ACTOR_BOSS_GANON, CVarGetInteger(CVAR("GanonDatingSim"), 0), [](void* actorRef) {
dialogIndex = 0;
affection = 0;
});
COND_VB_SHOULD(VB_GANONDORF_DECIDE_TO_FIGHT, CVarGetInteger(CVAR("GanonDatingSim"), 0), {
MessageContext* msgCtx = &gPlayState->msgCtx;
if (dialogIndex == -1) {
if (affection >= TARGET_AFFECTION) {
gPlayState->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
gSaveContext.nextCutsceneIndex = 0xFFF2;
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
gPlayState->transitionType = TRANS_TYPE_FADE_WHITE;
GameInteractor::State::TriforceHuntCreditsWarpActive = 0;
*should = false;
return;
}
return;
}
affection += dialogs[dialogIndex].options[msgCtx->choiceIndex].affectionChange;
dialogIndex = dialogs[dialogIndex].options[msgCtx->choiceIndex].nextDialogIndex;
*should = false;
Message_StartTextbox(gPlayState, 0x70CB, NULL);
});
COND_ID_HOOK(OnOpenText, 0x70CB, CVarGetInteger(CVAR("GanonDatingSim"), 0), [](u16 * textId, bool* loadFromMessageTable) {
std::string message;
if (dialogIndex == -1) {
if (affection >= TARGET_AFFECTION) {
message = "I've never felt this way before...\x01Take my power, Link. I trust you.";
} else {
message = "Liar! You're just like the rest of\x01them! Now I must destroy you!";
}
} else {
message = dialogs[dialogIndex].ganonText + "\x01\x1C"
+ dialogs[dialogIndex].options[0].text + "\x01"
+ dialogs[dialogIndex].options[1].text + "\x01"
+ dialogs[dialogIndex].options[2].text;
}
auto messageEntry = CustomMessage(message);
messageEntry.Format();
messageEntry.LoadIntoFont();
*loadFromMessageTable = false;
});
}
static void DrawMenu() {
ImGui::SeparatorText(AUTHOR);
if (UIWidgets::EnhancementCheckbox("Ganon Dating Sim", CVAR("GanonDatingSim"))) {
ConfigurationChanged();
}
}
static void RegisterMod() {
// #region Leave this alone unless you know what you are doing
ConfigurationChanged();
// #endregion
}
static Holiday holiday(DrawMenu, RegisterMod);

View File

@ -341,6 +341,7 @@ typedef enum {
VB_SHOULD_GIVE_VANILLA_FISHING_PRIZE,
VB_GIVE_RANDO_FISHING_PRIZE,
VB_PLAY_THROW_ANIMATION,
VB_GANONDORF_DECIDE_TO_FIGHT,
/*** Give Items ***/
@ -592,7 +593,7 @@ struct HookInfo {
#define COND_VB_SHOULD(id, condition, body) \
{ \
static HOOK_ID hookId = 0; \
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::ShouldVanillaBehavior>(hookId); \
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::OnVanillaBehavior>(hookId); \
hookId = 0; \
if (condition) { \
hookId = REGISTER_VB_SHOULD(id, body); \

View File

@ -571,7 +571,7 @@ void BossGanon_IntroCutscene(BossGanon* this, PlayState* play) {
Play_ChangeCameraStatus(play, this->csCamIndex, CAM_STAT_ACTIVE);
this->csCamFov = 60.0f;
if (Flags_GetEventChkInf(EVENTCHKINF_BEGAN_GANONDORF_BATTLE) || IS_RANDO || IS_BOSS_RUSH) {
if (Flags_GetEventChkInf(EVENTCHKINF_BEGAN_GANONDORF_BATTLE) || IS_RANDO || IS_BOSS_RUSH || CVarGetInteger("gHoliday.NotProxySaw.GanonDatingSim", 0)) {
// watched cutscene already, skip most of it
this->csState = 17;
this->csTimer = 0;
@ -926,6 +926,9 @@ void BossGanon_IntroCutscene(BossGanon* this, PlayState* play) {
if ((this->csTimer <= 50) || (Message_GetState(&play->msgCtx) != TEXT_STATE_NONE)) {
break;
}
if (!GameInteractor_Should(VB_GANONDORF_DECIDE_TO_FIGHT, true)) {
break;
}
this->csState = 19;
this->csTimer = 0;