Talk:PSP Emulator Compatibility List

From PS4 Developer wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

General

Custom PSPemu Configuration Files

Configuration files created by users to improve PSP emulator compatibility on PS4.

God Of War - Ghost Of Sparta

config-title.txt
UCUS98737

--antialias=off
--godofwarhack=true
--forcenobilinear=true

LUA
UCUS98732

local axObj = getAXObject()
local emuObj = getEmuObject()

local patcher = function()

axObj.WriteMem32(0x08A15210,0x24020000)
end

emuObj.AddVsyncHook(patcher)
PPSSPP
0881681C

God of War: Chains of Olympus

config-title.txt
UCUS98653

--texclutmode=filter
--bend-30hz-lock=1
--godofwarhack=true

Dante's Inferno

config-title.txt
ULUS10469

--antialias=off
--texloadcores=48
--texclutmode=full
--vramcopyback=12
--locorocomeshsmooth=true
--texrecent=true
--umddelay=true
--depthscalehack=true
--forcenobilinear=true
--smoothlevel=0

LUA
UCUS98732

-- Dantes Inferno

apiRequest(1.0)  -- request version 1.0 API. Calling apiRequest() is mandatory.

local emuObj  = getEmuObject() -- emulator
local axObj  = getAXObject() -- allegrex

local patcher = function()

--30 FPS
local code_check1 = axObj.ReadMem16(0x001C239C)

local code_check2 = axObj.ReadMem16(0x103E4B40)

if code_check1 == 0x0064 and  code_check2 == 0x001E then


axObj.WriteMem32(0x203E4B40,0x0000001E)
axObj.WriteMem32(0x20022EE4,0x3D088889) --1/30 = 0.03333

end

end

emuObj.AddVsyncHook(patcher)

Tekken 6

config-title.txt
ULUS10466

--has-shown-start-select-help=0
--userui-settings-graphics=1
--globalgamedata-dir=global
--bend-30hz-lock=0
--replacementfilter=true
--depthscalehack=true
--texcachemode=patchworkheroes
--texloadcores=16
--present=vblankstart 
--texclutmode=full
--texrecent=true
--force-dsf-present=1
--gputhread=true
--gpu-renderthread=20
--force-triangle-clip-off=true
--umddelay=true

# Emu used = Syphon Filter Dark Mirror

Soulcalibur: Broken Destiny

config-title.txt
ULUS10457

--has-shown-start-select-help=0
--userui-settings-graphics=1
--globalgamedata-dir=global
--trophies=0
--umddelay=true
--bend-30hz-lock=0
--present=setframebuf #,setframebuf,drawsync
--texclutmode=filter  #,full
--texloadmode=launch  #ondemand_lz4
--depthscalehack=true
--texloadcores=8
--texrecent=true  #async, lastused

# Emu used = Syphon Filter Dark Mirror

Miami Vice: The Game

config-title.txt
ULUS10109

--antialias=off
--texclutmode=full
--texloadcores=12
--texcachemode=patchworkheroes
--present=setframebuf
--texrecent=true
--umddelay=true
--smoothlevel=0

Wild Arms XF

config-title.txt
ULUS10339

--title-id=ULUS10339
--has-shown-start-select-help=0
--vms=/temp0/vms
--ms0=/temp0/ms0
--multisaves=true
--notrophies=true

--antialias="off" #ssaa4x off msaa4x
--texcachemode=rondo #drawbounds,drawboundsloco,patchworkheroes,locoroco2,rondo
--texloadcores=10
--present=drawsync
--gputhread=true
--texrecent=true
--texclutmode=full

Burnout Dominator

config-title.txt
ULUS10236

---title-id=ULUS10236
--multisaves=true
--notrophies=true
--vms=/temp0/vms
--has-shown-start-select-help=1
--antialias="off"
--texclutmode=full
--texloadcores=12
--texcachemode=patchworkheroes
--present=setframebuf
--texrecent=true
--umddelay=true

ULUS10236_patches.lua
ULUS10236

-- Burnout Dominator
-- lua by Stayhye

apiRequest(1.0)  -- request version 1.0 API. Calling apiRequest() is mandatory.

local emuObj  = getEmuObject() -- emulator
local axObj  = getAXObject() -- allegrex

local patcher = function()
--30 FPS V.2 [Default]
local code_check1 = axObj.ReadMem16(0x02574C)
if code_check1 == 0x0000 then
axObj.WriteMem32(0x2002574C,0x14A0001A)
axObj.WriteMem32(0x201A0358,0xE60C0034)
axObj.WriteMem32(0x204F08BC,0x3D088888)
axObj.WriteMem32(0x2019AE90,0x3C043F80)
end
--[[
--60 FPS V.2
local code_check2 = axObj.ReadMem16(0x02574C)
if code_check2 == 0x001A then
axObj.WriteMem32(0x2002574C, 0x00000000)
axObj.WriteMem32(0x201A0358, 0x00000000)
axObj.WriteMem32(0x204F08BC, 0x3C888888)
axObj.WriteMem32(0x2019AE90, 0x3C043F00)
end
--]]
end

emuObj.AddVsyncHook(patcher)

emuObj.SetTextureHashMode("patchworkheroes")

Tom Clancy's Ghost Recon Advanced Warfighter 2

config-title.txt
ULUS10237

# Ghost Recon: Advanced Warfighter 2 (all regions)

--has-shown-start-select-help=1

--antialias=off

--texclutmode=full

--bend-30hz-lock=0

--texloadcores=12
--texcachemode=patchworkheroes
--present=setframebuf
--texrecent=true
--umddelay=true
--smoothlevel=0

--forcenobilinear=true

--active-sku="ULUS10237"
--title-id=ULUS10237

--psp-right-stick-action=1
--psp-right-stick-deadzone-x=15
--psp-right-stick-deadzone-y=15
--psp-right-stick-deadzone-semicircle-arc=40

#  Emu used = Syphon Filter Dark Mirror

Call of Duty: Roads to Victory

config-title.txt
ULES00643

# Call of Duty: Roads to Victory (all regions)

--has-shown-start-select-help=1

--bend-30hz-lock=0

--antialias=off
--texclutmode=full
--texloadcores=12
--texcachemode=patchworkheroes
--present=setframebuf
--texrecent=true
--umddelay=true

--forcenobilinear=true

--active-sku="ULES00643"
--title-id=ULES00643

--psp-right-stick-action=1
--psp-right-stick-deadzone-x=15
--psp-right-stick-deadzone-y=15
--psp-right-stick-deadzone-semicircle-arc=40

--app-volume=0.8

#  Emu used = Syphon Filter Dark Mirror

SpongeBob's Truth or Square

config-title.txt
ULUS10478

# SpongeBob's Truth or Square (all regions)

--has-shown-start-select-help=1
--bend-30hz-lock=1

--force-dsf-present=1

--forcenobilinear=true
--depthscalehack=true

--active-sku="ULUS10478"
--title-id=ULUS10478

--antialias=off
--texloadcores=48
--texcachemode=patchworkheroes
--present=setframebuf
--texrecent=true
--umddelay=true
--smoothlevel=0
--texclutmode=full  
--vramcopyback=12
--locorocomeshsmooth=true
--gpu-renderthread=20

# following settings are machine-generated
--region-dir=SIEA
--ps4-trophies=0
--ps5-uds=0
--trophies=0

--globalgamedata-dir=global

# Emu used = Syphon Filter Dark Mirror

Harvest Moon Hero of Leaf Valley

config-title.txt
ULUS10458

# Harvest Moon Hero of Leaf Valley (all regions)

--has-shown-start-select-help=1

--bend-30hz-lock=0
--force-dsf-present=1
--depthscalehack=true

--gpu-renderthread=20
--antialias="msaa4x"
--anisolevel=4

--texclutmode=full
--texloadcores=48
--texcachemode=patchworkheroes
--present=vblankstart
--texrecent=true
--umddelay=true
--smoothlevel=0
--locorocomeshsmooth=true

--active-sku="ULUS10458"
--title-id=ULUS10458

# following settings are machine-generated
--region-dir=SIEA
--ps4-trophies=0
--ps5-uds=0
--trophies=0

--globalgamedata-dir=global

# Emu used = Syphon Filter Dark Mirror

Gurumin: A Monstrous Adventure

config-title.txt
ULUS10228

# Gurumin: A Monstrous Adventure (all regions)

--image="data/USER_L0.IMG"
--title-id=ULUS10228
   
--gpu-renderthread=0

--antialias=ssaa4x
--texclutmode=full
--smoothlevel=0
--texcachemode=patchworkheroes
--present=vblankstart

--texrecent=true
--umddelay=true
--gputhread=true

--vramcopyback=45
--texloadcores=48

--locorocomeshsmooth=true
--depthscalehack=true

--multisaves=true
--notrophies=true

# Emu used = Ridge Racer 2

Incomplete configurations

This is a list of configurations that were unsuccessful or were never completed, or information that might help people in the future.
A place for research and sharing useful info.

Crash Tag Team Racing

LUA
ULUS10044

Reaches 0x8A7292C 	jal	zz_sceKernelLoadModule
Similarly to YU-GI-OH! 5D's Tag Force 4, and then crashes after 2 instructions.

YU-GI-OH! 5D's Tag Force 4

LUA
ULUS10481

local axObj = getAXObject()
local emuObj = getEmuObject()

local patcher = function()

axObj.WriteMem32(0x8818780,0x10000025)
end

emuObj.AddVsyncHook(patcher)

Official PSPemu Configuration Files

Configuration files extracted from official packages to improve PSP emulator compatibility on PS4

Syphon Filter: Dark Mirror

config-title.txt
UCUS98641

# SyphonFilterDarkMirror (all regions)

--texclutmode=filter

--bend-30hz-lock=1

--psp-right-stick-action=1
--psp-right-stick-deadzone-x=15
--psp-right-stick-deadzone-y=15
--psp-right-stick-deadzone-semicircle-arc=40

--app-volume=0.8


# following settings are machine-generated
--region-dir=SIEA
--ps4-trophies=1
--ps5-uds=1
--trophies=1

--globalgamedata-dir=global

UCUS98641_patches.lua

-- Lua 5.3
-- Title: Syphon Filter: Dark Mirror

-- Patches for fixing issues with post fx in games using the Syphon Filter/Resistance engine

apiRequest(1.0)	-- request version 1.0 API. Calling apiRequest() is mandatory.

local emuObj = getEmuObject()
local cpu = getAXObject() 

-- The bloom filter uses 1.5 pixel jitter to make a ghetto blur. When up-ressed, this doesn't look good.
-- To compensate, reduce the jitter amount before rendering.
function BloomJitterPlusAdjust()
	-- 1.5 pixel "+" pattern
	emuObj.AdjustUVJitter(0, 4, 0.0, 1.5)
	emuObj.AdjustUVJitter(4, 4, 0.0, -1.5)
	emuObj.AdjustUVJitter(8, 4, 1.5, 0.0)
	emuObj.AdjustUVJitter(12, 4, -1.5, 0.0)
end

function BloomJitterCrossAdjust()
	-- 1.5 pixel "x" pattern
	emuObj.AdjustUVJitter(0, 4, 1.5, 1.5)
	emuObj.AdjustUVJitter(4, 4, -1.5, 1.5)
	emuObj.AdjustUVJitter(8, 4, 1.5, -1.5)
	emuObj.AdjustUVJitter(12, 4, -1.5, -1.5)
end

local jitterFixPlus = emuObj.AddGPUHook(0x40dc000, 0, 16, 0x40d4000, BloomJitterPlusAdjust)
local jitterFixCross = emuObj.AddGPUHook(0x40d4000, 0, 16, 0x40dc000, BloomJitterCrossAdjust)

function depthquery()
	local querystruct = 0x8eda968		-- this is always in a fixed location
	-- the depth query struct is fixed to 24 entries
	-- 0..15 seem to be always used for lights, 16..23 are for npcs
	for i=0,23 do
		local querytype = cpu.ReadMem32(querystruct+0)
		local valid = cpu.ReadMem32(querystruct+1*4)
		if valid ~= 0xffffffff then
			--local queryx = cpu.ReadMem32(querystruct+2*4)
			--local queryy = cpu.ReadMem32(querystruct+3*4)
			--local querydepth = cpu.ReadMem32(querystruct+4*4)
			--local querywidth = cpu.ReadMem32(querystruct+5*4)
			--local queryheight = cpu.ReadMem32(querystruct+6*4)
			--local param1c = cpu.ReadMem32(querystruct+7*4)
			--local param20 = cpu.ReadMem32(querystruct+8*4)
			local param24 = cpu.ReadMem32(querystruct+9*4)
			--local result = cpu.ReadMemFloat(querystruct+10*4)
			if param24 <= 0 then
				cpu.WriteMem32(querystruct+1*4, 0xffffffff)		-- to be removed from the list -> mark as invalid
			else
				if querytype == 3 then		-- n x n coverage based occlusion used by lights. Object opacity is set to (visible_samples / total_samples)
					cpu.WriteMemFloat(querystruct+10*4, 0.0)	-- always hide lights
				else						-- Enemies use a 5-point (corners + center) occlusion check. Object is visible if any of the points is visible.
					cpu.WriteMemFloat(querystruct+10*4, 1.0)	-- set always visible
				end
			end
		end
		querystruct = querystruct + 0x2c
	end
end

cpu.AddHook(0x8c163d4, 0x27bdff80, depthquery)			-- = addiu sp, sp, -0x80
-- the hook code replaces the occlusion function, so just adjust the stack and return
cpu.InsnReplace(0x8c163d8, 0x34040000, 0x27bd0080)		-- addiu sp, sp, 0x80
cpu.InsnReplace(0x8c163dc, 0xafa40048, 0x03e00008)		-- jr ra
cpu.InsnReplace(0x8c163e0, 0x3c0408ee, 0x00000000)		-- nop

Echochrome

config-title.txt
UCES01011

# Echochrome (all regions)

# following settings are machine-generated
--region-dir=SIEA
--ps4-trophies=0
--ps5-uds=0
--trophies=0

config-region.txt

--image="data/USER_L0.IMG"
--antialias=SSAA4x
--multisaves=true
--notrophies=true

NPUG80135_patches.lua

-- Lua 5.3
-- Title: Echochrome  NPUG 80135  (US)

--  WBD  5/10/2022	prevent Console Msg about Memory Stick from being displayed
--  WBD  5/22/2022  remove Send and Receive menu options

apiRequest(1.0)	-- request version 1.0 API. Calling apiRequest() is mandatory.

local gpr	= require( "ax-gpr-alias" ) -- you can access Allegrex GPR by alias (gpr.a0 / gpr["a0"])
local emuObj = getEmuObject()
local cpu = getAXObject()

local hook = 0x88468f0

function SkipMsg()
	local v1 = cpu.GetGpr(gpr.v1)
	local v0 = cpu.GetGpr(gpr.v0)
	
	cpu.SetGpr(gpr.a0, v1)
	cpu.SetGpr(gpr.v0, 0)
	cpu.WriteMem32(v1+4, v0)
	cpu.SetPC(hook+0xc)
	print "_NOTE: Skipping Memory Stick Message"
end
cpu.AddHook(hook, 0x00602021, SkipMsg)


function DisableSendReceive()
	cpu.WriteMem32(0x8909940, 0)		-- overwrite Send with 0
	cpu.WriteMem32(0x890991c, 0)		-- overwrite Receive with 0
end
cpu.AddHook(0x8846fb4, 0xae130090, DisableSendReceive)

LocoRoco Midnight Carnival

config-title.txt
NPEG00024

# LocorocoMidnightCarnival (all regions)

--ps5-uds=0# following settings are machine-generated
--region-dir=SIEE
--ps4-trophies=0
--ps5-uds=0
--trophies=0

config-region.txt

; Windows configuration file for PSPHD

; Game Image
--image="data\USER_L0.IMG"

; Use this to run the automatic font dumper.
;--boot="host0:../tools/glyphdump.prx"

; Uncomment these to play around with font dumping.
;--fontsave="host0:fontdump"
;--fontreplace="host0:fontreplace"

; Scaling factor (Windows only - 1: 480x272, 2: 960x544, 3: 1440x816, 4: 1920x1088 ... 8: 3840x2176)
--scale=3

; Language selection (Windows only - the PS4 version auto-selects based on the PS4 language setting)
; Switch the PSP language to one of the following:
; "en": English (default)
; "jp": Japanese
; "fr": French
; "es": Spanish
; "de": German
; "it": Italian
; "nl": Dutch
; "pt": Portuguese
; "ru": Russian
; "ko": Korean
; "chs": Chinese Simplified
; "cht": Chinese Traditional
;--lang="en"

; Redirect host0: to a another directory (uncomment to enable).
; By default it's mapped to the working directory where the executable starts
;--host="D:\Sony\PSPHD"

; To dump the original video in PMF format, uncomment the --dumpvideos line
; For example, with the current setting, it will save them in a "D:\Sony\PSPHD\videos" directory (make sure the directory exists)
;--dumpvideos="host0:videos"

; To dump the original audio in Atrac3 format, uncomment the --dumpaudio line
; For example, with the current setting, it will save them in a "D:\Sony\PSPHD\audio" directory (make sure the directory exists)
;--dumpaudio="host0:audio"

; To save the in-game textures as the game runs, uncomment the --texsave line
; For example, with the current setting, it will save them in a "D:\Sony\PSPHD\texdump" directory (make sure the directory exists)
;--texsave="host0:texdump"
;--texmissingsave="host0:texdump"

; To replace specific textures as the game runs, uncomment the --texreplace line
; For example, with the current setting, it will load them from the "D:\Sony\PSPHD\texreplace" directory
; If the --scale setting is set to 4 or 8, the program will also look for replacement textures on '4x' or '8x' directories within this directory
;--texreplace="host0:texreplace"

; This forces alpha blending to on for replaced textures. (uncomment to enable)
; With this we can freely make use of a normal alpha channel on replacement textures
;--replacementalpha=true

; This enables bilinear filtering on replaced textures. (uncomment to enable)
;--replacementfilter=true

; Antialiasing mode. SSAA4x looks best, MSAA4x only smooths edges.
; Choices: off, SSAA4x, MSAA4x
--antialias=SSAA4x

; Allows to switch between replacement and original textures using L3 on the DS4 or the T key.
;--texswitch=true

; Turns on the auto-resampler. Assumes textures in texreplace are at 8x resolution and resamples them at load
;--autoresampler=true

; Turns on filtering of CLUT hashes to avoid repeat indexed textures
;--texclutmode=filter

; Enable Multiple Savegames
--multisaves=true

; Custom locoroco2 texture hasher
;--texcachemode="locoroco2"

NPEG00024_patches.lua

-- Lua 5.3
-- Title: Locoroco Midnight Carnival NPEG-00024  (EU)

--  WBD  5/25/2022	prevent RANKING option from being selected

apiRequest(1.0)	-- request version 1.0 API. Calling apiRequest() is mandatory.

local gpr	= require( "ax-gpr-alias" ) -- you can access Allegrex GPR by alias (gpr.a0 / gpr["a0"])
local emuObj = getEmuObject()
local cpu = getAXObject()


function DisableRanking()
	local a2 = cpu.GetGpr(gpr.a2)
	local a1 = cpu.GetGpr(gpr.a1)
	local check = cpu.ReadMem8(a1+0x2c)			-- make sure we're in the correct menu
	local ptr = a1+a2+0x34
	local new_indx = cpu.ReadMem8(ptr)
	if (new_indx == 2) then
		if (a2 == 2 and check == 0x2b) then		-- moving right
			cpu.WriteMem8(ptr, 3)
			print "_NOTE: NEW changed to 3"

		elseif (a2 == 3 and check == 0x3e) then		-- moving left
			cpu.WriteMem8(ptr, 1)
			print "_NOTE: NEW changed to 1"
		end
	end
end

cpu.AddHook(0x8a205c4, 0x00c58821, DisableRanking)

Patapon 2

LUA
UCUS98732

-- Lua 5.3
-- Title:   Patapon 2 PSP - UCUS-98732 (USA)
-- Author:  Ernesto Corvi

-- Changelog:
-- v1.1: US only.  Change the word "Paraget" to "Patagate" in two strings.

apiRequest(1.0)	-- request version 1.0 API. Calling apiRequest() is mandatory.

local gpr		= require( "ax-gpr-alias" ) -- you can access Allegrex GPR by alias (gpr.a0 / gpr["a0"])
local emuObj	= getEmuObject() -- emulator
local axObj		= getAXObject() -- allegrex
local pad		= require("pad")

-- Hook memcpy to catch framebuffer effects
axFuncReplace(0x881D194, "patapon_memcpy")

-- Accelerate some functions
axFuncReplace(0x8804670, "__ptmf_scall")
axFuncReplace(0x8892230, "Renderer__makeWorldMatrix__4psysFv")
axFuncReplace(0x88209A8, "patapon_strcmp")
axFuncReplace(0x8815130, "sceGupSetStatus")
axFuncReplace(0x8851D84, "FMtx44__setRow__3PydFv")
axFuncReplace(0x88437F0, "Script__Talk__Controller__setDeltaTime__3PydFv")
axFuncReplace(0x8843B6C, "Script__Talk__Controller__setCmdId__3PydFv")
axFuncReplace(0x88441DC, "Script__Talk__Controller__getArgValuePtr__3PydFv_0")
axFuncReplace(0x89B25B0, "sceGmoCol4Multiply")
axFuncReplace(0x8910A60, "Gfx__CacheModel__getNodeMtx__6SystemFv")
axFuncReplace(0x8911440, "Gfx__StaticGmoModel__getNodeIdx__6SystemFv")
axFuncReplace(0x89114C8, "Gfx__StaticGmoModel__getNodeMtx__6SystemFv")
axFuncReplace(0x891157C, "Gfx__StaticGmoModel__getNodeMtx__6SystemFv_0")
axFuncReplace(0x881462C, "sceGuEnable", 0x8B3C050) -- param = gupbase pointer
axFuncReplace(0x8814684, "sceGuDisable", 0x8B3C050) -- param = gupbase pointer
axFuncReplace(0x89B2D84, "sceGmoFCurveEval_fastpath", 0x89B2D88) -- param = function entry if not fast path
--axFuncReplace(0x88D0788, "Game__Map__Weather__WindLocus__update__4LaboFv_loop", 0x88D0864) -- param = continue address

axFuncReplace(0x890FCBC, "convertLowerString__6SystemFv")
axFuncReplace(0x8877104, "convertLowerString__6SystemFv") -- convertLowerString__21@unnamed@BNDFile_cpp@Fv, same functionality
axFuncReplace(0x897927C, "__extendsfdf2")
axFuncReplace(0x8979AF8, "__muldf3")
axFuncReplace(0x8979A8C, "__adddf3")
axFuncReplace(0x897A750, "__truncdfsf2")
axFuncReplace(0x88CBD64, "RemapPacket", 0x8ACC394) -- param comes from RemapPacketAddr24 & RemapPacketAddr16
axFuncReplace(0x890FEA0, "patapon_strcmp") -- strcmpFast__6SystemFv ('fast' strcmp)


-- Switch Select command to "Options" button.
emuObj.PadSetButtonsMode(pad.BUTTONS_MODE_OPTION_IS_SELECT)

-- Remove "Transfer Patapon Saved Data" option from New Game option
--axInsnReplace(0x8A46660, 0x24070002, 0x24070001) -- li  a3,0x2  (change 2 menu options to 1)
emuObj.RemapSavedata("UCUS98711", "CUSA06171", "504e802b04a1838c32b616abbe0b475fbea1c823825ef0df06cc2bad129ce2f7")

-- Fix "Tree of Life" unaligned lines and shadows
axObj.AddHook(0x884600C, 0x8c850010, function() -- PSP::Gfx::PrimitiveContext::setVertex2f
	local context = axObj.GetGpr(gpr.a0)
	local cmdCount = axObj.ReadMem32(context + 0x14)
	if (cmdCount & 1) == 1 then -- we have at least 2 commands
		local cmdBuffer = axObj.ReadMem32(context + 0x10)
		local cx = axObj.GetFpr(12)
		local cy = axObj.GetFpr(13)
		local ox = axObj.ReadMemFloat(cmdBuffer-12)
		local oy = axObj.ReadMemFloat(cmdBuffer-8)
		
		if cx == ox then
			axObj.SetFpr(12, cx + 0.5)
			axObj.WriteMemFloat(cmdBuffer-12, ox + 0.5)
		elseif cy == oy then
			axObj.SetFpr(13, cy + 0.5)
			axObj.WriteMemFloat(cmdBuffer-8, oy + 0.5)
		end
	end
end)

-- LANGUAGES --
local langCode = "us" -- default
--local languageList = {"Japanese","English","UK","Italian","German","Spanish","French","Korean","Chinese","ns","nf","Dutch","Portuguese","gr","Belgium"}
--local gameLanguageCode = {"jp","us","uk","it","de","sp","fr","kr","cn","ns","nf","nl","pt","gr","be"}
local languageList = {"","English","","","","","","","","Spanish","French","","","",""}
local gameLanguageCode = {"","us","","","","","","","","ns","nf","","","",""}

-- US: english = 1, spanish = 9, french = 0xA (from Localize__Manager__setDefaultLangage)
-- EU: uk = 2, italian = 3, german = 4, spanish = 5, french = 6
-- JP: jp = 0
-- HP: ko = 7, ch = 8, 
	
-- GLOBAL FUNCTIONS --

local GLOBAL = 0x8B7D088 -- reawakeDeathUnit - offset 0x88A95E8 in $v1

function getGlobalAddr() -- gets Global to user data.
	-- address comes from: Labo::Bases::Camp::Controller::reawakeDeathUnit - offset 0x88A95E8 in $v1
	-- add 0x20 to address to align it with the word "none"
	
	local main = axObj.ReadMem32(GLOBAL)				-- fixed Global address from: 0x88A95E8 -> 0x8c9fbc0
	if main == 0xFFFFFFFF or main == 0 then
		return 0xFFFFFFFF
	end
	local ptr = axObj.ReadMem32(main + 0x10c0)			--> sets to: 0x8d07840
	if ptr == 0xFFFFFFFF or ptr == 0 then
		return 0xFFFFFFFF
	end

	return ptr
end

-- MAIN FUNCTIONS --

local H1 = function() -- Labo::Bases::Camp::Scene::updateTips
	local v0 = axObj.GetGpr(gpr.v0)
	if v0 > 0 then
		emuObj.ThrottleMax()
	else
		emuObj.ThrottleNormal()
	end
end

local H2 = function() -- GameSystem__SaveDataController__setStateMessage
	local ptr = axObj.GetGpr(gpr.a2)
	local str = axObj.ReadMemStr16(ptr)
	local newStr = "Now loading. Do not turn off the power."
	-- english: Now loading./Do not remove the Memory Stick Duo™ /or turn off the system power.
	-- spanish: Cargando./No extraigas el Memory Stick Duo™ /ni apagues el sistema.
	-- french: Chargement./Ne pas retirer le Memory Stick Duo™ /ou éteindre le système.
	-- italian: Caricamento in corso.../Non rimuovere il Memory Stick Duo™ /e non spegnere il sistema.
	-- german: Lädt./Bitte den Memory Stick Duo™ nicht entfernen /und das System nicht ausschalten.
	-- japanese: システムデータをロード中です。/Memory Stick Duo™を抜き挿ししたり、/電源を切ったりしないでください。
	-- chinese: 系統資料載入中。/請勿插拔Memory Stick Duo™/或是關閉主機的電源。
	-- korean: 시스템 데이터를 불러오는 중입니다./Memory Stick Duo™를 빼거나/전원을 끄지 마십시오.
	
	if string.find(str, "Now loading") then
		newStr = "Now loading."										-- English: Now loading./Do not remove the Memory Stick Duo™ /or turn off the system power.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Checking Memory Stick") then
		newStr = "Please wait."										-- English: Checking Memory Stick Duo™.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Now saving")then
		newStr = "Now saving."										-- English: Now saving./Do not remove the Memory Stick Duo™ /or turn off the system power.
		axObj.WriteMemStr16Z(ptr, newStr)
--
	elseif string.find(str, "Cargando.") then
		newStr = "Cargando..."										-- Spanish: Cargando./No extraigas el Memory Stick Duo™ /ni apagues el sistema.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Guardando...")then
		newStr = "Espera..."										-- Spanish: Guardando.../No extraigas el Memory Stick Duo™ /ni apagues el sistema.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Comprobando el Memory Stick") then
		newStr = "Guardando..."										-- Spanish: Comprobando el Memory Stick Duo™.
		axObj.WriteMemStr16Z(ptr, newStr)
--
	elseif string.find(str, "Chargement.") then
		newStr = "Chargement."										-- French: Chargement./Ne pas retirer le Memory Stick Duo™ /ou éteindre le système.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Vérification du Memory Stick")then
		newStr = "Veuillez patienter."								-- French: Vérification du Memory Stick Duo™.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Sauvegarde.") then
		newStr = "Sauvegarde en cours."								-- French: Sauvegarde./Ne pas retirer le Memory Stick Duo™ /ou éteindre le système.
		axObj.WriteMemStr16Z(ptr, newStr)
--
	elseif string.find(str, "Caricamento in corso") then
		newStr = "Caricamento in corso."							-- Italian: Caricamento in corso.../Non rimuovere il Memory Stick Duo™ /e non spegnere il sistema.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Controllo del Memory Stick")then
		newStr = "Attendi."											-- Italian: Controllo del Memory Stick Duo™.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Salvataggio in corso") then
		newStr = "Salvataggio in corso."							-- Italian: Salvataggio in corso.../Non rimuovere il Memory Stick Duo™ /e non spegnere il sistema.
		axObj.WriteMemStr16Z(ptr, newStr)
--
	elseif string.find(str, "Lädt") then
		newStr = "Lädt."											-- German: Lädt./Bitte den Memory Stick Duo™ nicht entfernen /und das System nicht ausschalten.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Memory Stick Duo™ wird überprüft")then
		newStr = "Bitte warten."									-- German: Memory Stick Duo™ wird überprüft.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Speichert.") then
		newStr = "Speichert."										-- German: Speichert./Bitte den Memory Stick Duo™ nicht entfernen und /das System nicht ausschalten.
		axObj.WriteMemStr16Z(ptr, newStr)
--
	elseif string.find(str, "システムデータをロード中です。") then
		newStr = "ロード中。"											-- Japanese: システムデータをロード中です。/Memory Stick Duo™を抜き挿ししたり、/電源を切ったりしないでください。
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Memory Stick Duo™のチェック中です。")then
		newStr = "お待ちください。"										-- Japanese: Memory Stick Duo™のチェック中です。
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "システムデータをセーブ中です。") then
		newStr = "セーブ中。"											-- Japanese: システムデータをセーブ中です。/Memory Stick Duo™を抜き挿ししたり、/電源を切ったりしないでください。
		axObj.WriteMemStr16Z(ptr, newStr)
--	
	elseif string.find(str, "系統資料載入中。") then
		newStr = "載入中。"											-- Chinese: 系統資料載入中。/請勿插拔Memory Stick Duo™/或是關閉主機的電源。
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Memory Stick Duo™確認中。")then
		newStr = "請稍候。"											-- Chinese: Memory Stick Duo™確認中。
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "保存中。") then
		newStr = "存檔中。"											-- Chinese: 保存中。/請勿插拔Memory Stick Duo™/或是關閉主機的電源。
		axObj.WriteMemStr16Z(ptr, newStr)
--
	elseif string.find(str, "시스템 데이터를 불러오는 중입니다") then
		newStr = "불러오는 중입니다."										-- Korean: 시스템 데이터를 불러오는 중입니다./Memory Stick Duo™를 빼거나/전원을 끄지 마십시오.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "Memory Stick Duo™ 체크 중입니다")then
		newStr = "잠시 기다려 주십시오."									-- Korean: Memory Stick Duo™ 체크 중입니다.
		axObj.WriteMemStr16Z(ptr, newStr)
	elseif string.find(str, "시스템 데이터를 저장 중입니다") then
		newStr = "저장 중입니다."										-- Korean: 시스템 데이터를 저장 중입니다./Memory Stick Duo™를 빼거나,/전원을 끄지 마십시오.
		axObj.WriteMemStr16Z(ptr, newStr)
	end
end

local H3 = function()	-- Localize__Manager__getLanguageName
	local v0 = axObj.GetGpr(gpr.v0)
	local langPtr = axObj.ReadMem32(v0)
	langCode = axObj.ReadMemStr(langPtr)
end

local bundleFileName = ""
local H4 = function() -- System::Util__BNDFile__doNameCallback
	local ptr = axObj.GetGpr(gpr.a0)
	bundleFileName = axObj.ReadMemStr(ptr)
end

local H5 = function() -- Labo::GameSystem__callbackFunc_MemoryObject
	local ptr = axObj.GetGpr(gpr.s5)
	local dataPtr = axObj.ReadMem32(ptr)
	
	if bundleFileName == "colony_data.pac" then
		axObj.WriteMem16(dataPtr + 0x79ba, 4)
	end
end

-- Black Smith - Remove "KeyGuide" bug when hit anvil head while quenching --
local blackSmithRunning = false
local H6 = function() -- Sound__SubGame__Blacksmith__Command__start__4LaboFv
	blackSmithRunning = true
end
local H7 = function() -- Sound__BeatCommander__endSubGame__4LaboFv
	if blackSmithRunning == true then
		local a0 = axObj.GetGpr(gpr.a0)
		axObj.WriteMem8(a0 + 0x19c, 1)	-- set memory to 1 (instead of 0) otherwise brings up bad "KeyGuide"
	end
	
	blackSmithRunning = false
end

-- TIPS System hacks --
axInsnReplace(0x8A73A44, 0x3C0342A8, 0x3C0342A4) -- change required number of Tips from 84 to 82.
local H8 = function() -- GameSystem__Tips__Viewer__setup__4LaboFv
	local global = getGlobalAddr()
	if global == 0xFFFFFFFF then
		return
	end

	local unitTable = axObj.ReadMem32(global + 0x1068)	--> sets to: 0x8d13580 (unit table)
	local tipsPtr = unitTable + 0x1F5E4
	
	local badTips = axObj.ReadMem32(tipsPtr + 8)
	badTips = badTips & 0xFFBBFFFF		-- remove tips 0x53 and 0x57 as they referred to Multiplayer
	axObj.WriteMem32(tipsPtr + 8, badTips)
end

-- Remove AutoSave menu from initial startup --
local H9 = function() -- GameSystem__SaveDataController__update__4LaboFv
	local s3 = axObj.GetGpr(gpr.s3)
	local flg = axObj.ReadMem32(s3 + 0x7eed)
	local val = axObj.ReadMem32(s3 + 0x7efc)
	
	if flg == 0 and val == 0x14 then
		axObj.WriteMem32(s3 + 0x7efc, 0x13)
	end
end

-- Change game save name to "Patapon 2 Remastered" --
local H10 = function() -- Utility__SaveDataUtility__setDataParamsfoString
	local ptr = axObj.GetGpr(gpr.s1)
	local strPtr = axObj.ReadMem32(ptr)
	local newStr = "PATAPON™ 2 Remastered"
	
	axObj.WriteMemStrZ(strPtr, newStr)
end

-- Change description for the "Friendship" weapon to remove game sharing text --
local	itemsTable = {}
		itemsTable[1] = "Proof of friendship establish"			-- English
		itemsTable[2] = "Prueba de la amistad establecida"		-- Spanish
		itemsTable[3] = "Preuve de l'amitié établie"			-- French
		itemsTable[4] = "Preuve d'une amitié"					-- French alt
		
function changeStrings(strPtr) -- modify strings
	local str = axObj.ReadMemStr16(strPtr) -- ptr to the string
	local strFind = string.gsub(str, "/", " ")	-- change any slash to space to strings can match.
	strFind = string.gsub(strFind, "  ", " ")	-- change any double spaces due to above change to only 1 space.
	
	for i = 1, #itemsTable do
		local startPos, endPos = string.find(strFind, itemsTable[i])
	
		if startPos ~= nil then
			str = string.sub(str, 1, (startPos-1) )
			-- SPECIAL fixes --
			str = string.gsub(str, "Un oiseau avec de bons HP et /une grosse attaque.","Un oiseau qui augmente vos/HP.") -- French incorrect grammar (bird)
			str = string.gsub(str, "aumente","augmente") -- French incorrect grammar.

			axObj.WriteMemStr16Z(strPtr, str)
		end
	end
end
		
local H11 = function() -- from Bases__Item__ExplanationWindow__setItemId
	local ptr = axObj.GetGpr(gpr.a0)
	local a2 = axObj.GetGpr(gpr.a2)
	local valPtr = axObj.ReadMem32(ptr)
	local v1 = valPtr + 8
	local v0 = a2 * 4
	v0 = v0 + v1
	local strPtr = axObj.ReadMem32(v0)
	strPtr = strPtr + valPtr

	changeStrings(strPtr)
end

-- Skip Memory message when selecting "Delete Save Data" on "Save the adventure" dialogue.
local menuSkip = false
local H12 = function()		-- Bases__Talk__CommandCamp__showDialog
	menuSkip = true
end
local H13 = function()		-- Bases__Talk__CommandCamp__showDialog
	if menuSkip == true then
		axObj.SetGpr(gpr.v1, 0)
		menuSkip = false
	end
end
local H14 = function()		-- Bases__Talk__CommandCamp__showDialog
	if menuSkip == true then
		axObj.SetPC(0x88D908C)
	end
end


-- HOOKS --
local hook1  = axObj.AddHook(0x88E9564, 0x0002102B, H1)		-- Labo::Bases__Camp__Scene__updateTips
local hook2  = axObj.AddHook(0x899E718, 0x00403021, H2)		-- GameSystem__SaveDataController__setStateMessage
local hook3  = axObj.AddHook(0x897771C, 0x00431021, H3)		-- Localize__Manager__getLanguageName
local hook4  = axObj.AddHook(0x88774D0, 0x00402821, H4)		-- System::Util__BNDFile__doNameCallback
local hook5  = axObj.AddHook(0x886889C, 0x02002021, H5)		-- Labo::GameSystem__callbackFunc_MemoryObject
local hook6  = axObj.AddHook(0x898BCDC, 0x27BDFFE0, H6)		-- Sound__SubGame__Blacksmith__Command__start__4LaboFv
local hook7  = axObj.AddHook(0x89220F8, 0xAC80019C, H7)		-- Sound__BeatCommander__endSubGame__4LaboFv
local hook8  = axObj.AddHook(0x8A734DC, 0x27BDFFC0, H8)		-- GameSystem__Tips__Viewer__setup__4LaboFv
local hook9  = axObj.AddHook(0x899CF4C, 0x92637EED, H9)		-- GameSystem__SaveDataController__update__4LaboFv
local hook10 = axObj.AddHook(0x88E7E48, 0x2490009C, H10)	-- Utility__SaveDataUtility__setDataParamsfoString
local hook11 = axObj.AddHook(0x897CF90, 0x26041718, H11)	-- Bases__Item__ExplanationWindow__setItemId
local hook12 = axObj.AddHook(0x88D9114, 0xAEA00014, H12)	-- Bases__Talk__CommandCamp__showDialog
local hook13 = axObj.AddHook(0x88D90B4, 0x9063C550, H13)	-- Bases__Talk__CommandCamp__showDialog
local hook14 = axObj.AddHook(0x88D907C, 0x8FA2003C, H14)	-- Bases__Talk__CommandCamp__showDialog
local hook15 = axObj.AddHook(0x8A394B4, 0x26241718, H11)	-- Bases__Organization__Managed__ItemSelectWindow__onSlotChange (note uses H11)


-- US game bug fix.  "Paraget" -> "Patagate" --
axObj.AddHook(0x88DC5F4, 0x00409021, function() -- from Bases__Camp__Person__Behavior__Idle__update__4LaboFv
	local strPtr = axObj.GetGpr(gpr.v0) + 0xE	-- 0xE skip over X/Y positions.
	local str = axObj.ReadMemStr16(strPtr)
	
	if string.find(str, "The Paraget will") then
		-- org string: The Paraget will teleport you to/another world…
		local newStr = "The Patagate can teleport you to/another world…"
		axObj.WriteMemStr16Z(strPtr, newStr)
	elseif string.find(str, "Paraget Shrine") then
		-- org string: This is the Paraget Shrine./Only <N0> and <N1> can/enter.
		local newStr = "This is the Patagate Shrine/Only <N0> and <N1> can/enter."
		axObj.WriteMemStr16Z(strPtr, newStr)
	end
end)

--[[
axObj.AddHook(0x08982F48, 0x24070001, function()
	if emuObj.NeoMode() then
		axObj.SetGpr(gpr.a3, 0) -- turn on 60fps mode
	end
end)
]]--

--- MOVIE FIX ---
local movieLastTime = 0.0
local movieFix = function() -- Labo::GameSystem__MovieModule__render
	local t = axObj.GetFpr(0)
	if t == 0 and movieLastTime > 0 then
		local s0 = axObj.GetGpr(gpr.s0)
		axObj.WriteMemFloat(s0 + 0x44, movieLastTime)
	elseif t > 0 then
		movieLastTime = t
	end
end

axObj.AddHook(0x8A6A1DC, 0xe6000044, movieFix)


--- PAT2-16 FIX ---
axObj.AddHook(0x890E9E0, 0x02002021, function() -- Labo::Game__Gimmick__WindowAttacher__update
	local ptr = axObj.GetGpr(gpr.sp) + 0x28
	local posy = axObj.ReadMemFloat(ptr + 4)
	
	if posy < -30 then
		local obj = axObj.GetGpr(gpr.a0)
		axObj.WriteMem8(obj + 0x2a8, 0)
	end
end)