From 43b14838b725227cd5f93053103e13823882def2 Mon Sep 17 00:00:00 2001 From: Lywx <36680385+KiritoDv@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:04:59 -0600 Subject: [PATCH] Added nintendo switch support (#16) This PR adds support for building sm on the nintendo switch, the installation instructions are pretty much the same, with the difference that you need a switch with atmosphere installed and the devkitpro development environment, to install on the switch just copy the .ini, the nro and the smc file. --------- Co-authored-by: snesrev <111028570+snesrev@users.noreply.github.com> --- src/main.c | 32 +++- src/platform/switch/.gitignore | 5 + src/platform/switch/Makefile | 224 ++++++++++++++++++++++++++ src/platform/switch/icon.jpg | Bin 0 -> 48994 bytes src/platform/switch/sm.ini | 92 +++++++++++ src/platform/switch/src/switch_impl.c | 45 ++++++ src/platform/switch/src/switch_impl.h | 8 + src/sm_cpu_infra.c | 23 ++- 8 files changed, 411 insertions(+), 18 deletions(-) create mode 100644 src/platform/switch/.gitignore create mode 100644 src/platform/switch/Makefile create mode 100644 src/platform/switch/icon.jpg create mode 100644 src/platform/switch/sm.ini create mode 100644 src/platform/switch/src/switch_impl.c create mode 100644 src/platform/switch/src/switch_impl.h diff --git a/src/main.c b/src/main.c index cd762dc..ec09d5e 100644 --- a/src/main.c +++ b/src/main.c @@ -22,6 +22,10 @@ #include "util.h" #include "spc_player.h" +#ifdef __SWITCH__ +#include "switch_impl.h" +#endif + static void playAudio(Snes *snes, SDL_AudioDeviceID device, int16_t *audioBuffer); static void renderScreen(Snes *snes, SDL_Renderer *renderer, SDL_Texture *texture); static void SDLCALL AudioCallback(void *userdata, Uint8 *stream, int len); @@ -309,6 +313,9 @@ static const struct RendererFuncs kSdlRendererFuncs = { #undef main int main(int argc, char** argv) { +#ifdef __SWITCH__ + SwitchImpl_Init(); +#endif argc--, argv++; const char *config_file = NULL; if (argc >= 2 && strcmp(argv[0], "--config") == 0) { @@ -367,6 +374,20 @@ int main(int argc, char** argv) { g_renderer_funcs = kSdlRendererFuncs; } + // init snes, load rom + const char* filename = argv[0] ? argv[0] : "sm.smc"; + Snes *snes = SnesInit(filename); + + if(snes == NULL) { + #ifdef __SWITCH__ + ThrowMissingROM(); + #else + char buf[256]; + snprintf(buf, sizeof(buf), "unable to load rom: %s", filename); + Die(buf); + #endif + return 1; + } SDL_Window *window = SDL_CreateWindow(kWindowTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, g_win_flags); if(window == NULL) { @@ -403,9 +424,6 @@ int main(int argc, char** argv) { g_audiobuffer = (uint8 *)malloc(g_frames_per_block * have.channels * sizeof(int16)); } - // init snes, load rom - Snes *snes = SnesInit(argv[0] ? argv[0] : "sm.smc"); - PpuBeginDrawing(snes->snes_ppu, g_pixels, 256 * 4, 0); PpuBeginDrawing(snes->my_ppu, g_my_pixels, 256 * 4, 0); @@ -420,7 +438,7 @@ int main(int argc, char** argv) { for (int i = 0; i < SDL_NumJoysticks(); i++) OpenOneGamepad(i); - + bool running = true; uint32 lastTick = SDL_GetTicks(); uint32 curTick = 0; @@ -539,6 +557,10 @@ int main(int argc, char** argv) { g_renderer_funcs.Destroy(); +#ifdef __SWITCH__ + SwitchImpl_Exit(); +#endif + SDL_DestroyWindow(window); SDL_Quit(); return 0; @@ -653,7 +675,7 @@ static void HandleCommand(uint32 j, bool pressed) { case kKeys_WindowBigger: ChangeWindowScale(1); break; case kKeys_WindowSmaller: ChangeWindowScale(-1); break; case kKeys_DisplayPerf: g_display_perf ^= 1; break; - case kKeys_ToggleRenderer: + case kKeys_ToggleRenderer: g_ppu_render_flags ^= kPpuRenderFlags_NewRenderer; g_new_ppu = (g_ppu_render_flags & kPpuRenderFlags_NewRenderer) != 0; break; diff --git a/src/platform/switch/.gitignore b/src/platform/switch/.gitignore new file mode 100644 index 0000000..24c39e2 --- /dev/null +++ b/src/platform/switch/.gitignore @@ -0,0 +1,5 @@ +/bin +/*.nacp +/*.nro +/*.elf +/*.smc \ No newline at end of file diff --git a/src/platform/switch/Makefile b/src/platform/switch/Makefile new file mode 100644 index 0000000..d624f72 --- /dev/null +++ b/src/platform/switch/Makefile @@ -0,0 +1,224 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) +# +# NO_ICON: if set to anything, do not use icon. +# NO_NACP: if set to anything, no .nacp file is generated. +# APP_TITLE is the name of the app stored in the .nacp file (Optional) +# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) +# APP_VERSION is the version of the app stored in the .nacp file (Optional) +# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) +# ICON is the filename of the icon (.jpg), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .jpg +# - icon.jpg +# - /default_icon.jpg +# +# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .json +# - config.json +# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead +# of a homebrew executable (.nro). This is intended to be used for sysmodules. +# NACP building is skipped as well. +#--------------------------------------------------------------------------------- +SRC_DIR := ../../ +TARGET := sm +BUILD := bin +SOURCES := $(SRC_DIR) $(SRC_DIR)/snes $(SRC_DIR)/platform/switch/src $(SRC_DIR)/../third_party/gl_core + +CFILES := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/snes/*.c $(SRC_DIR)/platform/switch/src/*.c) $(SRC_DIR)/../third_party/gl_core/gl_core_3_1.c + +INCLUDES := include $(SRC_DIR)/../ ./src/ +APP_TITLE := Super Metroid +APP_AUTHOR := snesrev & Lywx +APP_VERSION := $(shell git rev-parse --short HEAD) $(shell git rev-parse --abbrev-ref HEAD) + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE + +CFLAGS := -g -Wall -O2 -ffunction-sections -Wno-parentheses \ + $(ARCH) $(DEFINES) + +CFLAGS += -D__SWITCH__ $(INCLUDE) -DSTBI_NO_THREAD_LOCALS `sdl2-config --cflags` + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions +CFLAGS += -std=gnu11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := `$(PREFIX)pkg-config --libs sdl2` -lnx -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + + +export DEPSDIR := $(CURDIR)/$(BUILD) + +#CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +#CFILES := $(wildcard ../../*.c ../../snes/*.c) ../../third_party/gl_core/gl_core_3_1.c ../../third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c +#CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +#SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +export LD := $(CXX) +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(notdir $(CFILES:.c=.o)) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +$(info $(OFILES)) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.jpg) + ifneq (,$(findstring $(TARGET).jpg,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).jpg + else + ifneq (,$(findstring icon.jpg,$(icons))) + export APP_ICON := $(TOPDIR)/icon.jpg + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +ifeq ($(strip $(NO_ICON)),) + export NROFLAGS += --icon=$(APP_ICON) +endif + +ifeq ($(strip $(NO_NACP)),) + export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp +endif + +ifneq ($(APP_TITLEID),) + export NACPFLAGS += --titleid=$(APP_TITLEID) +endif + +ifneq ($(ROMFS),) + export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @echo $(CFILES) ... + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... +ifeq ($(strip $(APP_JSON)),) + @rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf +else + @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf +endif + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(APP_JSON)),) + +all : $(OUTPUT).nro + +ifeq ($(strip $(NO_NACP)),) +$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp +else +$(OUTPUT).nro : $(OUTPUT).elf +endif + +else + +all : $(OUTPUT).nsp + +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm + +$(OUTPUT).nso : $(OUTPUT).elf + +endif + +$(OUTPUT).elf : $(OFILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/platform/switch/icon.jpg b/src/platform/switch/icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..71414da171fa1aa3ecc2c2b7e6e663974c8e2581 GIT binary patch literal 48994 zcmbrl2UJt*)-D`HWz$4JI+DFbKq*FgF_NQfKtYJ~o`{Gv5dxwC0y#>Pz6B}Lve}3j zibxYsAd&>w5Q<1I0to`rBms#bjemL0`0jtkKkgmhH~zaAi!eym%AD(+^O?^q@4?i; zBIty*PvG(aHGFQ6lb6hKFTzYYPX*&)UM^|$4r zvmk+g{r@oVrVa@B4Uzy(JK+3z+yu^_*Zk`>%qQ^P{qy(y?*FQPUhlk)F7QpWAoHK! z`+s%(yvhI74SrsH@Bt+8%OOBkfkP6Y!xD!CBn};rL0~}oqyN4)pv1q9Lx%;996cuZ zi;%Dg@PXzNpu>j*1P&h&IC}KR5#ZCY!26&h5=SL})46<1%HButH0q@8qo-xRs9dS< zl6DxOpV7M&{#Zy@MpjN^Tj614AQY6I1iwEiA3BUbA*|a&~cbbNBGQ?RUpN zATTK6e&mCP=&0!Ugv6xeCn>4fInQ$Q@(Z39{#E{>;$`J4d{skZQ}f%F*0y&<61lsl z_wT;`Porbw6O&WZGgR8rm*th!uWRd!o!#$y%pa_M_D{Wj>iJ*C|5h*HAsjk<V%+c-)7Ac5WpquQY1e2D{)$l3xu@c=}mF)S+6`6^iQ59<*vj4chq zy4r5z8;r+xyVq@{@&Wv`7t=+GVxmKat#E`DCFS`=np#^JVURX~3!u;fj-#&|{6kdbH z_Rm^U%)6_{bpBH(@u~xmKX!V4lJ@x}o(7i;%9lY%H?($)oKE|_BXgE4MiUA6Zu33+ zcfyE)w(-|hyRk~w$P$R{`tL_<4!`f?@|IxftgPepa-unBKG=8rv#N}}CMvE^ikR-3 z_H7L76YWlvO6h-Ca=BgKs^F0BXYJ;km}|Li`dTNM?fYGneasJM4Q+hFIsj#{vcNg4 z;GCu1%;O}V){DlZWp0F-35CuDm)O@KG9$aVm;bOyRQ&^W%&^3xiP6-U;(zkZnz zv(D9??^)FxW39}FGV+tBg3v=MeLK{$(Y4!eviDX48ULwgtXSh#{ka}Dj~%o}l|B{8HtG$X?p}0FEWXr>PES71w)aPu zD$|p*xaJ>F%hwl(PKB$2 znvm;tM@5^yJssa=CdneyU_9f!>HggWWh}9iR|K_T^j@a>6HmcO3b1r8ygINHLYGa} z|17&@cIIQdb3mbk2fEsE9Al+cRK6a)Rf?-tu%6w0M{V~#26_tM@>m)brmPm0uGY4tn{tFI`SB>PsFiy-B#lTM9w`7l^d zNCGJbAOSSx393z6G-VMbZz=5lHa4MuV=1EFt!hf^yrM+>fR64fJXOc-8bxw7q0;&> z9#N|7tZ~-0`bzO~N*PCkNv!s2s{gahC`+G-c-iKl27#dby zmjt!Sy)!~ZoEz3anF&C$YqM9B%!#ab?H5aF7p4;9`&lg_*?w~C)3Mjhe3EMu2430M znpU|%BcZAujpYMzs;)h82L1Ic!P47NPP$%p=g*rYiJu#Kr8TKp;gLUqdM8-btGI@Y?F{~@jhwX~(F^~?AZf^>8?qkPTlCf* znpP$@7kw7L(K_ni-dz8_2wwQDCs1qoU43I~_UH1bt&nAHVXWfnb3654hZ-?y@}|-{ zQRf2-{EVv#0-Z_~UaFt(9`BkgRgMfCsWz3Wwsfe_coyiCYb0wLmV-imibD8U8B%mN zC&d)rkXF!2YCcz_m*gfAmF_5)syz#~EMC82;4A#pSw%Sa*O!IqUuxC=cFlWu6m$}F zcd^K`$lLsSTdMYzN!DslH1}c>gYdYT;jIw4BaG2|j9!n#4>ce6 ze~yBNMUY405wk*8%Jk;?`**4ws*@^RN`mB49ZH08-@qTUv>6YLdBudQ=`A19NwRrp zd>R7@t0WoMyqC5*RQOJZ8v08RN=8<7Ky$Q^vb#x2EGt>wm+`ssQvB4TL57=_i}!Os z_e3Q_zl8l^=54xvPnHN*iT7%Sp@yqtg;FzmyRc6fYL94|HYEnz(5M5@FO5)zo}7vx zLwwA=JU-ZlqV0R5#qhzq=S3E8i-WSi(oca2!K5pR&N}gnZCa(X!%+)!`bCEI7iVThtw4Wq2CnR&4rymxL`sN_qOWpF}e7Rg48cz;*)IQIEXgot2a758Fd zZ_UixYxxJDThRorl&=kIzZT=bs(TqXpnPToqrw=w`8slgNVW#QgR*UNeDELmBTd4K{XasgB0F|i;qZKM0${_j8 zdBcvY@N&|7%tfFE$_Ty1=_TF^RO|Hz@|^1p#xpmVtsZaj#;xH_H}K*N!S0|oF{Q@j zAe5Q%TTPX$6AtVxVaZyB#?H%R2~v3bC5(X|B@G=#$!@wd)p;*q_X_f_15iV4T{rkd z+((a+{LLbKP^Ta(XHh)8RJ8d3^tgEge8QK0X(5?!#G-)}gPx)*9a!fS*Z3E5u8nLP zY=N1{?^?1*?~p`U8^}qPdq@+A1v`4L=IZC2|%^g>#6bL&zp#Rdd;uI`Qsy+v_7H)OxSc>}ShQxXrw3?3b?x zpg3rr7&E58o4`WP z^QRMo|3o%sbz?zXWtL(UtB7XU0od-hlvu_s&Xwj4K4qdAYvkNUPfC7uIhYwDVmJ0} zH1_55SO`w_ohRh!ayv!q%?n&N^6GJ!;nw%$%@%FyrXVxPF!|6TV?2NtESRuN9Hoh_ zB&>6;KTr{~_G(7y`}8SfmanedK&8)N=LysAm$DM)LA(>_>U4}JEo%>+vg7m1X5__fjIC>z3|1`i{ZwG$8t|E17;eH zrL0Ie;qIj${kukCcoXx}0_FkupAB>BvSBz0x{RhQF3bfvRr#K7LQ7 zYa~zD*w0Fhc zgTh1o%o>-(4*O@3-??(t&Q*DSm0%IrFk;;cS7G#{9yh)Wi9Q&o&~wMJo2ILDyV6S9 z?6*u|;{m_OLXu$oi-wv$zwfJAiRWmIP^CE(3%h0UBa(bV9dFNIOu?M_IXeVwgthN8sGF~v5UpBqF>$@xypIEK&@<0?IDqnG zT|!`>I+Dxf!p(l)ENw4ZdtC0D_J*v_z5i-b=o_AD(y5ZsD0*DEu4y&*o&Y&U!K>go z)pzg-PSQS^V0`9v`L^w4@99PaFL$p)oivH~tzp8z`<5bBrQZfA=>6n1X7=k{q~DlF z^QXAwFX6Mk*h01REfYUocB|+ee=F^}=Qruj8ZmbMF3rl(UIkG!l|jqMK%0eh2iIr! z3$x!f-0}UcG#RexOBo2v^$QKlWb+hF^SR=g2M#~}T-^LN zIT$^kh!2R)Q`_4(mS(7E7iJ0zM@X^b6mDno6rFJn$||Uao@g_ ztnfFVSqjtdz@7KA5jTjh9+pF9w|jetXE&89do@=Ey$Q?L;&pQ?dOHQNtKqF=+DW^A{-4rK z*cF(cw*a+;ES{t={0JKALxo9u&!Ttj86kv(=Hbn)D{MtH<`VU@GDM>Huepn#wQIr= zpVv~VM6iuDEm9sr?Y-xa-Po%Gp;7=Ao$|w&XFClxv>PBKKYVG{D?SCaP}15MHXha) zrKo16o4sa8R$Atrqh6|fdw;E`Mg8;&Y`$(fmdF=DH-C?y9e{+m)?Hyn3M;J;h1~oO`A{5UN+pD)OF;yySR! zv|0B3WKUvf!0yb#y2nc8p_b;r%2wRU&X6j`lk9G%o`_#=mnXKlo(NNlKuATb-vho% zIE7v%Vk@)}M;Jd8bN!Vp#6?>#CPR-7XwZydPgvEd#`zZpSrJ-;8h5;$`LBK6I57&K zy#_!g6<_wauE_y0eZ|Zd%~c{@q|P?osMhs4uNf zW=$EwqR<_?qTgotQPZ}}uf83x&7LLSSt1)YE`0d)qsrK8Z$BL^$pcWe8R*XR0}HZ} zcY(i&S|HiofliQpG@yGOcSw|SVIZun?qt|YXQY^ofJ>)>Tq>qu5_($|q10+TiEF2o zLH7S(_zR>Bgb&FR7xhGyoih$V?r+fP=Y6xtHiC&n*RI?9D~2WRG#~3Gysgdga*L|) zjwpxB;yKEX_smd$bKQxfVCx@}vlRFr3tj4}=H}MkJ$w?%y@cmlOz4vV!|KWsfrr-E z&}>Q|E~T2Psd5;daJFR`ElUdVd10CrJ$b`D@|VBHBcGqgHlP(hAVBoSOM~c%Oo)Vo zTaeuPl*azNy11yU$ntKInj5>RUe_sKOLxEB;4bNugY&tYW#0WSTvQ~^VWBA56fbyB z)B};^$}7drL9Ibq4P<}g3Jpy$A^WV0_uO7pHPKrG&JIgx1YUmUl+6!?1%~)u zV+d|3G7dn6eO{A87TgCq7iu`^$*?Vb7|@GUUdpt&6MrH6%(rP~i^6j;)S(=bh0?(`@T+ z7ZP56dgt2Y_~5-Y$NTlFm0$t}9wBOU0v$@0>Vn!2ihlgcPIxnT@|Cj5t*6@0&t(37 z^Xu1c@2h@iP6V?bs?p<#3e#rJp0K5K7st|ZN|=FOO%*{Ztmkm2dl6j3+C3BLDUd-? z);sEYG(Gao_=SSE4CAQL`@tizSh*)Q4AD@0}&^5#VH%;5K=4lga%c|cy2+Adg;6!_C&p0v6xbB%=M>ESzN!| z3lh|dIMrw2wzmi~%Sz2i~B#<;G}{iv1R2Qk&NROL^Rr0*G_TRx0v2! zR<{S;7Jt6nmX3lBB|#+mp5Hv%d%kuvLf(~VGwpyF{FE!i=Sw~1Rgj?YY@RYkrwgT? zW-??;wSyDE?)-&8uJb@xvDmZQuvzZqCm;Nfvr~Lk^6dhzI*y}s$#Sb#-9|Hg!JE8d z5~*bL7N1roOlVkmv;9wfNE%kDQ!Z`@_x9+w3XT~|iVUU~0<})k_+D@tEK&I^J&Wm@ z0QFp|6N)Xr!NU3B1K8qBX8lXnoe9X+;PKEc+lwBVVtSN!WA{0&z^d-PR_<%)R3ooQ z^txndDEEv5>!3lZ3(o&kwms%_u9t?VfMa90_2WP`Rk2eCW|*DkDZfHxJt`OyWni_2 zF4eK?3R$sF@U&ys$jE7KsH5f(kWlK(fs2>k?6)xOR0N8sK+SJ@s)}%Hx?v|xAaoA1WhhVNT4R}Emg8+K#ozvv>A`x@=kNOvTAU2-+}Gkb4X z#hN67U;cR6H>dj=Rc2z6x>%TLFZ? zEf-}l0WSm|RDzTDA)mk`(T9>~+u|>L&D&h$Ug)Oi04n71J$jucc zgC|4uwn`>K^UT1Tw#u<;T3kg6rBT5c=j$khIN2G6yUaLM`DDBO92RipwRgPa>Gsc> zH%3Bh_5?Z3PsYl3?%qiZ^$f{T9Vn{JIbnL;=y#&^3W)`Ha@`3td{WQK9#{q@#}s@m!#r%P+ET3b|XJffy;Hg4nwTW5=-+*c&U0ValcL+CF5R5<>6ZT z8$~Nm#Sebvcy-EWK!P8Uspn{coa+YG=z<99(r^-9c%;L`G8E1~L6A8BeXOOyxspLh zZW{8{{}-qH%lUu$gTJ4lLAZuA!v2%m7;320l>6reI29|YCF3&sd0=6x@SkKC2K19s z$GcyNznMIA29x`Bt)7>#%&B6cMMiahpgJK&!vV_$?6&icNi>AqfR6mj5V(j-)B|tx zLysvkdWxQk=}uu|Zwf5yjh~NaD2O>1%O`0*+P!NiE0vOGiz6CGOIPT<6K_UPmL z%X6CJw<6(rX*D#EJ6JSzO9U7yrN@9+n$D(ceQ z?&p5;oi-k&il+S$P@J?&f{s4D?X`e(KFu$=c-=80;A8iv3J0eOhg^@K7q=GI9q>oh z&t8KhmzX}A$*_*7RD1R;=*o@UlJTuGC9exRC*k#~QRIJ>9R-_MU}hAH!~ie;=!ImJ ziqeyr!$jnC3tt+?J&%*YhO&@$2cQH!zN~EOd9FNtm4C+Lb&D?zDS;(g&^#4ujriv- zDSGq&-szlveE_=S27L%$rtQ`=9)0d-Vx}pz*{HO;0r)%`>-z*ZL1?_d==R0N+CBSv zgLzV2{s7eET)q`bv6`_pt}RQhb;yXOC$9PMaBuVVUDe;_B*G&5ti3+j#-z+X^uyD} z*X0ubt7aOsrtqzUx{=>OXLh_sM>E|NCOkh2xQ#X0^o1aZj9`~JS#CPll{?Pl)Q zyk+9@V|jUzZbiuRqTA2SVw01^FZMTVE(zJSqx9+1r6S^)B$9-1z|M_(v$3M+8RsM^xK{JPeEwX*ZIYl(=?;{=Qo)RIvdkCH_H4B%XYu zn`&&7_-3j`JIF2FP%X(kccdjpHqwO-76VqS3LL+(`PaQ;|0-W(h0D67*^vUHNp+piY2QiJ&Ldqbj`S zJP=-i5$mO=#`I^`nr71m&4}M(gw%tty{^%EeJ1f`Qw#b4^pF0=n$^?fVfm*k`>$=% z@mJh}3fjwcdi)B2diz*~3p$E+!TFU-iO_hNWzE zi33moEOTZet;X&1T6AYtHTM=P3%_RiHvg4pUm*5nP+`cA6#s^?`x~5V70n&>?T>>! z-v|1&w5DEtao=o0Jqx`ppIn#FgCfY$=mk{x3MBE<$ZqiN<$L zhiCZlau>-;m*NVc9{U{lKp9auP z#pIFgcw^d2;g=!L8J5a!osuMf0~zm(e*9Tly=1?iX&8IRCN1bO`dx8-PVVpJBICIg zgKTwqhK4?ZZ_WCH5>?^yC)wr1FPm*0px6%Fkh6?DarXX5nB1OZg%O0PSE3AKxBB62r*A43u z1^v%f>cUR6G1n?j{@=Ja`nbcLQmhr^4A!4KEX_iGD6GtEKLzxjs~3p?hcT!P?iBa- zC9@xLRko<*G%-bvBKgP~_V&d2Z}+})W7BSA2QSP|lExU-Yp1{`Sd`>4D#S?W%QQj4 z$2bOh0J_22IsgSN>T(&2;l-}Z>_KcJY5_qBNn=ha=)a<2=P!&Tiife|g#T{!HysF~ zva(G0eMGDCrKbV<)TGN5G(2xW|06>@IJ4X(r$eK8b@N$lH51eC^`;P;-w9*I&?!{e zExl?qfx4XzCKt*kcXsifzFtTCO6S*?Ar3&n=))8n!fx{=Ns4V_E9cTmMT|dq`kv2D z=&zacp}KArneeSRC5C2Z>*R-G@FA3u_|1m46{H*co0Q12RXL?^$z!aZ&WI!?8bbo7 z-tVX)eyoNB$K!_+@aIOC9TVLqMZy+D>8_sy1bXC;heBhajT=a(ZeP@XoTf(g-jFca zFOpY#_mt>q+?o1FJZYMS-=X>Z0)O7)wES(ML6qH`ywywJWhOI9aq5YDv2LJN63Wc) z-tzdg`a8?kmp~OyX&3irW`Wl$pxPl!ob;u-q|>{5^{ePS+9esSb=}^8I9#%>m!)f$ zG4#lV)-SJOZ&4(!1hs5O1nuEWo$z~jG$-xz^1?%YEPrP1o>5QMUxJ^Iq%85XkP{dW z8j=-{oZ`!)W3B6CQ1hX@3>r4ko$14S+7+d=i%{+5nI|>Wgr4x_S3j!T^THj?7!2lU z9aCry!d4@jS~d?rKpIbjCASB2+_|!o7z>7Pufi}_1xL>a1htFj&OMK z*UOF)Yq4;mlR6|x*lum@LCssB9(4e^ZM1cbvGlbBs4b0bGvi`U8@qPZfuNF$U{)G< zBUzfY^^}pHh)|{Hv&Tuws;o)U0cgW6rdRn_`l=9+uFQFoqtrZ~0>&A3N1WsM>ri;Q zvdD&fsc*tyFs>2)Z@s9!$?ejBUIBn!bX>235%&z1p1sD00eT%q%l?Bu(mC0w0Av(1 z6Q!CXcOzppIj&bbKUKcrU{g+W9@OLAZGt-|c4oSU6sYU&52TI?Ybt7t#Whl_tI~>? zxtcA5zkE#SlyB2ittfgo$E$-itM_JAWC6nHvi2x-QyT z^&m7@`Q3!|I#G1s67mGLYI<9M6;H;f;;=Uvp~wBB?nUwPy9$Ok+vC*+>F9;(m8b_0 zgR*@a4ia9Cki<#Y z9fpH9`W8~f(+r*x@@2%Yr~G7I{3a_)m3*gID*XdoBr}LG{_V|owT-w9!!q}9b?Zux zhxx6%`H&Xmrq!lH&k{zK{cEfO)R=MnF`d)>THyfngu<(*=0DM|qT^02gJ;duS=Bf{ z;Q4W7OW_(cFTqJxut68Ra=m+ny<8e2FPD@A_(>NBtJ?AEDg&x6mq-^zp) z&|s3S8;{$CdctHy=}Zy*QqMgs-bcsX4wX5y!HY-_@HfTR>Rru$x~`vki6` zsa5^-#gLuY{VX~%7f)zu3yfRpCMaS;>E+$WCE}FPQ3;s-Zoa0&kTi4y-$Nx!{v>qYc)2B@`l8zV=rrjE!5!nmV5@My{-GRdVDo zTD&5z{rysLhB~>#rGJvDKM#q)N^U4CbvnMf{EGGJf?E?oB*6ZpPJqiRU77GRCANRN zX7%x^e`OSs*boI(YSb}Z~)cj>_(AJ&I>tv zC0Hz*s`%%;Bu@XUHS5XEcMeAVRQaPM?N*Q+04faEucJ>6nc~$sigOYbN+B%Yfs*rbnwr{d_CDPAC9kN+>1bTZA?J1pH zX&<(tD3(OEHt|!KE+mgQItBUZRLVQ$1twQ&{f?*3%{)%c&bVe-nEC^7{?c{Jglc59s0l zqv81hC?9iUcsKM|tELL^ORK2?%EZn$FD#wTwMr%rb!eFhoEtdTcMI>M=@)r!MStDz zei?#M`ODyB8tICi2JSod@E4Z2WNW!$ZQ(7APvu!%ORb5{eN`igCX?NFj7=auP+KjG zU;H!Fo~rdw1j-55lI^g{vtT51r39GHBYZH+6Zz5XEXIBu>Rg4rg$?n=dlF&l5tH91VW;HJ}o7w_tgdo(`bk%_Yn#U=y1?am|!UkH81p4NFd~SD{62hQvQ=O7Eub zT;u=2lV>zz9C1f|jUVgNBO?~}ayC$X&)(20c?FH@ZrEzAyNyETr6#emo-_R|dbtSr zor~dt70iqvo^bF;w&2&Rg+cAq%IOp2H>W3(fPCs3P=(yxAlDye9sA zxohFgBr!{ltI5dP%%S2~S7C3=^nwt-HZa6f_P|@XG;y%7XMf=dEAF+pVtR#^nVH-=*0ocz`J83LYQ+`Ao}i^c z?pMl8t!(SqUJBnO?h|%;n~2b1i7Z)d{lY|CSmNij0~1FlHuwfv!X)kPFfrt2rtTvA z2w}Pb1k~sRy9+PlWT4qLv|?nrzs#{_u<@v;L!*VceLR4lk)wlhsQ_ z#uIMiq_9L7kH9FhWgN{hG#5IOO{GS+{r02&Y$Hw9jgehM`Q>PVkDr zjSC6wN_5#S?2N=_yU&MMb#w&(G=v+htdZoIxTt`f;rjK)31M64NOo>6EB-iEyb-<^ zFLD5quQ+~p9gUg&(RPN=5EO@qo5VJ0a8;UFi5zL}(Q%9z<0A7Gz=OG`vGi1o3nz?G znQB1T3WORke7z4qsT*B|6Ge261AmYej}KN>JOHJHCi-xcaX!4PsFmOcEgtE(5qZJG zVVy8-qF>a@kn}G9=2${YAHO5tr%@wrsN=2$gas$xTuo0lJARUZ;28~GiJLd9INOJ< z!sxcX*Q0HUe^N1_&cz|gx%|exLh!VFsZ>G$2ihp{VGJ9Y$}C{VjUKXlb^wYh>BJ0S zMw;cVerbUDf(6!K^6hZ?LRZ|`*0H<#1W7E>hq;k)%rn@NMX3LN06Mw;cHwruebc!1 zXlzgZy`24t#&3x$Zd|)NyaH$}3paHvCyWc?3o^WJUP# z%9+}d6F-2KSxU$@X+Kht(7diY7|2i2#|G?hpBUO@u5#yx_<8de7F+YrQo`pYs7eTU z8h@D0hj9c_b->Q-9^))JTcGJVHA znWlBeCY?XT|2S|d9rg1+<*qu`aoFKZulb2O0~1TloegFpT|D^! z7`x~>3o_}1+VaJff%k3<>%)}Wh5Ly0vzx_<4+1Vj_!S(HRw3R#6 z7zwGq5>e**8_^Y?fJX{xIOLu)$7R?2=AxH|;)gOwJ=Z5wQN~sGCy(C>n<|y6&2y>E z)3WtD>hUr};c3Rzm4Z|h*|PLE+jID{c*ke>Rzl3;pd$YtY*$|VUF`Qf4K5;!j>k^6 zV%N^{4Ll(h`wGr~691dAe6}7lkY!69PA@eXhw9K`KHnn}dx@?y-}M5F3=LZ{qJpcx znqp9WYGp6i|0wc3jt?73yO;gkLB>5-`V;)SuMpXIUXkATPn{_RH;?A3FG`vT&ro62 z4uzGD$-eIW8X3`&jt*r0>z7_@3>aG_H4IR+%j4@1okm9=73+*`jJ?1+ zeel)nx6cr@R0#U3RH4vz47D6#C)TvIC%*ZEbD1@~DBiOGM#pr`_$L`?LWBc>gb-V4 zLkre+*;x-!yu!Gb<{KCh%|a^)^GaWFT6Vi52OC4VWJQ!A?xXluLQY1-Ouh^nY{dh^~M6XO#>7 z%qnDap}aD^7=FdX?zEg};!xe;n^Di+w8f{cx+^Vcxc?PX5!|=dF<-gyW3!s$jJd*E zW{9}cacTOY#{$_8N)`vr$u|b6pD%hfbp+4ahLYahMcJrT(6kZ9nga}C^6%T+e%Ako z?$E0SEA{=dCBb;E0riLIVnlJ#sZtust@wvno>S#>S~z+(q&DCm zSIG4{`yCZ>vMb6-FXJsxd!OvD%J~=6H0lwTozC9quU;yHii!GZ3^i-r5fqo}cT0bu zcDyJ_tvt}tVdX|p;5kcVF_Lb7(RiD$%k^n`{=#h;m?p=zm213)5`6yL;C*J)wc4R}M6hP3(>q}xDimWUbpQ}vbdX475NazEUPZvT}CRUb>T_F_1NpST53idm6 z#YAOPCRe2NV5{aQ?}D_BL0AD~3+v|yWYjv6>>>N-wAC$j%M9Ur_OnWk>l41pYB9LfCw!n$B-gbJsZo|$ z%ox+j4b~V(6>LJw<$V}a0UAMaK_Tk4l;?wOO-pk8fABxzn!xFN7$yV=;O)LI(Z03~ z3`8y!naob_ly4Zn`>kxGc|m5w#pt0SyeimZz*qz+U+DP)cjm0}R-jhMQ=~c9tl>9K^{wpBOCw0>e0;!drV!uo# zYJAt|2l$UiabYnw!R%?AF6t6`Wh!M+SK8D|D0A7KxFQUB>YwA)x03Pg^Oow%iD;Z! z+&EA{Za1NalGRDdavc-fn~?THybk@Dy}^ue+PpUsodwS}{xbUg^LdH8zkS-8mZ+V# z*BltsQ#ozLyI6oaZj=I5XGopOtVjelt{g|*lhh$zsWrVa^SaYP%bC=FpcB)7j*$+$E8&;j& zd8K+}G<<*9@&NRQSuW7cp9S+&Qwc-SFk;042mz$>FUtKIz9XMjc!>Vzfb4(nKKr@9 zZV&PpKnK1m|Koxr*MJ_g_#=rxg|IS!V(=D@WrexOtN#;?<(P8>{xOcR2k?!&(5>(~ zrOYEX=gP;ui<`)x2lLoz{$R)|!ZtJ%l3(KQ?tgr_pm@oc%!6xpalkdS*i03PO@958 zio|kGv9`wE>M){11N*+>JmOwpI8iryZ$~T5fOdCMB>Q#&^7Tr=Ldc#Mq=n?u@fXRb z`qoAqN7f@rS*ZYX$phD3d;Ff=)d)NLG&6mSEGwS_<=QYHUEAqqKtVLYoMw~&t0z!T z)3=#Dk7(jR<#~%IV9l@uYSU6!k@a`;i4U0_B3`4AdSCq9J~)75Fq{)5*4=JtQ{q=_ zk>}Hxj+5FOXp!IQtW9AWr^A}qou^;Rw0uK3y>d-fjg}7N?>viYiz*)!vb;VVt~Hqy z;pK9zgc?^-c(WsG;!Wp*SPC;(DyclJoU^GK#ERObGEP>-eFNsa_th!J{hI6W>3Al9 zEJ`@(1iIpL?Uc3+o4nKg^d{*vHU$3(WiyVAH_MHlRNWgKWmRayvpfuHOs? z`3dxgNmwLRS*8~o!hyV|uUt!GBBwh?r(^xKh!ac@3&*A?-Sr7|g>j$KspSI5JqOz#f24ONtf(EgC$fSm5FvDr~Ln%E~B5a-uzFf#W?t@wT@QXb%CYoeE!j6646rVG_3LwqW1E zEj--j!i;ILLKZhRHZ}BO-wp=H`jIy9c?DB26$Wn%$& zik|G=G2J-?vTrZ+H8nQBnLYV-h23pu2luC#-9rO49yGQH`|1tRY8{BPIOo6V`v$za zvDnHtZmN4lF;IVq(HH=M+u)0_UYA7cy`ouc%pJI$BJ_i2rxvTq`|Iy%bxeKNr8QF-DDt! zr+LBa$Q>OVOnu_ge5eoj>o-9vc58D(me;%+3K-p^$))?2a8HX>WYsm>A9fU&k1F^a+6hep>-{oB7RT84rDJ6(k)&aYqJ3~ zoDyI@dpN(nJFPK%%ea|j80-yum77MT01-SUf3~4c5?gh0d2w=#&;)A)8lLjt2{Zgw zXNzh#az~vhhx6YAa&qx~1voBe1F>y1zC^;nSpW|>8P`US=SvXS$FSYzJYc%a-WCRo zHtz`W`wu`Z;C-P3(C9Gl;^fCL++kp?Rs=E#&9JYUd?~YXptV|1T*=$r!2ZzTuK{~e z32W3Ht~W4FbZa^}88=1v4qPk@Ja*Wg4#^)_9Cj8DxM?SF#{&>MJSH^p0OX5g0Z8nt z2%aVIWni;$-Ao*-8B2c>iyPorb$e#T<947}qP^K*DHd48owH_JxM}eD?XAn~<97+o zGAb&3!4@V!NV}Jrh+$bS`15W=49uVF7reW1&y}yS3~pNGXfprw0nBifdl?+Md8v*Y zLSUsJD7YD(@;Yl0V5YL{c*p$w8EiFd$K&EG$KM9Xks(8aSTe#j>mFa7m-S#lg?|Pc z&=XN^PTk%YiV~dM!tRJ4fGV-<5M+H=0`Q>FD(C4z3(oAxi38Bm8A1y)j$}k;xN=jr ztcr@Jc;WFM_bOGRw;V=>2Fa0zl8>$J-w9EfnW2Fdl0~soucSYk(TB*a0ZbAG=6s z01WYG2#{r<^R_uQLx6KQngcGnn$Lu3^1UDOs()~N_J<7V!|O`&-Ba6Jgy6mNa>I-` z3cyb}$Z9{gck{!zjomM+UzS(D;Iy|Xnn1gm`zwEdd}Dwx0S@KiJo0`*(`^ncWbaxJ zp@E5;iM)hsVq%K zuO9Q2zWkDxUOe2E+RAKSd(u1&0x|6iA39CZF)>3Wu~$6PnJ{-!%w0?HOe|8uM%wDf zlt+^$DZ4}18TQZxI@jK?l29SL@x`4POfq>bd$CUk=`eT!v9LZ>=aWR{Kx(MfKALe$ zvX-677#7AN2-{v^hKNIl59wqB1mdUE<`{rL^nlZqe@acD8KnV5aezVmOYA?f0RXWI zP;gEBo&|`Fv>wsdgf|3us6F@P$G`N9E#D-rtPZso(rAvVfYhfb7pBeNN$gV3c;3OFN>QVNot#?Q`|Z3BD)&+nB-R>DQVUhZsojL7h(0hA|*C zDF#{X^NMV;*zWwz9fugasK;4qQ_7p zua@^z?ft6fH0ym=9&CEyCVy&VDQh6#jRT+I?w>Ln{IY+&F*I$3wVS0v9db?rK(hh% zRyB3t>@wJu&7ts$gQ@iZ`P%BN%yd{rE5rRaZ!K>{byR)%g8MEz;+O!NgrC?gZUnfX z0hOhv)BFEW_oiV@W!t(iwX3mgDWw1#BwH!PK3b@NgsffVR!UJ)ii!x5LIgyFsHlLD ztZf4*T}lxm(qyYeAp{Jqh(J=(McS0~AxKDQqL7#dvq-YC7T=`qInTZ4d%o|U`}h9P zM@7h7YmPa_JKlGUF;TdX9>Ep`XS*aInPj zt1$=3hG{)}K%%|@*8}8ZX${I62BAT|Iw`80qUM`!!c`X-4T!3WUW5M_$qv-=I`DgZ z<@|greF4t7NLZw)Lah7weUO5xKZJK1xgc~`YA<-ua1_hAV-)n_Tpc`f(6*mFh)=OZ z?nYI@%Xw%_l0&C8NCWc`BEm)^dtCW_aC!Nr6_IFF{|1y0rmU+%o2bEU3Jjg*Ccx(< zi{bheWIk9d2vi|({YH($F?Bz}6!8SeteL`IW5q%wWzjR#K-5bF&{jFUQ2qwQIdT{; z0QSeeEvG7nCgLL%WDZs?)sgxqdHrI{2iN*jSWW{7b15G>Y1|*#q#B zuMX~LY56!E;r5X$nwF^s!cBH_896jzpo&2##QQ`wv8Q?kM!urI*%1JflMyLH!Qk|e zYJ=5c)Pd0WkgDX;6i_JuQVLaYhjPRCRWgBlYH@od)5*k1VmmJ7q)pt8}U`1%r?B3sEvHBqLyBEPOJjSlFSi z865PRngQhu(`e|;h@vWV^Q6QZ@5E;M>#FQaJ4%)_rI-iH(Xng{|1PYfqqv$H0$Pk- zsUcG!^AE{N_&ogf(3}u4z@N;D{h8JCFzQ5S zex}Yhw&aeVByutLDZU>j?`4!KaPF<<<9c%GUN(E+vgydUoL|=#j5{&jFhxpm>i((+ zdI&e3HqP|GvMq2k&^&%-aFmS76b9!f&qVWI1ep3K zz4(LH<$lqAl$>!~1!q>ZB|7o&#?EWu=+hMfrxtur8q36d-jp~K`*<}vB8Z9=s5u9v z6b0;9&L2U~&w*3`@vVG^vT>E;rdc!E%c?t2U+&-A9VCTxH-Mf2xB+MK6hb}z+P?(6 zBqs&~20vh=fyGW69-m-|sAVjW$~v(Bp@zk9ISiD_%shQ4>ZXufK<6P-`bc+_CL*EK zN;*sF2a9;UVZeaA*h^G9;1ouBH5ajppt>N0Q+Tu5_qlt{;xo{y#uii6nOMG#`y4)dcHn{p zn?YU7b#M_qU~<;%V>-sNuf$Z2Wz0|J->A(IbE~tlM66f`k}-u4Q9X+>=fLMCj%!sj zwC5+lLk^&{nMA+tED@R^hjSq{(3}2c1%C<36eNqHY|%zYow*NIQ}$_&O5n3?Qq@{_ z?&>JgPq^_u8?gzoK9*$DPr}B(+^`n?4hI$ z%4_$iNltnZU|mAMhP+)9%Bxlj>%LyVk1eu z6BpuLh-t;c5!Zx1JikR5(Yd-Yh8n87;N?i{jdo?1dm-6FQ>+YXIlu{r!{*`EDkZF8 zdIH82D5}54lJ#+;e7iUJJJcSj0tWauUpO#2_gV_V1mAE$fkv{-vyd=J0JBqUEu$XH z7T{|HH)G9jBaj#p)w(y3T$HZ)NaPD6d;TR$==o)BKpnfn$aL&A6kd+;iHW}K2M>^l z0>XfanyYa{sD03jfJg3=)YAxb0)N}CHpKDDbq9Ik0Tj4=mHS{s4CV3=b5x?=#8-gW zv*3&XjGX{y!3DhAGyrb~9euiBkj_c1aREv|YN4gOgca~P&~#7;@E15hFu)2;^RncI z;j?~TY4$p%LaVujU6=V17J;L{7r`RNBB_Rd8o+>=Dq{w8^D+RVpd+T8P=@e*ky;R| z3R)Bx`#XbS)G*UUxrGKz zqsE7E@%@y#dwS7`5Qx2YveS-@&>8$sT!;o634`PoIsJM4qyQ(AlGwyHU;_B#8HGsu zahU%>wfbU}@k4!e{vs>}bwu4KAtnE~QC?~URg>+|J6>rVlG{DWYtw%+xaL=YK)uf7 zm|BlTF7#R~RMc_p`EA0smZO$r+jGOF41GG69u}aWt-w18Y8ImdG)^(+m?Z>85&-&_ z4S`7Qg7EDXxui42oxH4Nj;1t%D2fY`@JbAP#5zk4I2e2Uahkp#T6IGP6~2!P;1-Q$53I7zcKDy&$|!uUe{2lFyY)vW#>Qr%tM4`Oh_hzJBf}rhqfSRbxJp`a46$(Z;(%}j z4)Qk`a4xXglqG%)KzC$N&qO&OAkN-)L&Cb@3$Xss9PKd|2CU?O4J?b6glfk7>xG6@ zAUEF@%O@%!F<-lxhp|O$z#e>QqNLUa&YGPj1$U4W!NbcDQ1ILXkGkOfbH>D8ASD4> z;(h>1TnLVB@7zHedjh-$RN?xO`mD_myt)xSEjw7dLI(vZqrteeDH~Jm!>@z*9~t$I zeEX7Fv+F1Lm3_nQU|ta8JFw20##gL6jHWrN2!TF96?AS3x-PDmX^M@u8V=4xXpY#A z7bN8q;yQl5lXV=whiBQU51x_?Qbl|~2ZRCO4ou0x#?K#D>XN<65g0^pL4gp2#+r^6 zLfIdHOpVKnmjmp}mW+>0$P4zc&36`u$HaOdJXR@c4{+BrES)cn7|>H?1khflP65{K zjP8H`h=M?-wX0yaSIW?-njtd;LC)1H=Gdbs*&6qgZ=4T)LsUseuTfy(5>NAuQsto8*M!P;5 zn_z3?UECyoKV|9V3*9J$Iu2Ysar$2f!N(|v%7jr#OOnxOb*a?GAK%DCQFbt0M`fx z87gB|1LZe!)81DVn`X@lsbX8fn!NiU(9z)F=@{o<*6BE4DAi~&{7gI`5(5U=QX7Lu z07!5kt@#nfwB^nfLaDpPUgl={?(I3kVA3Tl-99<2){VP92P^E`&7mV!udJvSLRVQ< zi;y(h`Bg2{PA3Zz?AG4(+@pj&6(b#b#UK>o5{zn`YTdD%w5g*m?P<;y$3D0;8h@$` z1u~EpyT&b@;EYH01JofVxx~qs&oC->Mz&`KAJp*!)&b+*=!hV20B8P*SE_?U6=0j+ z$M{i06b00KvCwZH`Yond#^LC2j&%#DItn}$i9N5 zomf`YSAOTrYA9IPac(+7%v!hsirz46s?s0lhO?l(@L9>fAa!XhZDg@KIJ*j1$|Sj?M5&6^6Pz-<>$Y z-^C|aTr+6&YeOhfFC_(-ndj)cdG&1dO}M@dXi6bi0S;j5e8{whKbHrb8%)ic%S6@8 zC=Ngxj`%XJJx-?KBE;MQvsU_@<{RRg$pCUSMoZfTV5ukJUaF2W$({pOkeK~5-XM@( z9U3a9UJ~4lc$#Q8#=kR#k%JN;V13QnlNW zYS>PW}tGCh8y?U*#isH4_I(znEJt@GnG^h(Y+Wx#(94OBcVbP`cx; zu+&z~MOX;Sw3bIP#SYM!N<7#IXqTE>w`$jb!?Cy_6R@%%L=}T$+y@prSN~Rm^Ra4X zlRun-k^Vk9tGBco55YfRX$f+L2#_fF;t#B|!QQBX0CT)pI=r{5+r+{24wrb3}krXmG8t|8pv zNoaBd0gNqG1t$e(`J+PJ_kxd24_j0Bq(O4IDwwSTJMOA+K z9`9UQ`z1%}w0zd=kSDna%jNA5nZD>XIToJO??tZ@&13)Z)^w#07HdDiVQB}d--a(? zBX=w60*iTFufE@hl-jhJ=hS+?3D`_5{v-GEh9;)@%O}}RZ0xjm+#yvwGc=cMPiuu!kb*u!q5ar~{3Sz)Zb+(JJE z7>4G{5tzsDVAnX<{i9+nDIMHPRKQ`s_O>{~Rs0HP`fsILBM1hi7agnm zixn5R3VvcWChP>DB7=#U0~j(O6_uQvHTy7_ zzn3a>yAK9F&dW0qG;R&tuRueT>Mmo8X&X2WZ`HGAhw*+KJT7>?7d4>IdKvY_xl=ju zAVyfS;)_347Oz4HKCim3&YFGN@Eu4tTJhFuaR}Yzx&HctkiOfRZ^`BRNkcvKqW9Co z-ygxoEFMIk9d)&;t>x|)MkMSo?Dozc(bVq!b=Is%*<$^3Sxk4d$?y}OkS7w^&ses2pz_D z_u$3QNEZ7mSi1K;{<(e>yb=(kscLXyf+Y(F;Cdp)#1gQ3;NQczH)5$10AYeQv{1qz z0eAzD`iM}d>;kVBVOFYMXc-*)9mJmBfJ?FQBNU$4O4(CS1=?4F$aeQ;uu1R zqOOt(*iNN=c(AFa@mIumAG?e1Sl(HFFt)GCas8fJT4;@5f91QH@;8hxO<)`1_M$Yr ziw7S4whz9Hp#Q0omi&l{P!I`10c)t_Z3|i1&jz2VNTDbR!FW6Bn2u~9NubVYJFTg} zA=_Z7q=(hLg6s#>=X;P#M=MpEPa*Fm!2_m4SlJvXnQz@pNMu_=6=VVUOFsC`CQ69T zQ?SqB9pF=$O|}~}1OWZ>2Y*4qcL58<%F#Xj%2kZF$VtcO&lL{IPjNeQ^D)y>9a9&H zeihBQisdW#m3S4#y2*J!_nGwT--6gmP|B38cQHHZ2R&GL-nXO+v~*i>C@hVZBt2* zopNK@598Pqhb@r92DjmVvEP-4y%$p~O^VvBNtz%(>n*cp!*SK+d_{h~<6^kT9k+lh zwtVD^cD571qrlT6C=;C6s#^0(@pYaM&qist*!VlW$;2F_i9T=Ijqk#87`BWy1Y`h~ zJP_>W(^#W~s+IzbrC>N~92>#;Ok}vnc(H{sC%SOjH*Vw6lCV{`&$RG!W2x#cvbp|l zBgxZ7jxtCtSlR_X>N-yK!TaB6+pEF$)iQ$K$IQzF-r+jl4`_>bsK<3UM`L>&OUfQ~ zXrfL*CyacQScZ^r@%+8>OmK)7P+nuMp!~BR2h1TWWoh({gLsBalk8N{pe-mV-w3|tn>O45R#KIG1;vm-cS9Ygph2qo9**kT;Zg*m8U<(`fN^!K zk63=?4J-xc!u9+aWWl^NTB21cdfO9`SX z8KkH}h|0N=9{pZGX}m(+L?l(Eej2dcOQA7u?f*!Q!Ew`W2ifr;(AG=1A8eQEgTdF6 z8p#A1Q_0swVrOuG6#VfHkRP*={cf3o5*0*kBbNf&NEn8z_KITQU{n$)^b||mIVjEf zwLDh>v;gn`V1tKp1q-S3O|%gAtSnIsWu$p%=#e-RxBqbM`fhf_Gw%bulRtc~Hhz;IXvcJm6#f+O}sV z!=k*qO@)k(fYn=fSUO|uirDO-duY4IYX3`?8#YFuWcRl8X49X^ec4@=)x|Y~xZ4MT z$)fuN{)fIw?RgqxjB^b==Tr$Rt3Ha%-@A zSQ0|HIqcNMXu}?3PbZ>R&bzB3zm;Q&4ME^&1K$0sxLrBeoXfKn>L^f z0EaHfhEjl@YUC0t+Alw{1w}OhOJnHNEOri+&ANAanEL)VCm-wx2%Je;2^TP_vE_Gm z42viE$HtM&wT~5b?7khOA^r)VdnKAowMiLTd?Swp3PSz5VMP{*6O)u8FC*(As9$M@ zkS_@s8fs81_Q!k$GSs0(c3iCycPb4wmt3^fWiX zX_hs-nZ_jupf^IZK#Nq){pj5DjD$u=3ke~`C2(#h!y*h`iTtsA8H5so3C5B}LN@!` zBDf4+Z`#)l;tT2`U~DUyHt{!iqV{)oErcE0B=)R{=oloLS?&_~!jX{477#V=)4|Qh z@O2aofK&&AWfFkC%Yn}*V-~>g{nl`MNx(th`)H3hR`PWY+n@_-AN(MRilz0=n(3fT zWJpc91xx>~$dc6XAQemds5|uoD)asdgq;Vo!mZb$2=jDvSZiK2vACL@hvO zzV+V@3LK63{jPkz4nTLD%j#!0fYK=w-Ygcd9^two^i3eJy(1dSvto>o-Ka^P%j>}$ ztsgh{uVezQ<(&MtVOrX(*%p&9O?iGVZbyv!Xgx=H_PK=8l*|H9$)i~iL)~l?^g#f% ze-M;{=&hXrt~Hz}l_(U~0)C}O0IX05S7KDrbj(4g3pBNBtuh=AGzG^*d|>QDBhZ!j zTd>ots8Fe(L8add1Ae^%l7hA025$1ph{=;h zZL4*{Pz5g^<#MzU5#9A~^;m6jID>X$xUXx*T)Y_pKK-^^19d4*fa_O*^T-C(hOp@{ zAlcWV_Blum2nkcLMvBEnj2qw()X~J?VY!iQHLafSM@J;a4^6(SGT|av1om&r{3Be7 zS1TC#tl$SgrY-o3x2^@$5y-3CRF{X{zEaEkFL{T%Oy#x>Vi7Y`FZuXbe&SON8Z~Un zmi(T9qMW9C)&+eNJ%W zN_E|j;Ex1jH9ZVt>V(SFHMGzPHlS*dd<;T{8}QRHRKQ#vyqEwgh|Z0cDQ->ul}=&Y zNxYjSdfPY(-%v_pv@yid%~ZC}Wyndxj1L1{r1?z?BRTZ4cW^1Gjakw{E8laqfb!1m z(sgCE>NwdiE7Eqk0zVJB#YdZBcjf9;TZHIt=X@kkPo1Q!0PXJqYF`_^H0(@CC$}<+ zrX(0Fy2s?ke14m*Aet1`01d2Y4*6k}SE&P(*R0tI#0Hlvygg^VL$$m?ajU7S3)IeS z4WUKKX3f6BoOrLmyz|E)A8sDL9#z}l$jgIyTm6Ud>`?md7-OaC=%){8LU ztY`_UgwQV&@SMUcyG);=?fE)Kp z_FpVw78m3QZcv{_1uif0tjMw01X78@u6@CZv2&^sm3F z-BO-9Y$xJvHD+AUvIB)!_OxR4p>ZjXSD2S%%)^TT%@=QMs;er03ZG@z3x>=wrj45w z9D)U)k$X6vC^YHUHpw1LT9J7fqfK3<^Fbm4jON5sP>7UQAQtg|=Z6sEA$78z)12!7 zz%tGB9buWtZPsj=L?J1sr=dPa`ma*;CX_B1BnuJP4tMpRjx_LV#N$j?ex|NL zv7ai2{i|1A%k}L3iL9=^%8xTOb;V)KiC`p0pSMn!2*xcui* z{YUy0-xv<(7rvI4&uj3QBD~wyAm>(gI7~gymzVjSp(wKyJxI zl%k=#ODG{7s>|Beer23mj9V`5Z=@u^fO-5Cq!O+mvan1Z5b!Vz5mroyzbZ7$!}wsI z0q&~6!MX|M2A&%mk@gNj?V?Thc(6-p!*DBK|If7eBO)3%a=j*)2!Lb z*uN@Cw!})1!+H!jLsc_w)(uN7@Bv%^;vr{7BIbktcMkuvi{u7@LZ(oaeG7U`sGFno zRA~$g9rd@Fn}n&|dz(%Ecsb@a#h>g4`qLRKSVZ?(^=lxkf(HlwDnfy0&Rw2Hi7~7} zcReBLWemFa%ZFY-k3%HKW*DGCfu7^LlS~X-D7lYr_8S~jU`0F#u5Z-vnV%&3e*zE> z>dzplB{qYAp_5=u<)4^KC^#2gDd?Q$HI!p#{is~nfx^jnB^}nB^ZS|RRLVY zSLc9kroWhFIDOWv4q(SKbKJ5LC>VfTR@4pCLM(1a#Q<)Z1r$QSE&G5K{lzUG0xJUC zGU_r{3)KY$Na7{xs^`4bCKnu_(%Ycakf3*mWtXrVtQdh54^4-k!*3v^F?f*t7RyAa zdhAx~G%%atXvQISI(?&_gB_HSU1abx7*JV3Fo&R^o-(qkj2}Nw0GMiq&5>d3a--x0 z(46M~t?L{2`|MAx{RVBuZOH?9g@iy`-24g6NF|?WMvANwM)KsgTX8c+WOs-*wdXG+< zk{rSR0Gty-I05jh;Os-;NX&)5YUbD)@WzE7r!NaeFblxx^?oXL=tLnTBR?SDfK#)^ zu(FBGuuH4NI&<7mW8#1Bie6Lsek63+TIpkSrZfv#0>THYJrYqUVj~0uuE2YMC)}P1 ze*;o5=y}5=?>D{x^Gc1m&*iAqAhG+k=&CL+xN8E=ikUcB_th&pyyFsO|=^~p}T zRT&a-8THZnIgVF-&tn%*%fTfj_PDj=W+i1gTn|j-HW2rk9C<5oP>CEDhSkXF%mZ(C zQC?tN+(Jocn}%MHnB{aZ$uej<7MZSnSxd2i&&{cO==}R|<2ro6*mq>_E@QvZ02(?l zo&#Y{-@^_GA}(WYgP=&omKNHg=(h(d*bAps?+fr(flkTYSS;RwtVp>quVmKjI9@GO zlnfklt3>!yR@R^n#y3|es)-?oM|QLkKF11Se^65x1TQ}{9eV<-w|+Am*A-Rh4N1SG znJZIQdp7P7Afd+4B6jD$s(_VIgH*xxC>@Sdk^`a*0#m zB8Quw$zEC9og-tE&Z*w70pgNA^hlPdpF&b6yj35XZ*mow zwn+5*0Y)xiFCi#nfy3o#=A}=7qGfP2XR^rsz`t_G7$_>ZMIsti3obSXVATpFanX(V2_0Lc|h zrTf{7VyMcW09`9=5h^}Ri?i-Kj-O6wQt3A{OzWfNV*9O8vC^w6K|yWD9=w?W(3K#wJj_1o|i>%fd-NAm)&gdIlHu=vKQa*ypuj zyl#Y6VSvt|uKb+xcI}yWrHs!%*x$m1YQgOi+io%4EwRjoPzki-{>dRI7jVQ;j192^rR$Kf~*C0Cm3ul&0vEPV^TwcF=b@N^u!BfBk!mnd-V$f#Sl0D4GUBP z0{T1KxLJzPgWuX?;s!tjyaMr8zKk$VOo6npo`t`c7@Gp!v|Ba67vL=#LDE%o`#B!@ zH73j)r%hi;S!u4z`c7Qc{%&TK%Qa0lbEfK6R1Nk|BYC{m3xEO+xcEVcm=|MiVk{=5 z)SHI(_m<|ii9iYq*Bp~04B?O*xi_O#xbqU@JsdoW@P_M5+V*}868u|o~BfM|=n=mVAEZ`6JOa#d3Q`bPf%oWi1GAAbffnc2e zzT6OtWq|saaegq2ZsX5~bY!&-t|mFpnr&c@&S3Y4H^Eac{tbVjx0^Myw`dTePTA|g zGqwMQm(+p)^CkEd@1fVIIfys#pQ`~Bn=x(M8vKW`%4APf15Yls1oj(=TUjUnuD^=F z`u&iUs%N59)DB+?bVVS|t|kIEd;u3~6+9vG0WeY@mm5JVbF@09k!TCc?BPPTW^oD0 z`zG*}a1UQ8RI+tYoZ19>`KqA4b~fq)+GGMy$263%dag?*f^DhfaokaP^YBI^KiPNj zYw8g>C?HVVINShL^g?0}{NiQ)?p8XthsPxrVLq%W8@5ja8j5baPHlwt%$kiHKyVB>w~SPx1<| zOwu}8a?KQQz34jeO;_<(|7&(-+daw@$w$o_n71UKGsscGdcuHYJ{&^Sd$ZMfwcZ$C zN_WF8AiXDVLxnoHk*2>Fa_Zg8-B=fZV^w!)#aASH&d#ufD76C(io^1MxqsT8b-S~y zJv=b$tlpPW*?t*%2A}uGQr8lW-H_6MW;aOBGVB~63FNks)bY6pU2G=j=g4GBZI3vP2c&gF9qG<&&oM7Od0p3ye6(%Eq&Er3doM7AL?OJ$ROWz zc)hsr0HPZH2mgGv2pfH!y-{#n?-{?t$!{IvL~>hlwzA|UtW1`%OB%rC2bCL+BFEI7 z=}_>2W}64&8-5%r3E$`-+pMPCb;=GWuDB&r`TwiQi%b174wncE=+uRN98UaG#YX>i z`U1x)AMtKj^m+3TDte5KNA#(`hj5q10>uGz2I*S4*%x*Q7pIm}C8@SdNzRdRs5MDx|bx3Vl3Pyr;49_$jn__me%S=7@F zc}sSV$M*A$O^xpEuG>n&Q~{baS##cRp|)FVdQFf&#`^apds+Cd)fR`)t(8pV+C6%~ zq~o5jgn^=5pUqII$bB(i6t?bupQKG&{7&}I05##j9;a-_c+$FrW-u;?Xx`+#*ycFn zdOH2ZT9&!IgzGifdxYaTcsw~@xoQ6{uwgrY8-$J)CxCg;@cR0IDJ*n#+*6jn<|RAi zL{;C8D;GU-*YaN!FYn_hL-${GEk4b*5`O46LpLG3(!0(}$QBMVXmGL)Iv3;l*Z$ zh9w(1E@eCaDx2QJ9?0$9(Ku$H$I?AK*0gR{%bSlkv@PA{OA7dr)Jxd9y!n2`vb*?A zx>f1Rq3|PrRDb1Yo!B(C3+{tM?w{fGHU?Tc?;!0>Ng(^2hz8J8 z?VhSTE3h#n{N;<|*|GC(*xHP$qiii@CIYhCVog54OInlTi^qxiLLa9#`vGodt==!Km_GW|B4EZQI7nRZ*Bv^Igf;JG)6 z7n_-E2ga2+YyV6>&+$rp!do_Xtzhf{eG(^>Kmdg(dbIf!Dbs|BNotrq93JUrM8j*6(%4 zP9o9kt?GQqM<{H|h5?Z_up)nvjk6{#W1DY<*Y5R4pQ}!I&@>-AXO4C0TvwfXdo?HE zAALI)2YB>f$?^HICwynIhrqMzxz)$|$v*t;(^oGZ4Nf{e_kT2aGJMU;_!W;Ifhiz_ zx7p5(QQ2IJ8*S5z!b7OHI1>-g4^bMvy|imnpfm1yB5#3n-|2^Al~diV)2CKE_wtBl zILv$agS2!YsN~@bwK5Nn8PCjh*(CU-bigLu@$)->fEr^3+3xeZ#c_>4H~NQq7P~J^ z;Ox(H?rJ=mV%-0%4bxaOUt?^1JNnk-87w0#4Y{_*b6@_4nOBXE zDw7MIO4jMcoqRIKwMZeEv8b8aZkW}fu2bUZ_54613WQA&)7kQg6U0b+&#AxzPJG)a)S$r=* z+ul`7s+o#<6BIpcZ+SF|#NFL~@v6F49i3`zzOnCFVJ~ug6mtUD*j*pXQG72B zYa?|&tBiXM^ z<9+cDWAz=2$cMJvGaPZ)XZ!A6>CcN9^iSze?=!V^%Q)!8ho1!gk4l|;Ak%2^C zi2Y+FHRQi(as0X=Y%uatZ}bw_=!H|%cg4PEvG|-&x7^3*0M*ElX#o(V&?PU`)9V3 zg^8TrW|Snfzddc^*mwE;8FhrQmii)o?aAwXk56#CpiuT*_t9b>nRz2+@zB)ZnMuAn zk)9|+{DYtWfUKe|J{L*8&}Th!6WT87ygTmK!t4B}_wMj0FCFnIao&+u2gZEq7IfZ& zpeq+akhAYAVSA-IZsIC0R^!2YXO_2b-Oz(v=IrOHw!a-~?3Tw3*&RV9Rz!X~Vp>PHPH`B`kT1h;|=;bR3CZH@{(PzS3c%a0h$+O47h&T2rh3?jEKg zX2<3D%}e9+H+nX>i7rb&R4rKeD0`F3(UbyCPk8v-zOXh~Zc(MnVo#6WU5CF{ zQBbe@#xO-6C`}6Q(?%D6cEIO?hs?EXJ&1DEz6FzNAHu_++K2|5jhPe6!IjJBLGeTk zV|lY|N~Vuo+VUW%Ivt|jm)U!6<0#5kUYTCttB-6+y}jd7WmNNdt$fqVN6W95r5|!Z zvInB8_AIM(?ua;=KBCu|qGuU1no@B;!aUm~MHz zp6=(gr7)qaer!b!JoJmYGJrC8F#SBgroo+U;hB3aB7Gm`${HW?Ojc*4QvYxs54Vt= z&+SI-_xv#tox0bHI41M%7sPB4th-&lh}c)AAKjj2tRPgSuD`PRRLc3HQ9%0AY){4> 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 literal 0 HcmV?d00001 diff --git a/src/platform/switch/sm.ini b/src/platform/switch/sm.ini new file mode 100644 index 0000000..bcba937 --- /dev/null +++ b/src/platform/switch/sm.ini @@ -0,0 +1,92 @@ +[General] + +# Disable the SDL_Delay that happens each frame (Gives slightly better perf if your +# display is set to exactly 60hz) +DisableFrameDelay = 1 + +[Graphics] +# Window size ( Auto or WidthxHeight ) +WindowSize = 1920x1080 + +# Fullscreen mode (0=windowed, 1=desktop fullscreen, 2=fullscreen w/mode change) +Fullscreen = 0 + +# Window scale (1=100%, 2=200%, 3=300%, etc.) +WindowScale = 1 + +# Use an optimized (but potentially more buggy) SNES PPU implementation +NewRenderer = 1 + +# Display the world map with higher resolution +EnhancedMode7 = 1 + +# Don't keep the aspect ratio +IgnoreAspectRatio = 1 + +# Enable this option to remove the sprite limits per scan line +NoSpriteLimits = 1 + +# Use either SDL, SDL-Software, or OpenGL as the output method +# SDL-Software rendering might give better performance on Raspberry pi. +OutputMethod = SDL + +# Set to true to use linear filtering. Gives less crisp pixels. Works with SDL and OpenGL. +LinearFiltering = 0 + +# Set a glsl shader. Only supported with the OpenGL output method +# This can be the path to a .glsl or .glslp file +# Get them with: git clone https://github.com/snesrev/glsl-shaders +#Shader = glsl-shaders/hqx/hq4x.glslp + +[Sound] +EnableAudio = 1 + +# DSP frequency in samples per second (e.g. 48000, 44100, 32000, 22050, 11025) +AudioFreq = 44100 + +# number of separate sound channels (1=mono, 2=stereo) +AudioChannels = 2 + +# Audio buffer size in samples (power of 2; e.g., 4096, 2048, 1024) [try 1024 if sound is crackly]. The higher the more lag before you hear sounds. +AudioSamples = 1024 + +[KeyMap] +# Change what keyboard keys map to the joypad +# Order: Up, Down, Left, Right, Select, Start, A, B, X, Y, L, R + +# This default is suitable for QWERTY keyboards. +Controls = Up, Down, Left, Right, Right Shift, Return, x, z, s, a, c, v + +# This default is suitable for QWERTZ keyboards. +#Controls = Up, Down, Left, Right, Right Shift, Return, x, y, s, a, c, v + +# This one is suitable for AZERTY keyboards. +#Controls = Up, Down, Left, Right, Right Shift, Return, x, w, s, q, c, v + +CheatLife = w +CheatJump = Ctrl+q +ClearKeyLog = k +StopReplay = l +Fullscreen = Alt+Return +Reset = Ctrl+r +Pause = Shift+p +PauseDimmed = p +Turbo = Tab +ReplayTurbo = t +WindowBigger = Ctrl+Up +WindowSmaller = Ctrl+Down + +VolumeUp = Shift+= +VolumeDown = Shift+- + +Load = F1, F2, F3, F4, F5, F6, F7, F8, F9, F10 +Save = Shift+F1,Shift+F2,Shift+F3,Shift+F4,Shift+F5,Shift+F6,Shift+F7,Shift+F8,Shift+F9,Shift+F10 +Replay= Ctrl+F1,Ctrl+F2,Ctrl+F3,Ctrl+F4,Ctrl+F5,Ctrl+F6,Ctrl+F7,Ctrl+F8,Ctrl+F9,Ctrl+F10 + +LoadRef = 1,2,3,4,5,6,7,8,9,0,-,=,Backspace +ReplayRef = Ctrl+1,Ctrl+2,Ctrl+3,Ctrl+4,Ctrl+5,Ctrl+6,Ctrl+7,Ctrl+8,Ctrl+9,Ctrl+0,Ctrl+-,Ctrl+=,Ctrl+Backspace + +[GamepadMap] +# Any keys used in KeyMap can be used also in this section. +# The shoulder button is called L1/Lb and L2, and the thumbstick button is called L3 +Controls = DpadUp, DpadDown, DpadLeft, DpadRight, Back, Start, B, A, Y, X, Lb, Rb diff --git a/src/platform/switch/src/switch_impl.c b/src/platform/switch/src/switch_impl.c new file mode 100644 index 0000000..0a5eba4 --- /dev/null +++ b/src/platform/switch/src/switch_impl.c @@ -0,0 +1,45 @@ +#include "switch_impl.h" + +#include +#include +#include + +void SwitchImpl_Init() { + appletInitializeGamePlayRecording(); + appletSetGamePlayRecordingState(true); + appletSetFocusHandlingMode(AppletFocusHandlingMode_NoSuspend); + socketInitializeDefault(); +#ifdef DEBUG + nxlinkStdio(); +#endif +} + +void SwitchImpl_Exit() { + appletSetGamePlayRecordingState(false); + socketExit(); +} + +void PrintErrorMessageToScreen(const char* str, ...) { + consoleInit(NULL); + + va_list args; + va_start(args, str); + vprintf(str, args); + va_end(args); + + while (appletMainLoop()) { + consoleUpdate(NULL); + } + + consoleExit(NULL); +} + +// Error messages + +void ThrowMissingROM() { + PrintErrorMessageToScreen( + "\x1b[2;2HYou've launched Super Metroid without the rom file." + "\x1b[4;2HPlease relaunch making sure sm.smc exists." + "\x1b[44;2HMade with <3 by snesrev and Lywx" + ); +} \ No newline at end of file diff --git a/src/platform/switch/src/switch_impl.h b/src/platform/switch/src/switch_impl.h new file mode 100644 index 0000000..9962dab --- /dev/null +++ b/src/platform/switch/src/switch_impl.h @@ -0,0 +1,8 @@ +#pragma once + +void SwitchImpl_Init(); +void SwitchImpl_Exit(); + +// Error messages + +void ThrowMissingROM(); \ No newline at end of file diff --git a/src/sm_cpu_infra.c b/src/sm_cpu_infra.c index 338fff8..c9e8415 100644 --- a/src/sm_cpu_infra.c +++ b/src/sm_cpu_infra.c @@ -388,7 +388,6 @@ static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev) { memcpy(&a->ram[0x611], &b->ram[0x611], 6); // coroutine_state (copy from mine to theirs) memcpy(&a->ram[0x77e], &b->ram[0x77e], 5); // my counter memcpy(&a->ram[0xe20], &b->ram[0xe20], 2); // enemy_population_ptr - if (memcmp(b->ram, a->ram, 0x20000)) { fprintf(stderr, "@%d: Memory compare failed (mine != theirs, prev):\n", snes_frame_counter); @@ -502,7 +501,7 @@ int RunAsmCode(uint32 pc, uint16 a, uint16 x, uint16 y, int flags) { bool dc = g_snes->debug_cycles; g_cpu->db = pc >> 16; - + g_cpu->a = a; g_cpu->x = x; g_cpu->y = y; @@ -572,14 +571,12 @@ void RtlUpdateSnesPatchForBugfix() { Snes *SnesInit(const char *filename) { g_snes = snes_init(g_ram); - + g_cpu = g_snes->cpu; - + bool loaded = loadRom(filename, g_snes); if (!loaded) { - char buf[256]; - snprintf(buf, sizeof(buf), "unable to load rom: %s", filename); - Die(buf); + return NULL; } g_sram = g_snes->cart->ram; @@ -601,7 +598,7 @@ Snes *SnesInit(const char *filename) { { uint8 t[2] = { 0x0a, 0x0a }; PatchBytes(0x8584B2, t, 2); } // HandleMessageBoxInteraction has a loop // LoadRoomPlmGfx passes bad value - { uint8 t[] = { 0xc0, 0x00, 0x00, 0xf0, 0x03, 0x20, 0x64, 0x87, 0x60}; PatchBytes(0x84efd3, t, sizeof(t)); } + { uint8 t[] = { 0xc0, 0x00, 0x00, 0xf0, 0x03, 0x20, 0x64, 0x87, 0x60}; PatchBytes(0x84efd3, t, sizeof(t)); } { uint8 t[] = { 0xd3, 0xef }; PatchBytes(0x848243, t, sizeof(t)); } // EprojColl_8676 doesn't initialize Y @@ -629,12 +626,12 @@ Snes *SnesInit(const char *filename) { { uint8 t[] = { 0x18, 0x18, 0x18 }; PatchBytes(0xA98C12, t, sizeof(t)); } { uint8 t[] = { 0x60 }; PatchBytes(0x8085F6, t, sizeof(t)); } - + // Remove 4 frames of delay in reset routine { uint8 t[] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }; PatchBytes(0x80843C, t, sizeof(t)); } { uint8 t[] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }; PatchBytes(0x808475, t, sizeof(t)); } { uint8 t[] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }; PatchBytes(0x808525, t, sizeof(t)); } - + // Remove WaitUntilEndOfVblank in WaitUntilEndOfVblankAndClearHdma - We run frame by frame. { uint8 t[] = { 0x18, 0x18, 0x18, 0x18 }; PatchBytes(0x8882A1, t, sizeof(t)); } @@ -677,7 +674,7 @@ Snes *SnesInit(const char *filename) { // Patch ClearMessageBoxBg3Tilemap { uint8 t[] = { 0x18, 0x18, 0x18 }; PatchBytes(0x858203, t, sizeof(t)); } // WaitForLagFrame { uint8 t[] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }; PatchBytes(0x858236, t, sizeof(t)); } // HandleMusicQueue etc - + // Patch WriteMessageTilemap { uint8 t[] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }; PatchBytes(0x8582B8, t, sizeof(t)); } @@ -834,7 +831,7 @@ again_theirs: again_mine: g_snes->ppu = g_snes->my_ppu; RestoreSnapshot(&g_snapshot_before); - + g_snes->runningWhichVersion = 2; RunOneFrameOfGame(); DrawFrameToPpu(); @@ -903,4 +900,4 @@ void RtlRunFrameCompare(uint16 input, int run_what) { g_use_my_apu_code = true; RunOneFrameOfGame_Both(); } -} \ No newline at end of file +} \ No newline at end of file