diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8345e33..4be215f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -127,6 +127,8 @@ set (SOURCES
${CMAKE_SOURCE_DIR}/src/game/input.cpp
${CMAKE_SOURCE_DIR}/src/game/controls.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/ui/ui_renderer.cpp
diff --git a/assets/config_menu.rml b/assets/config_menu.rml
index 6387f7b..e32e950 100644
--- a/assets/config_menu.rml
+++ b/assets/config_menu.rml
@@ -62,7 +62,7 @@
Debug
-
+
diff --git a/assets/config_menu/debug.rml b/assets/config_menu/debug.rml
index 801bf2c..db0950a 100644
--- a/assets/config_menu/debug.rml
+++ b/assets/config_menu/debug.rml
@@ -11,36 +11,27 @@
class="config-debug-option__label"
>Warp
-
diff --git a/assets/recomp.rcss b/assets/recomp.rcss
index eb5723a..61e6039 100644
--- a/assets/recomp.rcss
+++ b/assets/recomp.rcss
@@ -1 +1 @@
-h1{font-size:64dp;letter-spacing:4.48dp;line-height:64dp;font-style:normal;font-weight:700}h2{font-size:48dp;letter-spacing:3.36dp;line-height:48dp;font-style:normal;font-weight:700}h3,.tab{font-size:32dp;letter-spacing:2.24dp;line-height:32dp;font-style:normal;font-weight:700}.label-lg,.menu-list-item__label,.button--large{font-size:32dp;letter-spacing:3.52dp;line-height:32dp;font-style:normal;font-weight:700}.label-md,.config-debug-option__label,.button,.config-option__title,.control-option__label{font-size:24dp;letter-spacing:2.64dp;line-height:24dp;font-style:normal;font-weight:700}.label-sm,.subtitle-title__disclaimer,.config-debug__select-wrapper .config-debug__select-label,.config-option__range-label,.config-option__list .config-option__tab-label{font-size:16dp;letter-spacing:2.24dp;line-height:16dp;font-style:normal;font-weight:700;text-transform:uppercase}body,.config-debug__select-wrapper select{font-size:16dp;letter-spacing:0dp;line-height:16dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto}.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}h1{font-size:64dp;letter-spacing:4.48dp;line-height:64dp;font-style:normal;font-weight:700}h2{font-size:48dp;letter-spacing:3.36dp;line-height:48dp;font-style:normal;font-weight:700}h3,.tab{font-size:32dp;letter-spacing:2.24dp;line-height:32dp;font-style:normal;font-weight:700}.label-lg,.menu-list-item__label,.button--large{font-size:32dp;letter-spacing:3.52dp;line-height:32dp;font-style:normal;font-weight:700}.label-md,.config-debug-option__label,.button,.config-option__title,.control-option__label{font-size:24dp;letter-spacing:2.64dp;line-height:24dp;font-style:normal;font-weight:700}.label-sm,.subtitle-title__disclaimer,.config-debug__select-wrapper .config-debug__select-label,.config-option__range-label,.config-option__list .config-option__tab-label{font-size:16dp;letter-spacing:2.24dp;line-height:16dp;font-style:normal;font-weight:700;text-transform:uppercase}body,.config-debug__select-wrapper select{font-size:16dp;letter-spacing:0dp;line-height:16dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto}.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}*{box-sizing:border-box}hr{display:block;background:#000;padding:1.5dp}body{font-family:chiaro;font-weight:normal;font-style:normal;font-size:20dp;color:#fff}div#window{position:relative;width:100%;height:100%;box-sizing:border-box;background-color:#121018;border-color:rgba(255,255,255,.2)}div#content{z-index:2;width:auto;height:100%;overflow:hidden auto;text-align:center}p{text-align:left}input.submit{margin-left:0}input.text,input.password{box-sizing:border-box;height:31dp;padding:11dp 10dp 0;cursor:text;text-align:left}textarea{padding:14dp 12dp 10dp;cursor:text;text-align:left}input.text,input.password,select,textarea{height:auto}table input.text{box-sizing:border-box;width:100%;margin:0;line-height:1;border-width:1.1dp;border-color:#000;background-color:#fff;font-size:15dp;decorator:none;height:auto}input.radio,input.checkbox{flex:0;tab-index:auto;focus:auto;nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto;width:0dp}scrollbarvertical,scrollbarhorizontal{margin:0;border:0}scrollbarvertical slidertrack,scrollbarhorizontal slidertrack{background:#dabaf7;opacity:.05}scrollbarvertical sliderbar,scrollbarhorizontal sliderbar{border-radius:5dp;background:#dabaf7;opacity:.1}scrollbarvertical sliderbar:hover:not(:active),scrollbarhorizontal sliderbar:hover:not(:active){opacity:.2}scrollbarvertical sliderbar:active,scrollbarhorizontal sliderbar:active{opacity:.3}scrollbarvertical sliderarrowdec,scrollbarvertical sliderarrowinc,scrollbarhorizontal sliderarrowdec,scrollbarhorizontal sliderarrowinc{width:0;height:0}scrollbarvertical{width:12dp}scrollbarvertical slidertrack{width:12dp}scrollbarvertical sliderbar{width:12dp}scrollbarhorizontal{height:12dp}scrollbarhorizontal slidertrack{height:12dp}scrollbarhorizontal sliderbar{height:12dp}.centered-page{display:flex;position:absolute;top:0;right:0;bottom:0;left:0;padding:64dp;background-color:rgba(255,255,255,.1)}.centered-page__modal{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%;background:rgba(8,7,13,.9);border-radius:16dp;border-color:rgba(255,255,255,.2);border-width:1.1dp}.centered-page__modal>.tabs{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%}.centered-page__modal panels{flex:1 1 100%}.control-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;width:100%;height:auto;padding:4dp 16dp 4dp 20dp;border-radius:8dp;background-color:rgba(0,0,0,0)}.control-option svg{image-color:#ccc}.control-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option:focus-visible:not(:disabled,[disabled]),.control-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.control-option:focus-visible:not(:disabled,[disabled]) svg,.control-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.control-option:disabled,.control-option[disabled]{opacity:.5}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"]{border-color:#f86039}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-icon{opacity:0}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-recording{opacity:1}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"]{border-color:#f86039}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-icon{opacity:0}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-recording{opacity:1}.control-option .icon-button{flex:1 1 auto}.control-option__label{flex:2 1 300dp;height:auto;white-space:nowrap}.control-option__bindings{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;flex:2 1 400dp;width:100%;height:56dp;padding:0 12dp 0 4dp}.control-option__binding{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;position:relative;align-items:center;justify-content:center;margin:0 4dp;flex:1 1 100%;width:100%;height:56dp;padding:8dp;background-color:rgba(190,184,219,.1);border-color:rgba(190,184,219,.1);border-width:1.1dp;border-radius:8dp}.control-option__binding svg{image-color:#ccc}.control-option__binding svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option__binding:focus,.control-option__binding:hover{color:#f2f2f2;background-color:rgba(255,255,255,.1);border-color:#f2f2f2}.control-option__binding:focus svg,.control-option__binding:hover svg{image-color:#f2f2f2}.control-option__binding:active{color:#f5f5f5}.control-option__binding:active svg{image-color:#f5f5f5}.control-option__binding:disabled,.control-option__binding[disabled]{color:#ccc;opacity:.5}.control-option__binding:disabled svg,.control-option__binding[disabled] svg{image-color:#ccc}.control-option__binding:not([disabled]){cursor:pointer}.control-option__binding-icon{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;opacity:1}@keyframes control-option__binding-recording-scale{0%{transform:scale(1)}50%{transform:scale(0.85)}to{transform:scale(1)}}.control-option__binding-recording{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:absolute;display:flex;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0;opacity:0}.control-option__binding-recording .control-option__binding-circle{width:24dp;height:24dp;background-color:#f86039;border-radius:24dp;animation:1.5s sine-in-out infinite control-option__binding-recording-scale}.control-option__binding-recording .control-option__binding-edge{position:absolute;transform:translate(-50%, -50%);top:50%;left:50%;width:36dp;height:36dp}.control-option__binding-recording .control-option__binding-edge>svg.control-option__binding-edge-svg{width:36dp;height:36dp;image-color:#f86039}.tabs tabs{display:flex;flex-direction:row;align-items:center;justify-content:flex-start}.tab{display:block;position:relative;padding:20dp 24dp;background-color:rgba(0,0,0,0);margin:0;color:rgba(255,255,255,.6);transition:color .05s linear-in-out;opacity:.9}.tab:selected{color:#f2f2f2}.tab:selected .tab__indicator{background-color:rgba(255,255,255,.6)}.tab:selected:hover{cursor:default}.tab:hover{cursor:pointer;opacity:1}.tab:focus{color:#f2f2f2;opacity:1}.tab__indicator{position:absolute;background-color:rgba(0,0,0,0);right:0;bottom:2dp;left:0;height:2dp}.config__exit-button{position:absolute;top:8dp;right:8dp}.config__form{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;display:flex;flex-direction:column;justify-content:space-between;flex:1 1 100%;width:100%;height:100%;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__wrapper{display:flex;flex-direction:column;border-radius:0dp;flex:1 1 100%;height:100%;padding:16dp;text-align:left;background-color:rgba(0,0,0,.35)}.config__header,.config__footer{display:flex;justify-content:space-between;align-items:center;width:100%;background-color:rgba(0,0,0,.35)}.config__header{border-bottom-color:rgba(255,255,255,.1);border-bottom-width:1.1dp;padding:12dp 20dp}.config__footer{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;padding:20dp 20dp;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__header-left{display:flex;flex-direction:row;flex:1 1 auto}.config__header-left>:not(:first-child){margin-left:8dp}.config__row{display:flex;flex-direction:row}.config-option{display:flex;flex-direction:column;flex:1;align-items:flex-start;justify-content:space-between;margin:8dp 0 16dp}.config-option__title{padding:0 12dp}.config-option__list{display:flex;padding:0;flex-direction:row;width:100%;align-items:flex-start;justify-content:flex-start}.config-option__list .config-option__tab-label{display:block;padding:12dp 0;margin:0 12dp;margin-right:16dp;color:rgba(255,255,255,.6);tab-index:none;transition:color .05s linear-in-out}.config-option__list .config-option__tab-label:hover{cursor:pointer}.config-option__list input.radio{visibility:visible;width:0;height:0}.config-option__list input.radio:checked+.config-option__tab-label{border-bottom:1dp;border-color:rgba(255,255,255,.3)}.config-option__list input.radio:checked+.config-option__tab-label:hover{cursor:default}.config-option__list input.radio:focus+.config-option__tab-label{color:#f2f2f2}.config-option__list input.range slidertrack{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-top:7dp;height:2dp;background-color:rgba(255,255,255,.2)}.config-option__list input.range sliderbar{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-left:-8dp;margin-right:-6dp;width:16dp;height:16dp;background-color:#ccc;border-radius:8dp;transition:background-color .05s linear-in-out}.config-option__list input.range sliderbar:hover{cursor:pointer;background-color:#f2f2f2}.config-option__list input.range sliderbar:active,.config-option__list input.range slidertrack:active+sliderbar{background-color:#17d6e8}.config-option__list input.range sliderarrowdec,.config-option__list input.range sliderarrowinc{display:none}.config-option__range-wrapper{margin-top:4dp;max-width:360dp}.config-option__range-label{flex:0 0 16dp;display:block;padding:0;margin:0 12dp;margin-right:16dp;color:#f2f2f2;tab-index:none}.input-config{padding:0}.input-config__horizontal-split{display:flex;position:relative;flex-direction:row;height:100%}.input-config__mappings{display:block;flex:1 1 auto;height:100%;min-width:640dp}.input-config__mappings-scroll{display:block;width:100%;max-height:100%;overflow-y:auto}.input-config__mappings-wrapper{padding:8dp}.input-config__visual-wrapper{display:block;width:auto;height:auto;max-width:1040.4444444444dp;max-height:780.3333333333dp;margin:auto 0;flex:1 1 100%}.input-config__visual-aspect{position:relative;width:100%;padding-bottom:75%;background-color:rgba(0,0,0,.35);margin:auto 0}.input-config__visual{display:flex;flex-direction:column;position:absolute;top:16dp;right:16dp;bottom:16dp;left:16dp;border-radius:108dp;background-color:rgba(255,255,255,.05)}.input-config__visual-half{display:flex;position:relative;flex-direction:row;flex:1 1 100%;padding:6%}.input-config__visual-half--bottom{align-items:flex-end;justify-content:space-between}.input-config__visual-quarter-left{display:flex;flex:1 1 50%;width:auto;align-items:flex-start;justify-content:flex-start}.input-config__visual-quarter-right{display:flex;flex:1 1 100%;align-items:flex-start;justify-content:flex-end}.input-config__visual-stick-wrapper{display:flex;position:absolute;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0}.input-config__visual-stick{display:flex;position:relative;align-items:center;justify-content:center;width:200dp;height:200dp;border-radius:100dp;background-color:rgba(255,255,255,.05)}.input-viz{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:relative;display:flex;align-items:center;justify-content:center}.input-viz>svg:not(.input-viz__dpad-arrow){position:absolute;top:0;right:0;left:0;bottom:0}[cur-input=NONE] .input-viz[visual-input]{opacity:1}.input-viz[visual-input~=A]{opacity:.25}[cur-input=A] .input-viz[visual-input~=A]{opacity:1}.input-viz[visual-input~=B]{opacity:.25}[cur-input=B] .input-viz[visual-input~=B]{opacity:1}.input-viz[visual-input~=Z]{opacity:.25}[cur-input=Z] .input-viz[visual-input~=Z]{opacity:1}.input-viz[visual-input~=START]{opacity:.25}[cur-input=START] .input-viz[visual-input~=START]{opacity:1}.input-viz[visual-input~=DPAD_UP]{opacity:.25}[cur-input=DPAD_UP] .input-viz[visual-input~=DPAD_UP]{opacity:1}.input-viz[visual-input~=DPAD_DOWN]{opacity:.25}[cur-input=DPAD_DOWN] .input-viz[visual-input~=DPAD_DOWN]{opacity:1}.input-viz[visual-input~=DPAD_LEFT]{opacity:.25}[cur-input=DPAD_LEFT] .input-viz[visual-input~=DPAD_LEFT]{opacity:1}.input-viz[visual-input~=DPAD_RIGHT]{opacity:.25}[cur-input=DPAD_RIGHT] .input-viz[visual-input~=DPAD_RIGHT]{opacity:1}.input-viz[visual-input~=L]{opacity:.25}[cur-input=L] .input-viz[visual-input~=L]{opacity:1}.input-viz[visual-input~=R]{opacity:.25}[cur-input=R] .input-viz[visual-input~=R]{opacity:1}.input-viz[visual-input~=C_UP]{opacity:.25}[cur-input=C_UP] .input-viz[visual-input~=C_UP]{opacity:1}.input-viz[visual-input~=C_DOWN]{opacity:.25}[cur-input=C_DOWN] .input-viz[visual-input~=C_DOWN]{opacity:1}.input-viz[visual-input~=C_LEFT]{opacity:.25}[cur-input=C_LEFT] .input-viz[visual-input~=C_LEFT]{opacity:1}.input-viz[visual-input~=C_RIGHT]{opacity:.25}[cur-input=C_RIGHT] .input-viz[visual-input~=C_RIGHT]{opacity:1}.input-viz[visual-input~=X_AXIS_NEG]{opacity:.25}[cur-input=X_AXIS_NEG] .input-viz[visual-input~=X_AXIS_NEG]{opacity:1}.input-viz[visual-input~=X_AXIS_POS]{opacity:.25}[cur-input=X_AXIS_POS] .input-viz[visual-input~=X_AXIS_POS]{opacity:1}.input-viz[visual-input~=Y_AXIS_NEG]{opacity:.25}[cur-input=Y_AXIS_NEG] .input-viz[visual-input~=Y_AXIS_NEG]{opacity:1}.input-viz[visual-input~=Y_AXIS_POS]{opacity:.25}[cur-input=Y_AXIS_POS] .input-viz[visual-input~=Y_AXIS_POS]{opacity:1}.input-viz__button{color:#f2f2f2}.input-viz__button svg{image-color:#f2f2f2}.input-viz__button--sm{width:64dp;height:64dp}.input-viz__button--sm>svg{width:64dp;height:64dp}.input-viz__button--md{width:76dp;height:76dp}.input-viz__button--md>svg{width:76dp;height:76dp}.input-viz__button--lg{width:84dp;height:84dp}.input-viz__button--lg>svg{width:84dp;height:84dp}.input-viz__button--C svg{image-color:#e9cd35}.input-viz__button--A svg{image-color:#33f}.input-viz__button--B svg{image-color:#45d043}.input-viz__Z{width:136dp;height:136dp}.input-viz__Z svg{image-color:#e9cd35}.input-viz__Z>svg{width:136dp;height:136dp}.input-viz.input-viz__dpad{width:192dp;height:192dp;position:relative}.input-viz.input-viz__dpad svg{image-color:#f2f2f2}.input-viz.input-viz__dpad>svg{width:192dp;height:192dp}.input-viz__dpad-split{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;width:100%;height:100%}.input-viz__dpad-split--vertical{flex-direction:column;align-items:center;justify-content:space-between}.input-viz__dpad-split--horizontal{flex-direction:row;align-items:center;justify-content:space-between}.input-viz__dpad-split>div{display:flex;flex:1 1 100%;width:64dp;height:64dp;align-items:center;justify-content:center;flex-direction:row}.input-viz__dpad-arrow{position:absolute;width:60dp;height:60dp}.input-viz__dpad-arrow--up{top:4dp;margin:0 auto}.input-viz__dpad-arrow--down{bottom:4dp;margin:0 auto;transform:rotate(180deg)}.input-viz__dpad-arrow--left{left:4dp;margin:auto 0;transform:rotate(-90deg)}.input-viz__dpad-arrow--right{right:4dp;margin:auto 0;transform:rotate(90deg)}.input-viz__R{width:96dp;height:96dp}.input-viz__R svg{image-color:#fff}.input-viz__R>svg{width:96dp;height:96dp}.input-viz__L{width:136dp;height:136dp}.input-viz__L svg{image-color:#17d6e8}.input-viz__L>svg{width:136dp;height:136dp}.input-config__c-buttons{position:relative;width:208dp;height:132dp}.input-config__c-buttons-lr,.input-config__c-buttons-du{display:flex;position:absolute;top:0;right:0;left:0;bottom:0}.input-config__c-buttons-lr{flex-direction:row;align-items:flex-start;justify-content:space-between}.input-config__c-buttons-du{flex-direction:column-reverse;align-items:center;justify-content:space-between}.input-config__c-buttons .input-viz[visual-input=C_UP]{margin-top:-32dp}.button{background-color:rgba(185,125,242,.05);color:#ccc;border-color:rgba(185,125,242,.8);transition:color .05s linear-in-out,background-color .05s linear-in-out;display:block;padding:23dp;border-radius:12dp;border-width:1.1dp;width:auto;height:auto}.button:focus{color:#f2f2f2;border-color:#b97df2;background-color:rgba(185,125,242,.3)}.button:disabled,.button[disabled]{color:rgba(255,255,255,.6)}.button:active{background-color:rgba(185,125,242,.2);color:#f5f5f5}.button--secondary{background-color:rgba(23,214,232,.05);color:#ccc;border-color:rgba(23,214,232,.8)}.button--secondary:focus{color:#f2f2f2;border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.button--secondary:disabled,.button--secondary[disabled]{color:rgba(255,255,255,.6)}.button--secondary:active{background-color:rgba(23,214,232,.2);color:#f5f5f5}.button--tertiary{background-color:rgba(242,242,242,.05);color:#ccc;border-color:rgba(242,242,242,.8)}.button--tertiary:focus{color:#f2f2f2;border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.button--tertiary:disabled,.button--tertiary[disabled]{color:rgba(255,255,255,.6)}.button--tertiary:active{background-color:rgba(242,242,242,.2);color:#f5f5f5}.button--success{background-color:rgba(69,208,67,.05);color:#ccc;border-color:rgba(69,208,67,.8)}.button--success:focus{color:#f2f2f2;border-color:#45d043;background-color:rgba(69,208,67,.3)}.button--success:disabled,.button--success[disabled]{color:rgba(255,255,255,.6)}.button--success:active{background-color:rgba(69,208,67,.2);color:#f5f5f5}.button--error{background-color:rgba(248,96,57,.05);color:#ccc;border-color:rgba(248,96,57,.8)}.button--error:focus{color:#f2f2f2;border-color:#f86039;background-color:rgba(248,96,57,.3)}.button--error:disabled,.button--error[disabled]{color:rgba(255,255,255,.6)}.button--error:active{background-color:rgba(248,96,57,.2);color:#f5f5f5}.button--warning{background-color:rgba(233,205,53,.05);color:#ccc;border-color:rgba(233,205,53,.8)}.button--warning:focus{color:#f2f2f2;border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.button--warning:disabled,.button--warning[disabled]{color:rgba(255,255,255,.6)}.button--warning:active{background-color:rgba(233,205,53,.2);color:#f5f5f5}.button:not([disabled]){cursor:pointer}.button:disabled,.button[disabled]{opacity:.5}.button__label{width:auto;height:auto}.icon-button{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;overflow:hidden;border-radius:26.9dp;border-width:1.1dp;border-color:rgba(0,0,0,0);background-color:rgba(0,0,0,0);width:53.8dp;height:53.8dp;min-width:53.8dp;min-height:53.8dp;max-width:53.8dp;max-height:53.8dp}.icon-button svg{image-color:#ccc}.icon-button svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.icon-button:focus,.icon-button:hover{color:#f2f2f2;background-color:rgba(255,255,255,.2)}.icon-button:focus svg,.icon-button:hover svg{image-color:#f2f2f2}.icon-button:active{color:#f5f5f5;background-color:rgba(255,255,255,.1)}.icon-button:active svg{image-color:#f5f5f5}.icon-button:disabled,.icon-button[disabled]{color:#ccc;opacity:.5}.icon-button:disabled svg,.icon-button[disabled] svg{image-color:#ccc}.icon-button:not([disabled]){cursor:pointer}.icon-button svg{width:32dp;height:32dp}.icon-button--primary{background-color:rgba(185,125,242,.05);border-color:rgba(185,125,242,.8)}.icon-button--primary:focus,.icon-button--primary:hover{border-color:#b97df2;background-color:rgba(185,125,242,.3)}.icon-button--primary:active{background-color:rgba(185,125,242,.2)}.icon-button--secondary{background-color:rgba(23,214,232,.05);border-color:rgba(23,214,232,.8)}.icon-button--secondary:focus,.icon-button--secondary:hover{border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.icon-button--secondary:active{background-color:rgba(23,214,232,.2)}.icon-button--tertiary{background-color:rgba(242,242,242,.05);border-color:rgba(242,242,242,.8)}.icon-button--tertiary:focus,.icon-button--tertiary:hover{border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.icon-button--tertiary:active{background-color:rgba(242,242,242,.2)}.icon-button--success{background-color:rgba(69,208,67,.05);border-color:rgba(69,208,67,.8)}.icon-button--success:focus,.icon-button--success:hover{border-color:#45d043;background-color:rgba(69,208,67,.3)}.icon-button--success:active{background-color:rgba(69,208,67,.2)}.icon-button--danger{background-color:rgba(248,96,57,.05);border-color:rgba(248,96,57,.8)}.icon-button--danger:focus,.icon-button--danger:hover{border-color:#f86039;background-color:rgba(248,96,57,.3)}.icon-button--danger:active{background-color:rgba(248,96,57,.2)}.icon-button--warning{background-color:rgba(233,205,53,.05);border-color:rgba(233,205,53,.8)}.icon-button--warning:focus,.icon-button--warning:hover{border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.icon-button--warning:active{background-color:rgba(233,205,53,.2)}.launcher{display:block;flex-direction:row;justify-content:space-between;position:relative;width:100%;height:100%;background-color:#08070d}.launcher__vertical-split{display:flex;position:absolute;flex-direction:column;align-items:flex-start;justify-content:space-between;top:0;right:50%;bottom:0;left:0}.launcher__vertical-split--right{align-items:flex-end;right:0;left:50%}@keyframes slide-mm-bg-over{0%{transform:translateX(100dp)}to{transform:translateX(0dp)}}.launcher__background-wrapper{display:flex;align-items:center;justify-content:flex-start;position:absolute;left:-70vw;right:-100%;top:-55vw;bottom:-50vw;transform:translateX(0dp);animation:25s cubic-out 1 slide-mm-bg-over}@keyframes fade-mm-in{0%{opacity:0}to{opacity:.1}}.launcher__background-mm{position:absolute;left:0;top:0;bottom:0;height:100%;width:auto;opacity:.1;animation:2.5s cubic-in-out 1 fade-mm-in}.launcher__title-quadrant{flex:1 1 auto;padding-top:96dp;padding-left:96dp;width:auto;height:auto}.launcher__title-quadrant--right{padding-right:96dp;padding-left:0}.launcher__content-quadrant{display:flex;position:relative;flex-direction:column;align-items:flex-start;justify-content:flex-end;padding:32dp;width:100%;height:auto;flex:1 1 100%}.menu-list-item{color:#ccc;display:flex;flex-direction:row;align-items:center;width:100%;height:auto;padding:16dp;border-radius:8dp;background-color:rgba(0,0,0,0);cursor:pointer}.menu-list-item svg{image-color:#ccc}.menu-list-item--right{align-content:flex-end;flex-direction:row-reverse}.menu-list-item--right .menu-list-item__bullet{opacity:1;margin-left:12dp}.menu-list-item--right.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item--right.menu-list-item:hover:not(:disabled,[disabled]){decorator:gradient(horizontal #7A2AC600 #DABAF714)}.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item:hover:not(:disabled,[disabled]){color:#b97df2;decorator:gradient(horizontal #7A2AC614 #DABAF700)}.menu-list-item:focus:not(:disabled,[disabled]) svg,.menu-list-item:hover:not(:disabled,[disabled]) svg{image-color:#b97df2}.menu-list-item:focus:not(:disabled,[disabled]) .menu-list-item__bullet,.menu-list-item:hover:not(:disabled,[disabled]) .menu-list-item__bullet{opacity:1}.menu-list-item:disabled,.menu-list-item[disabled]{opacity:.5;tab-index:none;cursor:default}.menu-list-item__bullet{opacity:0;margin-right:12dp}.subtitle-title{display:block;position:relative;width:auto;height:auto;flex-direction:column;align-items:flex-start;align-content:flex-start;background-color:rgba(0,0,0,0);color:#ccc;cursor:pointer;text-align:left;padding:0}.subtitle-title--right{align-content:flex-end}.subtitle-title--right,.subtitle-title--right>*{text-align:right}.subtitle-title[selected]{color:#f2f2f2;cursor:default}.subtitle-title:focus:not(:disabled,[disabled]),.subtitle-title:hover:not(:disabled,[disabled],[selected]){color:#b97df2}.subtitle-title:disabled,.subtitle-title[disabled]{opacity:.5;cursor:default;tab-index:none}.subtitle-title h3{margin-bottom:6dp}.subtitle-title h1{margin-top:6dp}.subtitle-title__disclaimer{margin-top:16dp}.toggle{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;flex-direction:row;align-items:center;justify-content:space-between;position:relative;width:162dp;height:72dp;background:rgba(0,0,0,0);border-radius:36dp;cursor:pointer;opacity:.9}.toggle:hover,.toggle:focus-visible,.toggle:focus{background-color:rgba(23,214,232,.3);opacity:1}.toggle:active{background-color:rgba(23,214,232,.05);opacity:1}.toggle .toggle__border{position:absolute;top:1.1dp;right:1.1dp;bottom:1.1dp;left:1.1dp;border-color:#a2eff6;border-width:1.1dp;display:block;border-radius:36dp}.toggle .toggle__floater{position:absolute;width:80dp;height:64dp;top:50%;left:4dp;transform:translateY(-50%);border-radius:32dp;background:#25a1ad}.toggle--checked .toggle__floater{left:78dp}.toggle--checked .toggle__icon.toggle__icon--left{color:#a2eff6;opacity:.9}.toggle--checked .toggle__icon.toggle__icon--right{color:#f2f2f2;opacity:1}.toggle__icons{display:flex;position:absolute;height:56dp;top:50%;transform:translateY(-50%);right:16dp;left:16dp;align-items:center;justify-content:space-between}.toggle__icon{transition:color .05s linear-in-out,background-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;width:56dp;height:56dp;color:#f2f2f2}.toggle__icon--right{opacity:1;color:#a2eff6}.config-debug{display:block;position:relative;width:100%;max-height:100%;padding:8dp}.config-debug__scroll{display:block;position:relative;width:100%;max-height:100%;overflow-y:auto}.config-debug-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;width:100%;height:auto;padding:4dp 16dp 4dp 20dp;border-radius:8dp;background-color:rgba(0,0,0,0)}.config-debug-option svg{image-color:#ccc}.config-debug-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug-option:focus-visible:not(:disabled,[disabled]),.config-debug-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.config-debug-option:focus-visible:not(:disabled,[disabled]) svg,.config-debug-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.config-debug-option:disabled,.config-debug-option[disabled]{opacity:.5}.config-debug-option .icon-button{flex:1 1 auto}.config-debug-option__label{flex:1 1 auto;height:auto;white-space:nowrap}.config-debug__option-controls{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;flex:1 1 100%;height:56dp;padding:0 12dp 0 12dp}.config-debug__select-wrapper{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:flex-start;flex:1 1 100%;width:auto;height:auto;padding:0 8dp}.config-debug__select-wrapper .config-debug__select-label{padding-right:16dp;flex:auto;width:auto}.config-debug__select-wrapper .config-debug__select-label>div{display:inline;width:auto;height:auto}.config-debug__select-wrapper select{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;border-color:rgba(255,255,255,.5);border-width:1.1dp;display:block;position:relative;box-sizing:border-box;padding:0;flex:1 1 100%;width:auto;height:40dp;border-radius:12dp;background-color:rgba(255,255,255,.05)}.config-debug__select-wrapper select svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug__select-wrapper select:hover{background-color:rgba(255,255,255,.2)}.config-debug__select-wrapper select selectvalue{display:inline;align-items:center;justify-content:flex-start;padding:12dp;margin:auto 0;height:auto}.config-debug__select-wrapper select selectbox{border-color:rgba(255,255,255,.8);border-width:1.1dp;background-color:#191622;padding:4dp 0;margin-top:2dp;border-radius:12dp}.config-debug__select-wrapper select selectbox option{transition:color .05s linear-in-out,background-color .05s linear-in-out;padding:8dp 12dp;background-color:rgba(0,0,0,0);color:#ccc;font-weight:400}.config-debug__select-wrapper select selectbox option:hover{background-color:rgba(190,184,219,.1)}.config-debug__select-wrapper select selectbox option:checked{color:#fff}body{box-sizing:border-box;color:#f2f2f2;font-family:chiaro}body[disable-mouse]{pointer-events:none}.rmlui-window{opacity:1;transition:opacity .1s quadratic-in-out}.rmlui-window--hidden{opacity:0;transition:none}*,*:before,*:after{box-sizing:border-box}button{background-color:#7a2ac6}
+h1{font-size:64dp;letter-spacing:4.48dp;line-height:64dp;font-style:normal;font-weight:700}h2{font-size:48dp;letter-spacing:3.36dp;line-height:48dp;font-style:normal;font-weight:700}h3,.tab{font-size:32dp;letter-spacing:2.24dp;line-height:32dp;font-style:normal;font-weight:700}.label-lg,.menu-list-item__label,.button--large{font-size:32dp;letter-spacing:3.52dp;line-height:32dp;font-style:normal;font-weight:700}.label-md,.config-debug-option__label,.button,.config-option__title,.control-option__label{font-size:24dp;letter-spacing:2.64dp;line-height:24dp;font-style:normal;font-weight:700}.label-sm,.subtitle-title__disclaimer,.config-debug__select-wrapper .config-debug__select-label,.config-option__range-label,.config-option__list .config-option__tab-label{font-size:16dp;letter-spacing:2.24dp;line-height:16dp;font-style:normal;font-weight:700;text-transform:uppercase}body,.config-debug__select-wrapper select{font-size:16dp;letter-spacing:0dp;line-height:16dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto}.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}h1{font-size:64dp;letter-spacing:4.48dp;line-height:64dp;font-style:normal;font-weight:700}h2{font-size:48dp;letter-spacing:3.36dp;line-height:48dp;font-style:normal;font-weight:700}h3,.tab{font-size:32dp;letter-spacing:2.24dp;line-height:32dp;font-style:normal;font-weight:700}.label-lg,.menu-list-item__label,.button--large{font-size:32dp;letter-spacing:3.52dp;line-height:32dp;font-style:normal;font-weight:700}.label-md,.config-debug-option__label,.button,.config-option__title,.control-option__label{font-size:24dp;letter-spacing:2.64dp;line-height:24dp;font-style:normal;font-weight:700}.label-sm,.subtitle-title__disclaimer,.config-debug__select-wrapper .config-debug__select-label,.config-option__range-label,.config-option__list .config-option__tab-label{font-size:16dp;letter-spacing:2.24dp;line-height:16dp;font-style:normal;font-weight:700;text-transform:uppercase}body,.config-debug__select-wrapper select{font-size:16dp;letter-spacing:0dp;line-height:16dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto}.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}*{box-sizing:border-box}hr{display:block;background:#000;padding:1.5dp}body{font-family:chiaro;font-weight:normal;font-style:normal;font-size:20dp;color:#fff}div#window{position:relative;width:100%;height:100%;box-sizing:border-box;background-color:#121018;border-color:rgba(255,255,255,.2)}div#content{z-index:2;width:auto;height:100%;overflow:hidden auto;text-align:center}p{text-align:left}input.submit{margin-left:0}input.text,input.password{box-sizing:border-box;height:31dp;padding:11dp 10dp 0;cursor:text;text-align:left}textarea{padding:14dp 12dp 10dp;cursor:text;text-align:left}input.text,input.password,select,textarea{height:auto}table input.text{box-sizing:border-box;width:100%;margin:0;line-height:1;border-width:1.1dp;border-color:#000;background-color:#fff;font-size:15dp;decorator:none;height:auto}input.radio,input.checkbox{flex:0;tab-index:auto;focus:auto;nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto;width:0dp}scrollbarvertical,scrollbarhorizontal{margin:0;border:0}scrollbarvertical slidertrack,scrollbarhorizontal slidertrack{background:#dabaf7;opacity:.05}scrollbarvertical sliderbar,scrollbarhorizontal sliderbar{border-radius:5dp;background:#dabaf7;opacity:.1}scrollbarvertical sliderbar:hover:not(:active),scrollbarhorizontal sliderbar:hover:not(:active){opacity:.2}scrollbarvertical sliderbar:active,scrollbarhorizontal sliderbar:active{opacity:.3}scrollbarvertical sliderarrowdec,scrollbarvertical sliderarrowinc,scrollbarhorizontal sliderarrowdec,scrollbarhorizontal sliderarrowinc{width:0;height:0}scrollbarvertical{width:12dp}scrollbarvertical slidertrack{width:12dp}scrollbarvertical sliderbar{width:12dp}scrollbarhorizontal{height:12dp}scrollbarhorizontal slidertrack{height:12dp}scrollbarhorizontal sliderbar{height:12dp}.centered-page{display:flex;position:absolute;top:0;right:0;bottom:0;left:0;padding:64dp;background-color:rgba(255,255,255,.1)}.centered-page__modal{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%;background:rgba(8,7,13,.9);border-radius:16dp;border-color:rgba(255,255,255,.2);border-width:1.1dp}.centered-page__modal>.tabs{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%}.centered-page__modal panels{flex:1 1 100%}.control-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;width:100%;height:auto;padding:4dp 16dp 4dp 20dp;border-radius:8dp;background-color:rgba(0,0,0,0)}.control-option svg{image-color:#ccc}.control-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option:focus-visible:not(:disabled,[disabled]),.control-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.control-option:focus-visible:not(:disabled,[disabled]) svg,.control-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.control-option:disabled,.control-option[disabled]{opacity:.5}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"]{border-color:#f86039}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-icon{opacity:0}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-recording{opacity:1}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"]{border-color:#f86039}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-icon{opacity:0}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-recording{opacity:1}.control-option .icon-button{flex:1 1 auto}.control-option__label{flex:2 1 300dp;height:auto;white-space:nowrap}.control-option__bindings{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;flex:2 1 400dp;width:100%;height:56dp;padding:0 12dp 0 4dp}.control-option__binding{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;position:relative;align-items:center;justify-content:center;margin:0 4dp;flex:1 1 100%;width:100%;height:56dp;padding:8dp;background-color:rgba(190,184,219,.1);border-color:rgba(190,184,219,.1);border-width:1.1dp;border-radius:8dp}.control-option__binding svg{image-color:#ccc}.control-option__binding svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option__binding:focus,.control-option__binding:hover{color:#f2f2f2;background-color:rgba(255,255,255,.1);border-color:#f2f2f2}.control-option__binding:focus svg,.control-option__binding:hover svg{image-color:#f2f2f2}.control-option__binding:active{color:#f5f5f5}.control-option__binding:active svg{image-color:#f5f5f5}.control-option__binding:disabled,.control-option__binding[disabled]{color:#ccc;opacity:.5}.control-option__binding:disabled svg,.control-option__binding[disabled] svg{image-color:#ccc}.control-option__binding:not([disabled]){cursor:pointer}.control-option__binding-icon{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;opacity:1}@keyframes control-option__binding-recording-scale{0%{transform:scale(1)}50%{transform:scale(0.85)}to{transform:scale(1)}}.control-option__binding-recording{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:absolute;display:flex;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0;opacity:0}.control-option__binding-recording .control-option__binding-circle{width:24dp;height:24dp;background-color:#f86039;border-radius:24dp;animation:1.5s sine-in-out infinite control-option__binding-recording-scale}.control-option__binding-recording .control-option__binding-edge{position:absolute;transform:translate(-50%, -50%);top:50%;left:50%;width:36dp;height:36dp}.control-option__binding-recording .control-option__binding-edge>svg.control-option__binding-edge-svg{width:36dp;height:36dp;image-color:#f86039}.tabs tabs{display:flex;flex-direction:row;align-items:center;justify-content:flex-start}.tab{display:block;position:relative;padding:20dp 24dp;background-color:rgba(0,0,0,0);margin:0;color:rgba(255,255,255,.6);transition:color .05s linear-in-out;opacity:.9}.tab:selected{color:#f2f2f2}.tab:selected .tab__indicator{background-color:rgba(255,255,255,.6)}.tab:selected:hover{cursor:default}.tab:hover{cursor:pointer;opacity:1}.tab:focus{color:#f2f2f2;opacity:1}.tab__indicator{position:absolute;background-color:rgba(0,0,0,0);right:0;bottom:2dp;left:0;height:2dp}.config__exit-button{position:absolute;top:8dp;right:8dp}.config__form{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;display:flex;flex-direction:column;justify-content:space-between;flex:1 1 100%;width:100%;height:100%;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__wrapper{display:flex;flex-direction:column;border-radius:0dp;flex:1 1 100%;height:100%;padding:16dp;text-align:left;background-color:rgba(0,0,0,.35)}.config__header,.config__footer{display:flex;justify-content:space-between;align-items:center;width:100%;background-color:rgba(0,0,0,.35)}.config__header{border-bottom-color:rgba(255,255,255,.1);border-bottom-width:1.1dp;padding:12dp 20dp}.config__footer{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;padding:20dp 20dp;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__header-left{display:flex;flex-direction:row;flex:1 1 auto}.config__header-left>:not(:first-child){margin-left:8dp}.config__row{display:flex;flex-direction:row}.config-option{display:flex;flex-direction:column;flex:1;align-items:flex-start;justify-content:space-between;margin:8dp 0 16dp}.config-option__title{padding:0 12dp}.config-option__list{display:flex;padding:0;flex-direction:row;width:100%;align-items:flex-start;justify-content:flex-start}.config-option__list .config-option__tab-label{display:block;padding:12dp 0;margin:0 12dp;margin-right:16dp;color:rgba(255,255,255,.6);tab-index:none;transition:color .05s linear-in-out}.config-option__list .config-option__tab-label:hover{cursor:pointer}.config-option__list input.radio{visibility:visible;width:0;height:0}.config-option__list input.radio:checked+.config-option__tab-label{border-bottom:1dp;border-color:rgba(255,255,255,.3)}.config-option__list input.radio:checked+.config-option__tab-label:hover{cursor:default}.config-option__list input.radio:focus+.config-option__tab-label{color:#f2f2f2}.config-option__list input.range slidertrack{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-top:7dp;height:2dp;background-color:rgba(255,255,255,.2)}.config-option__list input.range sliderbar{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-left:-8dp;margin-right:-6dp;width:16dp;height:16dp;background-color:#ccc;border-radius:8dp;transition:background-color .05s linear-in-out}.config-option__list input.range sliderbar:hover{cursor:pointer;background-color:#f2f2f2}.config-option__list input.range sliderbar:active,.config-option__list input.range slidertrack:active+sliderbar{background-color:#17d6e8}.config-option__list input.range sliderarrowdec,.config-option__list input.range sliderarrowinc{display:none}.config-option__range-wrapper{margin-top:4dp;max-width:360dp}.config-option__range-label{flex:0 0 16dp;display:block;padding:0;margin:0 12dp;margin-right:16dp;color:#f2f2f2;tab-index:none}.input-config{padding:0}.input-config__horizontal-split{display:flex;position:relative;flex-direction:row;height:100%}.input-config__mappings{display:block;flex:1 1 auto;height:100%;min-width:640dp}.input-config__mappings-scroll{display:block;width:100%;max-height:100%;overflow-y:auto}.input-config__mappings-wrapper{padding:8dp}.input-config__visual-wrapper{display:block;width:auto;height:auto;max-width:1040.4444444444dp;max-height:780.3333333333dp;margin:auto 0;flex:1 1 100%}.input-config__visual-aspect{position:relative;width:100%;padding-bottom:75%;background-color:rgba(0,0,0,.35);margin:auto 0}.input-config__visual{display:flex;flex-direction:column;position:absolute;top:16dp;right:16dp;bottom:16dp;left:16dp;border-radius:108dp;background-color:rgba(255,255,255,.05)}.input-config__visual-half{display:flex;position:relative;flex-direction:row;flex:1 1 100%;padding:6%}.input-config__visual-half--bottom{align-items:flex-end;justify-content:space-between}.input-config__visual-quarter-left{display:flex;flex:1 1 50%;width:auto;align-items:flex-start;justify-content:flex-start}.input-config__visual-quarter-right{display:flex;flex:1 1 100%;align-items:flex-start;justify-content:flex-end}.input-config__visual-stick-wrapper{display:flex;position:absolute;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0}.input-config__visual-stick{display:flex;position:relative;align-items:center;justify-content:center;width:200dp;height:200dp;border-radius:100dp;background-color:rgba(255,255,255,.05)}.input-viz{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:relative;display:flex;align-items:center;justify-content:center}.input-viz>svg:not(.input-viz__dpad-arrow){position:absolute;top:0;right:0;left:0;bottom:0}[cur-input=NONE] .input-viz[visual-input]{opacity:1}.input-viz[visual-input~=A]{opacity:.25}[cur-input=A] .input-viz[visual-input~=A]{opacity:1}.input-viz[visual-input~=B]{opacity:.25}[cur-input=B] .input-viz[visual-input~=B]{opacity:1}.input-viz[visual-input~=Z]{opacity:.25}[cur-input=Z] .input-viz[visual-input~=Z]{opacity:1}.input-viz[visual-input~=START]{opacity:.25}[cur-input=START] .input-viz[visual-input~=START]{opacity:1}.input-viz[visual-input~=DPAD_UP]{opacity:.25}[cur-input=DPAD_UP] .input-viz[visual-input~=DPAD_UP]{opacity:1}.input-viz[visual-input~=DPAD_DOWN]{opacity:.25}[cur-input=DPAD_DOWN] .input-viz[visual-input~=DPAD_DOWN]{opacity:1}.input-viz[visual-input~=DPAD_LEFT]{opacity:.25}[cur-input=DPAD_LEFT] .input-viz[visual-input~=DPAD_LEFT]{opacity:1}.input-viz[visual-input~=DPAD_RIGHT]{opacity:.25}[cur-input=DPAD_RIGHT] .input-viz[visual-input~=DPAD_RIGHT]{opacity:1}.input-viz[visual-input~=L]{opacity:.25}[cur-input=L] .input-viz[visual-input~=L]{opacity:1}.input-viz[visual-input~=R]{opacity:.25}[cur-input=R] .input-viz[visual-input~=R]{opacity:1}.input-viz[visual-input~=C_UP]{opacity:.25}[cur-input=C_UP] .input-viz[visual-input~=C_UP]{opacity:1}.input-viz[visual-input~=C_DOWN]{opacity:.25}[cur-input=C_DOWN] .input-viz[visual-input~=C_DOWN]{opacity:1}.input-viz[visual-input~=C_LEFT]{opacity:.25}[cur-input=C_LEFT] .input-viz[visual-input~=C_LEFT]{opacity:1}.input-viz[visual-input~=C_RIGHT]{opacity:.25}[cur-input=C_RIGHT] .input-viz[visual-input~=C_RIGHT]{opacity:1}.input-viz[visual-input~=X_AXIS_NEG]{opacity:.25}[cur-input=X_AXIS_NEG] .input-viz[visual-input~=X_AXIS_NEG]{opacity:1}.input-viz[visual-input~=X_AXIS_POS]{opacity:.25}[cur-input=X_AXIS_POS] .input-viz[visual-input~=X_AXIS_POS]{opacity:1}.input-viz[visual-input~=Y_AXIS_NEG]{opacity:.25}[cur-input=Y_AXIS_NEG] .input-viz[visual-input~=Y_AXIS_NEG]{opacity:1}.input-viz[visual-input~=Y_AXIS_POS]{opacity:.25}[cur-input=Y_AXIS_POS] .input-viz[visual-input~=Y_AXIS_POS]{opacity:1}.input-viz__button{color:#f2f2f2}.input-viz__button svg{image-color:#f2f2f2}.input-viz__button--sm{width:64dp;height:64dp}.input-viz__button--sm>svg{width:64dp;height:64dp}.input-viz__button--md{width:76dp;height:76dp}.input-viz__button--md>svg{width:76dp;height:76dp}.input-viz__button--lg{width:84dp;height:84dp}.input-viz__button--lg>svg{width:84dp;height:84dp}.input-viz__button--C svg{image-color:#e9cd35}.input-viz__button--A svg{image-color:#33f}.input-viz__button--B svg{image-color:#45d043}.input-viz__Z{width:136dp;height:136dp}.input-viz__Z svg{image-color:#e9cd35}.input-viz__Z>svg{width:136dp;height:136dp}.input-viz.input-viz__dpad{width:192dp;height:192dp;position:relative}.input-viz.input-viz__dpad svg{image-color:#f2f2f2}.input-viz.input-viz__dpad>svg{width:192dp;height:192dp}.input-viz__dpad-split{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;width:100%;height:100%}.input-viz__dpad-split--vertical{flex-direction:column;align-items:center;justify-content:space-between}.input-viz__dpad-split--horizontal{flex-direction:row;align-items:center;justify-content:space-between}.input-viz__dpad-split>div{display:flex;flex:1 1 100%;width:64dp;height:64dp;align-items:center;justify-content:center;flex-direction:row}.input-viz__dpad-arrow{position:absolute;width:60dp;height:60dp}.input-viz__dpad-arrow--up{top:4dp;margin:0 auto}.input-viz__dpad-arrow--down{bottom:4dp;margin:0 auto;transform:rotate(180deg)}.input-viz__dpad-arrow--left{left:4dp;margin:auto 0;transform:rotate(-90deg)}.input-viz__dpad-arrow--right{right:4dp;margin:auto 0;transform:rotate(90deg)}.input-viz__R{width:96dp;height:96dp}.input-viz__R svg{image-color:#fff}.input-viz__R>svg{width:96dp;height:96dp}.input-viz__L{width:136dp;height:136dp}.input-viz__L svg{image-color:#17d6e8}.input-viz__L>svg{width:136dp;height:136dp}.input-config__c-buttons{position:relative;width:208dp;height:132dp}.input-config__c-buttons-lr,.input-config__c-buttons-du{display:flex;position:absolute;top:0;right:0;left:0;bottom:0}.input-config__c-buttons-lr{flex-direction:row;align-items:flex-start;justify-content:space-between}.input-config__c-buttons-du{flex-direction:column-reverse;align-items:center;justify-content:space-between}.input-config__c-buttons .input-viz[visual-input=C_UP]{margin-top:-32dp}.button{background-color:rgba(185,125,242,.05);color:#ccc;border-color:rgba(185,125,242,.8);transition:color .05s linear-in-out,background-color .05s linear-in-out;display:block;padding:23dp;border-radius:12dp;border-width:1.1dp;width:auto;height:auto}.button:focus{color:#f2f2f2;border-color:#b97df2;background-color:rgba(185,125,242,.3)}.button:disabled,.button[disabled]{color:rgba(255,255,255,.6)}.button:active{background-color:rgba(185,125,242,.2);color:#f5f5f5}.button--secondary{background-color:rgba(23,214,232,.05);color:#ccc;border-color:rgba(23,214,232,.8)}.button--secondary:focus{color:#f2f2f2;border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.button--secondary:disabled,.button--secondary[disabled]{color:rgba(255,255,255,.6)}.button--secondary:active{background-color:rgba(23,214,232,.2);color:#f5f5f5}.button--tertiary{background-color:rgba(242,242,242,.05);color:#ccc;border-color:rgba(242,242,242,.8)}.button--tertiary:focus{color:#f2f2f2;border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.button--tertiary:disabled,.button--tertiary[disabled]{color:rgba(255,255,255,.6)}.button--tertiary:active{background-color:rgba(242,242,242,.2);color:#f5f5f5}.button--success{background-color:rgba(69,208,67,.05);color:#ccc;border-color:rgba(69,208,67,.8)}.button--success:focus{color:#f2f2f2;border-color:#45d043;background-color:rgba(69,208,67,.3)}.button--success:disabled,.button--success[disabled]{color:rgba(255,255,255,.6)}.button--success:active{background-color:rgba(69,208,67,.2);color:#f5f5f5}.button--error{background-color:rgba(248,96,57,.05);color:#ccc;border-color:rgba(248,96,57,.8)}.button--error:focus{color:#f2f2f2;border-color:#f86039;background-color:rgba(248,96,57,.3)}.button--error:disabled,.button--error[disabled]{color:rgba(255,255,255,.6)}.button--error:active{background-color:rgba(248,96,57,.2);color:#f5f5f5}.button--warning{background-color:rgba(233,205,53,.05);color:#ccc;border-color:rgba(233,205,53,.8)}.button--warning:focus{color:#f2f2f2;border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.button--warning:disabled,.button--warning[disabled]{color:rgba(255,255,255,.6)}.button--warning:active{background-color:rgba(233,205,53,.2);color:#f5f5f5}.button:not([disabled]){cursor:pointer}.button:disabled,.button[disabled]{opacity:.5}.button__label{width:auto;height:auto}.icon-button{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;overflow:hidden;border-radius:26.9dp;border-width:1.1dp;border-color:rgba(0,0,0,0);background-color:rgba(0,0,0,0);width:53.8dp;height:53.8dp;min-width:53.8dp;min-height:53.8dp;max-width:53.8dp;max-height:53.8dp}.icon-button svg{image-color:#ccc}.icon-button svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.icon-button:focus,.icon-button:hover{color:#f2f2f2;background-color:rgba(255,255,255,.2)}.icon-button:focus svg,.icon-button:hover svg{image-color:#f2f2f2}.icon-button:active{color:#f5f5f5;background-color:rgba(255,255,255,.1)}.icon-button:active svg{image-color:#f5f5f5}.icon-button:disabled,.icon-button[disabled]{color:#ccc;opacity:.5}.icon-button:disabled svg,.icon-button[disabled] svg{image-color:#ccc}.icon-button:not([disabled]){cursor:pointer}.icon-button svg{width:32dp;height:32dp}.icon-button--primary{background-color:rgba(185,125,242,.05);border-color:rgba(185,125,242,.8)}.icon-button--primary:focus,.icon-button--primary:hover{border-color:#b97df2;background-color:rgba(185,125,242,.3)}.icon-button--primary:active{background-color:rgba(185,125,242,.2)}.icon-button--secondary{background-color:rgba(23,214,232,.05);border-color:rgba(23,214,232,.8)}.icon-button--secondary:focus,.icon-button--secondary:hover{border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.icon-button--secondary:active{background-color:rgba(23,214,232,.2)}.icon-button--tertiary{background-color:rgba(242,242,242,.05);border-color:rgba(242,242,242,.8)}.icon-button--tertiary:focus,.icon-button--tertiary:hover{border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.icon-button--tertiary:active{background-color:rgba(242,242,242,.2)}.icon-button--success{background-color:rgba(69,208,67,.05);border-color:rgba(69,208,67,.8)}.icon-button--success:focus,.icon-button--success:hover{border-color:#45d043;background-color:rgba(69,208,67,.3)}.icon-button--success:active{background-color:rgba(69,208,67,.2)}.icon-button--danger{background-color:rgba(248,96,57,.05);border-color:rgba(248,96,57,.8)}.icon-button--danger:focus,.icon-button--danger:hover{border-color:#f86039;background-color:rgba(248,96,57,.3)}.icon-button--danger:active{background-color:rgba(248,96,57,.2)}.icon-button--warning{background-color:rgba(233,205,53,.05);border-color:rgba(233,205,53,.8)}.icon-button--warning:focus,.icon-button--warning:hover{border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.icon-button--warning:active{background-color:rgba(233,205,53,.2)}.launcher{display:block;flex-direction:row;justify-content:space-between;position:relative;width:100%;height:100%;background-color:#08070d}.launcher__vertical-split{display:flex;position:absolute;flex-direction:column;align-items:flex-start;justify-content:space-between;top:0;right:50%;bottom:0;left:0}.launcher__vertical-split--right{align-items:flex-end;right:0;left:50%}@keyframes slide-mm-bg-over{0%{transform:translateX(100dp)}to{transform:translateX(0dp)}}.launcher__background-wrapper{display:flex;align-items:center;justify-content:flex-start;position:absolute;left:-70vw;right:-100%;top:-55vw;bottom:-50vw;transform:translateX(0dp);animation:25s cubic-out 1 slide-mm-bg-over}@keyframes fade-mm-in{0%{opacity:0}to{opacity:.1}}.launcher__background-mm{position:absolute;left:0;top:0;bottom:0;height:100%;width:auto;opacity:.1;animation:2.5s cubic-in-out 1 fade-mm-in}.launcher__title-quadrant{flex:1 1 auto;padding-top:96dp;padding-left:96dp;width:auto;height:auto}.launcher__title-quadrant--right{padding-right:96dp;padding-left:0}.launcher__content-quadrant{display:flex;position:relative;flex-direction:column;align-items:flex-start;justify-content:flex-end;padding:32dp;width:100%;height:auto;flex:1 1 100%}.menu-list-item{color:#ccc;display:flex;flex-direction:row;align-items:center;width:100%;height:auto;padding:16dp;border-radius:8dp;background-color:rgba(0,0,0,0);cursor:pointer}.menu-list-item svg{image-color:#ccc}.menu-list-item--right{align-content:flex-end;flex-direction:row-reverse}.menu-list-item--right .menu-list-item__bullet{opacity:1;margin-left:12dp}.menu-list-item--right.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item--right.menu-list-item:hover:not(:disabled,[disabled]){decorator:gradient(horizontal #7A2AC600 #DABAF714)}.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item:hover:not(:disabled,[disabled]){color:#b97df2;decorator:gradient(horizontal #7A2AC614 #DABAF700)}.menu-list-item:focus:not(:disabled,[disabled]) svg,.menu-list-item:hover:not(:disabled,[disabled]) svg{image-color:#b97df2}.menu-list-item:focus:not(:disabled,[disabled]) .menu-list-item__bullet,.menu-list-item:hover:not(:disabled,[disabled]) .menu-list-item__bullet{opacity:1}.menu-list-item:disabled,.menu-list-item[disabled]{opacity:.5;tab-index:none;cursor:default}.menu-list-item__bullet{opacity:0;margin-right:12dp}.subtitle-title{display:block;position:relative;width:auto;height:auto;flex-direction:column;align-items:flex-start;align-content:flex-start;background-color:rgba(0,0,0,0);color:#ccc;cursor:pointer;text-align:left;padding:0}.subtitle-title--right{align-content:flex-end}.subtitle-title--right,.subtitle-title--right>*{text-align:right}.subtitle-title[selected]{color:#f2f2f2;cursor:default}.subtitle-title:focus:not(:disabled,[disabled]),.subtitle-title:hover:not(:disabled,[disabled],[selected]){color:#b97df2}.subtitle-title:disabled,.subtitle-title[disabled]{opacity:.5;cursor:default;tab-index:none}.subtitle-title h3{margin-bottom:6dp}.subtitle-title h1{margin-top:6dp}.subtitle-title__disclaimer{margin-top:16dp}.toggle{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;flex-direction:row;align-items:center;justify-content:space-between;position:relative;width:162dp;height:72dp;background:rgba(0,0,0,0);border-radius:36dp;cursor:pointer;opacity:.9}.toggle:hover,.toggle:focus-visible,.toggle:focus{background-color:rgba(23,214,232,.3);opacity:1}.toggle:active{background-color:rgba(23,214,232,.05);opacity:1}.toggle .toggle__border{position:absolute;top:1.1dp;right:1.1dp;bottom:1.1dp;left:1.1dp;border-color:#a2eff6;border-width:1.1dp;display:block;border-radius:36dp}.toggle .toggle__floater{position:absolute;width:80dp;height:64dp;top:50%;left:4dp;transform:translateY(-50%);border-radius:32dp;background:#25a1ad}.toggle--checked .toggle__floater{left:78dp}.toggle--checked .toggle__icon.toggle__icon--left{color:#a2eff6;opacity:.9}.toggle--checked .toggle__icon.toggle__icon--right{color:#f2f2f2;opacity:1}.toggle__icons{display:flex;position:absolute;height:56dp;top:50%;transform:translateY(-50%);right:16dp;left:16dp;align-items:center;justify-content:space-between}.toggle__icon{transition:color .05s linear-in-out,background-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;width:56dp;height:56dp;color:#f2f2f2}.toggle__icon--right{opacity:1;color:#a2eff6}.config-debug{display:block;position:relative;width:100%;max-height:100%;padding:8dp}.config-debug__scroll{display:block;position:relative;width:100%;max-height:100%;overflow-y:auto}.config-debug-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;width:100%;height:auto;padding:4dp 16dp 4dp 20dp;border-radius:8dp;background-color:rgba(0,0,0,0)}.config-debug-option svg{image-color:#ccc}.config-debug-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug-option:focus-visible:not(:disabled,[disabled]),.config-debug-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.config-debug-option:focus-visible:not(:disabled,[disabled]) svg,.config-debug-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.config-debug-option:disabled,.config-debug-option[disabled]{opacity:.5}.config-debug-option .icon-button{flex:1 1 auto}.config-debug-option__label{flex:1 1 auto;height:auto;white-space:nowrap}.config-debug__option-controls{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;flex:1 1 100%;height:56dp;padding:0 12dp 0 12dp}.config-debug__select-wrapper{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:flex-start;flex:1 1 100%;width:auto;height:auto;padding:0 8dp}.config-debug__select-wrapper .config-debug__select-label{padding-right:16dp;flex:auto;width:auto}.config-debug__select-wrapper .config-debug__select-label>div{display:inline;width:auto;height:auto}.config-debug__select-wrapper select{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;border-color:rgba(255,255,255,.5);border-width:1.1dp;display:block;position:relative;box-sizing:border-box;padding:0;flex:1 1 100%;width:auto;height:40dp;border-radius:12dp;background-color:rgba(255,255,255,.05)}.config-debug__select-wrapper select svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug__select-wrapper select:hover{background-color:rgba(255,255,255,.2)}.config-debug__select-wrapper select selectvalue{display:inline;align-items:center;justify-content:flex-start;padding:12dp;margin:auto 0;height:auto}.config-debug__select-wrapper select selectbox{border-color:rgba(255,255,255,.8);border-width:1.1dp;background-color:#191622;padding:4dp 0;margin-top:2dp;border-radius:12dp}.config-debug__select-wrapper select selectbox option{transition:color .05s linear-in-out,background-color .05s linear-in-out;padding:8dp 12dp;background-color:rgba(0,0,0,0);color:#ccc;font-weight:400}.config-debug__select-wrapper select selectbox option:hover{background-color:rgba(190,184,219,.1)}.config-debug__select-wrapper select selectbox option:checked{color:#fff}body{box-sizing:border-box;color:#f2f2f2;font-family:chiaro}body[disable-mouse]{pointer-events:none}.rmlui-window{opacity:1;transition:opacity .1s quadratic-in-out}.rmlui-window--hidden{opacity:0;transition:none}*,*:before,*:after{box-sizing:border-box}button{background-color:#7a2ac6}
diff --git a/assets/scss/styles/pages/config/debug.scss b/assets/scss/styles/pages/config/debug.scss
index 810378c..3f9169b 100644
--- a/assets/scss/styles/pages/config/debug.scss
+++ b/assets/scss/styles/pages/config/debug.scss
@@ -88,6 +88,7 @@
select {
@extend %body;
+ @extend %nav-all;
@include trans-colors-border;
@include border($color-white-a50);
display: block;
@@ -121,6 +122,7 @@
border-radius: $border-radius-md;
option {
+ @extend %nav-all;
@include trans-colors;
padding: space(8) space(12);
background-color: $color-transparent;
diff --git a/include/recomp_debug.h b/include/recomp_debug.h
new file mode 100644
index 0000000..3c0cfd2
--- /dev/null
+++ b/include/recomp_debug.h
@@ -0,0 +1,24 @@
+#ifndef __RECOMP_DEBUG_H__
+#define __RECOMP_DEBUG_H__
+
+#include
+#include
+
+namespace recomp {
+ struct SceneWarps {
+ int index;
+ std::string name;
+ std::vector entrances;
+ };
+
+ struct AreaWarps {
+ std::string name;
+ std::vector scenes;
+ };
+
+ extern std::vector game_warps;
+
+ void do_warp(int area, int scene, int entrance);
+}
+
+#endif
diff --git a/patches/debug_patches.c b/patches/debug_patches.c
new file mode 100644
index 0000000..c9a51c7
--- /dev/null
+++ b/patches/debug_patches.c
@@ -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();
+}
diff --git a/patches/input.h b/patches/input.h
index f94a942..8f3c1d7 100644
--- a/patches/input.h
+++ b/patches/input.h
@@ -16,5 +16,6 @@ DECLARE_FUNC(void, recomp_puts, const char* data, u32 size);
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_main, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq);
+DECLARE_FUNC(u16, recomp_get_pending_warp);
#endif
diff --git a/patches/syms.ld b/patches/syms.ld
index 97eeecc..dbc1b9a 100644
--- a/patches/syms.ld
+++ b/patches/syms.ld
@@ -1,5 +1,8 @@
__start = 0x80000000;
+/* Static symbols that aren't in the elf */
+sSceneEntranceTable = 0x801C5720;
+
/* Dummy addresses that get recompiled into function calls */
recomp_puts = 0x81000000;
recomp_exit = 0x81000004;
@@ -9,3 +12,4 @@ osRecvMesg_recomp = 0x81000010;
osSendMesg_recomp = 0x81000014;
recomp_get_gyro_deltas = 0x81000018;
recomp_get_aspect_ratio = 0x8100001C;
+recomp_get_pending_warp = 0x81000020;
diff --git a/src/game/debug.cpp b/src/game/debug.cpp
new file mode 100644
index 0000000..28e857c
--- /dev/null
+++ b/src/game/debug.cpp
@@ -0,0 +1,17 @@
+#include
+#include "recomp_debug.h"
+#include "recomp_helpers.h"
+#include "../patches/input.h"
+
+std::atomic 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));
+}
diff --git a/src/game/scene_table.cpp b/src/game/scene_table.cpp
new file mode 100644
index 0000000..d091770
--- /dev/null
+++ b/src/game/scene_table.cpp
@@ -0,0 +1,853 @@
+#include
+#include
+#include
+#include "recomp_debug.h"
+
+std::vector 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",
+ }
+ }
+ }},
+};
+
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 0a48b4c..73bf06c 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -51,7 +51,7 @@ ultramodern::gfx_callbacks_t::gfx_data_t create_gfx() {
SDL_Window* window;
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) {
exit_error("Failed to create window: %s\n", SDL_GetError());
diff --git a/src/ui/ui_config.cpp b/src/ui/ui_config.cpp
index 8b8fb32..7c5a7c3 100644
--- a/src/ui/ui_config.cpp
+++ b/src/ui/ui_config.cpp
@@ -1,6 +1,7 @@
#include "recomp_ui.h"
#include "recomp_input.h"
#include "recomp_config.h"
+#include "recomp_debug.h"
#include "../../ultramodern/config.hpp"
#include "../../ultramodern/ultramodern.hpp"
#include "RmlUi/Core.h"
@@ -69,6 +70,34 @@ void close_config_menu() {
}
}
+struct DebugContext {
+ Rml::DataModelHandle model_handle;
+ std::vector area_names;
+ std::vector scene_names;
+ std::vector 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 {
public:
ConfigMenu() {
@@ -114,6 +143,32 @@ public:
controls_model_handle.DirtyVariable("input_device_is_keyboard");
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("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("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) {
Rml::DataModelConstructor constructor = context->CreateDataModel("graphics_model");
@@ -290,9 +345,32 @@ public:
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>();
+
+ // 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 {
make_graphics_bindings(context);
make_controls_bindings(context);
+ make_debug_bindings(context);
}
};