Holiday Modding Event - Bomb Arrows (#4573)

* Bomb Arrows: Turn arrows into bomb arrows

* Bomb Arrows: Drain bombs when fired

* Bomb Arrows: Equip Over Bow

* Bomb Arrows: Item icons and ammo counts

* Bomb Arrows: Save files

* Bomb Arrows: Fix equip and ammo display bugs

* Bomb Arrows: Interactions with multi-arrows

* Bomb Arrows: Fix fuse graphics
This commit is contained in:
lilDavid 2024-11-22 21:03:37 -06:00 committed by GitHub
parent 0f48970576
commit f1dc432589
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 195 additions and 1 deletions

View File

@ -0,0 +1,136 @@
#include "Holiday.hpp"
#include "utils/StringHelper.h"
extern "C" {
#include "macros.h"
#include "functions.h"
#include "variables.h"
extern PlayState* gPlayState;
}
#include "src/overlays/actors/ovl_En_Arrow/z_en_arrow.h"
#include "src/overlays/actors/ovl_En_Bom/z_en_bom.h"
extern "C" {
void func_809B45E0(EnArrow*, PlayState*);
void func_809B4640(EnArrow*, PlayState*);
}
#define AUTHOR "lilDavid"
#define CVAR(v) "gHoliday." AUTHOR "." v
static void OnConfigurationChanged() {
if (!CVarGetInteger(CVAR("BombArrows.Enabled"), 0))
CVarSetInteger(CVAR("BombArrows.Active"), 0);
COND_HOOK(OnSaveFile, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](int32_t file) {
std::string cvar = StringHelper::Sprintf("%s%d", CVAR("BombArrows.Save"), file);
CVarSetInteger(cvar.c_str(), CVarGetInteger(CVAR("BombArrows.Active"), 0));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
});
COND_HOOK(OnLoadFile, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](int32_t file) {
std::string cvar = StringHelper::Sprintf("%s%d", CVAR("BombArrows.Save"), file);
CVarSetInteger(CVAR("BombArrows.Active"), CVarGetInteger(cvar.c_str(), 0));
});
COND_HOOK(OnCopyFile, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](int32_t from, int32_t to) {
std::string cvarFrom = StringHelper::Sprintf("%s%d", CVAR("BombArrows.Save"), from);
std::string cvarTo = StringHelper::Sprintf("%s%d", CVAR("BombArrows.Save"), to);
CVarSetInteger(cvarTo.c_str(), CVarGetInteger(cvarFrom.c_str(), 0));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
});
COND_HOOK(OnDeleteFile, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](int32_t file) {
std::string cvar = StringHelper::Sprintf("%s%d", CVAR("BombArrows.Save"), file);
CVarSetInteger(cvar.c_str(), 0);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
});
COND_ID_HOOK(OnActorInit, ACTOR_EN_ARROW, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](void* actorRef) {
EnArrow* arrow = (EnArrow*) actorRef;
if (!CVarGetInteger(CVAR("BombArrows.Active"), 0) ||
arrow->actor.params != ARROW_NORMAL || AMMO(ITEM_BOMB) == 0 ||
gSaveContext.minigameState == 1 || gPlayState->shootingGalleryStatus > 1)
return;
EnBom* bomb = (EnBom*) Actor_SpawnAsChild(&gPlayState->actorCtx, &arrow->actor, gPlayState, ACTOR_EN_BOM,
arrow->actor.world.pos.x, arrow->actor.world.pos.y, arrow->actor.world.pos.z,
0, 0, 0, BOMB_BODY);
if (bomb == nullptr)
return;
Actor_SetScale(&bomb->actor, 0.003f);
bomb->timer = 65;
});
COND_ID_HOOK(OnActorUpdate, ACTOR_EN_ARROW, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](void* actorRef) {
EnArrow* arrow = (EnArrow*) actorRef;
if (!arrow->actor.child || arrow->actor.child->id != ACTOR_EN_BOM)
return;
EnBom* bomb = (EnBom*) arrow->actor.child;
bomb->actor.world.pos = arrow->actor.world.pos;
f32 r = 8.0f;
f32 xrot = arrow->actor.world.rot.x;
f32 yrot = arrow->actor.world.rot.y;
bomb->actor.world.pos.x += r * Math_CosS(xrot) * Math_SinS(yrot);
bomb->actor.world.pos.y -= r * Math_SinS(xrot) + 2.0f;
bomb->actor.world.pos.z += r * Math_CosS(xrot) * Math_CosS(yrot);
if (arrow->actor.parent == nullptr) {
if (bomb->timer > 60) {
Inventory_ChangeAmmo(ITEM_BOMB, -1);
}
bomb->timer = 52;
} else {
bomb->timer = 62;
}
if (arrow->actionFunc == func_809B45E0 ||
arrow->actionFunc == func_809B4640 ||
arrow->actor.params == ARROW_NORMAL_LIT)
{
arrow->actor.child = nullptr;
bomb->actor.parent = nullptr;
bomb->timer = 2;
Actor_Kill(&arrow->actor);
}
});
COND_ID_HOOK(OnActorKill, ACTOR_EN_ARROW, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](void* actorRef) {
EnArrow* arrow = (EnArrow*) actorRef;
if (!arrow->actor.child || arrow->actor.child->id != ACTOR_EN_BOM)
return;
Actor_Kill(arrow->actor.child);
});
COND_ID_HOOK(OnActorUpdate, ACTOR_EN_BOM, CVarGetInteger(CVAR("BombArrows.Enabled"), 0), [](void* actorRef) {
EnBom* bomb = (EnBom*) actorRef;
if (!bomb->actor.parent || bomb->actor.parent->id != ACTOR_EN_ARROW)
return;
if (bomb->timer > 55 && bomb->timer < 60)
bomb->timer += 4;
if (bomb->timer > 45 && bomb->timer < 50)
bomb->timer += 4;
});
}
static void DrawMenu() {
ImGui::SeparatorText(AUTHOR);
if (UIWidgets::EnhancementCheckbox("Bomb Arrows", CVAR("BombArrows.Enabled"))) {
OnConfigurationChanged();
}
}
static void RegisterMod() {
// #region Leave this alone unless you know what you are doing
OnConfigurationChanged();
// #endregion
CVarSetInteger(CVAR("BombArrows.Active"), 0);
}
static Holiday holiday(DrawMenu, RegisterMod);

View File

@ -37,6 +37,7 @@ DEFINE_HOOK(OnOpenText, (u16 * textId, bool* loadFromMessageTable));
DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, va_list originalArgs));
DEFINE_HOOK(OnSaveFile, (int32_t fileNum));
DEFINE_HOOK(OnLoadFile, (int32_t fileNum));
DEFINE_HOOK(OnCopyFile, (int32_t sourceFileNum, uint32_t destFileNum));
DEFINE_HOOK(OnDeleteFile, (int32_t fileNum));
DEFINE_HOOK(OnDialogMessage, ());

View File

@ -184,6 +184,10 @@ void GameInteractor_ExecuteOnLoadFile(int32_t fileNum) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnLoadFile>(fileNum);
}
void GameInteractor_ExecuteOnCopyFile(int32_t sourceFileNum, int32_t destFileNum) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnCopyFile>(sourceFileNum, destFileNum);
}
void GameInteractor_ExecuteOnDeleteFile(int32_t fileNum) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnDeleteFile>(fileNum);
}

View File

@ -40,6 +40,7 @@ bool GameInteractor_Should(GIVanillaBehavior flag, uint32_t result, ...);
// MARK: - Save Files
void GameInteractor_ExecuteOnSaveFile(int32_t fileNum);
void GameInteractor_ExecuteOnLoadFile(int32_t fileNum);
void GameInteractor_ExecuteOnCopyFile(int32_t sourceFileNum, int32_t destFileNum);
void GameInteractor_ExecuteOnDeleteFile(int32_t fileNum);
// MARK: - Dialog

View File

@ -2458,6 +2458,7 @@ void SaveManager::CopyZeldaFile(int from, int to) {
fileMetaInfo[to].buildVersionPatch = fileMetaInfo[from].buildVersionPatch;
SohUtils::CopyStringToCharArray(fileMetaInfo[to].buildVersion, fileMetaInfo[from].buildVersion,
ARRAY_COUNT(fileMetaInfo[to].buildVersion));
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnCopyFile>(from, to);
}
void SaveManager::DeleteZeldaFile(int fileNum) {

View File

@ -4722,6 +4722,11 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) {
}
ammo = AMMO(i);
if (CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0) &&
gSaveContext.equips.buttonItems[button] == ITEM_BOW &&
AMMO(ITEM_BOMB) != 0 && AMMO(ITEM_BOMB) < AMMO(ITEM_BOW)) {
ammo = AMMO(ITEM_BOMB);
}
gDPPipeSync(OVERLAY_DISP++);
@ -4734,6 +4739,11 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) {
if (ammo < 0) {
ammo = 0;
}
} else if (gSaveContext.equips.buttonItems[button] == ITEM_BOW &&
CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
if (AMMO(ITEM_BOMB) != 0 && ammo == MIN(CUR_CAPACITY(UPG_QUIVER), CUR_CAPACITY(UPG_BOMB_BAG))) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 255, 0, alpha);
}
} else if (((i == ITEM_BOW) && (AMMO(i) == CUR_CAPACITY(UPG_QUIVER))) ||
((i == ITEM_BOMB) && (AMMO(i) == CUR_CAPACITY(UPG_BOMB_BAG))) ||
((i == ITEM_SLINGSHOT) && (AMMO(i) == CUR_CAPACITY(UPG_BULLET_BAG))) ||
@ -5311,6 +5321,9 @@ void Interface_Draw(PlayState* play) {
if (gSaveContext.equips.buttonItems[1] < 0xF0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->cLeftAlpha);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM);
if (gSaveContext.equips.buttonItems[1] == ITEM_BOW && CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
Interface_DrawItemIconTexture(play, gItemIcons[ITEM_BOMB], 1);
}
Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[1]], 1);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
@ -5324,6 +5337,9 @@ void Interface_Draw(PlayState* play) {
if (gSaveContext.equips.buttonItems[2] < 0xF0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->cDownAlpha);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM);
if (gSaveContext.equips.buttonItems[2] == ITEM_BOW && CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
Interface_DrawItemIconTexture(play, gItemIcons[ITEM_BOMB], 2);
}
Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[2]], 2);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
@ -5337,6 +5353,9 @@ void Interface_Draw(PlayState* play) {
if (gSaveContext.equips.buttonItems[3] < 0xF0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->cRightAlpha);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM);
if (gSaveContext.equips.buttonItems[3] == ITEM_BOW && CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
Interface_DrawItemIconTexture(play, gItemIcons[ITEM_BOMB], 3);
}
Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[3]], 3);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
@ -5396,6 +5415,9 @@ void Interface_Draw(PlayState* play) {
if (gSaveContext.equips.buttonItems[4] < 0xF0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadUpAlpha);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM);
if (gSaveContext.equips.buttonItems[4] == ITEM_BOW && CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
Interface_DrawItemIconTexture(play, gItemIcons[ITEM_BOMB], 4);
}
Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[4]], 4);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
@ -5407,6 +5429,9 @@ void Interface_Draw(PlayState* play) {
if (gSaveContext.equips.buttonItems[5] < 0xF0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadDownAlpha);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM);
if (gSaveContext.equips.buttonItems[5] == ITEM_BOW && CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
Interface_DrawItemIconTexture(play, gItemIcons[ITEM_BOMB], 5);
}
Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[5]], 5);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
@ -5418,6 +5443,9 @@ void Interface_Draw(PlayState* play) {
if (gSaveContext.equips.buttonItems[6] < 0xF0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadLeftAlpha);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM);
if (gSaveContext.equips.buttonItems[6] == ITEM_BOW && CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
Interface_DrawItemIconTexture(play, gItemIcons[ITEM_BOMB], 6);
}
Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[6]], 6);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
@ -5429,6 +5457,9 @@ void Interface_Draw(PlayState* play) {
if (gSaveContext.equips.buttonItems[7] < 0xF0) {
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadRightAlpha);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM);
if (gSaveContext.equips.buttonItems[7] == ITEM_BOW && CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0)) {
Interface_DrawItemIconTexture(play, gItemIcons[ITEM_BOMB], 7);
}
Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[7]], 7);
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,

View File

@ -287,7 +287,12 @@ void EnBom_Update(Actor* thisx, PlayState* play2) {
// spawn spark effect on even frames
effPos = thisx->world.pos;
if (CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0) &&
thisx->parent && thisx->parent->id == ACTOR_EN_ARROW) {
effPos.y += 5.0f;
} else {
effPos.y += 17.0f;
}
if ((play->gameplayFrames % 2) == 0) {
EffectSsGSpk_SpawnFuse(play, thisx, &effPos, &effVelocity, &effAccel);
}

View File

@ -1136,6 +1136,21 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) {
}
}
if (CVarGetInteger("gHoliday.lilDavid.BombArrows.Enabled", 0)) {
if (pauseCtx->equipTargetSlot == SLOT_BOW) {
CVarSetInteger("gHoliday.lilDavid.BombArrows.Active", 0);
}
u8 equipped_slot = gSaveContext.equips.cButtonSlots[pauseCtx->equipTargetCBtn];
if (!CVarGetInteger("gHoliday.lilDavid.BombArrows.Active", 0) &&
pauseCtx->equipTargetItem == ITEM_BOMB && equipped_slot == SLOT_BOW)
{
CVarSetInteger("gHoliday.lilDavid.BombArrows.Active", 1);
pauseCtx->equipTargetItem = ITEM_BOW;
pauseCtx->equipTargetSlot = SLOT_BOW;
Audio_PlaySoundGeneral(NA_SE_SY_SET_FIRE_ARROW, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
}
// If the item is on another button already, swap the two
uint16_t targetButtonIndex = pauseCtx->equipTargetCBtn + 1;
for (uint16_t otherSlotIndex = 0; otherSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots);