summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAECX <aecx@aecx.cc>2020-02-19 19:02:19 +0100
committerAECX <aecx@aecx.cc>2020-02-19 19:02:19 +0100
commit007e7792181fd99b33ffa62f073dcc9bb9585343 (patch)
tree0368f4e11ee6e89ad945df803b45d4c7c538a263
parentdcf489730c56fe2c843a18cf5af7d1db24e3d6c2 (diff)
0.2a
m---------Externals/libtp0
-rw-r--r--include/main.h101
-rw-r--r--notes.txt17
-rw-r--r--source/main.cpp319
4 files changed, 430 insertions, 7 deletions
diff --git a/Externals/libtp b/Externals/libtp
-Subproject 5e040c3cdd334d7a2c40a41d0990486ba98a7cd
+Subproject 187164dc5dbe9bd7c4499a4887472a1c16470b7
diff --git a/include/main.h b/include/main.h
index 959868c..a72e484 100644
--- a/include/main.h
+++ b/include/main.h
@@ -1,4 +1,103 @@
+#pragma once
+
+#include "display/console.h"
+#include "types.h"
+
namespace mod
{
void main();
-} \ No newline at end of file
+ void onFrameDraw();
+
+ bool onFinish(void* d_a_alink);
+
+ void ook();
+ void diababa();
+ void dangoro();
+ void fyrus();
+ void dekutoad();
+ void morpheel();
+ void deathsword();
+ void stallord();
+ void darkhammer();
+ void blizetta();
+ void darknut();
+ void armogohma();
+ void arealfos();
+ void argarok();
+ void zant();
+ void ganon();
+
+ void (*onFrameDraw_Return)() = nullptr;
+ bool (*onGanonFinish_Return)(void* d_a_alink) = nullptr;
+ s32 (*createItemForPresentDemo_Return)(const float pos[3],
+ s32 item,
+ u8 unk3,
+ s32 unk4,
+ s32 unk5,
+ const float unk6[3],
+ const float unk7[3]) = nullptr;
+ s32 (*createItemForTrBoxDemo_Return)(const float pos[3],
+ s32 item,
+ s32 unk3,
+ s32 unk4,
+ const float unk5[3],
+ const float unk6[3]) = nullptr;
+
+ struct bossFightInfo
+ {
+ char stage[8];
+ u8 room;
+ u8 state;
+ u8 spawnpoint;
+ u8 expectedItemID;
+ void (*preHook)();
+ };
+
+ libtp::display::Console* console;
+
+ bossFightInfo bossFights[16] = {
+ {"D_MN05B", 51, 0xFF, 0x00, 0x40, ook}, // -Ook
+ {"D_MN05A", 50, 0xFF, 0x01, 0x22, diababa}, // Diababa
+ {"D_MN04B", 51, 0xFF, 0x03, 0x43, dangoro}, // -Dangoro
+ {"D_MN04A", 50, 0xFF, 0x01, 0x22, fyrus}, // Fyrus
+ {"D_MN01B", 51, 0xFF, 0x00, 0x44, dekutoad}, // -Deku Toad
+ {"D_MN01A", 50, 0xFF, 0x02, 0x22, morpheel}, // Morpheel
+ {"D_MN10B", 51, 0xFF, 0x01, 0x41, deathsword}, // -Death Sword
+ {"D_MN10A", 50, 0xFF, 0x01, 0x22, stallord}, // Stallord
+ {"D_MN11B", 51, 0xFF, 0x00, 0x42, darkhammer}, // -Dark Hammer
+ {"D_MN11A", 50, 0xFF, 0x00, 0x22, blizetta}, // Blizetta
+ {"D_MN06B", 51, 0xFF, 0x00, 0x46, darknut}, // -Darknut
+ {"D_MN06A", 50, 0xFF, 0x01, 0x22, armogohma}, // Armogohma
+ {"D_MN07B", 51, 0xFF, 0x02, 0x47, arealfos}, // -Arealfos
+ {"D_MN07A", 50, 0xFF, 0x00, 0x22, argarok}, // Argarok
+ {"D_MN08D", 53, 0xFF, 0x00, 0x22, zant}, // Zant
+ {"D_MN09A", 50, 0xFF, 0x00, 0x00, ganon} // Ganon
+ };
+
+ // TODO: Create a class for this
+ // TODO: Find a way to determine 50hz mode
+
+ u32 drawFrameCalls;
+
+ // Number of all frames while mini-game was active
+ u32 totalFrames;
+
+ // Timer for boss rush
+ u32 frameTimer;
+ u32 hours;
+ u32 minutes;
+ u32 seconds;
+
+ // Helpers
+ u32 lastInput;
+ u32 HUDbuttonCombo;
+ u32 StartbuttonCombo;
+ u32 StartbuttonCombo_BossOnly;
+ u8 currentBossFight;
+ u8 clawshotItemWheelIndex;
+ u8 itemWheelPos;
+
+ bool HUD;
+ bool gameActive;
+
+} // namespace mod \ No newline at end of file
diff --git a/notes.txt b/notes.txt
new file mode 100644
index 0000000..7758253
--- /dev/null
+++ b/notes.txt
@@ -0,0 +1,17 @@
+ook 0x1D:128 (ook) 0x16:16 (midna)
+diababa 0x13:2
+dangoro 0x1D:128 0x0A:64 (doors unlocked)
+fyrus 0x1D:64 0x1D:8
+deku toad 0x1D:128
+morpheel 0x1D:64
+death sword 0x1D:128 0x02:8 (spinner chest)
+stallord 0x1D:64
+dark hammer 0x1D:128
+blizetta 0x1D:64
+darknut 0x1D:128
+armogohma 0x1D:64
+arealfos 0x1D:128 0x03:1 (double claw chest)
+argarok 0x1D:64
+phantom zant 0x17:16
+zant 0x1D:64
+ganon (ending blow event) \ No newline at end of file
diff --git a/source/main.cpp b/source/main.cpp
index d62475d..0155224 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -1,21 +1,328 @@
#include "main.h"
+#include <data/stages.h>
#include <display/console.h>
+#include <patch.h>
+#include <tools.h>
#include <tp/JFWSystem.h>
+#include <tp/d_a_alink.h>
+#include <tp/d_com_inf_game.h>
+#include <tp/f_ap_game.h>
+#include <tp/f_op_actor_mng.h>
+#include <tp/m_do_controller_pad.h>
#include <cstdint>
+#include <cstdio>
#include <cstring>
namespace mod
{
void main()
{
- libtp::display::Console console{"AECX",
- "Boss Rush",
- "Fast pace fighting action, beat boss after boss",
- "as quickly as possible. At the end of each fight",
- "you'll be teleported to the next one...",
- "Version: 0.1a"};
+ // TEST
+ sprintf(libtp::display::print(15, ""), "AreaNodeAddr: %04x", (u32)&libtp::tp::d_com_inf_game::dComIfG_gameInfo.unk_958);
+
+ // END TEST
+
+ console = new libtp::display::Console("AECX", "Boss Rush", "Fast paced fighting action, beat boss after boss",
+ "as quickly as possible. At the end of each fight",
+ "you'll be teleported to the next one...", "Version: 0.2a");
+
+ // Hook to a suitable function
+ // This one runs every frame
+ onFrameDraw_Return = libtp::patch::hookFunction(libtp::tp::f_ap_game::fapGm_Execute, onFrameDraw);
+
+ createItemForPresentDemo_Return = libtp::patch::hookFunction(
+ libtp::tp::f_op_actor_mng::createItemForPresentDemo,
+ [](const float pos[3], s32 item, u8 unk3, s32 unk4, s32 unk5, const float unk6[3], const float unk7[3]) {
+ if (item == bossFights[currentBossFight].expectedItemID)
+ {
+ currentBossFight++;
+ bossFights[currentBossFight].preHook();
+ // Go to next boss fight
+ libtp::tools::triggerSaveLoad(bossFights[currentBossFight].stage, bossFights[currentBossFight].room,
+ bossFights[currentBossFight].spawnpoint, bossFights[currentBossFight].state);
+ }
+
+ return createItemForPresentDemo_Return(pos, item, unk3, unk4, unk5, unk6, unk7);
+ });
+
+ createItemForTrBoxDemo_Return = libtp::patch::hookFunction(
+ libtp::tp::f_op_actor_mng::createItemForTrBoxDemo,
+ [](const float pos[3], s32 item, s32 unk3, s32 unk4, const float unk5[3], const float unk6[3]) {
+ if (item == bossFights[currentBossFight].expectedItemID)
+ {
+ currentBossFight++;
+ bossFights[currentBossFight].preHook();
+ // Go to next boss fight
+ libtp::tools::triggerSaveLoad(bossFights[currentBossFight].stage, bossFights[currentBossFight].room,
+ bossFights[currentBossFight].spawnpoint, bossFights[currentBossFight].state);
+ }
+
+ return createItemForTrBoxDemo_Return(pos, item, unk3, unk4, unk5, unk6);
+ });
+
+ onGanonFinish_Return = libtp::patch::hookFunction(libtp::tp::d_a_alink::procGanonFinish, onFinish);
+
+ HUDbuttonCombo = libtp::tp::m_do_controller_pad::Button_R | libtp::tp::m_do_controller_pad::Button_Z;
+ StartbuttonCombo = libtp::tp::m_do_controller_pad::Button_R | libtp::tp::m_do_controller_pad::Button_Start;
+
return;
}
+
+ bool onFinish(void* d_a_alink)
+ {
+ if (gameActive)
+ {
+ gameActive = false;
+ libtp::display::print(10, "gg & gz!");
+ }
+ return onGanonFinish_Return(d_a_alink);
+ }
+
+ void onFrameDraw()
+ {
+ // Clear console after 900 frames
+ if (drawFrameCalls < 900)
+ {
+ drawFrameCalls++;
+ }
+ else if (drawFrameCalls == 900)
+ {
+ drawFrameCalls++;
+ // Init console for our purpose(s)
+ libtp::display::clearConsole(0, 25);
+
+ // Fully transparent
+ libtp::display::setConsoleColor(0xFF, 0xFF, 0xFF, 0x0);
+ libtp::display::setConsole(true, 25);
+ }
+ else
+ {
+ // Check for button combo
+ // TODO: create libtp wrapper function
+
+ u32 cInput = libtp::tp::m_do_controller_pad::cpadInfo.buttonInput;
+
+ if (cInput != lastInput)
+ {
+ if ((cInput & HUDbuttonCombo) == HUDbuttonCombo)
+ {
+ // Toggle HUD
+ HUD = !HUD;
+ libtp::display::setConsole(HUD, 0);
+ }
+
+ if (!gameActive && (cInput & StartbuttonCombo) == StartbuttonCombo)
+ {
+ // Start gamemode, reset timers etc.
+ frameTimer = 0;
+ totalFrames = 0;
+ hours = 0;
+ minutes = 0;
+ seconds = 0;
+ currentBossFight = 0;
+ itemWheelPos = 0;
+
+ libtp::display::clearConsole(0, 25);
+
+ gameActive = true;
+
+ // Make sure user has everything
+ for (u8 i = 0; i < currentBossFight; i++)
+ {
+ bossFights[i].preHook();
+ }
+
+ // Trigger first fight
+ bossFights[currentBossFight].preHook();
+ libtp::tools::triggerSaveLoad(bossFights[currentBossFight].stage, bossFights[currentBossFight].room,
+ bossFights[currentBossFight].spawnpoint, bossFights[currentBossFight].state);
+ }
+ else if ((cInput & StartbuttonCombo) == StartbuttonCombo)
+ {
+ gameActive = false;
+ }
+ } // End input check
+
+ if (gameActive)
+ {
+ frameTimer++;
+ totalFrames++;
+ // Update every second to save some processing power
+ if (frameTimer == 30)
+ {
+ frameTimer = 0;
+ seconds++;
+
+ if (seconds == 60)
+ {
+ seconds = 0;
+ minutes++;
+ if (minutes == 60)
+ {
+ minutes = 0;
+ hours++;
+ }
+ }
+ }
+ }
+
+ // Print HUD if active
+ if (HUD)
+ {
+ sprintf(libtp::tp::jfw_system::systemConsole->consoleLine[5].line, "Boss: %d", currentBossFight + 1);
+ sprintf(libtp::tp::jfw_system::systemConsole->consoleLine[6].line, "Frames: %u", totalFrames);
+ sprintf(libtp::tp::jfw_system::systemConsole->consoleLine[7].line, "%02d:%02d:%02d", hours, minutes, seconds);
+ }
+ }
+
+ lastInput = libtp::tp::m_do_controller_pad::cpadInfo.buttonInput;
+ return onFrameDraw_Return();
+ }
+
+ // Prehooks
+ void ook()
+ {
+ // Give bottles
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xA7] = 115;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xA8] = 115;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xA9] = 115;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xAA] = 115;
+
+ // Item wheel bottles
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 11;
+ itemWheelPos++;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 12;
+ itemWheelPos++;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 13;
+ itemWheelPos++;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 14;
+ itemWheelPos++;
+
+ // Give ending blow
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.eventBits[0x29] = 0xFF;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.eventBits[0x2A] = 0xFF;
+ }
+ void diababa()
+ {
+ // Add gale
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x9C] = 0x40;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 0;
+ itemWheelPos++;
+ }
+ void dangoro()
+ {
+ // Iron boots
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x9F] = 0x45;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 0x3;
+ itemWheelPos++;
+ }
+ void fyrus()
+ {
+ // Add Heroe's Bow + ammo
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xEC] = 30;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xA0] = 0x43;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 0x4;
+ itemWheelPos++;
+ }
+
+ void dekutoad()
+ {
+ // Add Waterbombbag + ammo
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xED] = 15; // Ammo bomb bag 1
+ // Bomb Bag + Waterbombs in bomb bag slot 1
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xAB] = 0x71;
+ // Reference id for bomb bag slot 1
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 15;
+ itemWheelPos++;
+ }
+
+ void morpheel()
+ {
+ // Zora Armor inventory flag
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x0D1] |= 0x2;
+
+ // Add clawshot
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xA5] = 0x44;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 0x9;
+
+ clawshotItemWheelIndex = itemWheelPos;
+ itemWheelPos++;
+ }
+
+ void deathsword()
+ {
+ // Set transform flag
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.eventBits[0xD] |= 0x4;
+ // Give midna
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.eventBits[0xC] |= 0x10;
+ // Give senses
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.eventBits[0x43] |= 0x8;
+
+ // MDH Flag (or white midna but that's sad)
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.eventBits[0x1E] |= 0x8;
+
+ // midna on back
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x30] |= 0x8;
+
+ // Midna Charge
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.eventBits[0x5] |= 0x1;
+
+ // Set Master sword inventory flag
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x0D2] |= 0x2;
+
+ // Equip Master sword (0x49 / 73)
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x014] = 0x49;
+ }
+ void stallord()
+ {
+ // Give spinner
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x09E] = 0x41;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 0x2;
+ itemWheelPos++;
+ }
+
+ void darkhammer()
+ {
+ // Nothing I guess
+ }
+ void blizetta()
+ {
+ // Give ball and chain
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x0A2] = 0x42;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 0x6;
+ itemWheelPos++;
+ }
+ void darknut()
+ {
+ // Nothing I guess
+ }
+ void armogohma()
+ {
+ // Dominion rod
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x0A4] = 0x46;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 0x8;
+ itemWheelPos++;
+ }
+ void arealfos()
+ {
+ // Nothing I guess
+ }
+ void argarok()
+ {
+ // 2nd clawshot
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xA6] = 0x47;
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0xB4 + itemWheelPos] = 10;
+ itemWheelPos++;
+ }
+ void zant()
+ {
+ // Light sword
+ libtp::tp::d_com_inf_game::dComIfG_gameInfo.scratchPad.wQuestLogData[0x0D6] = 0xFF;
+ }
+ void ganon()
+ {
+ // Nothing I guess
+ }
} // namespace mod \ No newline at end of file