18 Commits e493ced631 ... 22047cec12

Author SHA1 Message Date
  somewhatlurker 22047cec12 TLAC slider emulator: more directly emulate input data to avoid tracking section state, testing for ps4 official controller slider support 4 years ago
  somewhatlurker 674d96a6f0 try supporting FT senyou controller 4 years ago
  nastys 65ce65f0d5 [Launcher] Fix default boolean values 4 years ago
  nastys 729989f6fa [Patches] Fix look animation patches overflow causing the mouth animations not to work correctly 4 years ago
  nastys 939de3da22 Revert "Fix mouth patches (hopefully)" 4 years ago
  nastys 4d3a6dca8c Fix mouth patches (hopefully) 4 years ago
  nastys 33b8a9279f [Patches] More graphics settings 4 years ago
  somewhatlurker c98ca5cdbf Novidia: smaller texture uploads when using glTexSubImage 4 years ago
  nastys b1fe9ecc4d [Patches] Hand size option 4 years ago
  nastys 9690ae6b8b [Patches+TLAC] Force toon (NPR1; option in launcher + press F9 to toggle) 4 years ago
  nastys b03aadbd3e [TLAC] Fake coin emulation 4 years ago
  nastys 47388e9a95 [TLAC] Add JVS_SW1 and JVS_SW2 4 years ago
  nastys f7d6b01680 Force PDA/FT look 4 years ago
  nastys 7088eef983 Update config.ini 4 years ago
  nastys bc8d564314 Force PDA/FT mouth/expressions 4 years ago
  nastys acf901811d Re-enable Novidia 4 years ago
  nastys 41b8ecd81f No hand scaling 4 years ago
  nastys 4f3cdd5e0b Quick Startup; Novidia disabled by default; Credits now require coins if Freeplay is disabled on 7.10 4 years ago

+ 57 - 25
source-code/data/plugins/config.ini

@@ -7,7 +7,7 @@
 Enable=1
 
 [GPU]
-# Force GPU model (-1=auto; 0=Kepler; 1=Maxwell; 2=Turing)
+# Force GPU model -- -1=auto, 0=Kepler, 1=Maxwell, 2=Turing
 Model=-1
 
 [Launcher]
@@ -25,49 +25,63 @@ Command_Line=
 Use_divahook_bat=0
 
 [Patches]
+#Disable movies (enable this if the game hangs when loading certain PVs)
+No_Movies=0
+#Enable custom MP4 adv movies (experimental)
+MP4_Movies=1
 #Enable or disable mouse cursor
 Cursor=1
 #Use 2 channels instead of 4 (when not using DivaSound)
 Stereo=1
-#Hide "CREDIT(S)"/"FREE PLAY"
-Hide_Freeplay=0
-#Show "FREE PLAY" instead of "CREDIT(S)"
-Freeplay=1
-#Show "PD Loader <version>" instead of "FREE PLAY"
-PDLoaderText=1
-#Set the card reader and network status icons -- 0=default, 1=hidden, 2=error, 3=OK, 4=partial OK
-Status_Icons=0
+#Skip one or more menus -- 0=disabled, 1=guest, 2=guest+normal
+Quick_Start=1
+#Disable the scrolling sound effect
+No_Scrolling_SFX=0
+#Enhanced Stage Manager (sets a custom number of stages; "stage_manager" should be disabled in "components.ini")
+#Number of stages (0 = disabled)
+Enhanced_Stage_Manager=0
+#Use encore stages or not
+Enhanced_Stage_Manager_Encore=1
+#Change the mouth animations -- 0=default, 1=force PDA, 2=force FT
+Force_Mouth=0
+#Change the expressions -- 0=default, 1=force PDA, 2=force FT
+Force_Expressions=0
+#Change the look animations -- 0=default, 1=force PDA, 2=force FT
+Force_Look=0
+#Disable hand scaling
+No_Hand_Scaling=0
+#Default hand size -- -1=default, 12200=PDA
+Default_Hand_Size=-1
+#Hide the volume and SE control buttons
+Hide_Volume=0
+#Remove the photo controls during PV playback
+No_PV_UI=0
 #Hide the watermark that's usually shown in PV viewing mode
 Hide_PV_Watermark=0
-#Permanently the photo controls during PV playback
-No_PV_UI=0
+#Set the card reader and network status icons -- 0=default, 1=hidden, 2=error, 3=OK, 4=partial OK
+Status_Icons=0
 #Disable showing lyrics
 No_Lyrics=0
-#Disable movies (enable this if the game hangs when loading certain PVs)
-No_Movies=0
-#Enable custom MP4 adv movies (experimental)
-MP4_Movies=1
-#Hide the volume and SE control buttons
-Hide_Volume=0
 #Disable the error banner
 No_Error=1
+#Hide "CREDIT(S)"/"FREE PLAY"
+Hide_Freeplay=0
+#Show "FREE PLAY" instead of "CREDIT(S)" and don't require credits
+Freeplay=1
+#Show "PD Loader" instead of "FREE PLAY"
+PDLoaderText=1
 #Freeze the timer
 No_Timer=1
 #Disable the timer sprite
 No_Timer_Sprite=1
-#Allow using a real arcade slider attached to COM11
-Hardware_Slider=0
-#Enhanced Stage Manager (sets a custom number of stages; "stage_manager" should be disabled in "components.ini")
-#Number of stages (0 = disabled)
-Enhanced_Stage_Manager=0
-#Use encore stages or not
-Enhanced_Stage_Manager_Encore=1
 #Unlock PSEUDO modules (incomplete, will default to Miku)
 Unlock_Pseudo=0
 #Enable the card menu (incomplete, it doesn't bypass the card prompt)
-Card=1
+Card=0
 #Enable custom patches
 Custom_Patches=1
+#Prevent data deletion
+Prevent_Data_Deletion=0
 
 [Graphics]
 # Set to -1 to unlock the frame rate.
@@ -81,6 +95,24 @@ FPS.Limit.Verbose=0
 TAA=1
 # Morphological Anti-Aliasing
 MLAA=1
+# MAG Filter -- 0=default (bilinear), 1=nearest-neighbour, 2=sharpen, 3=cone (smooth)
+MAG=0
+# Depth of Field
+DOF=1
+# Reflections
+Reflections=1
+# Shadows
+Shadows=1
+# Transparent Meshes
+Punchthrough=1
+# Glare
+Glare=1
+# Shader
+Shader=1
+# Toon shader (press F9 to toggle) -- 0=default, 1=force on, 2=force off
+NPR1=0
+# Disable all 3D passes. WARNING: The extended data will be deleted unless Prevent Data Deletion is enabled.
+2D=0
 # FrameRateManager motion rate (fps)
 FRM.Motion.Rate=400
 

+ 12 - 0
source-code/data/plugins/keyconfig.ini

@@ -24,9 +24,19 @@ rumble =true
 # Pause when focus is lost
 autopause =true
 
+# allow using slider in menus
+# (recommended to disable this and remove MENU_L/R bindings if you have a real slider)
+slider_in_menus =false
+
+# use the hardware slider from hori FT official controller
+# warning: alpha untested feature, may not work
+ps4_official_slider =false
+
 # JVS Buttons:
 JVS_TEST = F1
 JVS_SERVICE = F2
+JVS_SW1 = F11
+JVS_SW2 = F12
 
 JVS_START = Enter, Ds4_Options, XINPUT_START, MouseMiddle
 JVS_TRIANGLE = W, I, Ds4_Triangle, Ds4_DPad_Up, Ds4_L_Trigger, Ds4_R_Trigger, XINPUT_Y, XINPUT_UP, XINPUT_LT, XINPUT_RT
@@ -41,6 +51,8 @@ MENU_L = Left, Up, Ds4_L1, XINPUT_LS, Ds4_DPad_Left, Ds4_DPad_Up, XINPUT_LEFT, X
 MENU_R = Right, Down, Ds4_R1, XINPUT_RS, Ds4_DPad_Right, Ds4_DPad_Down, XINPUT_RIGHT, XINPUT_DOWN, E, O, Ds4_L_Stick_Right, XINPUT_LRIGHT, Ds4_L_Stick_Down, XINPUT_LDOWN, Ds4_R_Stick_Right, XINPUT_RRIGHT, Ds4_R_Stick_Down, XINPUT_RDOWN
 MENU_CIRCLE = Spacebar
 
+COIN = F10
+
 # Touch Slider:
 LEFT_SIDE_SLIDE_LEFT = Q, Ds4_L_Stick_Left, XINPUT_LLEFT
 LEFT_SIDE_SLIDE_RIGHT = E, Ds4_L_Stick_Right, XINPUT_LRIGHT

+ 41 - 23
source-code/source/plugins/Launcher/framework.h

@@ -159,61 +159,79 @@ ConfigOptionBase* internalResolutionArray[] = {
 };
 
 ConfigOptionBase* optionsArray[] = {
-	new BooleanOption(L"hide_freeplay", PATCHES_SECTION, CONFIG_FILE, L"Hide \"FREE PLAY\"/\"CREDIT(S)\"", L"Hide the \"FREE PLAY\"/\"CREDIT(S)\" text.", false, false),
-	new BooleanOption(L"freeplay", PATCHES_SECTION, CONFIG_FILE, L"FREE PLAY", L"Show \"FREE PLAY\" instead of \"CREDIT(S)\".", true, false),
-	new BooleanOption(L"pdloadertext", PATCHES_SECTION, CONFIG_FILE, L"PD Loader FREE PLAY", L"Show \"PD Loader\" instead of \"FREE PLAY\".", true, false),
-	new OptionMetaSpacer(8),
-
 	new BooleanOption(L"no_movies", PATCHES_SECTION, CONFIG_FILE, L"Disable Movies", L"Disable movies (enable this if the game hangs when loading certain PVs).", false, false),
 	new BooleanOption(L"mp4_movies", PATCHES_SECTION, CONFIG_FILE, L"Custom MP4 Adv Movies", L"Enable MP4 (instead of WMV) advertise/attract movies.", false, false),
-	new OptionMetaSpacer(8),
-
 	new BooleanOption(L"cursor", PATCHES_SECTION, CONFIG_FILE, L"Cursor", L"Enable or disable the mouse cursor.", true, false),
 	new BooleanOption(L"stereo", PATCHES_SECTION, CONFIG_FILE, L"Stereo", L"Use 2 channels instead of 4 (when not using DivaSound).", true, false),
+	new OptionMetaSpacer(8),
+
+	new DropdownOption(L"quick_start", PATCHES_SECTION, CONFIG_FILE, L"Quick Start:", L"Skip one or more menus.", 1, std::vector<LPCWSTR>({ L"Disabled", L"Guest", L"Guest + Normal" })),
+	new BooleanOption(L"no_scrolling_sfx", PATCHES_SECTION, CONFIG_FILE, L"Disable Scrolling SFX", L"Disable the scrolling sound effect.", false, false),
+	new OptionMetaSpacer(8),
+
+	new NumericOption(L"Enhanced_Stage_Manager", PATCHES_SECTION, CONFIG_FILE, L"Number of Stages:", L"Set the number of stages (0 = default).", 0, 0, INT_MAX),
+	new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"Encore", L"Enable encore stages.", true, false),
+	new OptionMetaSpacer(8),
+
+	new DropdownOption(L"force_mouth", PATCHES_SECTION, CONFIG_FILE, L"Mouth Type:", L"Change the mouth animations.", 0, std::vector<LPCWSTR>({ L"Default", L"Force PDA", L"Force FT" })),
+	new DropdownOption(L"force_expressions", PATCHES_SECTION, CONFIG_FILE, L"Expression Type:", L"Change the expressions.", 0, std::vector<LPCWSTR>({ L"Default", L"Force PDA", L"Force FT" })),
+	new DropdownOption(L"force_look", PATCHES_SECTION, CONFIG_FILE, L"Look Type:", L"Change the look animations.", 0, std::vector<LPCWSTR>({ L"Default", L"Force PDA", L"Force FT" })),
+	new BooleanOption(L"no_hand_scaling", PATCHES_SECTION, CONFIG_FILE, L"No Hand Scaling", L"Disable hand scaling.", false, false),
+	new NumericOption(L"default_hand_size", PATCHES_SECTION, CONFIG_FILE, L"Default Hand Size:", L"-1: default\n12200: PDA", -1, -1, INT_MAX),
+	new OptionMetaSpacer(8),
+
 	new BooleanOption(L"hide_volume", PATCHES_SECTION, CONFIG_FILE, L"Hide Volume Buttons", L"Hide the volume and SE control buttons.", false, false),
 	new BooleanOption(L"no_pv_ui", PATCHES_SECTION, CONFIG_FILE, L"Disable PV UI", L"Remove the photo controls during PV playback.", false, false),
 	new BooleanOption(L"hide_pv_watermark", PATCHES_SECTION, CONFIG_FILE, L"Hide PV Watermark", L"Hide the watermark that's usually shown in PV viewing mode.", false, false),
+	new DropdownOption(L"status_icons", PATCHES_SECTION, CONFIG_FILE, L"Network Status Icons:", L"Set the state of card reader and network status icons.", 3, std::vector<LPCWSTR>({ L"Default", L"Hidden", L"Error", L"OK", L"Partial OK" })),
 	new BooleanOption(L"no_lyrics", PATCHES_SECTION, CONFIG_FILE, L"Disable Lyrics", L"Disable showing lyrics.", false, false),
 	new BooleanOption(L"no_error", PATCHES_SECTION, CONFIG_FILE, L"Disable Error Banner", L"Disable the error banner on the attract screen.", true, false),
+	new BooleanOption(L"hide_freeplay", PATCHES_SECTION, CONFIG_FILE, L"Hide \"FREE PLAY\"/\"CREDIT(S)\"", L"Hide the \"FREE PLAY\"/\"CREDIT(S)\" text.", false, false),
+	new BooleanOption(L"freeplay", PATCHES_SECTION, CONFIG_FILE, L"FREE PLAY", L"Show \"FREE PLAY\" instead of \"CREDIT(S)\" and don't require credits.", true, false),
+	new BooleanOption(L"pdloadertext", PATCHES_SECTION, CONFIG_FILE, L"PD Loader FREE PLAY", L"Show \"PD Loader\" instead of \"FREE PLAY\".", true, false),
 	new BooleanOption(L"no_timer", PATCHES_SECTION, CONFIG_FILE, L"Freeze Timer", L"Disable the timer.", true, false),
 	new BooleanOption(L"no_timer_sprite", PATCHES_SECTION, CONFIG_FILE, L"Disable Timer Sprite", L"Disable the timer sprite.", true, false),
-	new DropdownOption(L"status_icons", PATCHES_SECTION, CONFIG_FILE, L"Status Icons:", L"Set the state of card reader and network status icons.", 3, std::vector<LPCWSTR>({ L"Default", L"Hidden", L"Error", L"OK", L"Partial OK" })),
-	new OptionMetaSpacer(8),
-
-	new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"Encore Stages", L"Enable encore stages.", true, false),
-	new NumericOption(L"Enhanced_Stage_Manager", PATCHES_SECTION, CONFIG_FILE, L"Number of stages:", L"Set the number of stages (0 = default).", 0, 0, INT_MAX),
 	new OptionMetaSpacer(8),
 
 	new BooleanOption(L"unlock_pseudo", PATCHES_SECTION, CONFIG_FILE, L"Unlock PSEUDO modules (incomplete)", L"Lets you play any PV with any performer.\n(incomplete, recommended modules will default to Miku)", false, false),
-	new BooleanOption(L"card", PATCHES_SECTION, CONFIG_FILE, L"Unlock card menu (incomplete)", L"Enables the card menu.\n(incomplete, it doesn't bypass the card prompt)", true, false),
-	new OptionMetaSpacer(8),
-
-	new BooleanOption(L"hardware_slider", PATCHES_SECTION, CONFIG_FILE, L"Use Hardware Slider", L"Enable this if using a real arcade slider.\n(set the slider to port COM11)", false, false),
+	new BooleanOption(L"card", PATCHES_SECTION, CONFIG_FILE, L"Unlock card menu (incomplete)", L"Enables the card menu.\n(incomplete, it doesn't bypass the card prompt)", false, false),
 	new OptionMetaSpacer(8),
 
 	new BooleanOption(L"TAA", GRAPHICS_SECTION, CONFIG_FILE, L"TAA", L"Temporal Anti-Aliasing", true, false),
 	new BooleanOption(L"MLAA", GRAPHICS_SECTION, CONFIG_FILE, L"MLAA", L"Morphological Anti-Aliasing", true, false),
+	new DropdownOption(L"MAG", GRAPHICS_SECTION, CONFIG_FILE, L"Filter:", L"Image filter.\n\nBilinear: default filter\nNearest-neighbour: sharpest, but blocky\nSharpen: sharp filter\nCone: smooth filter", 0, std::vector<LPCWSTR>({ L"Bilinear (default)", L"Nearest-neighbour", L"Sharpen", L"Cone" })),
+	new BooleanOption(L"DOF", GRAPHICS_SECTION, CONFIG_FILE, L"Depth of Field", L"Blurs the background. Disable for better performance.", true, false),
+	new BooleanOption(L"reflections", GRAPHICS_SECTION, CONFIG_FILE, L"Reflections", L"Enable or disable reflections.", true, false),
+	new BooleanOption(L"shadows", GRAPHICS_SECTION, CONFIG_FILE, L"Shadows", L"Enable or disable shadows.", true, false),
+	new BooleanOption(L"punchthrough", GRAPHICS_SECTION, CONFIG_FILE, L"Transparent Meshes", L"Show transparent meshes.", true, false),
+	new BooleanOption(L"glare", GRAPHICS_SECTION, CONFIG_FILE, L"Glare", L"Enable or disable glare.", true, false),
+	new BooleanOption(L"shader", GRAPHICS_SECTION, CONFIG_FILE, L"Shader", L"Enable or disable high-quality shaders.", true, false),
+	new DropdownOption(L"NPR1", GRAPHICS_SECTION, CONFIG_FILE, L"Toon (F9):", L"NPR1 shader\n\nPress F9 to toggle.", 0, std::vector<LPCWSTR>({ L"Default", L"Force on", L"Force off" })),
+	new BooleanOption(L"2D", GRAPHICS_SECTION, CONFIG_FILE, L"Disable 3D rendering", L"Disable all 3D passes.\n\nWARNING: The extended data will be deleted unless Prevent Data Deletion is enabled.", false, false),
+	new OptionMetaSpacer(8),
+
 	new BooleanOption(L"FPS.Limit.LightMode", GRAPHICS_SECTION, CONFIG_FILE, L"Use Lightweight Limiter", L"Makes the FPS limiter use less CPU.\nMay have less consistent performance.", true, false),
 	new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Allows you to set a frame rate cap. Set to -1 to unlock the frame rate.", 60, -1, INT_MAX),
 	new NumericOption(L"frm.motion.rate", GRAPHICS_SECTION, CONFIG_FILE, L"FRM Motion Rate:", L"Sets the motion rate (fps) for the Frame Rate Manager component.\nLarger values should be smoother, but more CPU intensive and possibly buggier.", 300, 1, INT_MAX),
 	new OptionMetaSpacer(8),
 
-	new BooleanOption(L"autopause", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Pause automatically", L"Pause when focus is lost.", true, true),
+	new BooleanOption(L"autopause", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Pause Automatically", L"Pause when focus is lost.", true, true),
 	new OptionMetaSpacer(8),
 
 	new BooleanOption(L"rumble", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Rumble", L"Enables rumble during chainslides.", true, true),
 	new NumericOption(L"xinput_preferred", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Controller Num:", L"Sets the preferred XInput controller.\nIf unavailable, the next connected controller is used.", 0, 0, 3),
 	new OptionMetaSpacer(8),
-	
-	new BooleanOption(L"opengl_patch_a", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch A", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", L"", false),
-	new BooleanOption(L"opengl_patch_b", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch B", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", L"", false),
+
+	new BooleanOption(L"opengl_patch_a", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch A", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false),
+	new BooleanOption(L"opengl_patch_b", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch B", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false),
 	new OptionMetaSpacer(8),
 
-	new BooleanOption(L"custom_patches", PATCHES_SECTION, CONFIG_FILE, L"Enable custom patches", L"Enables all custom patches.", true, false),
-	new BooleanOption(L"no_gpu_dialog", LAUNCHER_SECTION, CONFIG_FILE, L"Disable GPU Warning", L"Disables the warning dialog for unsupported GPUs.", L"", false),
+	new BooleanOption(L"custom_patches", PATCHES_SECTION, CONFIG_FILE, L"Enable Custom Patches", L"Enables all custom patches.", true, false),
+	new BooleanOption(L"no_gpu_dialog", LAUNCHER_SECTION, CONFIG_FILE, L"Disable GPU Warning", L"Disables the warning dialog for unsupported GPUs.", false, false),
 	//new BooleanOption(L"ignore_exe_checksum", PATCHES_SECTION, CONFIG_FILE, L"Ignore exe checksum", L"Use at your own risk.", false, false),
+	new BooleanOption(L"prevent_data_deletion", PATCHES_SECTION, CONFIG_FILE, L"Prevent Data Deletion", L"Prevents the game from deleting files.", false, false),
 	new StringOption(L"command_line", LAUNCHER_SECTION, CONFIG_FILE, L"Command Line:", L"Allows setting command line parameters for the game when using the launcher.\nDisabling the launcher will bypass this.", L"", false),
-	new BooleanOption(L"use_divahook_bat", LAUNCHER_SECTION, CONFIG_FILE, L"Use divahook.bat", L"Launches divahook.bat intead of diva.exe.", L"", false),
+	new BooleanOption(L"use_divahook_bat", LAUNCHER_SECTION, CONFIG_FILE, L"Use divahook.bat", L"Launches divahook.bat intead of diva.exe.", false, false),
 };
 
 ConfigOptionBase* playerdataArray[] = {

+ 8 - 1
source-code/source/plugins/Novidia/src/dllmain.cpp

@@ -7,20 +7,27 @@
 // two versions because apparently TexSubImage can cause major stuttering
 void h_uploadModelTransformBuf_TexImage(DWORD* a1, int a2)
 {
+	if (a2 > 0x100)
+		return;
+
 	uploadModelTransformBuf(a1, a2);
 	
 	glActiveTexture(GL_TEXTURE8);
 	glBindTexture(GL_TEXTURE_1D, buf_tex);
+	// can't change tex size without making shader sad :(
 	glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 0x3000 / sizeof(float) / 4, 0, tex_upload_format, GL_FLOAT, *(float**)0x1411a3330);
 	glActiveTexture(GL_TEXTURE0);
 }
 void h_uploadModelTransformBuf_TexSubImage(DWORD* a1, int a2)
 {
+	if (a2 > 0x100)
+		return;
+
 	uploadModelTransformBuf(a1, a2);
 
 	glActiveTexture(GL_TEXTURE8);
 	glBindTexture(GL_TEXTURE_1D, buf_tex);
-	glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 0x3000 / sizeof(float) / 4, tex_upload_format, GL_FLOAT, *(float**)0x1411a3330);
+	glTexSubImage1D(GL_TEXTURE_1D, 0, 0, a2 * 3, tex_upload_format, GL_FLOAT, *(float**)0x1411a3330);
 	glActiveTexture(GL_TEXTURE0);
 }
 

+ 303 - 8
source-code/source/plugins/Patches/dllmain.cpp

@@ -137,8 +137,6 @@ void ApplyPatches() {
 	};
 	const struct { void* Address; std::vector<uint8_t> Data; } patches_710[] =
 	{
-		// Always return true for the SelCredit enter SelPv check
-		{ (void*)0x0000000140393610, { 0xB0, 0x01, 0xC3, 0x90, 0x90, 0x90 } },
 		// Just completely ignore all SYSTEM_STARTUP errors
 		{ (void*)0x00000001403F5080, { 0xC3 } },
 		// Always exit TASK_MODE_APP_ERROR on the first frame
@@ -176,6 +174,8 @@ void ApplyPatches() {
 		{ (void*)0x0000000140136CFA,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } },
 		// enable module selector without use_card
 		{ (void*)0x00000001405C513B,{ 0x01 } },
+		// fix back button
+		{ (void*)0x0000000140578FB8, { 0xE9, 0x73, 0xFF, 0xFF, 0xFF } },
 		// Force Hide IDs
 		{ (void*)0x00000001409A5918, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
 		{ (void*)0x00000001409A5928, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
@@ -222,8 +222,26 @@ void ApplyPatches() {
 	auto nOGLPatchB = GetPrivateProfileIntW(L"patches", L"opengl_patch_b", FALSE, CONFIG_FILE);
 	auto nTAA = GetPrivateProfileIntW(L"graphics", L"taa", TRUE, CONFIG_FILE);
 	auto nMLAA = GetPrivateProfileIntW(L"graphics", L"mlaa", TRUE, CONFIG_FILE);
+	auto nDoF = GetPrivateProfileIntW(L"graphics", L"dof", TRUE, CONFIG_FILE);
+	auto nMAG = GetPrivateProfileIntW(L"graphics", L"mag", 0, CONFIG_FILE);
 	auto nStereo = GetPrivateProfileIntW(L"patches", L"stereo", TRUE, CONFIG_FILE);
 	auto nCustomPatches = GetPrivateProfileIntW(L"patches", L"custom_patches", TRUE, CONFIG_FILE);
+	auto nQuickStart = GetPrivateProfileIntW(L"patches", L"quick_start", 1, CONFIG_FILE);
+	auto nNoScrollingSfx = GetPrivateProfileIntW(L"patches", L"no_scrolling_sfx", FALSE, CONFIG_FILE);
+	auto nNoHandScaling = GetPrivateProfileIntW(L"patches", L"no_hand_scaling", FALSE, CONFIG_FILE);
+	auto nDefaultHandSize = GetPrivateProfileIntW(L"patches", L"default_hand_size", -1, CONFIG_FILE);
+	auto nForceMouth = GetPrivateProfileIntW(L"patches", L"force_mouth", 0, CONFIG_FILE);
+	auto nForceExpressions = GetPrivateProfileIntW(L"patches", L"force_expressions", 0, CONFIG_FILE);
+	auto nForceLook = GetPrivateProfileIntW(L"patches", L"force_look", 0, CONFIG_FILE);
+	auto nNpr1 = GetPrivateProfileIntW(L"graphics", L"npr1", 0, CONFIG_FILE);
+	auto nReflections = GetPrivateProfileIntW(L"graphics", L"reflections", TRUE, CONFIG_FILE);
+	auto nShadows = GetPrivateProfileIntW(L"graphics", L"shadows", TRUE, CONFIG_FILE);
+	auto nPunchthrough = GetPrivateProfileIntW(L"graphics", L"punchthrough", TRUE, CONFIG_FILE);
+	auto nGlare = GetPrivateProfileIntW(L"graphics", L"glare", TRUE, CONFIG_FILE);
+	auto nShader = GetPrivateProfileIntW(L"graphics", L"shader", TRUE, CONFIG_FILE);
+	auto n2D = GetPrivateProfileIntW(L"graphics", L"2D", FALSE, CONFIG_FILE);
+	auto nNoDelete = GetPrivateProfileIntW(L"patches", L"prevent_data_deletion", FALSE, CONFIG_FILE);
+
 
 	std::string version_string = std::to_string(game_version);
 	version_string.insert(version_string.begin()+1, '.');
@@ -285,7 +303,7 @@ void ApplyPatches() {
 			*((byte*)0x000000014049258A + 2) = 0x90;
 			VirtualProtect((BYTE*)0x000000014049258A, 3, oldProtect, &bck); }
 
-			printf("[TLAC] MLAA disabled\n");
+			printf("[Patches] MLAA disabled\n");
 		}
 
 		// Replace the hardcoded videos with MP4s, if they exist
@@ -554,7 +572,7 @@ void ApplyPatches() {
 			*((byte*)0x00000001404AB11A + 2) = 0x90;
 			VirtualProtect((BYTE*)0x00000001404AB11A, 3, oldProtect, &bck); }
 
-			printf("[TLAC] MLAA disabled\n");
+			printf("[Patches] MLAA disabled\n");
 		}
 
 		// Replace the hardcoded videos with MP4s, if they exist
@@ -577,6 +595,9 @@ void ApplyPatches() {
 		// Enable "FREE PLAY" mode
 		if (nFreeplay || nHideFreeplay)
 		{
+			// Always return true for the SelCredit enter SelPv check
+			InjectCode((void*)0x0000000140393610, { 0xB0, 0x01, 0xC3, 0x90, 0x90, 0x90 });
+
 			InjectCode((void*)0x00000001403BABEA, { 0x75 });
 			printf("[Patches] Show FREE PLAY instead of CREDIT(S)\n");
 
@@ -765,11 +786,285 @@ void ApplyPatches() {
 		{
 			InjectCode((void*)0x0000000140565E6B, { 0x90, 0x90 });
 		}
-		// The original slider update needs to run for hardware sliders to work -- only patch it when using emulation
-		if (!nHardwareSlider)
+		// Quick start
 		{
-			// Don't update the touch slider state so we can write our own
-			InjectCode((void*)0x000000014061579B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 });
+			if (nQuickStart == 1) // skip the card/guest screen
+			{
+				InjectCode((void*)0x0000000140578EA9, { 0xE9, 0x8E, 0x00, 0x00, 0x00 });
+			}
+			else if (nQuickStart == 2) // skip everything; normal mode
+			{
+				InjectCode((void*)0x0000000140578EA9, { 0xE9, 0xF1, 0x00, 0x00, 0x00 });
+				InjectCode((void*)0x0000000140578E9D, { 0xC7, 0x47, 0x68, 0x28, 0x00, 0x00, 0x00 }); // skip back button error
+			}
+		}
+		// Disable scrolling sound effect
+		if (nNoScrollingSfx)
+		{
+			InjectCode((void*)0x00000001405C84B3, { 0x90, 0x90, 0x90, 0x90, 0x90 });
+		}
+		// Disable hand scaling
+		if (nNoHandScaling)
+		{
+			InjectCode((void*)0x0000000140120709, { 0xE9, 0x82, 0x0A, 0x00 });
+		}
+		// Default hand size
+		if (nDefaultHandSize != -1)
+		{
+			printf("[Patches] Changing default hand size...\n");
+			const float num = (float)nDefaultHandSize / 10000.0;
+			DWORD oldProtect;
+			float* addr1 = (float*)(0x140506B59);
+			float* addr2 = (float*)(0x140506B60);
+			/*float* addr3 = (float*)(0x140506B67);
+			float* addr4 = (float*)(0x140506B71);*/
+			VirtualProtect(addr1, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
+			VirtualProtect(addr2, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
+			/*VirtualProtect(addr3, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
+			VirtualProtect(addr4, 4, PAGE_EXECUTE_READWRITE, &oldProtect);*/
+			*addr1 = *addr2 /*= *addr3 = *addr4*/ = num;
+			VirtualProtect(addr1, 4, oldProtect, nullptr);
+			VirtualProtect(addr2, 4, oldProtect, nullptr);
+			/*VirtualProtect(addr3, 4, oldProtect, nullptr);
+			VirtualProtect(addr4, 4, oldProtect, nullptr);*/
+			printf("[Patches] New default hand size: %f\n", num);
+		}
+		// Force mouth animations
+		{
+			if (nForceMouth == 1) // PDA
+			{
+				printf("[Patches] Forcing PDA mouth...\n");
+				int* mouth_table = (int*)(0x1409A1DC0);
+				DWORD oldProtect;
+				VirtualProtect(mouth_table, 44, PAGE_EXECUTE_READWRITE, &oldProtect);
+				for (int i = 0; i < 11; i++)
+				{
+					mouth_table[i]++;
+				}
+				VirtualProtect(mouth_table, 44, oldProtect, nullptr);
+				printf("[Patches] PDA mouth forced\n");
+			}
+			else if (nForceMouth == 2) // FT
+			{
+				printf("[Patches] Forcing FT mouth...\n");
+				int* mouth_table_oldid = (int*)(0x1409A1E1C);
+				DWORD oldProtect;
+				VirtualProtect(mouth_table_oldid, 44, PAGE_EXECUTE_READWRITE, &oldProtect);
+				for (int i = 0; i < 11; i++)
+				{
+					mouth_table_oldid[i]--;
+				}
+				VirtualProtect(mouth_table_oldid, 44, oldProtect, nullptr);
+				printf("[Patches] FT mouth forced\n");
+			}
+		}
+		// Force expressions
+		{
+			if (nForceExpressions == 1) // PDA
+			{
+				printf("[Patches] Forcing PDA expressions...\n");
+				int* exp_table = (int*)(0x140A21900);
+				DWORD oldProtect;
+				VirtualProtect(exp_table, 104, PAGE_EXECUTE_READWRITE, &oldProtect);
+				for (int i = 0; i < 26; i++)
+				{
+					exp_table[i] += 2;
+				}
+				VirtualProtect(exp_table, 104, oldProtect, nullptr);
+				printf("[Patches] PDA expressions forced\n");
+			}
+			else if (nForceExpressions == 2) // FT
+			{
+				printf("[Patches] Forcing FT expressions...\n");
+				int* exp_table_oldid = (int*)(0x140A219D0);
+				DWORD oldProtect;
+				VirtualProtect(exp_table_oldid, 104, PAGE_EXECUTE_READWRITE, &oldProtect);
+				for (int i = 0; i < 26; i++)
+				{
+					exp_table_oldid[i] -= 2;
+				}
+				VirtualProtect(exp_table_oldid, 104, oldProtect, nullptr);
+				printf("[Patches] FT expressions forced\n");
+			}
+		}
+		// Force look animations
+		{
+			if (nForceLook == 1) // PDA
+			{
+				printf("[Patches] Forcing PDA look...\n");
+				int* look_table = (int*)(0x1409A1D70);
+				DWORD oldProtect;
+				VirtualProtect(look_table, 36, PAGE_EXECUTE_READWRITE, &oldProtect);
+				for (int i = 0; i < 9; i++)
+				{
+					look_table[i]++;
+				}
+				VirtualProtect(look_table, 36, oldProtect, nullptr);
+				printf("[Patches] PDA look forced\n");
+			}
+			else if (nForceLook == 2) // FT
+			{
+				printf("[Patches] Forcing FT look...\n");
+				int* look_table_oldid = (int*)(0x1409A1D9C);
+				DWORD oldProtect;
+				VirtualProtect(look_table_oldid, 36, PAGE_EXECUTE_READWRITE, &oldProtect);
+				for (int i = 0; i < 9; i++)
+				{
+					look_table_oldid[i]--;
+				}
+				VirtualProtect(look_table_oldid, 36, oldProtect, nullptr);
+				printf("[Patches] FT look forced\n");
+			}
+		}
+		// NPR1
+		{
+			if (nNpr1 == 1) // force on
+			{
+				InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E });
+				InjectCode((void*)0x0000000140502FC6, { 0x01, 0x00, 0x00, 0x00, 0xC3 });
+
+				printf("[Patches] NPR1 forced\n");
+			}
+			else if (nNpr1 == 2) // force off
+			{
+				InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E });
+				InjectCode((void*)0x0000000140502FC6, { 0x00, 0x00, 0x00, 0x00, 0xC3 });
+
+				printf("[Patches] NPR1 disabled\n");
+			}
+		}
+		// Depth of Field
+		if (!nDoF)
+		{
+			InjectCode((void*)0x00000001409476AB, { 0x90, 0x90, 0x90, 0x90, 0x90 });
+
+			InjectCode((void*)0x00000001411AB650, { 0b00000001 });
+		}
+		// MAG filter
+		if (nMAG > 0)
+		{
+			//InjectCode((void*)0x00000001404AB142, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+
+			unsigned char filter;
+			switch (nMAG)
+			{
+			case 1: // nearest
+				filter = 0;
+				InjectCode((void*)0x00000001404ACE56, { 0x90, 0x90 });
+				break;
+			case 2: // sharpen
+				filter = 3; // sharpen(4tap)
+				break;
+			case 3: // cone
+				filter = 5; // cone(2tap)
+				break;
+			default:
+				filter = 1;
+			}
+			
+			//InjectCode((void*)0x00000001404A864F, { filter });
+			//InjectCode((void*)0x00000001411AC518, { filter });
+
+			InjectCode((void*)0x00000001404ACE8E, { 0xB9, filter, 0x00, 0x00 });
+			InjectCode((void*)0x00000001404ACE93, { 0x90 });
+		}
+		// Reflections
+		if (!nReflections)
+		{	
+			InjectCode((void*)0x1406477C0, { 0xE9, 0xF3, 0x00, 0x00, 0x00, 0x90 });
+			InjectCode((void*)0x1411ADAFC, { 0x00 });
+		}
+		// Shadows
+		if (!nShadows)
+		{
+			//InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 });
+			//InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)0x140502766, { 0x00 });
+			InjectCode((void*)0x1411AD438, { 0x00 });
+			InjectCode((void*)0x1411AD320, { 0x00 });
+		}
+		// Punch-through transparency
+		if (!nPunchthrough)
+		{
+			InjectCode((void*)0x1411AD43D, { 0x00 });
+		}
+		// Glare
+		if (!nGlare)
+		{
+			InjectCode((void*)0x1404B2168, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+		}
+		// Shader
+		if (!nShader)
+		{
+			InjectCode((void*)0x140C9C48E, { 0x00 });
+		}
+		// 2D
+		if (n2D)
+		{
+			//InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 });
+			InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)0x140502A3C, { 0x90, 0x90, 0x90, 0x90, 0x90 });
+			/*InjectCode((void*)0x1411AD320, { 0x00 }); // shadow
+			InjectCode((void*)0x1411AD323, { 0x00 }); // reflect
+			InjectCode((void*)0x1411AD321, { 0x00 }); // SS_SSS
+			InjectCode((void*)0x1411AD325, { 0x00 }); // preprocess
+			InjectCode((void*)0x1411AD328, { 0x00 }); // 3D*/
+			InjectCode((void*)0x1411AD32A, { 0x01 }); // post process
+			InjectCode((void*)0x1411AD32B, { 0x01 }); // sprite
+
+			InjectCode((void*)0x140A07920, { 0x00 }); // ignore objset
+		}
+		// Prevent data deletion
+		if (nNoDelete)
+		{
+			InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140712270 + 0x6C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140712270 + 0x6E), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x14081B6A4), { 0xC3 });
+
+			InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
+			InjectCode((void*)(0x14081B67A), { 0xC3 });
 		}
 	}
 

+ 58 - 1
source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp

@@ -14,6 +14,7 @@
 #include "../../FileSystem/ConfigFile.h"
 #include "../GameState.h"
 #include "../Pause.h"
+#include "../../Utils.h"
 
 const std::string KEY_CONFIG_FILE_NAME = "keyconfig.ini";
 
@@ -63,6 +64,8 @@ namespace TLAC::Components
 
 		TestBinding = new Binding();
 		ServiceBinding = new Binding();
+		Sw1Binding = new Binding();
+		Sw2Binding = new Binding();
 		StartBinding = new Binding();
 
 		SankakuBinding = new Binding();
@@ -78,11 +81,15 @@ namespace TLAC::Components
 
 		MenuCircleBinding = new Binding();
 
+		CoinBinding = new Binding();
+
 		FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), KEY_CONFIG_FILE_NAME);
 		configFile.OpenRead();
 
 		Config::BindConfigKeys(configFile.ConfigMap, "JVS_TEST", *TestBinding, { "F1" });
 		Config::BindConfigKeys(configFile.ConfigMap, "JVS_SERVICE", *ServiceBinding, { "F2" });
+		Config::BindConfigKeys(configFile.ConfigMap, "JVS_SW1", *Sw1Binding, { "F11" });
+		Config::BindConfigKeys(configFile.ConfigMap, "JVS_SW2", *Sw2Binding, { "F12" });
 		Config::BindConfigKeys(configFile.ConfigMap, "JVS_START", *StartBinding, { "Enter" });
 		Config::BindConfigKeys(configFile.ConfigMap, "JVS_TRIANGLE", *SankakuBinding, { "W", "I" });
 		Config::BindConfigKeys(configFile.ConfigMap, "JVS_SQUARE", *ShikakuBinding, { "A", "J" });
@@ -93,6 +100,7 @@ namespace TLAC::Components
 		Config::BindConfigKeys(configFile.ConfigMap, "MENU_L", *MenuLBinding, { "Left", "Up" });
 		Config::BindConfigKeys(configFile.ConfigMap, "MENU_R", *MenuRBinding, { "Down", "Right" });
 		Config::BindConfigKeys(configFile.ConfigMap, "MENU_CIRCLE", *MenuCircleBinding, { "D", "L", "Spacebar" });
+		Config::BindConfigKeys(configFile.ConfigMap, "COIN", *CoinBinding, { "F10" });
 
 		mouseScrollPvSelection = configFile.GetBooleanValue("mouse_scroll_pv_selection");
 	}
@@ -269,6 +277,10 @@ namespace TLAC::Components
 			buttons |= JVS_TEST;
 		if (buttonTestFunc(ServiceBinding))
 			buttons |= JVS_SERVICE;
+		if (buttonTestFunc(Sw1Binding))
+			buttons |= JVS_SW1;
+		if (buttonTestFunc(Sw2Binding))
+			buttons |= JVS_SW2;
 
 		if (buttonTestFunc(StartBinding))
 			buttons |= JVS_START;
@@ -287,6 +299,9 @@ namespace TLAC::Components
 		if (buttonTestFunc(RightBinding))
 			buttons |= JVS_R;
 
+		if (buttonTestFunc(CoinBinding))
+			addCoin();
+
 		return buttons;
 	}
 
@@ -330,6 +345,9 @@ namespace TLAC::Components
 		if (keyboard->IsIntervalTapped(VK_SPACE))
 			inputKey = 0x20;
 
+		if (keyboard->IsIntervalTapped(VK_F9))
+			toggleNpr1();
+
 		if (keyboard->IsDoubleTapped(VK_ESCAPE))
 			*(bool*)SHOULD_EXIT_BOOL_ADDRESS = true;
 
@@ -390,7 +408,7 @@ namespace TLAC::Components
 	void InputEmulator::SetMetaButtons()
 	{
 		// bit 0x6e is used to skip a bunch of screens
-		if ((inputState->Down.Buttons & (JVS_L | JVS_R)) == 0) // ask sega okay? idk why this is needed
+		if ((inputState->Down.Buttons & (JVS_L | JVS_R)) == 0) // ask sega, okay? idk why this is needed
 		{
 			if ((inputState->Tapped.Buttons & (JVS_START | JVS_TRIANGLE | JVS_SQUARE | JVS_CROSS | JVS_CIRCLE)) != 0)
 				inputState->SetBit(0x6e, true, InputBufferType_Tapped);
@@ -408,4 +426,43 @@ namespace TLAC::Components
 				inputState->SetBit(0x6e, false, InputBufferType_Released);
 		}
 	}
+
+	void InputEmulator::addCoin()
+	{
+		printf("[TLAC] Adding coin\n");
+		unsigned char* credits = (unsigned char*)0x14CD93788;
+		if (*credits < 9)
+		{
+			*(unsigned char*)0x14CD93A9C = 1;
+			(*credits)++;
+			(*(unsigned char*)0x14CD93A98)++;
+			if ((*(unsigned char*)0x14CD93A98) == 0) (*(unsigned char*)0x14CD93A98)++;
+		}
+	}
+
+	void InputEmulator::toggleNpr1()
+	{
+		switch(*(byte*)0x0000000140502FC6)
+		{
+		case 0xC3: // default -> force on
+			InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E });
+			InjectCode((void*)0x0000000140502FC6, { 0x01, 0x00, 0x00, 0x00, 0xC3 });
+			*(byte*)0x00000001411AD638 = 1;
+
+			printf("[TLAC] NPR1 forced\n");
+			break;
+		case 0x01: // default -> force off
+			InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E });
+			InjectCode((void*)0x0000000140502FC6, { 0x00, 0x00, 0x00, 0x00, 0xC3 });
+			*(byte*)0x00000001411AD638 = 0;
+
+			printf("[TLAC] NPR1 disabled\n");
+			break;
+		default: // force off -> default
+			InjectCode((void*)0x0000000140502FC0, { 0x89, 0x0D, 0x72 });
+			InjectCode((void*)0x0000000140502FC6, { 0xC3, 0xCC, 0xCC, 0xCC, 0xCC });
+
+			printf("[TLAC] NPR1 restored\n");
+		}
+	}
 }

+ 7 - 0
source-code/source/plugins/TLAC/Components/Input/InputEmulator.h

@@ -22,6 +22,8 @@ namespace TLAC::Components
 	public:
 		Input::Binding* TestBinding;
 		Input::Binding* ServiceBinding;
+		Input::Binding* Sw1Binding;
+		Input::Binding* Sw2Binding;
 
 		Input::Binding* StartBinding;
 		Input::Binding* SankakuBinding;
@@ -36,6 +38,8 @@ namespace TLAC::Components
 		Input::Binding* MenuRBinding;
 		Input::Binding* MenuCircleBinding;
 
+		Input::Binding* CoinBinding;
+
 		InputEmulator();
 		~InputEmulator();
 
@@ -104,5 +108,8 @@ namespace TLAC::Components
 		void UpdateInputBit(uint32_t bit, uint8_t keycode);
 		void UpdateSliderLR();
 		void SetMetaButtons();
+
+		void addCoin();
+		void toggleNpr1();
 	};
 }

+ 62 - 27
source-code/source/plugins/TLAC/Components/Input/TouchSliderEmulator.cpp

@@ -6,6 +6,7 @@
 #include "../../Input/Keyboard/Keyboard.h"
 #include "../../Input/Bindings/KeyboardBinding.h"
 #include "../../Input/KeyConfig/Config.h"
+#include "../../Input/DirectInput/Ds4/DualShock4.h"
 #include "../../FileSystem/ConfigFile.h"
 #include "../../Utilities/Math.h"
 #include <algorithm>
@@ -55,16 +56,22 @@ namespace TLAC::Components
 		FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), KEY_CONFIG_FILE_NAME);
 		configFile.OpenRead();
 
-		Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_LEFT", *LeftSideSlideLeft, { "Q" });
-		Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_RIGHT", *LeftSideSlideRight, { "E" });
+		usePs4OfficialSlider = configFile.GetBooleanValue("ps4_official_slider");
+		enableInMenus = configFile.GetBooleanValue("slider_in_menus");
 
-		Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_LEFT", *RightSideSlideLeft, { "U" });
-		Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_RIGHT", *RightSideSlideRight, { "O" });
+		if (!usePs4OfficialSlider)
+		{
+			Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_LEFT", *LeftSideSlideLeft, { "Q" });
+			Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_RIGHT", *LeftSideSlideRight, { "E" });
+
+			Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_LEFT", *RightSideSlideLeft, { "U" });
+			Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_RIGHT", *RightSideSlideRight, { "O" });
 
-		float touchSliderEmulationSpeed = configFile.GetFloatValue("touch_slider_emulation_speed");
-	
-		if (touchSliderEmulationSpeed != 0.0f)
-			sliderSpeed = touchSliderEmulationSpeed;
+			float touchSliderEmulationSpeed = configFile.GetFloatValue("touch_slider_emulation_speed");
+
+			if (touchSliderEmulationSpeed != 0.0f)
+				sliderSpeed = touchSliderEmulationSpeed;
+		}
 	}
 
 	void TouchSliderEmulator::Update()
@@ -74,20 +81,46 @@ namespace TLAC::Components
 
 	void TouchSliderEmulator::UpdateInput()
 	{
-		if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive() || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN))
+		if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive() || (!enableInMenus && !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)))
 			return;
 
-		sliderIncrement = GetElapsedTime() / sliderSpeed;
+		if (usePs4OfficialSlider)
+		{
+			DualShock4* ds4 = DualShock4::GetInstance();
+			if (ds4 == nullptr)
+				return;
+
+			Joystick ls = ds4->GetLeftStick();
+			Joystick rs = ds4->GetRightStick();
+
+			// test data
+			// normalised the same as ds4 sticks, except instead of ushort this uses bytes
+			// hopefully the scaling to 16 bits doesn't screw things up lol
+			//Joystick ls = Joystick((float)(0b10101010) / 255 * 2.0f - 1.0f, (float)(0b10000000) / 255 * 2.0f - 1.0f);
+			//Joystick rs = Joystick((float)(0b10000001) / 255 * 2.0f - 1.0f, (float)(0b11001100) / 255 * 2.0f - 1.0f);
+
+			uint32_t state = 0;
+			state |= (uint8_t)((ls.XAxis + 1.0) * 127.5) ^ 0b10000000;
+			state |= ((uint8_t)((ls.YAxis + 1.0) * 127.5) ^ 0b10000000) << 8;
+			state |= ((uint8_t)((rs.XAxis + 1.0) * 127.5) ^ 0b10000000) << 16;
+			state |= ((uint8_t)((rs.YAxis + 1.0) * 127.5) ^ 0b10000000) << 24;
+
+			ApplyBitfieldState(state);
+		}
+		else
+		{
+			sliderIncrement = GetElapsedTime() / sliderSpeed;
 
-		constexpr float sensorStep = (1.0f / SLIDER_SENSORS);
+			constexpr float sensorStep = (1.0f / SLIDER_SENSORS);
 
-		EmulateSliderInput(LeftSideSlideLeft, LeftSideSlideRight, ContactPoints[0], 0.0f, 0.5f);
-		EmulateSliderInput(RightSideSlideLeft, RightSideSlideRight, ContactPoints[1], 0.5f + sensorStep, 1.0f + sensorStep);
+			EmulateSliderInput(LeftSideSlideLeft, LeftSideSlideRight, ContactPoints[0], 0.0f, 0.5f);
+			EmulateSliderInput(RightSideSlideLeft, RightSideSlideRight, ContactPoints[1], 0.5f + sensorStep, 1.0f + sensorStep);
 
-		sliderState->ResetSensors();
+			sliderState->ResetSensors();
 
-		for (int i = 0; i < CONTACT_POINTS; i++)
-			ApplyContactPoint(ContactPoints[i], i);
+			for (int i = 0; i < CONTACT_POINTS; i++)
+				ApplyContactPoint(ContactPoints[i]);
+		}
 	}
 
 	void TouchSliderEmulator::OnFocusLost()
@@ -120,23 +153,25 @@ namespace TLAC::Components
 		contactPoint.InContact = leftDown || rightDown;
 	}
 
-	void TouchSliderEmulator::ApplyContactPoint(ContactPoint &contactPoint, int section)
+	void TouchSliderEmulator::ApplyContactPoint(ContactPoint& contactPoint)
 	{
-		sliderState->SectionTouched[section] = contactPoint.InContact;
-
-		int pressure = contactPoint.InContact ? FULL_PRESSURE : NO_PRESSURE;
-		float position = std::clamp(contactPoint.Position, 0.0f, 1.0f);
-
 		if (contactPoint.InContact)
 		{
+			float position = std::clamp(contactPoint.Position, 0.0f, 1.0f);
 			int sensor = (int)(position * (SLIDER_SENSORS - 1));
 
-			sliderState->SetSensor(sensor, pressure);
+			sliderState->SetSensor(sensor, FULL_PRESSURE);
 		}
+	}
 
-		constexpr float startRange = -1.0f;
-		constexpr float endRange   = +1.0f;
-
-		sliderState->SectionPositions[section] = contactPoint.InContact ? (ConvertRange(0.0f, 1.0f, startRange, endRange, position)) : 0.0f;
+	void TouchSliderEmulator::ApplyBitfieldState(uint32_t state)
+	{
+		for (int i = 0; i < 32; i++)
+		{
+			if (state & (1 << (31 - i)))
+				sliderState->SetSensor(i, FULL_PRESSURE);
+			else
+				sliderState->SetSensor(i, NO_PRESSURE);
+		}
 	}
 }

+ 6 - 1
source-code/source/plugins/TLAC/Components/Input/TouchSliderEmulator.h

@@ -25,6 +25,10 @@ namespace TLAC::Components
 		Input::Binding* RightSideSlideLeft;
 		Input::Binding* RightSideSlideRight;
 
+		bool usePs4OfficialSlider;
+
+		bool enableInMenus;
+
 		TouchSliderEmulator();
 		~TouchSliderEmulator();
 
@@ -53,7 +57,8 @@ namespace TLAC::Components
 		ContactPoint ContactPoints[CONTACT_POINTS];
 
 		void EmulateSliderInput(Input::Binding *leftBinding, Input::Binding *rightBinding, ContactPoint &contactPoint, float start, float end);
-		void ApplyContactPoint(ContactPoint &contactPoint, int section);
+		void ApplyContactPoint(ContactPoint &contactPoint);
+		void ApplyBitfieldState(uint32_t state);
 	};
 }
 

+ 0 - 0
source-code/source/plugins/TLAC/Components/Input/TouchSliderState.cpp


Some files were not shown because too many files changed in this diff