diff options
author | AECX <aecx@aecx.cc> | 2020-02-19 19:02:19 +0100 |
---|---|---|
committer | AECX <aecx@aecx.cc> | 2020-02-19 19:02:19 +0100 |
commit | 007e7792181fd99b33ffa62f073dcc9bb9585343 (patch) | |
tree | 0368f4e11ee6e89ad945df803b45d4c7c538a263 | |
parent | dcf489730c56fe2c843a18cf5af7d1db24e3d6c2 (diff) |
0.2a
m--------- | Externals/libtp | 0 | ||||
-rw-r--r-- | include/main.h | 101 | ||||
-rw-r--r-- | notes.txt | 17 | ||||
-rw-r--r-- | source/main.cpp | 319 |
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 |