Initial commit
This commit is contained in:
commit
a95d053a37
|
@ -0,0 +1,147 @@
|
|||
ddr5thmix-solo-src/build
|
||||
ddr5thmix-solo-src/build_soloio
|
||||
ddr5thmix-solo-src/tools/build/*
|
||||
ddr5thmix-solo-src/tools/py/*.c*
|
||||
ddr5thmix-solo-src/tools/py/*.html
|
||||
ddr5thmix-solo-src/data_raw
|
||||
!ddr5thmix-solo-src/data_raw/deleteme.txt
|
||||
ddr5thmix-solo-src/data_source
|
||||
!ddr5thmix-solo-src/data_source/deleteme.txt
|
||||
ddr5thmix-solo-src/data_modified_raw
|
||||
ddr5thmix-solo-src/\#*
|
||||
ddr5thmix-solo-src/stepx_*.sh
|
||||
|
||||
|
||||
*.iso
|
||||
*.zip
|
||||
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
|
@ -0,0 +1,44 @@
|
|||
# Dance Dance Revolution 5th Mix Solo
|
||||
This is an UNOFFICIAL patch for the System 573/arcade version of Dance Dance Revolution 5th Mix.
|
||||
|
||||
The game contains left over code that supports 6 panel gameplay and a large number of songs have 6 panel charts left over from 4th Mix Plus. This project is an attempt to restore that functionality as well as make improvements to the UI to bring it closer to what a real 5th Mix Solo might have felt like.
|
||||
|
||||
All source code is included.
|
||||
|
||||
|
||||
## KNOWN BUGS/ISSUES
|
||||
- Lights are not mapped correctly on solo cabinet (probably won't fix but I will accept a working PR)
|
||||
- Edits are bugged in 6 panel mode (won't fix)
|
||||
|
||||
## Instructions
|
||||
Note: **YOU MUST PROVIDE YOUR OWN DATA!**
|
||||
|
||||
[Microsoft Visual Studio 2015 x86 Redistributable](https://www.microsoft.com/en-US/download/details.aspx?id=48145) is required for tools to work properly.
|
||||
|
||||
1. Extract the contents of your Dance Dance Revolution 5th Mix CD to the `data_source` folder. You should have a `DAT` folder, `GAME.DAT`, `CARD.DAT`, and `PSX.EXE` file in this folder.
|
||||
2. Run `step1_extract.bat` (`step1_extract.sh` if you are on *nix) to generate the `data_raw` folder.
|
||||
3. Run `step2_make.bat` or `step2_make_soloio.bat` (`step2_make.sh` or `step2_make_soloio.sh` if you are on *nix) to build the `ddr5thsolo.iso`/`ddr5thsolo_soloio.iso` files. If you are using a real Solo machine then use `step2_make_soloio.bat`. If you are using MAME or an otherwise non-Solo machine then use `step2_make.bat`.
|
||||
|
||||
Additionally, if you are building this for MAME, you must use `chdman` (included with MAME) to build the required CHD.
|
||||
1. Generate CHD using `chdman.exe createcd -i ddr5thsolo.iso -o a27jaa02.chd -c none` (`-c none` is requested because the compression can throw timing off in MAME).
|
||||
2. Overwrite `roms/ddr5m/a27jaa02.chd` in your MAME folder with the newly generated `a27jaa02.chd`.
|
||||
3. Delete `nvram/ddr5m` in order to force reinstallation when you boot `ddr5m` next in MAME.
|
||||
4. You must run MAME from the command line instead of through the normal MAME UI to bypass hash check errors
|
||||
|
||||
If you wish to extract the CD bin/cue from a CHD file, use `chdman.exe extractcd -i a27jaa02.chd -o a27jaa02.cue`.
|
||||
|
||||
## Additional Instructions (*NIX ONLY)
|
||||
If you are building using *nix, you must compile the required Cython modules:
|
||||
1. `cd tools/py`
|
||||
2. `python3 -m pip install -r requirements.txt`
|
||||
2. `python3 setup.py build_ext --inplace`
|
||||
|
||||
|
||||
## Notes
|
||||
- Dipswitch 1 can be toggled on/off to enable/disable autoplay (even on real hardware)
|
||||
- There are various flags in [src/main.asm](https://github.com/987123879113/sys573mods/blob/main/ddr5thmix-solo-src/src/main.asm) that can be modified such as `FORCE_UNLOCK`, `SOLO_MODE`, `AUTOPLAY_ENABLED`, `AUTOPLAY_TIMING`, `DISABLE_ANNOUNCER`, and `DISABLE_CHEERING`.
|
||||
|
||||
## Thanks
|
||||
- @WannyTiggah for the edited title screen and icon edits
|
||||
- @SakamotoNeko13 for the edited 4PANEL/6PANEL graphics on the style select screen
|
||||
- @dragonminded for testing with a real Solo cabinet
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,58 @@
|
|||
[
|
||||
{
|
||||
"flag_loc": 1,
|
||||
"flag_comp": 1,
|
||||
"flag_enc": 1,
|
||||
"filename": "data/mdb/mdb.bin",
|
||||
"patch": "mdb.diff",
|
||||
"patch_format": "bsdiff4"
|
||||
},
|
||||
{
|
||||
"flag_loc": 0,
|
||||
"flag_comp": 1,
|
||||
"flag_enc": 0,
|
||||
"filename": "data/gpct/select/sslob_25.cmt",
|
||||
"patch": "sslob_25.diff",
|
||||
"patch_format": "bsdiff4"
|
||||
},
|
||||
{
|
||||
"flag_loc": 0,
|
||||
"flag_comp": 1,
|
||||
"flag_enc": 0,
|
||||
"filename": "data/gpct/select/sslop_25.cmt",
|
||||
"patch": "sslop_25.diff",
|
||||
"patch_format": "bsdiff4"
|
||||
},
|
||||
{
|
||||
"flag_loc": 0,
|
||||
"flag_comp": 1,
|
||||
"flag_enc": 0,
|
||||
"filename": "data/lang/japa/sstxt_25.cmt",
|
||||
"patch": "sstxt_25.diff",
|
||||
"patch_format": "bsdiff4"
|
||||
},
|
||||
{
|
||||
"flag_loc": 0,
|
||||
"flag_comp": 1,
|
||||
"flag_enc": 0,
|
||||
"filename": "data/gpct/select/cslbk_16.cmt",
|
||||
"patch": "cslbk_16.diff",
|
||||
"patch_format": "bsdiff4"
|
||||
},
|
||||
{
|
||||
"flag_loc": 0,
|
||||
"flag_comp": 1,
|
||||
"flag_enc": 0,
|
||||
"filename": "data/lang/japa/title_25.cmt",
|
||||
"patch": "title_25.diff",
|
||||
"patch_format": "bsdiff4"
|
||||
},
|
||||
{
|
||||
"flag_loc": 0,
|
||||
"flag_comp": 1,
|
||||
"flag_enc": 0,
|
||||
"filename": "data/gpct/select/selic_25.cmt",
|
||||
"patch": "selic_25.diff",
|
||||
"patch_format": "bsdiff4"
|
||||
}
|
||||
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
.org 0x80012860
|
||||
CheckAutoplayDipswitch:
|
||||
lb v0, 0x1f400004
|
||||
nop
|
||||
|
||||
andi v0, 1
|
||||
beq v0, 0, _CheckAutoplayDipswitchEnd
|
||||
nop
|
||||
|
||||
lb v0, 0x20(s3)
|
||||
nop
|
||||
|
||||
_CheckAutoplayDipswitchEnd:
|
||||
j CheckAutoplayDipswitchEnd
|
||||
nop
|
||||
|
||||
.org 0x8007f7f8
|
||||
; Enable autoplay
|
||||
j CheckAutoplayDipswitch
|
||||
nop
|
||||
CheckAutoplayDipswitchEnd:
|
||||
.org 0x8007f914
|
||||
; Disable random drops
|
||||
nop
|
||||
.org 0x8007f8a8
|
||||
; Disable randomness of timing
|
||||
li v0, 0
|
||||
nop
|
||||
nop
|
||||
.org 0x8007f8f4
|
||||
; Change allowable timing window of autoplay
|
||||
; Default is 16 which will result in a mix of perfect and marvelous judgements
|
||||
; 2 may possibly be a bit tight on real hardware, but MAX 300 is a pain and you get 1 or 2 goods at the end with a value of 4
|
||||
slti v0, s2, AUTOPLAY_TIMING
|
|
@ -0,0 +1,85 @@
|
|||
.psx
|
||||
.open "build/GAME.DAT", 0x80010000 - 0x60000 - 0x800
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Force full unlocks (songs and characters)
|
||||
; 0 = Off
|
||||
; 1 = On
|
||||
.definelabel FORCE_UNLOCK, 1
|
||||
|
||||
; Transforms 5th Mix into 5th Mix Solo
|
||||
; 0 = Off
|
||||
; 1 = On
|
||||
.definelabel SOLO_MODE, 1
|
||||
|
||||
; Use solo cabinet I/O
|
||||
; Still experimental so may not work properly on real hardware
|
||||
; 0 = Off
|
||||
; 1 = On
|
||||
; Can be defined in the ASM directly but it's easier for the build scripts to pass "-definelabel SOLO_IO 1" to armips
|
||||
;.definelabel SOLO_IO, 1
|
||||
|
||||
; Autoplay Enabled
|
||||
; When this option is enabled, dipswitch 1 can be used to toggle autoplay
|
||||
; 0 = Off
|
||||
; 1 = On
|
||||
.definelabel AUTOPLAY_ENABLED, 1
|
||||
|
||||
; Autoplay Timing Window
|
||||
; Default value is 16 which results in mixture of perfect and marvelous judgement.
|
||||
; Anything tigther than 2 will cause notes to be missed.
|
||||
.definelabel AUTOPLAY_TIMING, 2
|
||||
|
||||
; Disable announcer comments during song
|
||||
; 0 = Off
|
||||
; 1 = On
|
||||
.definelabel DISABLE_ANNOUNCER, 0
|
||||
|
||||
; Disable cheering during song
|
||||
; 0 = Off
|
||||
; 1 = On
|
||||
.definelabel DISABLE_CHEERING, 0
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
.if DISABLE_ANNOUNCER == 1
|
||||
.org 0x80080c50
|
||||
; Disable random announcer comments
|
||||
nop
|
||||
.org 0x80080204
|
||||
; Disable combo is continuing
|
||||
nop
|
||||
.endif
|
||||
|
||||
|
||||
.if DISABLE_CHEERING == 1
|
||||
.org 0x80080de8
|
||||
; Disable cheering
|
||||
nop
|
||||
.endif
|
||||
|
||||
|
||||
.if FORCE_UNLOCK == 1
|
||||
.org 0x8009bea0
|
||||
li v0, 0xffffffff
|
||||
jr ra
|
||||
nop
|
||||
.endif
|
||||
|
||||
|
||||
.if AUTOPLAY_ENABLED == 1
|
||||
.include "src/autoplay.asm"
|
||||
.endif
|
||||
|
||||
|
||||
.if SOLO_MODE == 1
|
||||
.include "src/solo.asm"
|
||||
.endif
|
||||
|
||||
|
||||
.ifdef SOLO_IO
|
||||
.include "src/solo_io.asm"
|
||||
.endif
|
||||
|
||||
|
||||
.close
|
|
@ -0,0 +1,347 @@
|
|||
; TODO: Remap solo scores to save as doubles?
|
||||
|
||||
.org 0x8002b8e0
|
||||
is_1p_panel_left_pressed:
|
||||
.org 0x8002b904
|
||||
is_1p_panel_right_pressed:
|
||||
.org 0x8002b808
|
||||
is_1p_start_pressed:
|
||||
.org 0x80041744
|
||||
draw_text:
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Custom code area
|
||||
|
||||
.org 0x80038ce4
|
||||
SoloRatingPatch:
|
||||
li v1, 2
|
||||
move v0, a0
|
||||
|
||||
bne a1, v1, SoloRatingNormalPath
|
||||
nop
|
||||
|
||||
j SoloRatingNormalRead
|
||||
addi v0, 0x04
|
||||
|
||||
SoloRatingNormalPath:
|
||||
sll v0, a1, 0x2
|
||||
addu v0, a0, v0
|
||||
|
||||
SoloRatingNormalRead:
|
||||
lh v0, 0x10(v0)
|
||||
sll v1, a2, 0x2
|
||||
|
||||
j SoloRatingPatchEnd
|
||||
nop
|
||||
|
||||
InputTestMenu:
|
||||
; Up-Left
|
||||
clear a0
|
||||
li a2,-0x1e
|
||||
li v0, UpLeftText
|
||||
sw s1,0x10(sp)
|
||||
sw v0,0x14(sp)
|
||||
lw a1,0x0(s0)
|
||||
jal draw_text
|
||||
li a3,0x1000
|
||||
|
||||
li a2,-0x1e
|
||||
li a3,0x1000
|
||||
lw a0,0x120(sp)
|
||||
nop
|
||||
srl a0,a0,16
|
||||
andi a0,a0,0x0001
|
||||
sltu a0,zero,a0
|
||||
li v0,0x80012d2c
|
||||
sll a1,a0,4
|
||||
add v0, a1
|
||||
lw a1,0x0(s0)
|
||||
sw s1,0x10(sp)
|
||||
sw v0,0x14(sp)
|
||||
sll a0,a0,0x1
|
||||
addiu a1,a1,0x48
|
||||
jal draw_text
|
||||
nop
|
||||
|
||||
; Up-Right
|
||||
clear a0
|
||||
li a2,-0x16
|
||||
li v0, UpRightText
|
||||
sw s1,0x10(sp)
|
||||
sw v0,0x14(sp)
|
||||
lw a1,0x0(s0)
|
||||
jal draw_text
|
||||
li a3,0x1000
|
||||
|
||||
li a2,-0x16
|
||||
li a3,0x1000
|
||||
lw a0,0x120(sp)
|
||||
nop
|
||||
srl a0,a0,16
|
||||
andi a0,a0,0x0002
|
||||
sltu a0,zero,a0
|
||||
li v0,0x80012d2c
|
||||
sll a1,a0,4
|
||||
add v0, a1
|
||||
lw a1,0x0(s0)
|
||||
sw s1,0x10(sp)
|
||||
sw v0,0x14(sp)
|
||||
sltu a0,zero,a0
|
||||
sll a0,a0,0x1
|
||||
jal draw_text
|
||||
addiu a1,a1,0x48
|
||||
|
||||
jal 0x80029728
|
||||
nop
|
||||
|
||||
j InputTestMenuEnd
|
||||
nop
|
||||
|
||||
UpLeftText:
|
||||
.asciiz "UP-LEFT"
|
||||
UpRightText:
|
||||
.asciiz "UP-RIGHT"
|
||||
|
||||
|
||||
; End custom code area
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
.org 0x8001c174
|
||||
this_machine_is_solo:
|
||||
; Always return 1 to enable solo machine mode
|
||||
li v0, 1
|
||||
|
||||
|
||||
.org 0x800909ec
|
||||
; Allow for selecting 6 panel mode on style select screen
|
||||
nop
|
||||
|
||||
|
||||
.org 0x8009b400
|
||||
nop
|
||||
j SoloRatingPatch
|
||||
nop
|
||||
nop
|
||||
SoloRatingPatchEnd:
|
||||
|
||||
|
||||
.org 0x8002b898
|
||||
; Disable 2nd player start button during style select screen
|
||||
jr ra
|
||||
clear v0
|
||||
|
||||
|
||||
; Use small stage number at top during gameplay
|
||||
.org 0x800571b0
|
||||
b 0x800571cc
|
||||
|
||||
|
||||
; Reposition arrows to be centered and evenly spaced around smaller stage number
|
||||
.org 0x80014110
|
||||
.dh 0xffac - 7
|
||||
.dh 0xffe1 - 2
|
||||
.dh 0xffff
|
||||
.dh 0x0034 + 5
|
||||
.dh 0xffc7 - 5
|
||||
.dh 0xff5f
|
||||
.dh 0x0019 + 3
|
||||
.dh 0xff5f
|
||||
.org 0x80014120
|
||||
.dh 0xffc2 - 3
|
||||
.dh 0xffe1 - 2
|
||||
.dh 0xffff
|
||||
.dh 0x001e + 1
|
||||
|
||||
|
||||
; Change graphics for 4 panel and 6 panel mode on style select screen
|
||||
.org 0x80016144
|
||||
; 4 Panel/Single
|
||||
.dh 0x0001 ; 4 Panel/Single flag
|
||||
.dh 0x002c + 0x63 ; Layer absolute x
|
||||
.dh 0x00fb ; Layer absolute y
|
||||
.dh 0x001c ; Character relative x
|
||||
.dh 0x0033 ; Character relative y
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.db 0x04 ; Stages bubble design + tail direction
|
||||
.db 0x78 ; More bubble relative y??
|
||||
.dh 0xffbe ; Bubble relative x
|
||||
.dh 0x000e ; Bubble relative y
|
||||
; 6 Panel
|
||||
.dh 0x000a ; 6 Panel
|
||||
.dh 0x00cd + 0x63
|
||||
.dh 0x00c0
|
||||
.dh 0x001c
|
||||
.dh 0x0051
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.db 0x03
|
||||
.db 0x5a
|
||||
.dh 0x0056
|
||||
.dh 0x0008
|
||||
; Disable last entry
|
||||
.dh 0 ; Disabled
|
||||
.dh 0xff00 ; Send off to outer space
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
.db 0
|
||||
.db 0
|
||||
.dh 0
|
||||
.dh 0
|
||||
|
||||
; Fix solo mode graphic going dim
|
||||
.org 0x800900dc
|
||||
nop
|
||||
|
||||
; Don't show "insert more coins to select other modes" message
|
||||
.org 0x8008e9e0
|
||||
nop
|
||||
|
||||
; Don't show secondary description text
|
||||
.org 0x8008e994
|
||||
j 0x8008ea04
|
||||
|
||||
; Force 6 panel description when 4 panel isn't selected
|
||||
.org 0x8008e944
|
||||
li v1, 0x0a
|
||||
.org 0x8008e96c
|
||||
li t1, 0x02
|
||||
|
||||
; Load "DOUBLE" text instead of "SINGLE" for 6 panel mode
|
||||
.org 0x8008e76c
|
||||
li v1, 0x0a
|
||||
|
||||
; Center bottom text on style select screen
|
||||
.org 0x80084398
|
||||
addiu s0, s0, -0xa0
|
||||
|
||||
; Disable right player side text during free play mode
|
||||
.org 0x80084438
|
||||
nop
|
||||
|
||||
; Make the character select screen show all 14 characters instead of 7 for 1P
|
||||
.org 0x80091ed4
|
||||
li v0, 0x0e
|
||||
|
||||
; Don't show "NOT ATTEND" image on 2P side
|
||||
.org 0x80091564
|
||||
b 0x80091dc0
|
||||
|
||||
; Change character update region width
|
||||
; 2P characters leave the white glow when moving the cursor on the background because
|
||||
; that region isn't being updated
|
||||
.org 0x80092268
|
||||
li s7, 0x240
|
||||
.org 0x80092398
|
||||
li s8, 0x240
|
||||
|
||||
; Don't draw 2P side character name
|
||||
.org 0x80090ed8
|
||||
addiu a2, v0, 0xcb
|
||||
li t1, 0
|
||||
|
||||
; Disable static image when character not selected
|
||||
.org 0x800910c8
|
||||
li s8, 0x180
|
||||
|
||||
; Remove black border triangles from character image area for 2P side
|
||||
.org 0x80090fcc
|
||||
li s8, 0x180
|
||||
|
||||
; Use 2P select icon instead of 1P icon at top of screen (required for image edits)
|
||||
.org 0x80083d04
|
||||
li v0, 0x0a
|
||||
.org 0x80083d10
|
||||
addiu v1, v1, 3
|
||||
|
||||
|
||||
; Fix I/O test menu exit key combo
|
||||
.org 0x8003c314
|
||||
jal is_1p_panel_left_pressed
|
||||
.org 0x8003c324
|
||||
jal is_1p_panel_right_pressed
|
||||
clear a0
|
||||
|
||||
.org 0x80012db8
|
||||
.asciiz " HOLD 1P LEFT +"
|
||||
.org 0x80012dd0
|
||||
.asciiz "PRESS 1P RIGHT = EXIT"
|
||||
|
||||
; Fix start button during free player
|
||||
.org 0x8001f984
|
||||
jal is_1p_start_pressed
|
||||
.org 0x8001f994
|
||||
jal is_1p_start_pressed
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; I/O Test Menu
|
||||
.org 0x8003bf08
|
||||
j InputTestMenu
|
||||
InputTestMenuEnd:
|
||||
|
||||
|
||||
; Fix centering of text
|
||||
.org 0x8003bad4
|
||||
li v0, -0x60
|
||||
.org 0x8003badc
|
||||
li v0, 0x30
|
||||
|
||||
|
||||
.org 0x8003c00c
|
||||
; Don't display 2P side buttons
|
||||
nop
|
||||
|
||||
.org 0x8003bf14
|
||||
; Select L Text
|
||||
li a2, 0xfffffff2
|
||||
.org 0x8003bf34
|
||||
; Select L ON/OFF
|
||||
li a2, 0xfffffff2
|
||||
|
||||
.org 0x8003bf64
|
||||
; Select R Text
|
||||
li a2, 0xfffffffa
|
||||
.org 0x8003bf84
|
||||
; Select R ON/OFF
|
||||
li a2, 0xfffffffa
|
||||
|
||||
.org 0x8003bfbc
|
||||
; Start Text
|
||||
li a2, 0x02
|
||||
.org 0x8003bfdc
|
||||
; Start ON/OFF
|
||||
li a2, 0x02
|
||||
|
||||
.org 0x8003c140
|
||||
; Service Switch Text
|
||||
li a2, 0x12
|
||||
.org 0x8003c164
|
||||
; Service Switch Text
|
||||
li a2, 0x12
|
||||
|
||||
.org 0x8003c194
|
||||
; Coin Mech ON/OFF
|
||||
li a2, 0x1a
|
||||
.org 0x8003c1b4
|
||||
; Coin Mech ON/OFF
|
||||
li a2, 0x1a
|
||||
|
||||
.org 0x8003c1f4
|
||||
; Coin Mech ON/OFF
|
||||
li a2, 0x2a
|
||||
.org 0x8003c244
|
||||
; Coin Mech ON/OFF
|
||||
li a2, 0x2a
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Custom code area
|
||||
; Shares a very close space to the code location used in solo.asm
|
||||
; so be careful that the two don't collide.
|
||||
|
||||
.org 0x80038e44
|
||||
PanelIoFix:
|
||||
nor a1, zero, a1
|
||||
nor a2, zero, a2
|
||||
nor v0, zero, v0
|
||||
|
||||
; This masks out unwanted inputs
|
||||
andi a1, 0xffff8f1f
|
||||
|
||||
; This converts the select l/r button inputs
|
||||
andi v1, a2, 0x200
|
||||
sll v1, 4
|
||||
or a1, v1
|
||||
xor a2, v1
|
||||
|
||||
andi v1, v0, 0x200
|
||||
sll v1, 5
|
||||
or a1, v1
|
||||
xor v0, v1
|
||||
|
||||
; Had to reuse v1 to not mess up any other registers, so read the value again
|
||||
lhu v1, 0x1f400004
|
||||
nop
|
||||
nor v1, zero, v1
|
||||
|
||||
j PanelIoFixEnd
|
||||
nop
|
||||
|
||||
; End custom code area
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
.org 0x800b0424
|
||||
j PanelIoFix
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
PanelIoFixEnd:
|
|
@ -0,0 +1,5 @@
|
|||
if not exist data_raw mkdir data_raw
|
||||
|
||||
tools\sys573tool.exe --mode dump --input data_source --output data_raw --key DDR5 --type ddr --input-filenames tools\ddr5th_filenames.json
|
||||
|
||||
pause
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir -p data_raw
|
||||
python3 tools/py/dump_sys573_gamefs.py --input data_source --output data_raw --key DDR5 --type ddr --input-filenames tools/ddr5th_filenames.json
|
|
@ -0,0 +1,11 @@
|
|||
if not exist build mkdir build
|
||||
|
||||
xcopy /Y /E /H /C data_source\* build
|
||||
if exist build\deleteme.txt del build\deleteme.txt
|
||||
|
||||
tools\sys573tool.exe --mode build --input data_raw --input-modified-list data_modified\modified.json --base data_source --key DDR5 --output build --patch-dir data_modified
|
||||
tools\thirdparty\armips.exe src\main.asm
|
||||
tools\sys573tool.exe --mode checksum --input build\GAME.DAT build\CARD.DAT --output build
|
||||
tools\thirdparty\mkisofs.exe -d -o ddr5thsolo.iso "build"
|
||||
|
||||
pause
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
|
||||
cp -r data_source/* build
|
||||
rm -f build/deleteme.txt
|
||||
|
||||
python3 tools/py/build_sys573_gamefs.py --input data_raw --input-modified-list data_modified/modified.json --base data_source --key DDR5 --output build --patch-dir data_modified
|
||||
|
||||
armips src/main.asm
|
||||
|
||||
python3 tools/py/calc_checksum.py --input build/GAME.DAT build/CARD.DAT --output build
|
||||
|
||||
mkisofs -d -o ddr5thsolo.iso "build"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
if not exist build mkdir build
|
||||
|
||||
xcopy /Y /E /H /C data_source\* build
|
||||
if exist build\deleteme.txt del build\deleteme.txt
|
||||
|
||||
tools\sys573tool.exe --mode build --input data_raw --input-modified-list data_modified\modified.json --base data_source --key DDR5 --output build --patch-dir data_modified
|
||||
tools\thirdparty\armips.exe -definelabel SOLO_IO 1 src\main.asm
|
||||
tools\sys573tool.exe --mode checksum --input build\GAME.DAT build\CARD.DAT --output build
|
||||
tools\thirdparty\mkisofs.exe -d -o ddr5thsolo_soloio.iso "build"
|
||||
|
||||
pause
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
|
||||
cp -r data_source/* build
|
||||
rm -f build/deleteme.txt
|
||||
|
||||
python3 tools/py/build_sys573_gamefs.py --input data_raw --input-modified-list data_modified/modified.json --base data_source --key DDR5 --output build --patch-dir data_modified
|
||||
|
||||
armips -definelabel SOLO_IO 1 src/main.asm
|
||||
|
||||
python3 tools/py/calc_checksum.py --input build/GAME.DAT build/CARD.DAT --output build
|
||||
|
||||
mkisofs -d -o ddr5thsolo_soloio.iso "build"
|
|
@ -0,0 +1,674 @@
|
|||
[
|
||||
"boot/checksum.dat",
|
||||
"boot/config.dat",
|
||||
"boot/psx.bin",
|
||||
"data/bpct/blue/aba_blue.cmt",
|
||||
"data/bpct/blue/bba_blue.cmt",
|
||||
"data/bpct/blue/c8c_blue.cmt",
|
||||
"data/bpct/blue/d8c_blue.cmt",
|
||||
"data/bpct/blue/eba_blue.cmt",
|
||||
"data/bpct/blue/f9a_blue.cmt",
|
||||
"data/bpct/blue/g99_blue.cmt",
|
||||
"data/bpct/blue/h97_blue.cmt",
|
||||
"data/bpct/blue/i87_blue.cmt",
|
||||
"data/bpct/blue/jd7_blue.cmt",
|
||||
"data/bpct/gren/a11_gren.cmt",
|
||||
"data/bpct/gren/b42_gren.cmt",
|
||||
"data/bpct/gren/c87_gren.cmt",
|
||||
"data/bpct/gren/d87_gren.cmt",
|
||||
"data/bpct/gren/eba_gren.cmt",
|
||||
"data/bpct/gren/f99_gren.cmt",
|
||||
"data/bpct/gren/g99_gren.cmt",
|
||||
"data/bpct/gren/h97_gren.cmt",
|
||||
"data/bpct/gren/i87_gren.cmt",
|
||||
"data/bpct/gren/j9c_gren.cmt",
|
||||
"data/bpct/redd/a87_redd.cmt",
|
||||
"data/bpct/redd/b8c_redd.cmt",
|
||||
"data/bpct/redd/cd6_redd.cmt",
|
||||
"data/bpct/redd/dd6_redd.cmt",
|
||||
"data/bpct/redd/eba_redd.cmt",
|
||||
"data/bpct/redd/f99_redd.cmt",
|
||||
"data/bpct/redd/g99_redd.cmt",
|
||||
"data/bpct/redd/h97_redd.cmt",
|
||||
"data/bpct/redd/i97_redd.cmt",
|
||||
"data/bpct/redd/jd7_redd.cmt",
|
||||
"data/bpct/yelo/a87_yelo.cmt",
|
||||
"data/bpct/yelo/b8c_yelo.cmt",
|
||||
"data/bpct/yelo/cd6_yelo.cmt",
|
||||
"data/bpct/yelo/dd6_yelo.cmt",
|
||||
"data/bpct/yelo/eba_yelo.cmt",
|
||||
"data/bpct/yelo/f99_yelo.cmt",
|
||||
"data/bpct/yelo/g99_yelo.cmt",
|
||||
"data/bpct/yelo/h97_yelo.cmt",
|
||||
"data/bpct/yelo/i97_yelo.cmt",
|
||||
"data/bpct/yelo/jd7_yelo.cmt",
|
||||
"data/chara/chara.lst",
|
||||
"data/chara/chara.pos",
|
||||
"data/chara/inst_d/inst_d.cmt",
|
||||
"data/chara/inst_d/inst_d.lst",
|
||||
"data/chara/inst_d/inst_d.pos",
|
||||
"data/chara/inst_d/inst_d.tmd",
|
||||
"data/chara/inst_s/inst_s.cmt",
|
||||
"data/chara/inst_s/inst_s.lst",
|
||||
"data/chara/inst_s/inst_s.pos",
|
||||
"data/chara/inst_s/inst_s.tmd",
|
||||
"data/fpga/fpga_mp3.bin",
|
||||
"data/gpct/dance/arroe_16.cmt",
|
||||
"data/gpct/dance/dangr_16.cmt",
|
||||
"data/gpct/dance/endgs_25.cmt",
|
||||
"data/gpct/dance/gauge_25.cmt",
|
||||
"data/gpct/dance/gaugw_25.cmt",
|
||||
"data/gpct/dance/gmob_25.cmt",
|
||||
"data/gpct/dance/gover_25.cmt",
|
||||
"data/gpct/dance/gread_25.cmt",
|
||||
"data/gpct/dance/hgove_25.cmt",
|
||||
"data/gpct/dance/mfrm_25.cmt",
|
||||
"data/gpct/demo/btile_25.cmt",
|
||||
"data/gpct/demo/cgchk_25.cmt",
|
||||
"data/gpct/demo/endin_25.cmt",
|
||||
"data/gpct/demo/endob_25.cmt",
|
||||
"data/gpct/demo/insb1_16.cmt",
|
||||
"data/gpct/demo/insb2_16.cmt",
|
||||
"data/gpct/demo/insb3_16.cmt",
|
||||
"data/gpct/demo/inst4_16.cmt",
|
||||
"data/gpct/demo/inst5_16.cmt",
|
||||
"data/gpct/demo/klogo_16.cmt",
|
||||
"data/gpct/demo/obk_16.cmt",
|
||||
"data/gpct/demo/oobj_25.cmt",
|
||||
"data/gpct/demo/padv_16.cmt",
|
||||
"data/gpct/demo/scrbk_16.cmt",
|
||||
"data/gpct/demo/scrob_25.cmt",
|
||||
"data/gpct/result/rslbk_16.cmt",
|
||||
"data/gpct/result/rsldl_25.cmt",
|
||||
"data/gpct/result/rslob_25.cmt",
|
||||
"data/gpct/select/albm0_25.cmt",
|
||||
"data/gpct/select/albm1_25.cmt",
|
||||
"data/gpct/select/chr01_25.cmt",
|
||||
"data/gpct/select/chr02_25.cmt",
|
||||
"data/gpct/select/chr03_25.cmt",
|
||||
"data/gpct/select/chr04_25.cmt",
|
||||
"data/gpct/select/chr05_25.cmt",
|
||||
"data/gpct/select/chr06_25.cmt",
|
||||
"data/gpct/select/chr07_25.cmt",
|
||||
"data/gpct/select/chr08_25.cmt",
|
||||
"data/gpct/select/chr09_25.cmt",
|
||||
"data/gpct/select/chr10_25.cmt",
|
||||
"data/gpct/select/chr11_25.cmt",
|
||||
"data/gpct/select/chr12_25.cmt",
|
||||
"data/gpct/select/chr13_25.cmt",
|
||||
"data/gpct/select/chr14_25.cmt",
|
||||
"data/gpct/select/chrna_25.cmt",
|
||||
"data/gpct/select/cslbk_16.cmt",
|
||||
"data/gpct/select/cslic_25.cmt",
|
||||
"data/gpct/select/cslob_25.cmt",
|
||||
"data/gpct/select/msbpm_16.cmt",
|
||||
"data/gpct/select/mslal_16.cmt",
|
||||
"data/gpct/select/mslbk_16.cmt",
|
||||
"data/gpct/select/mslob_25.cmt",
|
||||
"data/gpct/select/mslta_25.cmt",
|
||||
"data/gpct/select/msltt_16.cmt",
|
||||
"data/gpct/select/selcm_16.cmt",
|
||||
"data/gpct/select/seldw_16.cmt",
|
||||
"data/gpct/select/selic_25.cmt",
|
||||
"data/gpct/select/seltr_16.cmt",
|
||||
"data/gpct/select/selup_16.cmt",
|
||||
"data/gpct/select/sslbk_16.cmt",
|
||||
"data/gpct/select/ssldf_mm.cmt",
|
||||
"data/gpct/select/ssldm_mm.cmt",
|
||||
"data/gpct/select/sslob_25.cmt",
|
||||
"data/gpct/select/sslop_25.cmt",
|
||||
"data/lang/japa/blogo_16.cmt",
|
||||
"data/lang/japa/botan_25.cmt",
|
||||
"data/lang/japa/caut_25.cmt",
|
||||
"data/lang/japa/cstxt_25.cmt",
|
||||
"data/lang/japa/hbota_25.cmt",
|
||||
"data/lang/japa/hjoin_25.cmt",
|
||||
"data/lang/japa/hlink_25.cmt",
|
||||
"data/lang/japa/hmcme_16.cmt",
|
||||
"data/lang/japa/inst0_16.cmt",
|
||||
"data/lang/japa/inst1_16.cmt",
|
||||
"data/lang/japa/inst2_16.cmt",
|
||||
"data/lang/japa/inst3_16.cmt",
|
||||
"data/lang/japa/lhowt_25.cmt",
|
||||
"data/lang/japa/ljoin_25.cmt",
|
||||
"data/lang/japa/mcmes_16.cmt",
|
||||
"data/lang/japa/mstxt_25.cmt",
|
||||
"data/lang/japa/oblog_16.cmt",
|
||||
"data/lang/japa/ocd_25.cmt",
|
||||
"data/lang/japa/oklog_16.cmt",
|
||||
"data/lang/japa/otitl_25.cmt",
|
||||
"data/lang/japa/otosh_25.cmt",
|
||||
"data/lang/japa/owarn_16.cmt",
|
||||
"data/lang/japa/showt_25.cmt",
|
||||
"data/lang/japa/ssjoi_25.cmt",
|
||||
"data/lang/japa/sstxt_25.cmt",
|
||||
"data/lang/japa/title_25.cmt",
|
||||
"data/lang/japa/warn_16.cmt",
|
||||
"data/mdb/abso/abso_bk.cmt",
|
||||
"data/mdb/abso/abso_nm.cmt",
|
||||
"data/mdb/abso/abso_ta.cmt",
|
||||
"data/mdb/abso/all.csq",
|
||||
"data/mdb/abys/abys_bk.cmt",
|
||||
"data/mdb/abys/abys_nm.cmt",
|
||||
"data/mdb/abys/abys_ta.cmt",
|
||||
"data/mdb/abys/all.csq",
|
||||
"data/mdb/adre/adre_bk.cmt",
|
||||
"data/mdb/adre/adre_nm.cmt",
|
||||
"data/mdb/adre/adre_ta.cmt",
|
||||
"data/mdb/adre/all.csq",
|
||||
"data/mdb/agai/agai_bk.cmt",
|
||||
"data/mdb/agai/agai_nm.cmt",
|
||||
"data/mdb/agai/agai_ta.cmt",
|
||||
"data/mdb/agai/all.csq",
|
||||
"data/mdb/alla/all.csq",
|
||||
"data/mdb/alla/alla_bk.cmt",
|
||||
"data/mdb/alla/alla_nm.cmt",
|
||||
"data/mdb/alla/alla_ta.cmt",
|
||||
"data/mdb/baby/all.csq",
|
||||
"data/mdb/baby/baby_bk.cmt",
|
||||
"data/mdb/baby/baby_nm.cmt",
|
||||
"data/mdb/baby/baby_ta.cmt",
|
||||
"data/mdb/beto/all.csq",
|
||||
"data/mdb/beto/beto_bk.cmt",
|
||||
"data/mdb/beto/beto_nm.cmt",
|
||||
"data/mdb/beto/beto_ta.cmt",
|
||||
"data/mdb/bfor/all.csq",
|
||||
"data/mdb/bfor/bfor_bk.cmt",
|
||||
"data/mdb/bfor/bfor_nm.cmt",
|
||||
"data/mdb/bfor/bfor_ta.cmt",
|
||||
"data/mdb/bril/all.csq",
|
||||
"data/mdb/bril/bril_bk.cmt",
|
||||
"data/mdb/bril/bril_nm.cmt",
|
||||
"data/mdb/bril/bril_ta.cmt",
|
||||
"data/mdb/brok/all.csq",
|
||||
"data/mdb/brok/brok_bk.cmt",
|
||||
"data/mdb/brok/brok_nm.cmt",
|
||||
"data/mdb/brok/brok_ta.cmt",
|
||||
"data/mdb/bumb/all.csq",
|
||||
"data/mdb/bumb/bumb_bk.cmt",
|
||||
"data/mdb/bumb/bumb_nm.cmt",
|
||||
"data/mdb/bumb/bumb_ta.cmt",
|
||||
"data/mdb/burn/all.csq",
|
||||
"data/mdb/burn/burn_bk.cmt",
|
||||
"data/mdb/burn/burn_nm.cmt",
|
||||
"data/mdb/burn/burn_ta.cmt",
|
||||
"data/mdb/butt/all.csq",
|
||||
"data/mdb/butt/butt_bk.cmt",
|
||||
"data/mdb/butt/butt_nm.cmt",
|
||||
"data/mdb/butt/butt_ta.cmt",
|
||||
"data/mdb/cafe/all.csq",
|
||||
"data/mdb/cafe/cafe_bk.cmt",
|
||||
"data/mdb/cafe/cafe_nm.cmt",
|
||||
"data/mdb/cafe/cafe_ta.cmt",
|
||||
"data/mdb/capt/all.csq",
|
||||
"data/mdb/capt/capt_bk.cmt",
|
||||
"data/mdb/capt/capt_nm.cmt",
|
||||
"data/mdb/capt/capt_ta.cmt",
|
||||
"data/mdb/cats/all.csq",
|
||||
"data/mdb/cats/cats_bk.cmt",
|
||||
"data/mdb/cats/cats_nm.cmt",
|
||||
"data/mdb/cats/cats_ta.cmt",
|
||||
"data/mdb/clim/all.csq",
|
||||
"data/mdb/clim/clim_bk.cmt",
|
||||
"data/mdb/clim/clim_nm.cmt",
|
||||
"data/mdb/clim/clim_ta.cmt",
|
||||
"data/mdb/cong/all.csq",
|
||||
"data/mdb/cong/cong_bk.cmt",
|
||||
"data/mdb/cong/cong_nm.cmt",
|
||||
"data/mdb/cong/cong_ta.cmt",
|
||||
"data/mdb/cube/all.csq",
|
||||
"data/mdb/cube/cube_bk.cmt",
|
||||
"data/mdb/cube/cube_nm.cmt",
|
||||
"data/mdb/cube/cube_ta.cmt",
|
||||
"data/mdb/damd/all.csq",
|
||||
"data/mdb/damd/damd_bk.cmt",
|
||||
"data/mdb/damd/damd_nm.cmt",
|
||||
"data/mdb/damd/damd_ta.cmt",
|
||||
"data/mdb/dead/all.csq",
|
||||
"data/mdb/dead/dead_bk.cmt",
|
||||
"data/mdb/dead/dead_nm.cmt",
|
||||
"data/mdb/dead/dead_ta.cmt",
|
||||
"data/mdb/dive/all.csq",
|
||||
"data/mdb/dive/dive_bk.cmt",
|
||||
"data/mdb/dive/dive_nm.cmt",
|
||||
"data/mdb/dive/dive_ta.cmt",
|
||||
"data/mdb/dluv/all.csq",
|
||||
"data/mdb/dluv/dluv_bk.cmt",
|
||||
"data/mdb/dluv/dluv_nm.cmt",
|
||||
"data/mdb/dluv/dluv_ta.cmt",
|
||||
"data/mdb/dome/all.csq",
|
||||
"data/mdb/dome/dome_bk.cmt",
|
||||
"data/mdb/dome/dome_nm.cmt",
|
||||
"data/mdb/dome/dome_ta.cmt",
|
||||
"data/mdb/drop/all.csq",
|
||||
"data/mdb/drop/drop_bk.cmt",
|
||||
"data/mdb/drop/drop_nm.cmt",
|
||||
"data/mdb/drop/drop_ta.cmt",
|
||||
"data/mdb/dubi/all.csq",
|
||||
"data/mdb/dubi/dubi_bk.cmt",
|
||||
"data/mdb/dubi/dubi_nm.cmt",
|
||||
"data/mdb/dubi/dubi_ta.cmt",
|
||||
"data/mdb/dxyy/all.csq",
|
||||
"data/mdb/dxyy/dxyy_bk.cmt",
|
||||
"data/mdb/dxyy/dxyy_nm.cmt",
|
||||
"data/mdb/dxyy/dxyy_ta.cmt",
|
||||
"data/mdb/dyna/all.csq",
|
||||
"data/mdb/dyna/dyna_bk.cmt",
|
||||
"data/mdb/dyna/dyna_nm.cmt",
|
||||
"data/mdb/dyna/dyna_ta.cmt",
|
||||
"data/mdb/eaty/all.csq",
|
||||
"data/mdb/eaty/eaty_bk.cmt",
|
||||
"data/mdb/eaty/eaty_nm.cmt",
|
||||
"data/mdb/eaty/eaty_ta.cmt",
|
||||
"data/mdb/ecst/all.csq",
|
||||
"data/mdb/ecst/ecst_bk.cmt",
|
||||
"data/mdb/ecst/ecst_nm.cmt",
|
||||
"data/mdb/ecst/ecst_ta.cmt",
|
||||
"data/mdb/elec/all.csq",
|
||||
"data/mdb/elec/elec_bk.cmt",
|
||||
"data/mdb/elec/elec_nm.cmt",
|
||||
"data/mdb/elec/elec_ta.cmt",
|
||||
"data/mdb/endo/all.csq",
|
||||
"data/mdb/endo/endo_bk.cmt",
|
||||
"data/mdb/endo/endo_nm.cmt",
|
||||
"data/mdb/endo/endo_ta.cmt",
|
||||
"data/mdb/eran/all.csq",
|
||||
"data/mdb/eran/eran_bk.cmt",
|
||||
"data/mdb/eran/eran_nm.cmt",
|
||||
"data/mdb/eran/eran_ta.cmt",
|
||||
"data/mdb/estm/all.csq",
|
||||
"data/mdb/estm/estm_bk.cmt",
|
||||
"data/mdb/estm/estm_nm.cmt",
|
||||
"data/mdb/estm/estm_ta.cmt",
|
||||
"data/mdb/ever/all.csq",
|
||||
"data/mdb/ever/ever_bk.cmt",
|
||||
"data/mdb/ever/ever_nm.cmt",
|
||||
"data/mdb/ever/ever_ta.cmt",
|
||||
"data/mdb/feal/all.csq",
|
||||
"data/mdb/feal/feal_bk.cmt",
|
||||
"data/mdb/feal/feal_nm.cmt",
|
||||
"data/mdb/feal/feal_ta.cmt",
|
||||
"data/mdb/gain/all.csq",
|
||||
"data/mdb/gain/gain_bk.cmt",
|
||||
"data/mdb/gain/gain_nm.cmt",
|
||||
"data/mdb/gain/gain_ta.cmt",
|
||||
"data/mdb/getm/all.csq",
|
||||
"data/mdb/getm/getm_bk.cmt",
|
||||
"data/mdb/getm/getm_nm.cmt",
|
||||
"data/mdb/getm/getm_ta.cmt",
|
||||
"data/mdb/gher/all.csq",
|
||||
"data/mdb/gher/gher_bk.cmt",
|
||||
"data/mdb/gher/gher_nm.cmt",
|
||||
"data/mdb/gher/gher_ta.cmt",
|
||||
"data/mdb/gimm/all.csq",
|
||||
"data/mdb/gimm/gimm_bk.cmt",
|
||||
"data/mdb/gimm/gimm_nm.cmt",
|
||||
"data/mdb/gimm/gimm_ta.cmt",
|
||||
"data/mdb/gotc/all.csq",
|
||||
"data/mdb/gotc/gotc_bk.cmt",
|
||||
"data/mdb/gotc/gotc_nm.cmt",
|
||||
"data/mdb/gotc/gotc_ta.cmt",
|
||||
"data/mdb/hboo/all.csq",
|
||||
"data/mdb/hboo/hboo_bk.cmt",
|
||||
"data/mdb/hboo/hboo_nm.cmt",
|
||||
"data/mdb/hboo/hboo_ta.cmt",
|
||||
"data/mdb/hboy/all.csq",
|
||||
"data/mdb/hboy/hboy_bk.cmt",
|
||||
"data/mdb/hboy/hboy_nm.cmt",
|
||||
"data/mdb/hboy/hboy_ta.cmt",
|
||||
"data/mdb/hdam/all.csq",
|
||||
"data/mdb/hdam/hdam_bk.cmt",
|
||||
"data/mdb/hdam/hdam_nm.cmt",
|
||||
"data/mdb/hdam/hdam_ta.cmt",
|
||||
"data/mdb/heat/all.csq",
|
||||
"data/mdb/heat/heat_bk.cmt",
|
||||
"data/mdb/heat/heat_nm.cmt",
|
||||
"data/mdb/heat/heat_ta.cmt",
|
||||
"data/mdb/hhav/all.csq",
|
||||
"data/mdb/hhav/hhav_bk.cmt",
|
||||
"data/mdb/hhav/hhav_nm.cmt",
|
||||
"data/mdb/hhav/hhav_ta.cmt",
|
||||
"data/mdb/hher/all.csq",
|
||||
"data/mdb/hher/hher_bk.cmt",
|
||||
"data/mdb/hher/hher_nm.cmt",
|
||||
"data/mdb/hher/hher_ta.cmt",
|
||||
"data/mdb/hify/all.csq",
|
||||
"data/mdb/hify/hify_bk.cmt",
|
||||
"data/mdb/hify/hify_nm.cmt",
|
||||
"data/mdb/hify/hify_ta.cmt",
|
||||
"data/mdb/hotl/all.csq",
|
||||
"data/mdb/hotl/hotl_bk.cmt",
|
||||
"data/mdb/hotl/hotl_nm.cmt",
|
||||
"data/mdb/hotl/hotl_ta.cmt",
|
||||
"data/mdb/hypn/all.csq",
|
||||
"data/mdb/hypn/hypn_bk.cmt",
|
||||
"data/mdb/hypn/hypn_nm.cmt",
|
||||
"data/mdb/hypn/hypn_ta.cmt",
|
||||
"data/mdb/hyst/all.csq",
|
||||
"data/mdb/hyst/hyst_bk.cmt",
|
||||
"data/mdb/hyst/hyst_nm.cmt",
|
||||
"data/mdb/hyst/hyst_ta.cmt",
|
||||
"data/mdb/ibel/all.csq",
|
||||
"data/mdb/ibel/ibel_bk.cmt",
|
||||
"data/mdb/ibel/ibel_nm.cmt",
|
||||
"data/mdb/ibel/ibel_ta.cmt",
|
||||
"data/mdb/ifyo/all.csq",
|
||||
"data/mdb/ifyo/ifyo_bk.cmt",
|
||||
"data/mdb/ifyo/ifyo_nm.cmt",
|
||||
"data/mdb/ifyo/ifyo_ta.cmt",
|
||||
"data/mdb/inse/all.csq",
|
||||
"data/mdb/inse/inse_bk.cmt",
|
||||
"data/mdb/inse/inse_nm.cmt",
|
||||
"data/mdb/inse/inse_ta.cmt",
|
||||
"data/mdb/iton/all.csq",
|
||||
"data/mdb/iton/iton_bk.cmt",
|
||||
"data/mdb/iton/iton_nm.cmt",
|
||||
"data/mdb/iton/iton_ta.cmt",
|
||||
"data/mdb/iwas/all.csq",
|
||||
"data/mdb/iwas/iwas_bk.cmt",
|
||||
"data/mdb/iwas/iwas_nm.cmt",
|
||||
"data/mdb/iwas/iwas_ta.cmt",
|
||||
"data/mdb/kher/all.csq",
|
||||
"data/mdb/kher/kher_bk.cmt",
|
||||
"data/mdb/kher/kher_nm.cmt",
|
||||
"data/mdb/kher/kher_ta.cmt",
|
||||
"data/mdb/kick/all.csq",
|
||||
"data/mdb/kick/kick_bk.cmt",
|
||||
"data/mdb/kick/kick_nm.cmt",
|
||||
"data/mdb/kick/kick_ta.cmt",
|
||||
"data/mdb/kyhi/all.csq",
|
||||
"data/mdb/kyhi/kyhi_bk.cmt",
|
||||
"data/mdb/kyhi/kyhi_nm.cmt",
|
||||
"data/mdb/kyhi/kyhi_ta.cmt",
|
||||
"data/mdb/lase/all.csq",
|
||||
"data/mdb/lase/lase_bk.cmt",
|
||||
"data/mdb/lase/lase_nm.cmt",
|
||||
"data/mdb/lase/lase_ta.cmt",
|
||||
"data/mdb/lbfo/all.csq",
|
||||
"data/mdb/lbfo/lbfo_bk.cmt",
|
||||
"data/mdb/lbfo/lbfo_nm.cmt",
|
||||
"data/mdb/lbfo/lbfo_ta.cmt",
|
||||
"data/mdb/lcan/all.csq",
|
||||
"data/mdb/lcan/lcan_bk.cmt",
|
||||
"data/mdb/lcan/lcan_nm.cmt",
|
||||
"data/mdb/lcan/lcan_ta.cmt",
|
||||
"data/mdb/ldyn/all.csq",
|
||||
"data/mdb/ldyn/ldyn_bk.cmt",
|
||||
"data/mdb/ldyn/ldyn_nm.cmt",
|
||||
"data/mdb/ldyn/ldyn_ta.cmt",
|
||||
"data/mdb/lead/all.csq",
|
||||
"data/mdb/lead/lead_bk.cmt",
|
||||
"data/mdb/lead/lead_nm.cmt",
|
||||
"data/mdb/lead/lead_ta.cmt",
|
||||
"data/mdb/letb/all.csq",
|
||||
"data/mdb/letb/letb_bk.cmt",
|
||||
"data/mdb/letb/letb_nm.cmt",
|
||||
"data/mdb/letb/letb_ta.cmt",
|
||||
"data/mdb/lety/all.csq",
|
||||
"data/mdb/lety/lety_bk.cmt",
|
||||
"data/mdb/lety/lety_nm.cmt",
|
||||
"data/mdb/lety/lety_ta.cmt",
|
||||
"data/mdb/lupi/all.csq",
|
||||
"data/mdb/lupi/lupi_bk.cmt",
|
||||
"data/mdb/lupi/lupi_nm.cmt",
|
||||
"data/mdb/lupi/lupi_ta.cmt",
|
||||
"data/mdb/mats/all.csq",
|
||||
"data/mdb/mats/mats_bk.cmt",
|
||||
"data/mdb/mats/mats_nm.cmt",
|
||||
"data/mdb/mats/mats_ta.cmt",
|
||||
"data/mdb/mdb.bin",
|
||||
"data/mdb/moon/all.csq",
|
||||
"data/mdb/moon/moon_bk.cmt",
|
||||
"data/mdb/moon/moon_nm.cmt",
|
||||
"data/mdb/moon/moon_ta.cmt",
|
||||
"data/mdb/movi/all.csq",
|
||||
"data/mdb/movi/movi_bk.cmt",
|
||||
"data/mdb/movi/movi_nm.cmt",
|
||||
"data/mdb/movi/movi_ta.cmt",
|
||||
"data/mdb/mrtt/all.csq",
|
||||
"data/mdb/mrtt/mrtt_bk.cmt",
|
||||
"data/mdb/mrtt/mrtt_nm.cmt",
|
||||
"data/mdb/mrtt/mrtt_ta.cmt",
|
||||
"data/mdb/musi/all.csq",
|
||||
"data/mdb/musi/musi_bk.cmt",
|
||||
"data/mdb/musi/musi_nm.cmt",
|
||||
"data/mdb/musi/musi_ta.cmt",
|
||||
"data/mdb/myge/all.csq",
|
||||
"data/mdb/myge/myge_bk.cmt",
|
||||
"data/mdb/myge/myge_nm.cmt",
|
||||
"data/mdb/myge/myge_ta.cmt",
|
||||
"data/mdb/naha/all.csq",
|
||||
"data/mdb/naha/naha_bk.cmt",
|
||||
"data/mdb/naha/naha_nm.cmt",
|
||||
"data/mdb/naha/naha_ta.cmt",
|
||||
"data/mdb/nana/all.csq",
|
||||
"data/mdb/nana/nana_bk.cmt",
|
||||
"data/mdb/nana/nana_nm.cmt",
|
||||
"data/mdb/nana/nana_ta.cmt",
|
||||
"data/mdb/neve/all.csq",
|
||||
"data/mdb/neve/neve_bk.cmt",
|
||||
"data/mdb/neve/neve_nm.cmt",
|
||||
"data/mdb/neve/neve_ta.cmt",
|
||||
"data/mdb/nigh/all.csq",
|
||||
"data/mdb/nigh/nigh_bk.cmt",
|
||||
"data/mdb/nigh/nigh_nm.cmt",
|
||||
"data/mdb/nigh/nigh_ta.cmt",
|
||||
"data/mdb/ninz/all.csq",
|
||||
"data/mdb/ninz/ninz_bk.cmt",
|
||||
"data/mdb/ninz/ninz_nm.cmt",
|
||||
"data/mdb/ninz/ninz_ta.cmt",
|
||||
"data/mdb/nite/all.csq",
|
||||
"data/mdb/nite/nite_bk.cmt",
|
||||
"data/mdb/nite/nite_nm.cmt",
|
||||
"data/mdb/nite/nite_ta.cmt",
|
||||
"data/mdb/noli/all.csq",
|
||||
"data/mdb/noli/noli_bk.cmt",
|
||||
"data/mdb/noli/noli_nm.cmt",
|
||||
"data/mdb/noli/noli_ta.cmt",
|
||||
"data/mdb/olic/all.csq",
|
||||
"data/mdb/olic/olic_bk.cmt",
|
||||
"data/mdb/olic/olic_nm.cmt",
|
||||
"data/mdb/olic/olic_ta.cmt",
|
||||
"data/mdb/onda/all.csq",
|
||||
"data/mdb/onda/onda_bk.cmt",
|
||||
"data/mdb/onda/onda_nm.cmt",
|
||||
"data/mdb/onda/onda_ta.cmt",
|
||||
"data/mdb/ones/all.csq",
|
||||
"data/mdb/ones/ones_bk.cmt",
|
||||
"data/mdb/ones/ones_nm.cmt",
|
||||
"data/mdb/ones/ones_ta.cmt",
|
||||
"data/mdb/onet/all.csq",
|
||||
"data/mdb/onet/onet_bk.cmt",
|
||||
"data/mdb/onet/onet_nm.cmt",
|
||||
"data/mdb/onet/onet_ta.cmt",
|
||||
"data/mdb/only/all.csq",
|
||||
"data/mdb/only/only_bk.cmt",
|
||||
"data/mdb/only/only_nm.cmt",
|
||||
"data/mdb/only/only_ta.cmt",
|
||||
"data/mdb/onts/all.csq",
|
||||
"data/mdb/onts/onts_bk.cmt",
|
||||
"data/mdb/onts/onts_nm.cmt",
|
||||
"data/mdb/onts/onts_ta.cmt",
|
||||
"data/mdb/oops/all.csq",
|
||||
"data/mdb/oops/oops_bk.cmt",
|
||||
"data/mdb/oops/oops_nm.cmt",
|
||||
"data/mdb/oops/oops_ta.cmt",
|
||||
"data/mdb/oose/all.csq",
|
||||
"data/mdb/oose/oose_bk.cmt",
|
||||
"data/mdb/oose/oose_nm.cmt",
|
||||
"data/mdb/oose/oose_ta.cmt",
|
||||
"data/mdb/pafr/all.csq",
|
||||
"data/mdb/pafr/pafr_bk.cmt",
|
||||
"data/mdb/pafr/pafr_nm.cmt",
|
||||
"data/mdb/pafr/pafr_ta.cmt",
|
||||
"data/mdb/para2/all.csq",
|
||||
"data/mdb/para2/para2_bk.cmt",
|
||||
"data/mdb/para2/para2_nm.cmt",
|
||||
"data/mdb/para2/para2_ta.cmt",
|
||||
"data/mdb/peta/all.csq",
|
||||
"data/mdb/peta/peta_bk.cmt",
|
||||
"data/mdb/peta/peta_nm.cmt",
|
||||
"data/mdb/peta/peta_ta.cmt",
|
||||
"data/mdb/peti/all.csq",
|
||||
"data/mdb/peti/peti_bk.cmt",
|
||||
"data/mdb/peti/peti_nm.cmt",
|
||||
"data/mdb/peti/peti_ta.cmt",
|
||||
"data/mdb/pevo/all.csq",
|
||||
"data/mdb/pevo/pevo_bk.cmt",
|
||||
"data/mdb/pevo/pevo_nm.cmt",
|
||||
"data/mdb/pevo/pevo_ta.cmt",
|
||||
"data/mdb/pink/all.csq",
|
||||
"data/mdb/pink/pink_bk.cmt",
|
||||
"data/mdb/pink/pink_nm.cmt",
|
||||
"data/mdb/pink/pink_ta.cmt",
|
||||
"data/mdb/ponp/all.csq",
|
||||
"data/mdb/ponp/ponp_bk.cmt",
|
||||
"data/mdb/ponp/ponp_nm.cmt",
|
||||
"data/mdb/ponp/ponp_ta.cmt",
|
||||
"data/mdb/radi/all.csq",
|
||||
"data/mdb/radi/radi_bk.cmt",
|
||||
"data/mdb/radi/radi_nm.cmt",
|
||||
"data/mdb/radi/radi_ta.cmt",
|
||||
"data/mdb/reme/all.csq",
|
||||
"data/mdb/reme/reme_bk.cmt",
|
||||
"data/mdb/reme/reme_nm.cmt",
|
||||
"data/mdb/reme/reme_ta.cmt",
|
||||
"data/mdb/rhyt/all.csq",
|
||||
"data/mdb/rhyt/rhyt_bk.cmt",
|
||||
"data/mdb/rhyt/rhyt_nm.cmt",
|
||||
"data/mdb/rhyt/rhyt_ta.cmt",
|
||||
"data/mdb/righ/all.csq",
|
||||
"data/mdb/righ/righ_bk.cmt",
|
||||
"data/mdb/righ/righ_nm.cmt",
|
||||
"data/mdb/righ/righ_ta.cmt",
|
||||
"data/mdb/roma/all.csq",
|
||||
"data/mdb/roma/roma_bk.cmt",
|
||||
"data/mdb/roma/roma_nm.cmt",
|
||||
"data/mdb/roma/roma_ta.cmt",
|
||||
"data/mdb/sana/all.csq",
|
||||
"data/mdb/sana/sana_bk.cmt",
|
||||
"data/mdb/sana/sana_nm.cmt",
|
||||
"data/mdb/sana/sana_ta.cmt",
|
||||
"data/mdb/seve/all.csq",
|
||||
"data/mdb/seve/seve_bk.cmt",
|
||||
"data/mdb/seve/seve_nm.cmt",
|
||||
"data/mdb/seve/seve_ta.cmt",
|
||||
"data/mdb/sexy/all.csq",
|
||||
"data/mdb/sexy/sexy_bk.cmt",
|
||||
"data/mdb/sexy/sexy_nm.cmt",
|
||||
"data/mdb/sexy/sexy_ta.cmt",
|
||||
"data/mdb/shak/all.csq",
|
||||
"data/mdb/shak/shak_bk.cmt",
|
||||
"data/mdb/shak/shak_nm.cmt",
|
||||
"data/mdb/shak/shak_ta.cmt",
|
||||
"data/mdb/shoo/all.csq",
|
||||
"data/mdb/shoo/shoo_bk.cmt",
|
||||
"data/mdb/shoo/shoo_nm.cmt",
|
||||
"data/mdb/shoo/shoo_ta.cmt",
|
||||
"data/mdb/sprs/all.csq",
|
||||
"data/mdb/sprs/sprs_bk.cmt",
|
||||
"data/mdb/sprs/sprs_nm.cmt",
|
||||
"data/mdb/sprs/sprs_ta.cmt",
|
||||
"data/mdb/stil/all.csq",
|
||||
"data/mdb/stil/stil_bk.cmt",
|
||||
"data/mdb/stil/stil_nm.cmt",
|
||||
"data/mdb/stil/stil_ta.cmt",
|
||||
"data/mdb/stom/all.csq",
|
||||
"data/mdb/stom/stom_bk.cmt",
|
||||
"data/mdb/stom/stom_nm.cmt",
|
||||
"data/mdb/stom/stom_ta.cmt",
|
||||
"data/mdb/stop/all.csq",
|
||||
"data/mdb/stop/stop_bk.cmt",
|
||||
"data/mdb/stop/stop_nm.cmt",
|
||||
"data/mdb/stop/stop_ta.cmt",
|
||||
"data/mdb/summ/all.csq",
|
||||
"data/mdb/summ/summ_bk.cmt",
|
||||
"data/mdb/summ/summ_nm.cmt",
|
||||
"data/mdb/summ/summ_ta.cmt",
|
||||
"data/mdb/sync/all.csq",
|
||||
"data/mdb/sync/sync_bk.cmt",
|
||||
"data/mdb/sync/sync_nm.cmt",
|
||||
"data/mdb/sync/sync_ta.cmt",
|
||||
"data/mdb/talk/all.csq",
|
||||
"data/mdb/talk/talk_bk.cmt",
|
||||
"data/mdb/talk/talk_nm.cmt",
|
||||
"data/mdb/talk/talk_ta.cmt",
|
||||
"data/mdb/teng/all.csq",
|
||||
"data/mdb/teng/teng_bk.cmt",
|
||||
"data/mdb/teng/teng_nm.cmt",
|
||||
"data/mdb/teng/teng_ta.cmt",
|
||||
"data/mdb/tequ/all.csq",
|
||||
"data/mdb/tequ/tequ_bk.cmt",
|
||||
"data/mdb/tequ/tequ_nm.cmt",
|
||||
"data/mdb/tequ/tequ_ta.cmt",
|
||||
"data/mdb/them/all.csq",
|
||||
"data/mdb/them/them_bk.cmt",
|
||||
"data/mdb/them/them_nm.cmt",
|
||||
"data/mdb/them/them_ta.cmt",
|
||||
"data/mdb/trib/all.csq",
|
||||
"data/mdb/trib/trib_bk.cmt",
|
||||
"data/mdb/trib/trib_nm.cmt",
|
||||
"data/mdb/trib/trib_ta.cmt",
|
||||
"data/mdb/twis/all.csq",
|
||||
"data/mdb/twis/twis_bk.cmt",
|
||||
"data/mdb/twis/twis_nm.cmt",
|
||||
"data/mdb/twis/twis_ta.cmt",
|
||||
"data/mdb/walk/all.csq",
|
||||
"data/mdb/walk/walk_bk.cmt",
|
||||
"data/mdb/walk/walk_nm.cmt",
|
||||
"data/mdb/walk/walk_ta.cmt",
|
||||
"data/mdb/wild/all.csq",
|
||||
"data/mdb/wild/wild_bk.cmt",
|
||||
"data/mdb/wild/wild_nm.cmt",
|
||||
"data/mdb/wild/wild_ta.cmt",
|
||||
"data/mdb/xana/all.csq",
|
||||
"data/mdb/xana/xana_bk.cmt",
|
||||
"data/mdb/xana/xana_nm.cmt",
|
||||
"data/mdb/xana/xana_ta.cmt",
|
||||
"data/mdb/youn/all.csq",
|
||||
"data/mdb/youn/youn_bk.cmt",
|
||||
"data/mdb/youn/youn_nm.cmt",
|
||||
"data/mdb/youn/youn_ta.cmt",
|
||||
"data/mdb/your/all.csq",
|
||||
"data/mdb/your/your_bk.cmt",
|
||||
"data/mdb/your/your_nm.cmt",
|
||||
"data/mdb/your/your_ta.cmt",
|
||||
"data/motion/capoera1/capoera1.cmm",
|
||||
"data/motion/hiphop1/hiphop1.cmm",
|
||||
"data/motion/hiphop2/hiphop2.cmm",
|
||||
"data/motion/hopping1/hopping1.cmm",
|
||||
"data/motion/inst/inst.cmm",
|
||||
"data/motion/jazz1/jazz1.cmm",
|
||||
"data/motion/jazz2/jazz2.cmm",
|
||||
"data/motion/lock1/lock1.cmm",
|
||||
"data/motion/mhouse1/mhouse1.cmm",
|
||||
"data/motion/n31/n31.cmm",
|
||||
"data/motion/normal/normal.cmm",
|
||||
"data/motion/sino_/sino_.cmm",
|
||||
"data/motion/soul1/soul1.cmm",
|
||||
"data/motion/soul2/soul2.cmm",
|
||||
"data/motion/thouse2/thouse2.cmm",
|
||||
"data/motion/thouse3/thouse3.cmm",
|
||||
"data/motion/y11/y11.cmm",
|
||||
"data/motion/y31/y31.cmm",
|
||||
"data/mp3/mp3_tab.bin",
|
||||
"data/tex/rembind.bin",
|
||||
"data/tex/subbind.bin",
|
||||
"data/tim/arrow/arros_25.cmt",
|
||||
"data/tim/arrow/arrow_16.cmt",
|
||||
"data/tim/nfont/ac0808.cmt",
|
||||
"data/tim/nfont/ac1112.cmt",
|
||||
"data/tim/nfont/ac1616.cmt",
|
||||
"data/tim/nfont/nm1220.cmt",
|
||||
"data/tim/nfont/nm2020.cmt",
|
||||
"data/tim/nfont/nm2422.cmt",
|
||||
"data/tim/nfont/nm3222.cmt",
|
||||
"data/tim/nfont/sc1216.cmt",
|
||||
"data/tim/wfont/acxx12.cmt",
|
||||
"data/tim/wfont/acxx16.cmt",
|
||||
"data/tim/wfont/acxx20.cmt",
|
||||
"data/tim/wfont/nmxx32.cmt",
|
||||
"data/tim/wfont/rexx16.cmt",
|
||||
"data/tim/wfont/wfont_w.bin",
|
||||
"soft/s573/aout.exe"
|
||||
]
|
|
@ -0,0 +1,429 @@
|
|||
import argparse
|
||||
import copy
|
||||
import ctypes
|
||||
import glob
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import struct
|
||||
import string
|
||||
|
||||
import comp573
|
||||
import sum573
|
||||
|
||||
|
||||
def rebuild_checksum_table(cards):
|
||||
card_sizes = [len(x) // 0x8000 for x in cards]
|
||||
|
||||
CHUNK_SIZE = 0x20000
|
||||
LAST_CHUNK_OFFSET = len(cards[0]) - CHUNK_SIZE
|
||||
LAST_CHUNK_CHECKSUM_OFFSET = LAST_CHUNK_OFFSET + 0x10
|
||||
|
||||
# Set entire checksum.dat section to zero
|
||||
cards[0] = cards[0][:LAST_CHUNK_CHECKSUM_OFFSET] + bytearray([0] * 0x1ff0) + cards[0][LAST_CHUNK_OFFSET + 0x2000:]
|
||||
|
||||
# Calculate checksums for GAME.DAT
|
||||
cards = sum573.add_checksums(cards, card_sizes, CHUNK_SIZE, LAST_CHUNK_CHECKSUM_OFFSET, 0, 1)
|
||||
|
||||
# Balance out the sums at this point because otherwise the chunk checksum won't match
|
||||
cards = sum573.balance_sums(cards, card_sizes, LAST_CHUNK_OFFSET)
|
||||
|
||||
# Set the real checksum of the last section finally
|
||||
table_checksum_idx = len(cards[0]) // CHUNK_SIZE
|
||||
table_checksum_offset = LAST_CHUNK_CHECKSUM_OFFSET + ((table_checksum_idx - 1) * 4)
|
||||
cards[0][table_checksum_offset:table_checksum_offset+4] = sum573.checksum_chunk(cards[0], LAST_CHUNK_OFFSET, CHUNK_SIZE)
|
||||
|
||||
# Add checksums for other DATs now
|
||||
cards = sum573.add_checksums(cards, card_sizes, CHUNK_SIZE, LAST_CHUNK_CHECKSUM_OFFSET, 1, len(cards) - 1)
|
||||
|
||||
sum573.balance_sums(cards, card_sizes, LAST_CHUNK_OFFSET)
|
||||
|
||||
|
||||
def get_filename_hash(filename, entry):
|
||||
hash = 0
|
||||
|
||||
if 'filename_hash' in entry:
|
||||
return entry['filename_hash']
|
||||
|
||||
if filename.startswith("_output_") and filename.endswith(".bin"):
|
||||
hash = int(filename.replace("_output_", "").replace(".bin", ""), 16)
|
||||
return hash
|
||||
|
||||
for cidx, c in enumerate(filename):
|
||||
for i in range(6):
|
||||
hash = ctypes.c_int(((hash >> 31) & 0x4c11db7) ^ ((hash << 1) | ((ord(c) >> i) & 1))).value
|
||||
|
||||
hash &= 0xffffffff
|
||||
|
||||
return hash
|
||||
|
||||
|
||||
def encrypt_data(data, input_key):
|
||||
def calculate_key(input):
|
||||
key = 0
|
||||
|
||||
for c in input.upper():
|
||||
if c in string.ascii_uppercase:
|
||||
key -= 0x37
|
||||
|
||||
elif c in string.ascii_lowercase:
|
||||
key -= 0x57
|
||||
|
||||
elif c in string.digits:
|
||||
key -= 0x30
|
||||
|
||||
key += ord(c)
|
||||
|
||||
return key & 0xff
|
||||
|
||||
val = 0x41C64E6D
|
||||
key1 = (val * calculate_key(input_key)) & 0xffffffff
|
||||
counter = 0
|
||||
|
||||
for idx, c in enumerate(data):
|
||||
val = ((key1 + counter) >> 5) ^ c
|
||||
data[idx] = val & 0xff
|
||||
counter += 0x3039
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_filetable(input_folder, input_modified_list, patch_dir=""):
|
||||
entries = []
|
||||
new_entries = []
|
||||
|
||||
if input_modified_list and os.path.exists(input_modified_list):
|
||||
new_entries += json.load(open(input_modified_list))
|
||||
|
||||
metadata_path = os.path.join(input_folder, "_metadata.json")
|
||||
if os.path.exists(metadata_path):
|
||||
entries = json.load(open(metadata_path)).get('files', [])
|
||||
|
||||
for entry in json.load(open(metadata_path)).get('modified', []):
|
||||
exists = False
|
||||
for new_entry in new_entries:
|
||||
if entry['filename'] == new_entry['filename']:
|
||||
exists = True
|
||||
|
||||
if not exists:
|
||||
new_entries.append(entry)
|
||||
|
||||
new_entry_filenames = []
|
||||
if new_entries:
|
||||
for entry in new_entries:
|
||||
entry['_path'] = os.path.join(input_folder, entry['filename'])
|
||||
entry['filename_hash'] = get_filename_hash(entry['filename'], entry)
|
||||
entry['_modified'] = True
|
||||
|
||||
if entry.get('patch', None) is not None:
|
||||
entry['patch'] = os.path.join(patch_dir, entry['patch'])
|
||||
|
||||
new_entry_filenames.append(entry['filename'])
|
||||
|
||||
if entries:
|
||||
for entry in entries:
|
||||
entry['_path'] = os.path.join(input_folder, entry['filename'])
|
||||
entry['filename_hash'] = get_filename_hash(entry['filename'], entry)
|
||||
|
||||
if entry.get('patch', None) is not None:
|
||||
entry['patch'] = os.path.join(patch_dir, entry['patch'])
|
||||
|
||||
# # Free some space by removing any MP3s actually inside the flash card by default
|
||||
# if entry['filename'].startswith("data/mp3/enc"):
|
||||
# entry['_free'] = True
|
||||
|
||||
# # Free even more space by removing all of the data in the mdb folder besides the mdb.bin
|
||||
# if entry['filename'].startswith("data/mdb/") and entry['filename'] not in ['data/mdb/mdb.bin']:
|
||||
# entry['_free'] = True
|
||||
|
||||
# Free up the space used by files that will be overwritten
|
||||
if entry['filename'] in new_entry_filenames:
|
||||
for entry2 in new_entries:
|
||||
if entry2['filename'] == entry['filename']:
|
||||
size = entry['filesize']
|
||||
|
||||
if (size % 0x800) != 0:
|
||||
padding = 0x800 - (size % 0x800)
|
||||
|
||||
else:
|
||||
padding = 0x800
|
||||
|
||||
entry2['_orig_filesize'] = entry['filesize'] + padding
|
||||
|
||||
break
|
||||
|
||||
entry['_free'] = True
|
||||
|
||||
return sorted(entries + new_entries, key=lambda x: x['filename_hash'])
|
||||
|
||||
|
||||
def get_data_from_entry(entry):
|
||||
data = open(os.path.normpath(entry['_path']), "rb").read()
|
||||
|
||||
if entry.get('patch', None) is not None:
|
||||
if entry.get('patch_format') == "bsdiff4":
|
||||
import bsdiff4
|
||||
data = bsdiff4.patch(data, open(entry['patch'], "rb").read())
|
||||
|
||||
return bytearray(data)
|
||||
|
||||
|
||||
def create_gamedata(entries, base_offset, memory, enc_key, override_edit_section):
|
||||
# You can modify this to default to unused and you can probably squeeze a little bit more data
|
||||
# into the cards, but you will almost surely run over some data you shouldn't touch so be careful.
|
||||
memory_map = [bytearray([1] * len(mem)) for mem in memory] # 0 = unused, 1 = used
|
||||
memory_map[0][:0x200000] = [1] * 0x200000 # Reserve this section for the program code
|
||||
memory_map[1][0x18c0000:0x1b66800] = [1] * (0x1b66800 - 0x18c0000) # Reserve this section because it's where system sounds reside (not in actual file table)
|
||||
|
||||
if override_edit_section:
|
||||
memory_map[1][0x1b66800:0x2000000] = [0] * (0x2000000 - 0x1b66800) # Unreserve the space where edit data is normally stored
|
||||
|
||||
# Find the data
|
||||
entries_work = entries[::]
|
||||
|
||||
# Mark unmodified data as used and freed data as unused
|
||||
for entry in entries_work[::]:
|
||||
if entry.get('_modified', False):
|
||||
continue
|
||||
|
||||
cur_memory = entry['offset']
|
||||
|
||||
size = entry['filesize']
|
||||
if (size % 0x800) != 0:
|
||||
size += 0x800 - (size % 0x800)
|
||||
|
||||
if entry.get('_free', False):
|
||||
memory_map[entry.get('flag_loc', 0)][cur_memory:cur_memory + size] = [0] * size
|
||||
|
||||
else:
|
||||
memory_map[entry.get('flag_loc', 0)][cur_memory:cur_memory + size] = [1] * size
|
||||
|
||||
entries_work.remove(entry)
|
||||
|
||||
entries_work = [x for x in entries_work if not x.get('_free', False)]
|
||||
entries = [x for x in entries if not x.get('_free', False)]
|
||||
|
||||
entries_work_priority = [x for x in entries_work if x['filename'] in ['data/mp3/mp3_tab.bin', 'data/mdb/mdb.bin'] or x['filename'].startswith("boot/") or x['filename'].startswith("soft/")]
|
||||
entries_work = entries_work_priority + [x for x in entries_work if x not in entries_work_priority]
|
||||
|
||||
data_hashes = {}
|
||||
used_addresses = []
|
||||
cur_memory = 0
|
||||
|
||||
# Certain files need to be at specific offsets or else they won't work properly (seemingly, maybe it's a bug with my code somewhere)
|
||||
# so put any "important" files where they should be for the most part
|
||||
for entry in entries_work[::]:
|
||||
if not entry.get('_modified', False):
|
||||
continue
|
||||
|
||||
if not entry['filename'].startswith('boot/') and not entry['filename'].startswith('soft/') and not entry['filename'].startswith('data/fpga/'):
|
||||
continue
|
||||
|
||||
if 'offset' in entry:
|
||||
cur_memory = entry['offset']
|
||||
|
||||
data = get_data_from_entry(entry)
|
||||
|
||||
if entry.get('flag_comp', 0) == 1:
|
||||
data = comp573.encode_lz(data, len(data))
|
||||
|
||||
if entry.get('flag_enc', 0) == 1:
|
||||
data = encrypt_data(data, enc_key)
|
||||
|
||||
entry['filesize'] = len(data)
|
||||
|
||||
datahash = hashlib.sha1(data).hexdigest()
|
||||
data_hashes[datahash] = {
|
||||
'offset': cur_memory,
|
||||
'filesize': entry['filesize'],
|
||||
'loc': entry.get('flag_loc', 0),
|
||||
}
|
||||
|
||||
if len(data) > entry['filesize']:
|
||||
print("Filesize is too large: %08x vs %08x" % (len(data), entry['filesize']))
|
||||
|
||||
elif len(data) < entry['filesize']:
|
||||
entry['filesize'] = len(data)
|
||||
|
||||
# Pad with 0xff
|
||||
data += b'\xff' * (entry['filesize'] - len(data))
|
||||
|
||||
size = entry['filesize']
|
||||
padding = 0
|
||||
if (size % 0x800) != 0:
|
||||
padding = 0x800 - (size % 0x800)
|
||||
|
||||
else:
|
||||
padding = 0x800
|
||||
|
||||
size += padding
|
||||
|
||||
memory[entry.get('flag_loc', 0)][cur_memory + entry['filesize']:cur_memory + entry['filesize'] + padding] = bytearray([0xff] * padding)
|
||||
memory[entry.get('flag_loc', 0)][cur_memory:cur_memory + entry['filesize']] = data
|
||||
memory_map[entry.get('flag_loc', 0)][cur_memory:cur_memory + entry['filesize']] = [1] * size
|
||||
|
||||
entries_work.remove(entry)
|
||||
used_addresses.append((entry.get('flag_loc', 0), cur_memory))
|
||||
|
||||
# For everything else, just try to find a fitting space in the available areas
|
||||
entries_len = len(entries_work[::])
|
||||
for entry_idx, entry in enumerate(entries_work[::]):
|
||||
if not entry.get('_modified', False):
|
||||
continue
|
||||
|
||||
data = get_data_from_entry(entry)
|
||||
orig_len = len(data)
|
||||
|
||||
if entry.get('flag_comp', 0) == 1:
|
||||
data = comp573.encode_lz(data, len(data))
|
||||
|
||||
if entry.get('flag_enc', 0) == 1:
|
||||
data = encrypt_data(data, enc_key)
|
||||
|
||||
datahash = hashlib.sha1(data).hexdigest()
|
||||
|
||||
size = len(data)
|
||||
padding = 0
|
||||
if (size % 0x800) != 0:
|
||||
padding = 0x800 - (size % 0x800)
|
||||
|
||||
else:
|
||||
padding = 0x800
|
||||
|
||||
is_dupe = False
|
||||
if datahash in data_hashes:
|
||||
cur_memory = data_hashes[datahash]['offset']
|
||||
loc = data_hashes[datahash]['loc']
|
||||
is_dupe = True
|
||||
|
||||
else:
|
||||
# This code is not optimized. It sucks but it works.
|
||||
# The general idea I was trying to implement is to find the first
|
||||
# string of 0s in the memory map that could fit the size of the data
|
||||
# padded to the nearest sector (0x800).
|
||||
# The padding is key because if you can't clear out the sector properly
|
||||
# then the game has a higher chance of crashing for some reason.
|
||||
# Possibly due to decompression reading in garbage data as compressed data.
|
||||
for loc in range(0, len(memory_map)):
|
||||
loc = entry.get('flag_loc', 1)
|
||||
|
||||
cur_memory = 0
|
||||
|
||||
while cur_memory < len(memory_map[loc]):
|
||||
if (cur_memory % 0x800) != 0:
|
||||
cur_memory += (0x800 - (cur_memory % 0x800))
|
||||
|
||||
idx = memory_map[loc].find(0, cur_memory)
|
||||
|
||||
if idx == -1:
|
||||
cur_memory = -1
|
||||
break
|
||||
|
||||
if (idx % 0x800) != 0:
|
||||
cur_memory = idx + 1
|
||||
continue
|
||||
|
||||
cur_memory = idx
|
||||
idx = memory_map[loc].find(1, cur_memory, cur_memory + len(data) + padding)
|
||||
|
||||
if idx != -1:
|
||||
cur_memory = idx
|
||||
|
||||
if (idx % 0x800) != 0:
|
||||
cur_memory += 0x800 - (idx % 0x800)
|
||||
|
||||
continue
|
||||
|
||||
else:
|
||||
break
|
||||
|
||||
if cur_memory > len(memory_map[loc]):
|
||||
cur_memory = -1
|
||||
break
|
||||
|
||||
if cur_memory > len(memory_map[loc]):
|
||||
cur_memory = - 1
|
||||
continue
|
||||
|
||||
if loc == 0 and cur_memory + len(data) + padding >= base_offset:
|
||||
continue
|
||||
|
||||
if cur_memory > 0:
|
||||
break
|
||||
|
||||
if cur_memory == -1 or (loc == 0 and cur_memory + len(data) + padding >= base_offset):
|
||||
print("Couldn't find position for %08x" % len(data), entry)
|
||||
exit(1)
|
||||
|
||||
|
||||
print("%d / %d: Placing %08x @ %08x in card %d for %s" % (entry_idx, entries_len, len(data), cur_memory, loc, entry['filename']))
|
||||
|
||||
if not is_dupe and (loc, cur_memory) in used_addresses:
|
||||
print("Can't reuse address!")
|
||||
exit(1)
|
||||
|
||||
size += padding
|
||||
memory[loc][cur_memory:cur_memory + len(data)] = data
|
||||
memory[loc][cur_memory + len(data):cur_memory + len(data) + padding] = bytearray([0xff] * padding)
|
||||
memory_map[loc][cur_memory:cur_memory + len(data) + padding] = [1] * size
|
||||
|
||||
entry['filesize'] = len(data)
|
||||
used_addresses.append((loc, cur_memory))
|
||||
|
||||
data_hashes[datahash] = {
|
||||
'offset': cur_memory,
|
||||
'filesize': entry['filesize'],
|
||||
'loc': loc,
|
||||
}
|
||||
|
||||
# Update master entries for the file table lazily
|
||||
for e in entries:
|
||||
if e == entry:
|
||||
e['offset'] = cur_memory
|
||||
|
||||
entries_work.remove(entry)
|
||||
|
||||
entries = sorted(entries, key=lambda x: x['filename_hash'])
|
||||
|
||||
for idx, entry in enumerate(entries):
|
||||
print("%08x" % entry['filename_hash'], entry)
|
||||
memory[0][base_offset + 0x4000 + (idx * 0x10):base_offset + 0x4000 + ((idx + 1) * 0x10)] = struct.pack("<IHHBBHI", entry['filename_hash'], entry['offset'] // 0x800, entry.get('flag_loc', 0), entry.get('flag_comp', 0), entry.get('flag_enc', 0), entry.get('unk', 0), entry['filesize'])
|
||||
|
||||
idx = len(entries)
|
||||
memory[0][base_offset + 0x4000 + (idx * 0x10):base_offset + 0x4000 + ((idx + 1) * 0x10)] = struct.pack("<IIII", 0, 0, 0, 0)
|
||||
|
||||
return memory
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('--input', help='Input folder', default=None, required=True)
|
||||
parser.add_argument('--input-modified-list', help='Input modified list', default=None)
|
||||
parser.add_argument('--base', help='Base file folder', default=None, required=True)
|
||||
parser.add_argument('--output', help='Output file', default="output")
|
||||
parser.add_argument('--key', help='Encryption key', choices=['EXTREME', 'EURO2', 'MAX2', 'DDR5', 'MAMBO'], required=True)
|
||||
parser.add_argument('--override-edit-section', help='Allows use of end of CARD 2 which would otherwise be used for edit data saved to flash card. REQUIRED ENABLE_EDIT_SECTOR_OVERRIDE ENABLED IN ASM PATCHES!', default=False, action='store_true')
|
||||
parser.add_argument('--patch-dir', help='Path to use for patch files', default="")
|
||||
|
||||
args, _ = parser.parse_known_args()
|
||||
|
||||
os.makedirs(args.output, exist_ok=True)
|
||||
|
||||
# Settings are specific to DDR Extreme for now
|
||||
basefileinfo = [("GAME.DAT", 16), ("CARD.DAT", 32)]
|
||||
base_offset = 0xFE0000
|
||||
filetable = get_filetable(args.input, args.input_modified_list, args.patch_dir)
|
||||
|
||||
card_datas = create_gamedata(filetable, base_offset, [bytearray(open(os.path.join(args.base, info[0]), "rb").read()) for info in basefileinfo], args.key, args.override_edit_section)
|
||||
card_datas = [bytearray(data)[:basefileinfo[i][1] * 1024 * 1024] for i, data in enumerate(card_datas)]
|
||||
|
||||
rebuild_checksum_table(card_datas)
|
||||
|
||||
for i, data in enumerate(card_datas):
|
||||
open(os.path.join(args.output, basefileinfo[i][0]), "wb").write(data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,86 @@
|
|||
import argparse
|
||||
import os
|
||||
|
||||
import sum573
|
||||
|
||||
|
||||
def rebuild_checksum_table(cards):
|
||||
card_sizes = [len(x) // 0x8000 for x in cards]
|
||||
|
||||
CHUNK_SIZE = 0x20000
|
||||
LAST_CHUNK_OFFSET = len(cards[0]) - CHUNK_SIZE
|
||||
LAST_CHUNK_CHECKSUM_OFFSET = LAST_CHUNK_OFFSET + 0x10
|
||||
|
||||
# Set entire checksum.dat section to zero
|
||||
cards[0] = cards[0][:LAST_CHUNK_CHECKSUM_OFFSET] + bytearray([0] * 0x1ff0) + cards[0][LAST_CHUNK_OFFSET + 0x2000:]
|
||||
|
||||
# Calculate checksums for GAME.DAT
|
||||
cards = sum573.add_checksums(cards, card_sizes, CHUNK_SIZE, LAST_CHUNK_CHECKSUM_OFFSET, 0, 1)
|
||||
|
||||
# Balance out the sums at this point because otherwise the chunk checksum won't match
|
||||
cards = sum573.balance_sums(cards, card_sizes, LAST_CHUNK_OFFSET)
|
||||
|
||||
# Set the real checksum of the last section finally
|
||||
table_checksum_idx = len(cards[0]) // CHUNK_SIZE
|
||||
table_checksum_offset = LAST_CHUNK_CHECKSUM_OFFSET + ((table_checksum_idx - 1) * 4)
|
||||
cards[0][table_checksum_offset:table_checksum_offset+4] = sum573.checksum_chunk(cards[0], LAST_CHUNK_OFFSET, CHUNK_SIZE)
|
||||
|
||||
# Add checksums for other DATs now
|
||||
cards = sum573.add_checksums(cards, card_sizes, CHUNK_SIZE, LAST_CHUNK_CHECKSUM_OFFSET, 1, len(cards) - 1)
|
||||
|
||||
sum573.balance_sums(cards, card_sizes, LAST_CHUNK_OFFSET)
|
||||
|
||||
|
||||
def verify_checksums(cards):
|
||||
card_sizes = [len(x) // 0x8000 for x in cards]
|
||||
|
||||
chunk_size = 0x20000
|
||||
last_chunk_offset = len(cards[0]) - chunk_size
|
||||
last_chunk_checksum_offset = last_chunk_offset + 0x10
|
||||
|
||||
checksums = [int.from_bytes(cards[0][last_chunk_checksum_offset+x:last_chunk_checksum_offset+x+4], 'little') for x in range(0, 0x2000, 4)]
|
||||
|
||||
is_valid = True
|
||||
for real_card_index, card_data in enumerate(cards):
|
||||
for i in range(0, len(card_data) // chunk_size):
|
||||
offset = (i * chunk_size) + (0x20 if real_card_index == 0 and i == 0 else 0)
|
||||
length = chunk_size - (0x20 if real_card_index == 0 and i == 0 else 0)
|
||||
checksum_bytes = int.from_bytes(sum573.checksum_chunk(card_data, offset, length), 'little')
|
||||
|
||||
target_checksum = checksums[i + (sum(card_sizes[:real_card_index]) // 4)]
|
||||
if checksum_bytes != target_checksum:
|
||||
print("Sector %d of DAT %d is invalid! %08x vs %08x" % (i, real_card_index, checksum_bytes, target_checksum))
|
||||
is_valid = False
|
||||
|
||||
return is_valid
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('--input', help='Input DAT file (list all in order)', nargs='+', required=True)
|
||||
parser.add_argument('--output', help='Output folder', default="output")
|
||||
|
||||
args, _ = parser.parse_known_args()
|
||||
|
||||
cards = [bytearray(open(x, "rb").read()) for x in args.input]
|
||||
|
||||
for x in args.input:
|
||||
print(x)
|
||||
|
||||
is_valid = verify_checksums(cards)
|
||||
print("Is checksum table valid?", is_valid)
|
||||
|
||||
if not is_valid:
|
||||
rebuild_checksum_table(cards)
|
||||
|
||||
is_valid = verify_checksums(cards)
|
||||
print("Is checksum table valid?", is_valid)
|
||||
|
||||
os.makedirs(args.output, exist_ok=True)
|
||||
for i, x in enumerate(args.input):
|
||||
open(os.path.join(args.output, os.path.basename(x)), "wb").write(cards[i])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,335 @@
|
|||
# cython: cdivision=True
|
||||
# distutils: language=c++
|
||||
|
||||
from libc.stdint cimport uint8_t
|
||||
|
||||
cdef extern from *:
|
||||
"""
|
||||
template <typename T>
|
||||
T* array_new(int n) {
|
||||
return new T[n];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_delete(T* x) {
|
||||
delete [] x;
|
||||
}
|
||||
"""
|
||||
T* array_new[T](int)
|
||||
void array_delete[T](T* x)
|
||||
|
||||
from libcpp.vector cimport vector
|
||||
|
||||
|
||||
cdef inline int find_data(unsigned char *data, int data_len, unsigned char c, int offset):
|
||||
while offset < data_len:
|
||||
if data[offset] == c:
|
||||
return offset
|
||||
|
||||
offset += 1
|
||||
|
||||
return -1
|
||||
|
||||
|
||||
cpdef bytearray decode_lz(unsigned char *input_data, int data_len):
|
||||
cdef bytearray output = bytearray()
|
||||
cdef int idx = 0
|
||||
cdef int idx2 = 0
|
||||
cdef int start_offset = 0
|
||||
cdef int distance = 0
|
||||
cdef int control = 0
|
||||
cdef unsigned char data = 0
|
||||
cdef int length = 0
|
||||
|
||||
while True:
|
||||
control >>= 1
|
||||
|
||||
if (control & 0x100) == 0:
|
||||
control = input_data[idx] | 0xff00
|
||||
idx += 1
|
||||
|
||||
data = input_data[idx]
|
||||
idx += 1
|
||||
|
||||
if (control & 1) == 0:
|
||||
output.append(data)
|
||||
continue
|
||||
|
||||
# print("idx: %02x" % idx)
|
||||
|
||||
length = -1
|
||||
if (data & 0x80) == 0:
|
||||
distance = ((data & 0x03) << 8) | input_data[idx]
|
||||
length = (data >> 2) + 2
|
||||
idx += 1
|
||||
|
||||
elif (data & 0x40) == 0:
|
||||
distance = (data & 0x0f) + 1
|
||||
length = (data >> 4) - 7
|
||||
|
||||
# print("%04x %02x %02x" % (control, data, input_data[idx-1]), distance, length)
|
||||
|
||||
if length != -1:
|
||||
start_offset = len(output)
|
||||
idx2 = 0
|
||||
|
||||
while idx2 <= length:
|
||||
output.append(output[(start_offset - distance) + idx2])
|
||||
idx2 += 1
|
||||
|
||||
continue
|
||||
|
||||
if data == 0xff:
|
||||
break
|
||||
|
||||
length = data - 0xb9
|
||||
# print("%02x %02x" % (data, length))
|
||||
while length >= 0:
|
||||
output.append(input_data[idx])
|
||||
idx += 1
|
||||
length -= 1
|
||||
|
||||
return output
|
||||
|
||||
|
||||
cpdef bytearray encode_lz(unsigned char *data, int data_len):
|
||||
cdef uint8_t *output = array_new[uint8_t](data_len * 2)
|
||||
cdef int output_len = 0
|
||||
cdef int i = 0
|
||||
cdef int j = 0
|
||||
cdef int v = 0
|
||||
cdef int run_length = 0
|
||||
cdef int last_history_idx = 0
|
||||
cdef int history_idx = 0
|
||||
cdef int cmd_offset = 0
|
||||
cdef int cmd_bit = 0
|
||||
|
||||
cdef int offset = 0
|
||||
cdef list compress_commands = []
|
||||
cdef list history_commands = []
|
||||
|
||||
# Compress runs of previous characters
|
||||
while offset < data_len:
|
||||
# Run detection
|
||||
if output_len > 0 and data[offset] == output[output_len-1]:
|
||||
c = output[output_len-1]
|
||||
run_length = 1
|
||||
|
||||
while offset + run_length < data_len and data[offset+run_length] == c and run_length < 0x21:
|
||||
run_length += 1
|
||||
|
||||
if run_length > 1:
|
||||
compress_commands.append([
|
||||
'repeat',
|
||||
run_length
|
||||
])
|
||||
|
||||
j = 0
|
||||
while j < run_length:
|
||||
output[output_len] = c
|
||||
output_len += 1
|
||||
j += 1
|
||||
|
||||
offset += run_length
|
||||
continue
|
||||
|
||||
# History check
|
||||
last_history_idx = max(output_len - 0x400, 0)
|
||||
history_idx = find_data(output, output_len, data[offset], last_history_idx)
|
||||
if history_idx != -1:
|
||||
history_commands.clear()
|
||||
|
||||
while True:
|
||||
history_idx = find_data(output, output_len, data[offset], last_history_idx)
|
||||
last_history_idx = history_idx + 1
|
||||
|
||||
if history_idx == -1:
|
||||
break
|
||||
|
||||
# Check how long we can match the history
|
||||
i = 1
|
||||
|
||||
while offset + i < data_len:
|
||||
if history_idx + i > output_len and output[-1] == data[offset+i]:
|
||||
# Copy + repeat
|
||||
i += 1
|
||||
|
||||
elif history_idx + i < output_len and output[history_idx+i] == data[offset+i]:
|
||||
i += 1
|
||||
|
||||
else:
|
||||
break
|
||||
|
||||
history_back_idx = output_len - history_idx
|
||||
if i in [1, 2, 3, 4] and history_back_idx >= 1 and history_back_idx <= 16:
|
||||
# Can use a short copy
|
||||
history_commands.append([
|
||||
'short_copy',
|
||||
history_back_idx,
|
||||
i,
|
||||
1
|
||||
])
|
||||
|
||||
elif history_back_idx <= 0x3ff and i >= 3 and i <= 0x21:
|
||||
# Can use a long copy
|
||||
history_commands.append([
|
||||
'long_copy',
|
||||
history_back_idx,
|
||||
i,
|
||||
2
|
||||
])
|
||||
|
||||
best_compression = None
|
||||
for x in history_commands:
|
||||
if best_compression is None or x[2] - x[3] >= best_compression[2] - best_compression[3]:
|
||||
best_compression = x
|
||||
|
||||
if best_compression and best_compression[2] - best_compression[3] > 0:
|
||||
compress_commands.append(best_compression)
|
||||
|
||||
j = 0
|
||||
while j < best_compression[2]:
|
||||
output[output_len] = data[offset]
|
||||
output_len += 1
|
||||
offset += 1
|
||||
j += 1
|
||||
|
||||
continue
|
||||
|
||||
compress_commands.append([
|
||||
'raw',
|
||||
data[offset]
|
||||
])
|
||||
|
||||
output[output_len] = data[offset]
|
||||
output_len += 1
|
||||
offset += 1
|
||||
|
||||
compress_commands.append(['eof'])
|
||||
|
||||
# Step 2: Compress down raw runs
|
||||
# Step 3: Build down repeat commands
|
||||
compress_commands2 = []
|
||||
i = 0
|
||||
compress_commands_len = len(compress_commands)
|
||||
while i < compress_commands_len:
|
||||
if compress_commands[i][0] == 'raw':
|
||||
run_length = 1
|
||||
|
||||
while compress_commands[i+run_length][0] == 'raw':
|
||||
run_length += 1
|
||||
|
||||
if run_length == 1:
|
||||
compress_commands2.append(compress_commands[i])
|
||||
i += 1
|
||||
continue
|
||||
|
||||
raw_bulk = bytearray()
|
||||
for j in range(run_length):
|
||||
raw_bulk.append(compress_commands[i+j][1])
|
||||
|
||||
while len(raw_bulk) > 7:
|
||||
copy_len = min(len(raw_bulk), 0x46)
|
||||
chunk = raw_bulk[:copy_len]
|
||||
raw_bulk = raw_bulk[copy_len:]
|
||||
|
||||
compress_commands2.append([
|
||||
'raw_bulk',
|
||||
chunk,
|
||||
len(chunk)
|
||||
])
|
||||
|
||||
while len(raw_bulk) > 0:
|
||||
copy_len = 1
|
||||
chunk = raw_bulk[:copy_len]
|
||||
raw_bulk = raw_bulk[copy_len:]
|
||||
|
||||
compress_commands2.append([
|
||||
'raw',
|
||||
chunk[0]
|
||||
])
|
||||
|
||||
i += run_length
|
||||
|
||||
elif compress_commands[i][0] == 'repeat':
|
||||
history_back_idx = 1
|
||||
length = compress_commands[i][1]
|
||||
|
||||
while length > 0:
|
||||
if length in [1, 2, 3, 4] and history_back_idx >= 1 and history_back_idx <= 16:
|
||||
copy_len = length
|
||||
|
||||
# Can use a short copy
|
||||
compress_commands2.append([
|
||||
'short_copy',
|
||||
history_back_idx,
|
||||
copy_len,
|
||||
1
|
||||
])
|
||||
|
||||
length -= copy_len
|
||||
|
||||
elif history_back_idx <= 0x3ff and length >= 3:
|
||||
copy_len = min(length, 0x21)
|
||||
|
||||
# Can use a long copy
|
||||
compress_commands2.append([
|
||||
'long_copy',
|
||||
history_back_idx,
|
||||
copy_len,
|
||||
2
|
||||
])
|
||||
|
||||
length -= copy_len
|
||||
|
||||
i += 1
|
||||
|
||||
else:
|
||||
compress_commands2.append(compress_commands[i])
|
||||
i += 1
|
||||
|
||||
output_buffer = bytearray([0])
|
||||
cmd_offset = 0
|
||||
cmd_bit = 0
|
||||
|
||||
# Step 4: Build actual data now
|
||||
for x in compress_commands2:
|
||||
# print("%04x" % len(output_buffer), x)
|
||||
|
||||
if cmd_bit == 8:
|
||||
cmd_offset = len(output_buffer)
|
||||
output_buffer += int.to_bytes(0, 1, 'little')
|
||||
cmd_bit = 0
|
||||
|
||||
if x[0] == 'raw':
|
||||
output_buffer += int.to_bytes(x[1], 1, 'little')
|
||||
|
||||
elif x[0] == 'eof':
|
||||
output_buffer[cmd_offset] |= 1 << cmd_bit
|
||||
output_buffer += int.to_bytes(0xff, 1, 'little')
|
||||
|
||||
else:
|
||||
output_buffer[cmd_offset] |= 1 << cmd_bit
|
||||
|
||||
if x[0] == 'raw_bulk':
|
||||
# 1 + x bytes
|
||||
output_buffer += int.to_bytes(0xb9 + len(x[1]) - 1, 1, 'little')
|
||||
output_buffer += x[1]
|
||||
|
||||
elif x[0] == 'short_copy':
|
||||
# 1 byte
|
||||
v = ((x[2] + 6) << 4) | (x[1] - 1)
|
||||
output_buffer += int.to_bytes(v, 1, 'little')
|
||||
|
||||
elif x[0] == 'long_copy':
|
||||
# 2 bytes
|
||||
v = (((x[2] - 3) << 2) << 8) | (x[1] & 0x3ff)
|
||||
output_buffer += int.to_bytes(v, 2, 'big')
|
||||
|
||||
# if len(output_buffer) >= 0x170:
|
||||
# exit(1)
|
||||
|
||||
cmd_bit += 1
|
||||
|
||||
return output_buffer
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,243 @@
|
|||
# cython: cdivision=True
|
||||
|
||||
cpdef unsigned int get_filename_hash(unsigned char *filename, unsigned int filename_len):
|
||||
cdef int hash = 0
|
||||
cdef unsigned int cidx = 0
|
||||
cdef unsigned int i = 0
|
||||
|
||||
while cidx < filename_len:
|
||||
i = 0
|
||||
while i < 6:
|
||||
hash = ((hash >> 31) & 0x4c11db7) ^ ((hash << 1) | ((filename[cidx] >> i) & 1))
|
||||
i += 1
|
||||
|
||||
cidx += 1
|
||||
|
||||
return hash & 0xffffffff
|
||||
|
||||
|
||||
cdef rot(int c):
|
||||
return ((c >> 7) & 1) | ((c << 1) & 0xff)
|
||||
|
||||
|
||||
cdef int is_bit_set(int value, int n):
|
||||
return (value >> n) & 1
|
||||
|
||||
|
||||
cdef int bit_swap(int v, int b15, int b14, int b13, int b12, int b11, int b10, int b9, int b8, int b7, int b6, int b5, int b4, int b3, int b2, int b1, int b0):
|
||||
return (is_bit_set(v, b15) << 15) | \
|
||||
(is_bit_set(v, b14) << 14) | \
|
||||
(is_bit_set(v, b13) << 13) | \
|
||||
(is_bit_set(v, b12) << 12) | \
|
||||
(is_bit_set(v, b11) << 11) | \
|
||||
(is_bit_set(v, b10) << 10) | \
|
||||
(is_bit_set(v, b9) << 9) | \
|
||||
(is_bit_set(v, b8) << 8) | \
|
||||
(is_bit_set(v, b7) << 7) | \
|
||||
(is_bit_set(v, b6) << 6) | \
|
||||
(is_bit_set(v, b5) << 5) | \
|
||||
(is_bit_set(v, b4) << 4) | \
|
||||
(is_bit_set(v, b3) << 3) | \
|
||||
(is_bit_set(v, b2) << 2) | \
|
||||
(is_bit_set(v, b1) << 1) | \
|
||||
(is_bit_set(v, b0) << 0)
|
||||
|
||||
|
||||
cpdef bytearray decrypt(unsigned char *data, int data_len, unsigned short key1, unsigned short key2, unsigned char key3):
|
||||
cdef unsigned short v = 0
|
||||
cdef unsigned short m = 0
|
||||
cdef unsigned int idx = 0
|
||||
|
||||
output_data = bytearray(data_len * 2)
|
||||
|
||||
while idx < data_len:
|
||||
v = (data[idx * 2 + 1] << 8) | data[idx * 2]
|
||||
m = key1 ^ key2
|
||||
|
||||
v = bit_swap(
|
||||
v,
|
||||
15 - is_bit_set(m, 0xF),
|
||||
14 + is_bit_set(m, 0xF),
|
||||
13 - is_bit_set(m, 0xE),
|
||||
12 + is_bit_set(m, 0xE),
|
||||
11 - is_bit_set(m, 0xB),
|
||||
10 + is_bit_set(m, 0xB),
|
||||
9 - is_bit_set(m, 0x9),
|
||||
8 + is_bit_set(m, 0x9),
|
||||
7 - is_bit_set(m, 0x8),
|
||||
6 + is_bit_set(m, 0x8),
|
||||
5 - is_bit_set(m, 0x5),
|
||||
4 + is_bit_set(m, 0x5),
|
||||
3 - is_bit_set(m, 0x3),
|
||||
2 + is_bit_set(m, 0x3),
|
||||
1 - is_bit_set(m, 0x2),
|
||||
0 + is_bit_set(m, 0x2)
|
||||
)
|
||||
|
||||
|
||||
v ^= (is_bit_set(m, 0xD) << 14) ^ \
|
||||
(is_bit_set(m, 0xC) << 12) ^ \
|
||||
(is_bit_set(m, 0xA) << 10) ^ \
|
||||
(is_bit_set(m, 0x7) << 8) ^ \
|
||||
(is_bit_set(m, 0x6) << 6) ^ \
|
||||
(is_bit_set(m, 0x4) << 4) ^ \
|
||||
(is_bit_set(m, 0x1) << 2) ^ \
|
||||
(is_bit_set(m, 0x0) << 0)
|
||||
|
||||
v ^= bit_swap(
|
||||
key3,
|
||||
7, 0, 6, 1,
|
||||
5, 2, 4, 3,
|
||||
3, 4, 2, 5,
|
||||
1, 6, 0, 7
|
||||
)
|
||||
|
||||
output_data[idx * 2] = (v >> 8) & 0xff
|
||||
output_data[idx * 2 + 1] = v & 0xff
|
||||
|
||||
key1 = ((key1 & 0x8000) | ((key1 << 1) & 0x7FFE) | ((key1 >> 14) & 1)) & 0xFFFF
|
||||
|
||||
if (((key1 >> 15) ^ key1) & 1) != 0:
|
||||
key2 = ((key2 << 1) | (key2 >> 15)) & 0xFFFF
|
||||
|
||||
idx += 1
|
||||
key3 += 1
|
||||
|
||||
return output_data
|
||||
|
||||
cpdef bytearray encrypt(unsigned char *data, int data_len, unsigned short key1, unsigned short key2, unsigned char key3):
|
||||
cdef unsigned short v = 0
|
||||
cdef unsigned short m = 0
|
||||
cdef unsigned int idx = 0
|
||||
|
||||
output_data = bytearray(data_len * 2)
|
||||
|
||||
while idx < data_len:
|
||||
v = (data[idx * 2 + 1] << 8) | data[idx * 2]
|
||||
m = key1 ^ key2
|
||||
|
||||
v = bit_swap(
|
||||
v,
|
||||
15 - is_bit_set(m, 0xF),
|
||||
14 + is_bit_set(m, 0xF),
|
||||
13 - is_bit_set(m, 0xE),
|
||||
12 + is_bit_set(m, 0xE),
|
||||
11 - is_bit_set(m, 0xB),
|
||||
10 + is_bit_set(m, 0xB),
|
||||
9 - is_bit_set(m, 0x9),
|
||||
8 + is_bit_set(m, 0x9),
|
||||
7 - is_bit_set(m, 0x8),
|
||||
6 + is_bit_set(m, 0x8),
|
||||
5 - is_bit_set(m, 0x5),
|
||||
4 + is_bit_set(m, 0x5),
|
||||
3 - is_bit_set(m, 0x3),
|
||||
2 + is_bit_set(m, 0x3),
|
||||
1 - is_bit_set(m, 0x2),
|
||||
0 + is_bit_set(m, 0x2)
|
||||
)
|
||||
|
||||
|
||||
v ^= (is_bit_set(m, 0xD) << 14) ^ \
|
||||
(is_bit_set(m, 0xC) << 12) ^ \
|
||||
(is_bit_set(m, 0xA) << 10) ^ \
|
||||
(is_bit_set(m, 0x7) << 8) ^ \
|
||||
(is_bit_set(m, 0x6) << 6) ^ \
|
||||
(is_bit_set(m, 0x4) << 4) ^ \
|
||||
(is_bit_set(m, 0x1) << 2) ^ \
|
||||
(is_bit_set(m, 0x0) << 0)
|
||||
|
||||
v ^= bit_swap(
|
||||
key3,
|
||||
3, 4, 2, 5,
|
||||
1, 6, 0, 7,
|
||||
7, 0, 6, 1,
|
||||
5, 2, 4, 3
|
||||
)
|
||||
|
||||
output_data[idx * 2] = (v >> 8) & 0xff
|
||||
output_data[idx * 2 + 1] = v & 0xff
|
||||
|
||||
key1 = ((key1 & 0x8000) | ((key1 << 1) & 0x7FFE) | ((key1 >> 14) & 1)) & 0xFFFF
|
||||
|
||||
if (((key1 >> 15) ^ key1) & 1) != 0:
|
||||
key2 = ((key2 << 1) | (key2 >> 15)) & 0xFFFF
|
||||
|
||||
idx += 1
|
||||
key3 += 1
|
||||
|
||||
return output_data
|
||||
|
||||
|
||||
cpdef bytearray decrypt_ddrsbm(unsigned char *data, int data_len, unsigned short key):
|
||||
cdef unsigned int output_idx = 0
|
||||
cdef unsigned int idx = 0
|
||||
cdef unsigned int even_bit_shift = 0
|
||||
cdef unsigned int odd_bit_shift = 0
|
||||
cdef unsigned int is_even_bit_set = 0
|
||||
cdef unsigned int is_odd_bit_set = 0
|
||||
cdef unsigned int is_key_bit_set = 0
|
||||
cdef unsigned int is_scramble_bit_set = 0
|
||||
cdef unsigned int cur_bit = 0
|
||||
cdef unsigned int output_word = 0
|
||||
|
||||
output_data = bytearray(data_len * 2)
|
||||
key_data = bytearray(16)
|
||||
|
||||
# Generate key data based on input key
|
||||
key_state = is_bit_set(key, 0x0d) << 15 | \
|
||||
is_bit_set(key, 0x0b) << 14 | \
|
||||
is_bit_set(key, 0x09) << 13 | \
|
||||
is_bit_set(key, 0x07) << 12 | \
|
||||
is_bit_set(key, 0x05) << 11 | \
|
||||
is_bit_set(key, 0x03) << 10 | \
|
||||
is_bit_set(key, 0x01) << 9 | \
|
||||
is_bit_set(key, 0x0f) << 8 | \
|
||||
is_bit_set(key, 0x0e) << 7 | \
|
||||
is_bit_set(key, 0x0c) << 6 | \
|
||||
is_bit_set(key, 0x0a) << 5 | \
|
||||
is_bit_set(key, 0x08) << 4 | \
|
||||
is_bit_set(key, 0x06) << 3 | \
|
||||
is_bit_set(key, 0x04) << 2 | \
|
||||
is_bit_set(key, 0x02) << 1 | \
|
||||
is_bit_set(key, 0x00) << 0
|
||||
|
||||
while idx < 8:
|
||||
key_data[idx * 2] = key_state & 0xff
|
||||
key_data[idx * 2 + 1] = (key_state >> 8) & 0xff
|
||||
|
||||
key_state = (rot(key_state >> 8) << 8) | rot(key_state & 0xff)
|
||||
|
||||
idx += 1
|
||||
|
||||
while idx < data_len:
|
||||
output_word = 0
|
||||
cur_data = (data[(idx * 2) + 1] << 8) | data[(idx * 2)]
|
||||
|
||||
cur_bit = 0
|
||||
while cur_bit < 8:
|
||||
even_bit_shift = (cur_bit * 2) & 0xff
|
||||
odd_bit_shift = (cur_bit * 2 + 1) & 0xff
|
||||
|
||||
is_even_bit_set = int((cur_data & (1 << even_bit_shift)) != 0)
|
||||
is_odd_bit_set = int((cur_data & (1 << odd_bit_shift)) != 0)
|
||||
is_key_bit_set = int((key_data[idx % 16] & (1 << cur_bit)) != 0)
|
||||
is_scramble_bit_set = int((key_data[(idx - 1) % 16] & (1 << cur_bit)) != 0)
|
||||
|
||||
if is_scramble_bit_set == 1:
|
||||
is_even_bit_set, is_odd_bit_set = is_odd_bit_set, is_even_bit_set
|
||||
|
||||
if ((is_even_bit_set ^ is_key_bit_set)) == 1:
|
||||
output_word |= 1 << even_bit_shift
|
||||
|
||||
if is_odd_bit_set == 1:
|
||||
output_word |= 1 << odd_bit_shift
|
||||
|
||||
cur_bit += 1
|
||||
|
||||
output_data[output_idx] = (output_word >> 8) & 0xff
|
||||
output_data[output_idx+1] = output_word & 0xff
|
||||
output_idx += 2
|
||||
idx += 1
|
||||
|
||||
return output_data
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
bsdiff4==1.2.1
|
||||
Cython==0.29.22
|
|
@ -0,0 +1,6 @@
|
|||
from distutils.core import setup
|
||||
from Cython.Build import cythonize
|
||||
|
||||
setup(
|
||||
ext_modules = cythonize(["comp573.pyx", "enc573.pyx", "sum573.pyx"], annotate=True, language_level=3)
|
||||
)
|
|
@ -0,0 +1,103 @@
|
|||
# cython: cdivision=True
|
||||
|
||||
cpdef inline unsigned short calc_final_sum(unsigned int val):
|
||||
cdef unsigned short output = val & 0xffff
|
||||
|
||||
while val > 0xffff:
|
||||
val = output + (val >> 16)
|
||||
output = val
|
||||
|
||||
return output
|
||||
|
||||
|
||||
cdef inline (unsigned int, unsigned int) sum_chunk(unsigned char *data, unsigned int offset, unsigned int chunk_size=0x20000):
|
||||
cdef unsigned int a = 0
|
||||
cdef unsigned int b = 0
|
||||
cdef unsigned int i = 0
|
||||
|
||||
while i < chunk_size:
|
||||
a += data[offset+i]
|
||||
b += data[offset+i+1]
|
||||
i += 2
|
||||
|
||||
return [a, b]
|
||||
|
||||
|
||||
cpdef bytearray checksum_chunk(unsigned char *data, unsigned int offset, unsigned int chunk_size=0x20000):
|
||||
cdef unsigned int sum1, sum2
|
||||
cdef unsigned short a = 0
|
||||
cdef unsigned short b = 0
|
||||
|
||||
sum1, sum2 = sum_chunk(data, offset, chunk_size)
|
||||
a = calc_final_sum(calc_final_sum(sum1) & 0xffff)
|
||||
b = calc_final_sum(calc_final_sum(sum2) & 0xffff)
|
||||
|
||||
return bytearray([a & 0xff, b & 0xff, (a >> 8) & 0xff, (b >> 8) & 0xff])
|
||||
|
||||
|
||||
cpdef list balance_sums(list cards, list card_sizes, unsigned int last_chunk_offset):
|
||||
cdef unsigned int last_chunk_checksum_offset = last_chunk_offset + 0x10
|
||||
cdef unsigned int i = 0
|
||||
cdef unsigned int j = 0
|
||||
cdef unsigned int a = 0
|
||||
cdef unsigned int b = 0
|
||||
cdef unsigned int pad = 0
|
||||
cdef unsigned char val = 0
|
||||
cdef unsigned int card_sum = sum(card_sizes)
|
||||
|
||||
cards[0][last_chunk_checksum_offset + card_sum:last_chunk_offset + 0x2000] = bytearray([0] * (0x2000 - card_sum - 0x10))
|
||||
|
||||
a, b = sum_chunk(cards[0], last_chunk_offset, 0x2000)
|
||||
while i < 2:
|
||||
pad = 0x10000 - calc_final_sum(a if i == 0 else b)
|
||||
j = card_sum
|
||||
|
||||
while pad > 0 and j < 0x2000:
|
||||
val = pad if pad < 0xff else 0xff
|
||||
|
||||
cards[0][last_chunk_checksum_offset + j + i] += val
|
||||
|
||||
pad -= val
|
||||
j += 2
|
||||
|
||||
i += 1
|
||||
|
||||
return cards
|
||||
|
||||
|
||||
cpdef add_checksums(list cards, list card_sizes, unsigned int chunk_size, unsigned int last_chunk_checksum_offset, unsigned int card_start_index, unsigned int card_count):
|
||||
cdef unsigned int real_card_index = 0
|
||||
cdef unsigned int i = 0
|
||||
cdef unsigned int card_offset = 0
|
||||
cdef unsigned int checksum_offset = 0
|
||||
cdef unsigned int total_cards = len(cards)
|
||||
cdef bytearray final_sum
|
||||
|
||||
while real_card_index < total_cards:
|
||||
card_data = cards[real_card_index]
|
||||
|
||||
if real_card_index < card_start_index:
|
||||
# Skip first DAT because it's already been done
|
||||
real_card_index += 1
|
||||
continue
|
||||
|
||||
if real_card_index - card_start_index > card_count:
|
||||
break
|
||||
|
||||
card_offset = (sum(card_sizes[:real_card_index]) // 4) * real_card_index
|
||||
|
||||
i = 0
|
||||
s = len(card_data) // chunk_size
|
||||
while i < s:
|
||||
offset = (i * chunk_size) + (0x20 if real_card_index == 0 and i == 0 else 0)
|
||||
length = chunk_size - (0x20 if real_card_index == 0 and i == 0 else 0)
|
||||
final_sum = checksum_chunk(card_data, offset, length)
|
||||
|
||||
checksum_offset = last_chunk_checksum_offset + ((i + card_offset) * 4)
|
||||
cards[0][checksum_offset:checksum_offset+4] = final_sum
|
||||
|
||||
i += 1
|
||||
|
||||
real_card_index += 1
|
||||
|
||||
return cards
|
|
@ -0,0 +1,23 @@
|
|||
import argparse
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('--mode', help='Operation mode', required=True, choices=['dump', 'build', 'checksum'])
|
||||
|
||||
args, _ = parser.parse_known_args()
|
||||
|
||||
if args.mode == "dump":
|
||||
import dump_sys573_gamefs
|
||||
dump_sys573_gamefs.main()
|
||||
|
||||
elif args.mode == "build":
|
||||
import build_sys573_gamefs
|
||||
build_sys573_gamefs.main()
|
||||
|
||||
elif args.mode == "checksum":
|
||||
import calc_checksum
|
||||
calc_checksum.main()
|
||||
|
||||
else:
|
||||
print("Unknown mode:", args.mode)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue