Implemented warp debug menu feature

This commit is contained in:
Mr-Wiseguy 2024-03-01 18:42:05 -05:00
parent 8dcca10fed
commit beec29217c
13 changed files with 1094 additions and 25 deletions

View File

@ -127,6 +127,8 @@ set (SOURCES
${CMAKE_SOURCE_DIR}/src/game/input.cpp ${CMAKE_SOURCE_DIR}/src/game/input.cpp
${CMAKE_SOURCE_DIR}/src/game/controls.cpp ${CMAKE_SOURCE_DIR}/src/game/controls.cpp
${CMAKE_SOURCE_DIR}/src/game/config.cpp ${CMAKE_SOURCE_DIR}/src/game/config.cpp
${CMAKE_SOURCE_DIR}/src/game/scene_table.cpp
${CMAKE_SOURCE_DIR}/src/game/debug.cpp
${CMAKE_SOURCE_DIR}/src/game/quicksaving.cpp ${CMAKE_SOURCE_DIR}/src/game/quicksaving.cpp
${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp

View File

@ -62,7 +62,7 @@
<div>Debug</div> <div>Debug</div>
<div class="tab__indicator"></div> <div class="tab__indicator"></div>
</tab> </tab>
<panel class="config" > <panel class="config" data-model="debug_model">
<template src="config-menu__debug" /> <template src="config-menu__debug" />
</panel> </panel>
</tabset> </tabset>

View File

@ -11,36 +11,27 @@
class="config-debug-option__label" class="config-debug-option__label"
>Warp</label> >Warp</label>
<div class="config-debug__option-controls"> <div class="config-debug__option-controls">
<label class="config-debug__select-wrapper"> <div class="config-debug__select-wrapper">
<div class="config-debug__select-label"><div>Region</div></div> <div class="config-debug__select-label"><div>Region</div></div>
<select> <select data-value="area_index" onchange="area_index_changed">
<option selected>First</option> <option data-for="area, i : area_names" data-attr-value="i">{{area}}</option>
<option>Second</option>
<option>Third</option>
<option>Fourth</option>
</select> </select>
</label> </div>
<label class="config-debug__select-wrapper"> <div class="config-debug__select-wrapper">
<div class="config-debug__select-label"><div>Scene</div></div> <div class="config-debug__select-label"><div>Scene</div></div>
<select> <select data-value="scene_index" onchange="scene_index_changed">
<option selected>First</option> <option data-for="scene, i : scene_names" data-attr-value="i">{{scene}}</option>
<option>Second</option>
<option>Third</option>
<option>Fourth</option>
</select> </select>
</label> </div>
<label class="config-debug__select-wrapper"> <div class="config-debug__select-wrapper">
<div class="config-debug__select-label"><div>Entrance</div></div> <div class="config-debug__select-label"><div>Entrance</div></div>
<select> <select data-value="entrance_index">
<option>First</option> <option data-for="entrance, i : entrance_names" data-attr-value="i">{{entrance}}</option>
<option>Second</option>
<option>Third</option>
<option>Fourth</option>
</select> </select>
</label> </div>
</div> </div>
<button <button
class="icon-button icon-button--success" class="icon-button icon-button--success" onclick="do_warp"
> >
<svg src="icons/Arrow.svg" /> <svg src="icons/Arrow.svg" />
</button> </button>

File diff suppressed because one or more lines are too long

View File

@ -88,6 +88,7 @@
select { select {
@extend %body; @extend %body;
@extend %nav-all;
@include trans-colors-border; @include trans-colors-border;
@include border($color-white-a50); @include border($color-white-a50);
display: block; display: block;
@ -121,6 +122,7 @@
border-radius: $border-radius-md; border-radius: $border-radius-md;
option { option {
@extend %nav-all;
@include trans-colors; @include trans-colors;
padding: space(8) space(12); padding: space(8) space(12);
background-color: $color-transparent; background-color: $color-transparent;

24
include/recomp_debug.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef __RECOMP_DEBUG_H__
#define __RECOMP_DEBUG_H__
#include <vector>
#include <string>
namespace recomp {
struct SceneWarps {
int index;
std::string name;
std::vector<std::string> entrances;
};
struct AreaWarps {
std::string name;
std::vector<SceneWarps> scenes;
};
extern std::vector<AreaWarps> game_warps;
void do_warp(int area, int scene, int entrance);
}
#endif

97
patches/debug_patches.c Normal file
View File

@ -0,0 +1,97 @@
#include "patches.h"
#include "input.h"
#include "z64debug_display.h"
void Message_FindMessage(PlayState* play, u16 textId);
extern SceneEntranceTableEntry sSceneEntranceTable[];
char text_buffer[1024];
void do_warp(PlayState* play, u16 entrance){
play->nextEntrance = entrance;
gSaveContext.save.entrance = play->nextEntrance;
play->state.running = false;
play->state.init = gGameStateOverlayTable[GAMESTATE_PLAY].init;
play->state.size = gGameStateOverlayTable[GAMESTATE_PLAY].instanceSize;
// Gets the ingame name, may be useful for mods later on
// SceneEntranceTableEntry* scene_entrance_table_entry = &sSceneEntranceTable[entrance >> 9];
// if (scene_entrance_table_entry->table) {
// EntranceTableEntry* entrance_table_entry = scene_entrance_table_entry->table[0];
// recomp_printf("entrance_table_entry: 0x%08X\n", (uintptr_t)entrance_table_entry);
// int scene_id = ABS(entrance_table_entry->sceneId);
// recomp_printf("scene_id: %d\n", scene_id);
// SceneTableEntry* scene = &gSceneTable[scene_id];
// int title_text_id = scene->titleTextId;
// recomp_printf("title_text_id: %d\n", title_text_id);
// recomp_printf("play->msgCtx.messageEntryTable: 0x%08X\n", (uintptr_t)play->msgCtx.messageEntryTableNes);
// Message_FindMessageNES(play, title_text_id);
// recomp_printf("font->messageStart: 0x%08X font->messageEnd: 0x%08X\n", play->msgCtx.font.messageStart, play->msgCtx.font.messageEnd);
// DmaRequest req;
// req.vromAddr = play->msgCtx.font.messageStart + SEGMENT_ROM_START(message_data_static);
// req.dramAddr = text_buffer;
// req.size = play->msgCtx.font.messageEnd;
// recomp_printf("dma from vrom 0x%08X to vram 0x%08x of 0x%04X bytes\n", req.vromAddr, req.dramAddr, req.size);
// DmaMgr_ProcessMsg(&req);
// if (text_buffer[2] != (char)0xFE) {
// recomp_printf("Invalid text\n");
// *(volatile int*)0 = 0;
// }
// recomp_printf("text_buffer: %s\n", text_buffer + 11);
// }
// int scene = (entrance & 0xFF00) >> 8;
}
void debug_play_update(PlayState* play) {
u16 pending_warp = recomp_get_pending_warp();
if (pending_warp != 0xFFFF) {
do_warp(play, pending_warp);
}
}
extern Input D_801F6C18;
// @recomp Patched to add a point to modify state before the frame's update.
void Play_Main(GameState* thisx) {
static Input* prevInput = NULL;
PlayState* this = (PlayState*)thisx;
// @recomp
debug_play_update(this);
// @recomp avoid unused variable warning
(void)prevInput;
prevInput = CONTROLLER1(&this->state);
DebugDisplay_Init();
{
GraphicsContext* gfxCtx = this->state.gfxCtx;
if (1) {
this->state.gfxCtx = NULL;
}
Play_Update(this);
this->state.gfxCtx = gfxCtx;
}
{
Input input = *CONTROLLER1(&this->state);
if (1) {
*CONTROLLER1(&this->state) = D_801F6C18;
}
Play_Draw(this);
*CONTROLLER1(&this->state) = input;
}
CutsceneManager_Update();
CutsceneManager_ClearWaiting();
}

View File

@ -16,5 +16,6 @@ DECLARE_FUNC(void, recomp_puts, const char* data, u32 size);
DECLARE_FUNC(void, recomp_exit); DECLARE_FUNC(void, recomp_exit);
DECLARE_FUNC(void, recomp_handle_quicksave_actions, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq); DECLARE_FUNC(void, recomp_handle_quicksave_actions, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq);
DECLARE_FUNC(void, recomp_handle_quicksave_actions_main, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq); DECLARE_FUNC(void, recomp_handle_quicksave_actions_main, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq);
DECLARE_FUNC(u16, recomp_get_pending_warp);
#endif #endif

View File

@ -1,5 +1,8 @@
__start = 0x80000000; __start = 0x80000000;
/* Static symbols that aren't in the elf */
sSceneEntranceTable = 0x801C5720;
/* Dummy addresses that get recompiled into function calls */ /* Dummy addresses that get recompiled into function calls */
recomp_puts = 0x81000000; recomp_puts = 0x81000000;
recomp_exit = 0x81000004; recomp_exit = 0x81000004;
@ -9,3 +12,4 @@ osRecvMesg_recomp = 0x81000010;
osSendMesg_recomp = 0x81000014; osSendMesg_recomp = 0x81000014;
recomp_get_gyro_deltas = 0x81000018; recomp_get_gyro_deltas = 0x81000018;
recomp_get_aspect_ratio = 0x8100001C; recomp_get_aspect_ratio = 0x8100001C;
recomp_get_pending_warp = 0x81000020;

17
src/game/debug.cpp Normal file
View File

@ -0,0 +1,17 @@
#include <atomic>
#include "recomp_debug.h"
#include "recomp_helpers.h"
#include "../patches/input.h"
std::atomic<uint16_t> pending_warp = 0xFFFF;
void recomp::do_warp(int area, int scene, int entrance) {
const recomp::SceneWarps game_scene = recomp::game_warps[area].scenes[scene];
int game_scene_index = game_scene.index;
pending_warp.store(((game_scene_index & 0xFF) << 8) | ((entrance & 0x0F) << 4));
}
extern "C" void recomp_get_pending_warp(uint8_t* rdram, recomp_context* ctx) {
// Return the current warp value and reset it.
_return(ctx, pending_warp.exchange(0xFFFF));
}

853
src/game/scene_table.cpp Normal file
View File

@ -0,0 +1,853 @@
#include <cstdint>
#include <vector>
#include <string>
#include "recomp_debug.h"
std::vector<recomp::AreaWarps> recomp::game_warps {
{ "Clock Town", {
{
0, "Mayor's Residence", {
"Entrance",
"Post Couple's Mask",
}
},
{
8, "Honey & Darling's Shop", {
"Entrance",
}
},
{
14, "Curiosity Shop", {
"Entrance",
"Back Entrance",
"Peephole",
"Exiting peephole",
}
},
{
36, "Milk Bar", {
"Entrance",
}
},
{
40, "Treasure Chest Shop", {
"Entrance",
"After game",
}
},
{
44, "Clock Tower Roof", {
"Entrance",
"After cutscene"
}
},
{
54, "Deku Scrub Playground", {
"Entrance",
"Game Finished",
}
},
{
58, "Shooting Gallery", {
"Entrance (with label)",
"Entrance",
}
},
{
86, "Post Office", {
"Entrance",
}
},
{
98, "Trading Post", {
"Entrance (with label)",
"Entrance",
}
},
{
108, "Lottery Shop", {
"Entrance",
}
},
{
162, "Swordsman's School", {
"Entrance",
}
},
{
188, "Stock Pot Inn", {
"Front entrance",
"From balcony",
"Near granny",
"Kitchen",
"Anju and Anju's mother cutscene",
"After Anju cutscene",
}
},
{
192, "Clock Tower", {
"From lost woods (cutscene)",
"Clock Town entrance",
"After learning song of healing",
"After moon falls",
"First song of time cutscene",
"From lost woods",
"Happy Mask Salesman cutscene",
}
},
{
202, "Bomb Shop", {
"Entrance (with label)",
"Entrance",
}
},
{
210, "East Clock Town", {
"From Termina Field",
"From South Clock Town (South entrance)",
"From Bombers' Hideout",
"From South Clock Town (North entrance)",
"From Treasure Chest Shop",
"From North Clock Town",
"From Honey & Darling's Shop",
"From the Mayor's Residence",
"From Town Shooting Gallery",
"From Stock Pot Inn",
"Stock Pot Inn balcony",
"From Milk Bar",
}
},
{
212, "West Clock Town", {
"From Termina Field",
"From South Clock Town (South entrance)",
"From South Clock Town (North entrance)",
"From Swordsman's School",
"From Curiosity Shop",
"From Trading Post",
"From Bomb Shop",
"From Post Office",
"From Lottery Shop",
"From Termina Field (?)",
}
},
{
214, "North Clock Town", {
"From Termina Field",
"From East Clock Town",
"From South Clock Town",
"From Fairy's Fountain",
"From Deku Scrub Playground",
"Near Termina Field entrance",
"Near Jim",
"After Sakon cutscene",
}
},
{
216, "South Clock Town", {
"From Clock Tower",
"From Termina Field",
"From East Clock Town (North entrance)",
"From West Clock Town (North entrance)",
"From North Clock Town",
"From West Clock Town (South entrance)",
"From Laundry Pool",
"From East Clock Town (South entrance)",
"Clock Tower balcony",
"From Song of Soaring",
"First song of time cutscene"
}
},
{
218, "Laundry Pool", {
"From South Clock Town",
"Curiosity Shop back entrance"
}
},
}},
{ "Swamp", {
{
12, "Southern Swamp (After Woodfall Temple)", {
"-swamp road",
"-boat house",
"-woodfall",
"-lower deku palace",
"-upper deku palace",
"-hags potion shop",
"-boat cruise",
"-woods of mystery",
"-swamp spider house",
"-ikana canyon",
"-owl statue",
}
},
{
4, "Hags' Potion Shop", {
"Entrance",
}
},
{
48, "Woodfall Temple", {
"Entrance",
"Deku Princess Room (First Visit)",
"Deku Princess Room",
}
},
{
56, "Odolwa Arena", {
"Entrance",
}
},
{
66, "Swamp Shooting Gallery", {
"Entrance",
}
},
{
72, "Swamp Spider House", {
"Entrance",
}
},
{
80, "Deku Palace", {
"From Southern Swamp",
"After getting caught",
"-deku king chamber",
"-deku king chamber (upper)",
"-deku shrine",
"From Southern Swamp (Alternate)",
"-jp grotto left, first room",
"-jp grotto left, second room",
"-jp grotto right, second room",
"From Bean Seller Grotto",
"-jp grotto right, first room",
}
},
{
118, "Deku Palace Royal Chamber", {
"-deku palace",
"-deku palace (upper)",
"-monkey released",
"-front of king",
}
},
{
122, "Road to Southern Swamp", {
"-termina field",
"-southern swamp",
"-swamp shooting gallery",
}
},
{
132, "Southern Swamp (Before Woodfall Temple)", {
"-road to southern swamp",
"-boat house",
"-woodfall",
"-deku palace",
"-deku palace (shortcut)",
"-hags potion shop",
"-boat ride",
"-woods of mystery",
"-swamp spider house",
"-ikana canyon",
"-owl statue",
}
},
{
134, "Woodfall", {
"-southern swamp",
"-unknown",
"-fairy fountain",
"-unknown",
"-owl statue",
}
},
{
158, "Deku Shrine", {
"-deku palace",
"-deku palace"
}
},
{
168, "Swamp Tourist Center", {
"Entrance",
"-koume",
"-tingle's dad",
}
},
{
194, "Woods of Mystery", {
"Entrance",
}
}
}},
{ "Snowhead", {
{
50, "Road to Mountain Village", {
"From Termina Field",
"From Mountain Village",
}
},
{
60, "Snowhead Temple", {
"Entrance (First Visit)",
"Entrance",
}
},
{
82, "Mountain Smithy", {
"Entrance",
}
},
{
94, "Goron Shrine", {
"Main Entrance (First Visit)",
"From Shop",
"After Goron's Lullaby cutscene",
"Main Entrance",
}
},
{
116, "Goron Shop", {
"Entrance",
}
},
{
130, "Goht Arena", {
"Entrance",
}
},
{
138, "Goron Village (After Snowhead Temple)", {
"-path to goron village (spring)",
"-unknown",
"-goron shrine",
"-lens of truth",
"-void out",
}
},
{
148, "Goron Village (Before Snowhead Temple)", {
"-path to goron village (winter)",
"-deku flower",
"-goron shrine",
"-lens of truth",
"-void out",
}
},
{
150, "Goron Graveyard", {
"-mountain village",
"-receiving goron mask",
}
},
{
154, "Mountain Village (Before Snowhead Temple)", {
"-after snowhead",
"-mountain smithy",
"-path to goron village (winter)",
"-goron graveyard",
"-path to snowhead",
"-on ice",
"-path to mountain village",
"-unknown",
"-owl statue",
}
},
{
174, "Mountain Village (After Snowhead Temple)", {
"-after snowhead",
"-mountain smithy",
"-path to goron village (spring)",
"-goron graveyard",
"-path to snowhead",
"-behind waterfall",
"-path to mountain village",
"-after snowhead (cutscene)",
"-owl statue",
}
},
{
178, "Snowhead", {
"-path to snowhead",
"-snowhead temple",
"-fairy fountain",
"-owl statue",
}
},
{
180, "Road to Goron Village (Before Snowhead Temple)", {
"-mountain village (winter)",
"-goron village (winter)",
"-goron racetrack",
}
},
{
182, "Road to Goron Village (After Snowhead Temple)", {
"-mountain village (spring)",
"-goron village (spring)",
"-goron racetrack",
}
},
{
208, "Goron Racetrack", {
"-path to mountain village",
"-race start",
"-race end",
}
}
}},
{ "Great Bay", {
{
34, "Pirates' Fortress (Outdoors)", {
"-exterior pirates fortress",
"-lower hookshot room",
"-upper hookshot room",
"-silver rupee room",
"-silver rupee room exit",
"-barrel room",
"-barrel room exit",
"-twin barrel room",
"-twin barrel room exit",
"-oob near twin barrel",
"-telescope",
"-oob hookshot room",
"-balcony",
"-upper hookshot room",
}
},
{
64, "Pirates' Fortress (Indoors)", {
"-hookshot room",
"-hookshot room upper",
"-100 rupee room",
"-100 rupee room (egg)",
"-barrel room",
"-barrel room (egg)",
"-twin barrel room",
"-twin barrel room (egg)",
"-telescope",
"-outside, underwater",
"-outside, telescope",
"-unknown",
}
},
{
68, "Pinnacle Rock", {
"Entrance",
"Respawn",
}
},
{
74, "Oceanside Spider House", {
"Entrance",
}
},
{
88, "Marine Research Lab", {
"Entrance",
}
},
{
96, "Zora Hall", {
"-zora cape",
"-zora cape (turtle)",
"-zora shop",
"-lulu's room",
"-evan's room",
"-japa's room",
"-mikau & tijo's room",
"-stage",
"-after rehearsal",
}
},
{
104, "Great Bay Coast", {
"-termina field",
"-zora cape",
"-void respawn",
"-pinnacle rock",
"-fisherman hut",
"-pirates fortress",
"-void resapwn (murky water)",
"-marine lab",
"-oceanside spider house",
"-during zora mask",
"-after zora mask",
"-owl statue",
"-thrown out",
"-after jumping game",
}
},
{
106, "Zora Cape", {
"-great bay coast",
"-zora hall",
"-zora hall (turtle)",
"-void respawn",
"-waterfall",
"-fairy fountain",
"-owl statue",
"-great bay temple",
"-after great bay temple",
"-unknown",
}
},
{
112, "Pirates' Fortress (Entrance)", {
"-great bay coast",
"-pirates fortress",
"-underwater passage",
"-underwater jet",
"-kicked out",
"-hookshot platform",
"-passage door",
}
},
{
114, "Fisherman's Hut", {
"Entrance",
}
},
{
140, "Great Bay Temple", {
"Entrance (After intro)",
"Entrance (With intro)"
}
},
{
142, "Waterfall Rapids", {
"-zora cape",
"-race start",
"-race end",
"-game won",
}
},
{
146, "Zora Hall (Room)", {
"-mikau from zora hall",
"-japas from zora hall",
"-lulu from zora hall",
"-evan from zora hall",
"-japa after jam session",
"-zora shop from zora hall",
"-evan after composing song",
}
},
{
184, "Gyorg Arena", {
"-great bay temple",
"-falling cutscene",
}
},
{
190, "-great bay (cutscene)", {
"zora cape",
}
}
}},
{ "Ikana", {
{
32, "Ikana Canyon", {
"-ikana road",
"-ghost hut",
"-music box house",
"-stone tower",
"-owl statue",
"-beneath the well",
"-sakon's hideout",
"-after stone tower",
"-ikana castle",
"-after house opens",
"-song of storms cave (house open)",
"-fairy fountain",
"-secret shrine",
"-from song of storms cave",
"-song of storms cave (house closed) ",
}
},
{
10, "Beneath the Graveyard", {
"Day 2",
"Day 1",
}
},
{
52, "Ancient Castle of Ikana", {
"From Beneath the Well",
"From Ikana Canyon",
"Outdoors (From main entrance)",
"Indoors (From main entrance)",
"Indoors (From ceiling)",
"Indoors (East Wing)",
"Indoors (From throne room)"
}
},
{
38, "Stone Tower Temple (Normal)", {
"Entrance (With Intro)",
"Entrance (After Intro)",
}
},
{
42, "Stone Tower Temple (Inverted)", {
"Entrance",
"-boss room entrance"
}
},
{
90, "Beneath the Graveyard", {
"Dampe's House",
"Beneath the Graveyard",
}
},
{
102, "Twinmold Arena", {
"Entrance",
"Entrane (1?)"
}
},
{
128, "Ikana Graveyard", {
"-road to ikana",
"-grave 1",
"-grave 2",
"-grave 3",
"-dampe's house",
"-after keeta defeated",
}
},
{
144, "Beneath the Well", {
"-ikana canyon",
"-ikana castle",
}
},
{
152, "Sakon's Hideout", {
"Entrance",
}
},
{
156, "Spirit House", {
"Entrance",
"-after minigame",
"-beat minigame",
}
},
{
160, "Road to Ikana", {
"-termina field",
"-ikana canyon",
"-ikana graveyard",
}
},
{
164, "Music Box House", {
"Entrance",
}
},
{
166, "Ancient Castle of Ikana (Throne room)", {
"Entrance",
}
},
{
170, "Stone Tower", {
"-ikana canyon",
"-unknown",
"-stone tower temple",
"-owl statue",
}
},
{
172, "Stone Tower (Inverted)", {
"-after inverting",
"-stone tower temple",
}
},
{
186, "Secret Shrine behind Waterfall", {
"Entrance",
}
}
}},
{ "Overworld", {
{
76, "Astral Observatory", {
"From Clock Town",
"From Termina Field",
"After telescope cutscene",
}
},
{
84, "Termina Field", {
"-west clock town",
"-road to southern swamp",
"-great bay coast",
"-path to mountain village",
"-road to ikana",
"-milk road",
"-south clock town",
"-east clock town",
"-north clock town",
"-observatory",
"-observatory (telescope)",
"-near ikana",
"-moon crash",
"-cremia hug",
"-skullkid cutscene",
"-west clock town",
}
}
}},
{ "Milk Road", {
{
6, "Romani Ranch (Indoors)", {
"Barn",
"House",
}
},
{
62, "Milk Road", {
"From Termina Field",
"From Romani Ranch",
"-gorman track (track exit)",
"-gorman track (main exit)",
"At Owl Statue",
"5?",
"6?",
}
},
{
100, "Romani Ranch", {
"Entrance",
"After practice",
"From Barn",
"From House",
"From Cucco Shack",
"From Doggy Racetrack",
"Near Barn (6?)",
"Near Barn (7?)",
"Near House (8?)",
"Near Barn (9?)",
"Talking to Romani",
"Near Barn (11?)",
}
},
{
124, "Doggy Racetrack", {
"-romani ranch",
"-after race",
}
},
{
126, "Cucco Shack", {
"-romani ranch",
"-after bunny hood",
}
},
{
206, "Gorman Track", {
"-milk road",
"-unknown",
"-beat minigame",
"-milk road behind fence",
"-milk road fence cutscene",
"-unknown",
"-start minigame",
}
}
}},
{ "Moon", {
{
2, "Majora Arena", {
"Entrance",
}
},
{
78, "Moon Trial (Deku)", {
"Entrance",
}
},
{
120, "Moon Trial (Goron)", {
"Entrance",
}
},
{
136, "Moon Trial (Zora)", {
"Entrance",
"Respawn",
}
},
{
198, "Moon Trial (Link)", {
"Entrance",
}
},
{
200, "Moon", {
"Entrance",
}
}
}},
{ "Other", {
{
20, "Secret Grottos", {
"Termina Field (Great Bay Gossip Stones)",
"Termina Field (Swamp Gossip Stones)",
"Termina Field (Ikana Gossip Stones)",
"Termina Field (Mountain Gossip Stones)",
"-generic grotto",
"Road to Goron Village (Springwater)",
"-maze straight (a)",
"Termina Field near Dodongos",
"-maze vines (lower)",
"-business scrub",
"-cows",
"Termina Field under boulder (Piece of Heart)",
"Deku Palace (Bean Seller)",
"Termina Field (Peahat)",
"-maze straight (b)",
"-maze grotto (upper)",
"-lens of truth",
}
},
{
46, "-before clock town", {
"-falling from cliff",
"-inside clock tower",
"-transformed to deku",
"-void respawn",
"-song of time flashback",
}
},
{
70, "Fairy's Fountain", {
"Clock Town",
"Woodfall",
"Snowhead",
"Great Bay Coast",
"Ikana Canyon",
"Clock Town (After cutscene)",
"Woodfall (After cutscene)",
"Snowhead (After cutscene)",
"Great Bay Coast (After cutscene)",
"Ikana Canyon (After cutscene)",
}
},
{
196, "Intro (Lost Woods)", {
"Skull kid intro cutscene",
"First Song of Time cutscene"
}
},
{
204, "Chamber of Giants", {
"Entrance",
}
}
}},
};

View File

@ -51,7 +51,7 @@ ultramodern::gfx_callbacks_t::gfx_data_t create_gfx() {
SDL_Window* window; SDL_Window* window;
ultramodern::WindowHandle create_window(ultramodern::gfx_callbacks_t::gfx_data_t) { ultramodern::WindowHandle create_window(ultramodern::gfx_callbacks_t::gfx_data_t) {
window = SDL_CreateWindow("Zelda 64: Recompiled", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE ); window = SDL_CreateWindow("Zelda 64: Recompiled", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1600, 960, SDL_WINDOW_RESIZABLE );
if (window == nullptr) { if (window == nullptr) {
exit_error("Failed to create window: %s\n", SDL_GetError()); exit_error("Failed to create window: %s\n", SDL_GetError());

View File

@ -1,6 +1,7 @@
#include "recomp_ui.h" #include "recomp_ui.h"
#include "recomp_input.h" #include "recomp_input.h"
#include "recomp_config.h" #include "recomp_config.h"
#include "recomp_debug.h"
#include "../../ultramodern/config.hpp" #include "../../ultramodern/config.hpp"
#include "../../ultramodern/ultramodern.hpp" #include "../../ultramodern/ultramodern.hpp"
#include "RmlUi/Core.h" #include "RmlUi/Core.h"
@ -69,6 +70,34 @@ void close_config_menu() {
} }
} }
struct DebugContext {
Rml::DataModelHandle model_handle;
std::vector<std::string> area_names;
std::vector<std::string> scene_names;
std::vector<std::string> entrance_names;
int area_index = 0;
int scene_index = 0;
int entrance_index = 0;
DebugContext() {
for (const auto& area : recomp::game_warps) {
area_names.emplace_back(area.name);
}
update_warp_names();
}
void update_warp_names() {
scene_names.clear();
for (const auto& scene : recomp::game_warps[area_index].scenes) {
scene_names.emplace_back(scene.name);
}
entrance_names = recomp::game_warps[area_index].scenes[scene_index].entrances;
}
};
DebugContext debug_context;
class ConfigMenu : public recomp::MenuController { class ConfigMenu : public recomp::MenuController {
public: public:
ConfigMenu() { ConfigMenu() {
@ -114,6 +143,32 @@ public:
controls_model_handle.DirtyVariable("input_device_is_keyboard"); controls_model_handle.DirtyVariable("input_device_is_keyboard");
controls_model_handle.DirtyVariable("inputs"); controls_model_handle.DirtyVariable("inputs");
}); });
recomp::register_event(listener, "area_index_changed",
[](const std::string& param, Rml::Event& event) {
debug_context.area_index = event.GetParameter<int>("value", 0);
debug_context.scene_index = 0;
debug_context.entrance_index = 0;
debug_context.update_warp_names();
debug_context.model_handle.DirtyVariable("scene_index");
debug_context.model_handle.DirtyVariable("entrance_index");
debug_context.model_handle.DirtyVariable("scene_names");
debug_context.model_handle.DirtyVariable("entrance_names");
});
recomp::register_event(listener, "scene_index_changed",
[](const std::string& param, Rml::Event& event) {
debug_context.scene_index = event.GetParameter<int>("value", 0);
debug_context.entrance_index = 0;
debug_context.update_warp_names();
debug_context.model_handle.DirtyVariable("entrance_index");
debug_context.model_handle.DirtyVariable("entrance_names");
});
recomp::register_event(listener, "do_warp",
[](const std::string& param, Rml::Event& event) {
recomp::do_warp(debug_context.area_index, debug_context.scene_index, debug_context.entrance_index);
});
} }
void make_graphics_bindings(Rml::Context* context) { void make_graphics_bindings(Rml::Context* context) {
Rml::DataModelConstructor constructor = context->CreateDataModel("graphics_model"); Rml::DataModelConstructor constructor = context->CreateDataModel("graphics_model");
@ -290,9 +345,32 @@ public:
controls_model_handle = constructor.GetModelHandle(); controls_model_handle = constructor.GetModelHandle();
} }
void make_debug_bindings(Rml::Context* context) {
Rml::DataModelConstructor constructor = context->CreateDataModel("debug_model");
if (!constructor) {
throw std::runtime_error("Failed to make RmlUi data model for the debug menu");
}
// Register the array type for string vectors.
constructor.RegisterArray<std::vector<std::string>>();
// Bind the warp parameter indices
constructor.Bind("area_index", &debug_context.area_index);
constructor.Bind("scene_index", &debug_context.scene_index);
constructor.Bind("entrance_index", &debug_context.entrance_index);
// Bind the vectors for warp names
constructor.Bind("area_names", &debug_context.area_names);
constructor.Bind("scene_names", &debug_context.scene_names);
constructor.Bind("entrance_names", &debug_context.entrance_names);
debug_context.model_handle = constructor.GetModelHandle();
}
void make_bindings(Rml::Context* context) override { void make_bindings(Rml::Context* context) override {
make_graphics_bindings(context); make_graphics_bindings(context);
make_controls_bindings(context); make_controls_bindings(context);
make_debug_bindings(context);
} }
}; };