mirror of
https://github.com/a2-4am/4cade.git
synced 2024-06-07 03:29:30 +00:00
Merge branch 'a2-4am:main' into main
This commit is contained in:
commit
52e71a450e
295
Makefile
295
Makefile
|
@ -23,216 +23,265 @@ ACME=acme
|
|||
# version 1.4.0 or later
|
||||
CADIUS=cadius
|
||||
|
||||
# https://www.gnu.org/software/parallel/
|
||||
PARALLEL=parallel
|
||||
|
||||
# https://python.org/
|
||||
PYTHON=python3
|
||||
|
||||
# https://bitbucket.org/magli143/exomizer/wiki/Home
|
||||
# version 3.1.0 or later
|
||||
EXOMIZER=exomizer mem -q -P23 -lnone
|
||||
|
||||
dsk: asm index
|
||||
dsk: index asmproboot asmlauncher extract
|
||||
cp res/blank.hdv build/"$(DISK)"
|
||||
cp res/_FileInformation.txt build/
|
||||
$(CADIUS) ADDFILE build/"$(DISK)" "/$(VOLUME)/" build/LAUNCHER.SYSTEM >>build/log
|
||||
$(CADIUS) ADDFILE build/"$(DISK)" "/$(VOLUME)/" build/LAUNCHER.SYSTEM -C >>build/log
|
||||
cp res/PREFS.CONF build/PREFS.CONF
|
||||
bin/padto.sh 512 build/PREFS.CONF >>build/log
|
||||
bin/padto.sh build/PREFS.CONF
|
||||
#
|
||||
# create _FileInformation.txt files for subdirectories
|
||||
#
|
||||
bin/buildfileinfo.sh res/TITLE.HGR "06" "4000"
|
||||
bin/buildfileinfo.sh res/TITLE.DHGR "06" "4000"
|
||||
bin/buildfileinfo.sh res/ACTION.GR "06" "6000"
|
||||
bin/buildfileinfo.sh res/ICONS "CA" "0000"
|
||||
bin/buildfileinfo.sh build/FX "06" "6000"
|
||||
bin/buildfileinfo.sh build/PRELAUNCH "06" "0106"
|
||||
cp src/prelaunch/_FileInformation.txt build/PRELAUNCH/
|
||||
#
|
||||
# add everything to the disk
|
||||
#
|
||||
for f in \
|
||||
build/TOTAL.DATA \
|
||||
res/TITLE \
|
||||
res/COVER \
|
||||
res/HELP \
|
||||
build/GAMES.CONF \
|
||||
build/PREFS.CONF \
|
||||
build/CREDITS \
|
||||
build/HELPTEXT \
|
||||
build/ATTRACT.IDX \
|
||||
build/SEARCH00.IDX \
|
||||
build/SEARCH01.IDX \
|
||||
build/SEARCH10.IDX \
|
||||
build/SEARCH11.IDX \
|
||||
build/FX.IDX \
|
||||
build/DFX.IDX \
|
||||
build/GAMEHELP.IDX \
|
||||
build/SLIDESHOW.IDX \
|
||||
build/MINIATTRACT.IDX \
|
||||
build/PRELAUNCH.IDX \
|
||||
build/ARTWORK.IDX \
|
||||
build/HGR0.IDX \
|
||||
build/HGR1.IDX \
|
||||
build/HGR2.IDX \
|
||||
build/HGR3.IDX \
|
||||
build/HGR4.IDX \
|
||||
build/HGR5.IDX \
|
||||
build/HGR6.IDX \
|
||||
build/DHGR.IDX \
|
||||
res/DECRUNCH \
|
||||
res/JOYSTICK \
|
||||
res/Finder.Data \
|
||||
res/Finder.Root; do \
|
||||
$(CADIUS) ADDFILE build/"$(DISK)" "/$(VOLUME)/" "$$f" >>build/log; \
|
||||
$(CADIUS) ADDFILE build/"$(DISK)" "/$(VOLUME)/" "$$f" -C >>build/log; \
|
||||
done
|
||||
for f in \
|
||||
res/TITLE.HGR \
|
||||
res/TITLE.DHGR \
|
||||
res/ACTION.GR \
|
||||
res/DEMO \
|
||||
res/TITLE.ANIMATED \
|
||||
res/ICONS \
|
||||
res/TITLE.ANIMATED \
|
||||
res/ICONS \
|
||||
build/FX \
|
||||
build/PRELAUNCH; do \
|
||||
rm -f "$$f"/.DS_Store; \
|
||||
$(CADIUS) ADDFOLDER build/"$(DISK)" "/$(VOLUME)/$$(basename $$f)" "$$f" >>build/log; \
|
||||
$(CADIUS) ADDFOLDER build/"$(DISK)" "/$(VOLUME)/$$(basename $$f)" "$$f" -C >>build/log; \
|
||||
done
|
||||
for i in 1 2 3 4 5 6; do \
|
||||
$(CADIUS) RENAMEFILE build/"$(DISK)" "/$(VOLUME)/DEMO/SPCARTOON.$${i}$${i}" "SPCARTOON.$${i}." >>build/log; \
|
||||
done
|
||||
for f in res/dsk/*.po; do \
|
||||
$(CADIUS) EXTRACTVOLUME "$${f}" build/X/ >>build/log; \
|
||||
done
|
||||
rm -f build/X/**/.DS_Store build/X/**/PRODOS* build/X/**/LOADER.SYSTEM*
|
||||
$(CADIUS) CREATEFOLDER build/"$(DISK)" "/$(VOLUME)/X/" >>build/log
|
||||
$(CADIUS) CREATEFOLDER build/"$(DISK)" "/$(VOLUME)/X/" -C >>build/log
|
||||
for f in build/X/*; do \
|
||||
$(CADIUS) ADDFOLDER build/"$(DISK)" "/$(VOLUME)/X/$$(basename $$f)" "$$f" >>build/log; \
|
||||
$(CADIUS) ADDFOLDER build/"$(DISK)" "/$(VOLUME)/X/$$(basename $$f)" "$$f" -C >>build/log; \
|
||||
done
|
||||
bin/changebootloader.sh build/"$(DISK)" build/proboothd
|
||||
|
||||
index: md
|
||||
# note: even though individual lines check individual files, you really want
|
||||
# to re-run this with a clean build/ directory if anything changes, because
|
||||
# everything is interconnected within TOTAL.DATA
|
||||
extract: preconditions md
|
||||
$(PARALLEL) '$(CADIUS) EXTRACTVOLUME {} build/X/ >>build/log' ::: res/dsk/*.po
|
||||
rm -f build/X/**/.DS_Store build/X/**/PRODOS* build/X/**/LOADER.SYSTEM*
|
||||
for f in $$(grep '^....1' res/GAMES.CONF | awk '!/^$$|^#/' | awk -F, '/,/ { print $$2 }' | awk -F= '{ print $$1 }'); do mv build/X/"$$(basename $$f)"/"$$(basename $$f)"* build/X.INDEXED/; rm -rf build/X/"$$(basename $$f)"; done
|
||||
(for f in build/X.INDEXED/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a -p build/TOTAL.DATA build/X.INDEXED > build/XSINGLE.IDX
|
||||
|
||||
index: preconditions md asmfx asmprelaunch asmdemo compress extract
|
||||
#
|
||||
# precompute binary data structure for mega-attract mode configuration file
|
||||
#
|
||||
[ -f build/ATTRACT.IDX ] || (bin/buildokvs.sh < res/ATTRACT.CONF > build/ATTRACT.IDX)
|
||||
[ -f build/index ] || (bin/buildokvs.sh < res/ATTRACT.CONF > build/ATTRACT.IDX)
|
||||
#
|
||||
# precompute binary data structure and substitute special characters
|
||||
# in game help and other all-text pages
|
||||
#
|
||||
[ -f build/HELPTEXT ] || (bin/converthelp.sh res/HELPTEXT build/HELPTEXT)
|
||||
[ -f build/CREDITS ] || (bin/converthelp.sh res/CREDITS build/CREDITS)
|
||||
for f in res/GAMEHELP/*; do \
|
||||
[ -f build/GAMEHELP/"$$(basename $$f)" ] || (bin/converthelp.sh "$$f" build/GAMEHELP/"$$(basename $$f)"); \
|
||||
done
|
||||
[ -f build/index ] || (bin/converthelp.sh res/HELPTEXT build/HELPTEXT)
|
||||
[ -f build/index ] || (bin/converthelp.sh res/CREDITS build/CREDITS)
|
||||
[ -f build/index ] || $(PARALLEL) 'bin/converthelp.sh "{}" "build/GAMEHELP/{/}"' ::: res/GAMEHELP/*
|
||||
#
|
||||
# create distribution version of GAMES.CONF without comments or blank lines
|
||||
# create a version of GAMES.CONF without comments or blank lines
|
||||
#
|
||||
[ -f build/GAMES.CONF ] || (awk '!/^$$|^#/' < res/GAMES.CONF > build/GAMES.CONF)
|
||||
[ -f build/index ] || (awk '!/^$$|^#/' < res/GAMES.CONF > build/GAMES.CONF)
|
||||
#
|
||||
# create gGamesListStore indexes
|
||||
# create a list of all game filenames, without metadata or display names, sorted by game filename
|
||||
#
|
||||
# grep "^00" < build/GAMES.CONF | bin/buildgamesstore.sh > build/GAMES00.IDX
|
||||
# grep "^0" < build/GAMES.CONF | bin/buildgamesstore.sh > build/GAMES01.IDX
|
||||
# grep "^.0" < build/GAMES.CONF | bin/buildgamesstore.sh > build/GAMES10.IDX
|
||||
# cat build/GAMES.CONF | bin/buildgamesstore.sh > build/GAMES11.IDX
|
||||
#
|
||||
# create gSearchStore indexes
|
||||
#
|
||||
[ -f build/DISPLAY.CONF ] || (bin/builddisplaynames.py < build/GAMES.CONF > build/DISPLAY.CONF)
|
||||
[ -f build/SEARCH00.IDX ] || (grep "^00" < build/DISPLAY.CONF | cut -d"," -f2 | bin/buildokvs.sh > build/SEARCH00.IDX)
|
||||
[ -f build/SEARCH01.IDX ] || (grep "^0" < build/DISPLAY.CONF | cut -d"," -f2 | bin/buildokvs.sh > build/SEARCH01.IDX)
|
||||
[ -f build/SEARCH10.IDX ] || (grep "^.0" < build/DISPLAY.CONF | cut -d"," -f2 | bin/buildokvs.sh > build/SEARCH10.IDX)
|
||||
[ -f build/SEARCH11.IDX ] || (cat build/DISPLAY.CONF | cut -d"," -f2 | bin/buildokvs.sh > build/SEARCH11.IDX)
|
||||
#
|
||||
# create a sorted list of game filenames, without metadata or display names
|
||||
#
|
||||
[ -f build/GAMES.SORTED ] || (awk -F, '/,/ { print $$2 }' < build/GAMES.CONF | awk -F= '{ print $$1 }' | sort > build/GAMES.SORTED)
|
||||
[ -f build/index ] || (awk -F, '/,/ { print $$2 }' < build/GAMES.CONF | awk -F= '{ print $$1 }' | sort > build/GAMES.SORTED)
|
||||
#
|
||||
# precompute indexed files for prelaunch
|
||||
# note: prelaunch must be first in TOTAL.DATA due to a hack in LoadStandardPrelaunch
|
||||
# note 2: these can not be padded because they are loaded at $0106 and padding would clobber the stack
|
||||
#
|
||||
[ -f build/PRELAUNCH.IDX ] || (bin/buildindexedfile.sh build/TOTAL.DATA build/PRELAUNCH.INDEXED < build/GAMES.SORTED > build/PRELAUNCH.IDX)
|
||||
[ -f build/index ] || (bin/buildindexedfile.sh build/TOTAL.DATA build/PRELAUNCH.INDEXED < build/GAMES.SORTED > build/PRELAUNCH.IDX)
|
||||
#
|
||||
# precompute indexed files for HGR & DHGR titles
|
||||
# note: these are not padded because they are all an exact block-multiple anyway
|
||||
#
|
||||
[ -f build/index ] || bin/padto.sh build/TOTAL.DATA
|
||||
[ -f build/index ] || ((for f in res/TITLE.HGR/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/TITLE.HGR build/HGR.TITLES.LOG > build/TITLE.IDX)
|
||||
[ -f build/index ] || ((for f in res/TITLE.DHGR/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/TITLE.DHGR build/DHGR.TITLES.LOG > build/DTITLE.IDX)
|
||||
[ -f build/index ] || bin/addfile.sh res/COVER build/TOTAL.DATA > src/index/res.cover.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/TITLE build/TOTAL.DATA > src/index/res.title.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/HELP build/TOTAL.DATA > src/index/res.help.idx.a
|
||||
#
|
||||
# precompute indexed files for game help
|
||||
# note: these can be padded because they're loaded into $800 at a time when $800..$1FFF is clobber-able
|
||||
#
|
||||
[ -f build/GAMEHELP.IDX ] || (bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/GAMEHELP < build/GAMES.SORTED > build/GAMEHELP.IDX)
|
||||
[ -f build/index ] || (bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/GAMEHELP < build/GAMES.SORTED > build/GAMEHELP.IDX)
|
||||
#
|
||||
# precompute indexed files for slideshows
|
||||
# note: these can be padded because they're loaded into $800 at a time when $800..$1FFF is clobber-able
|
||||
#
|
||||
[ -f build/SLIDESHOW.IDX ] || ((for f in res/SS/*; do \
|
||||
bin/buildokvs.sh < "$$f" > "build/SS/$$(basename $$f)"; \
|
||||
echo "$$(basename $$f)"; \
|
||||
done) | bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/SS > build/SLIDESHOW.IDX)
|
||||
[ -f build/MINIATTRACT.IDX ] || ((for f in res/ATTRACT/*; do \
|
||||
bin/buildokvs.sh < "$$f" > "build/ATTRACT/$$(basename $$f)"; \
|
||||
echo "$$(basename $$f)"; \
|
||||
done) | bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/ATTRACT > build/MINIATTRACT.IDX)
|
||||
[ -f build/index ] || $(PARALLEL) '[ $$(echo "{/}" | cut -c-3) = "ACT" ] && bin/buildslideshow.sh -d build/GAMES.CONF < "{}" > "build/SS/{/}" || bin/buildslideshow.sh build/GAMES.CONF < "{}" > "build/SS/{/}"' ::: res/SS/*
|
||||
[ -f build/index ] || ((for f in build/SS/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/SS > build/SLIDESHOW.IDX)
|
||||
[ -f build/index ] || $(PARALLEL) 'bin/buildokvs.sh < "{}" > "build/ATTRACT/{/}"' ::: res/ATTRACT/*
|
||||
[ -f build/index ] || ((for f in build/ATTRACT/[ABCDEFGHIJKLMNOP]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/ATTRACT > build/MINIATTRACT0.IDX)
|
||||
[ -f build/index ] || ((for f in build/ATTRACT/[QRSTUVWXYZ]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/ATTRACT > build/MINIATTRACT1.IDX)
|
||||
#
|
||||
# precompute indexed files for graphic effects
|
||||
# note: these can be padded because they're loaded into $6000 at a time when $6000..$BEFF is clobber-able
|
||||
#
|
||||
[ -f build/FX.IDX ] || (bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/FX.INDEXED < res/FX.CONF > build/FX.IDX)
|
||||
[ -f build/DFX.IDX ] || (bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/FX.INDEXED < res/DFX.CONF > build/DFX.IDX)
|
||||
[ -f build/index ] || (bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/FX.INDEXED < res/FX.CONF > build/FX.IDX)
|
||||
[ -f build/index ] || (bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/FX.INDEXED < res/DFX.CONF > build/DFX.IDX)
|
||||
[ -f build/index ] || (bin/buildindexedfile.sh -p -a build/TOTAL.DATA build/FX.INDEXED < res/SFX.CONF > build/SFX.IDX)
|
||||
#
|
||||
# precompute indexed files for HGR & DHGR action screenshots
|
||||
# note: these can not be padded because they are compressed and the decompressor needs the exact size
|
||||
#
|
||||
[ -f build/HGR0.IDX ] || ((for f in res/ACTION.HGR/[ABCD]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR0.IDX)
|
||||
[ -f build/HGR1.IDX ] || ((for f in res/ACTION.HGR/[EFGH]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR1.IDX)
|
||||
[ -f build/HGR2.IDX ] || ((for f in res/ACTION.HGR/[IJKL]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR2.IDX)
|
||||
[ -f build/HGR3.IDX ] || ((for f in res/ACTION.HGR/[MNOP]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR3.IDX)
|
||||
[ -f build/HGR4.IDX ] || ((for f in res/ACTION.HGR/[QRST]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR4.IDX)
|
||||
[ -f build/HGR5.IDX ] || ((for f in res/ACTION.HGR/[UVWX]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR5.IDX)
|
||||
[ -f build/HGR6.IDX ] || ((for f in res/ACTION.HGR/[YZ]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR6.IDX)
|
||||
[ -f build/DHGR.IDX ] || ((for f in res/ACTION.DHGR/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.DHGR > build/DHGR.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.HGR/[ABCD]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR0.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.HGR/[EFGH]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR1.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.HGR/[IJKL]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR2.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.HGR/[MNOP]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR3.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.HGR/[QRST]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR4.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.HGR/[UVWX]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR5.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.HGR/[YZ]*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.HGR > build/HGR6.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.DHGR/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ACTION.DHGR > build/DHGR.IDX)
|
||||
#
|
||||
# precompute indexed files for GR and DGR action screenshots
|
||||
# note: these can be padded because they are not compressed
|
||||
#
|
||||
[ -f build/index ] || ((for f in res/ACTION.GR/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a -p build/TOTAL.DATA res/ACTION.GR > build/GR.IDX)
|
||||
[ -f build/index ] || ((for f in res/ACTION.DGR/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a -p build/TOTAL.DATA res/ACTION.DGR > build/DGR.IDX)
|
||||
#
|
||||
# precompute indexed files for SHR artwork
|
||||
# note: these can not be padded because they are compressed and the decompressor needs the exact size
|
||||
#
|
||||
[ -f build/ARTWORK.IDX ] || ((for f in res/ARTWORK.SHR/*; do \
|
||||
echo "$$(basename $$f)"; \
|
||||
done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ARTWORK.SHR > build/ARTWORK.IDX)
|
||||
[ -f build/index ] || ((for f in res/ARTWORK.SHR/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA res/ARTWORK.SHR > build/ARTWORK.IDX)
|
||||
#
|
||||
# precompute indexed files for demo launchers
|
||||
# note: these can not be padded because some of them are loaded too close to $C000
|
||||
#
|
||||
[ -f build/index ] || ((for f in build/DEMO/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a build/TOTAL.DATA build/DEMO > build/DEMO.IDX)
|
||||
[ -f build/index ] || bin/addfile.sh build/DEMO.IDX build/TOTAL.DATA > src/index/demo.idx.a
|
||||
|
||||
asm: asmlauncher asmfx asmprelaunch asmproboot
|
||||
#
|
||||
# precompute indexed files for single-load game binaries
|
||||
# note: these can be padded because they are loaded at a time when all of main memory is clobber-able
|
||||
#
|
||||
[ -f build/index ] || ((for f in build/X.INDEXED/*; do echo "$$(basename $$f)"; done) | bin/buildindexedfile.sh -a -p build/TOTAL.DATA build/X.INDEXED > build/XSINGLE.IDX)
|
||||
[ -f build/index ] || bin/addfile.sh build/XSINGLE.IDX build/TOTAL.DATA > src/index/xsingle.idx.a
|
||||
#
|
||||
# create search indexes for each variation of (game-requires-joystick) X (game-requires-128K)
|
||||
# in the form of OKVS data structures, plus game counts in the form of source files
|
||||
#
|
||||
[ -f build/index ] || $(PARALLEL) ::: \
|
||||
'(grep "^00" < build/GAMES.CONF | bin/buildsearch.sh src/index/count00.a build/HGR.TITLES.LOG /dev/null > build/SEARCH00.IDX)' \
|
||||
'(grep "^0" < build/GAMES.CONF | bin/buildsearch.sh src/index/count01.a build/HGR.TITLES.LOG build/DHGR.TITLES.LOG > build/SEARCH01.IDX)' \
|
||||
'(grep "^.0" < build/GAMES.CONF | bin/buildsearch.sh src/index/count10.a build/HGR.TITLES.LOG /dev/null > build/SEARCH10.IDX)' \
|
||||
'(bin/buildsearch.sh src/index/count11.a build/HGR.TITLES.LOG build/DHGR.TITLES.LOG < build/GAMES.CONF > build/SEARCH11.IDX)'
|
||||
#
|
||||
# add IDX files to the combined index file and generate
|
||||
# the index records that callers use to reference them
|
||||
#
|
||||
[ -f build/index ] || bin/addfile.sh build/SEARCH00.IDX build/TOTAL.DATA > src/index/search00.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/CACHE00.IDX build/TOTAL.DATA > src/index/cache00.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/SEARCH01.IDX build/TOTAL.DATA > src/index/search01.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/CACHE01.IDX build/TOTAL.DATA > src/index/cache01.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/SEARCH10.IDX build/TOTAL.DATA > src/index/search10.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/CACHE10.IDX build/TOTAL.DATA > src/index/cache10.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/SEARCH11.IDX build/TOTAL.DATA > src/index/search11.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/CACHE11.IDX build/TOTAL.DATA > src/index/cache11.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/PRELAUNCH.IDX build/TOTAL.DATA > src/index/prelaunch.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/ATTRACT.IDX build/TOTAL.DATA > src/index/attract.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/FX.IDX build/TOTAL.DATA > src/index/fx.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/DFX.IDX build/TOTAL.DATA > src/index/dfx.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/SFX.IDX build/TOTAL.DATA > src/index/sfx.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/GAMEHELP.IDX build/TOTAL.DATA > src/index/gamehelp.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/SLIDESHOW.IDX build/TOTAL.DATA > src/index/slideshow.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/MINIATTRACT0.IDX build/TOTAL.DATA > src/index/miniattract0.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/MINIATTRACT1.IDX build/TOTAL.DATA > src/index/miniattract1.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/TITLE.IDX build/TOTAL.DATA > src/index/title.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/DTITLE.IDX build/TOTAL.DATA > src/index/dtitle.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HGR0.IDX build/TOTAL.DATA > src/index/hgr0.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HGR1.IDX build/TOTAL.DATA > src/index/hgr1.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HGR2.IDX build/TOTAL.DATA > src/index/hgr2.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HGR3.IDX build/TOTAL.DATA > src/index/hgr3.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HGR4.IDX build/TOTAL.DATA > src/index/hgr4.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HGR5.IDX build/TOTAL.DATA > src/index/hgr5.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HGR6.IDX build/TOTAL.DATA > src/index/hgr6.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/DHGR.IDX build/TOTAL.DATA > src/index/dhgr.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/GR.IDX build/TOTAL.DATA > src/index/gr.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/DGR.IDX build/TOTAL.DATA > src/index/dgr.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/ARTWORK.IDX build/TOTAL.DATA > src/index/artwork.idx.a
|
||||
#
|
||||
# add additional miscellaneous files
|
||||
#
|
||||
[ -f build/index ] || bin/addfile.sh build/COVERFADE build/TOTAL.DATA > src/index/coverfade.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/GR.FIZZLE build/TOTAL.DATA > src/index/gr.fizzle.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/DGR.FIZZLE build/TOTAL.DATA > src/index/dgr.fizzle.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/HELPTEXT build/TOTAL.DATA > src/index/helptext.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh build/CREDITS build/TOTAL.DATA > src/index/credits.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/DECRUNCH build/TOTAL.DATA > src/index/decrunch.idx.a
|
||||
[ -f build/index ] || bin/addfile.sh res/JOYSTICK build/TOTAL.DATA > src/index/joystick.idx.a
|
||||
touch build/index
|
||||
|
||||
asmlauncher: md
|
||||
asmlauncher: preconditions md
|
||||
$(ACME) -DBUILDNUMBER=`git rev-list --count HEAD` src/4cade.a 2>build/relbase.log
|
||||
$(ACME) -r build/4cade.lst -DBUILDNUMBER=`git rev-list --count HEAD` -DRELBASE=`cat build/relbase.log | grep "RELBASE =" | cut -d"=" -f2 | cut -d"(" -f2 | cut -d")" -f1` src/4cade.a
|
||||
|
||||
asmfx: md
|
||||
for f in src/fx/*.a; do \
|
||||
grep "^\!to" $${f} >/dev/null && $(ACME) $${f} || true; \
|
||||
done
|
||||
asmdemo: preconditions md
|
||||
$(PARALLEL) 'if grep -q "^!to" "{}"; then $(ACME) "{}"; fi' ::: src/demo/*.a
|
||||
|
||||
asmprelaunch: md
|
||||
for f in src/prelaunch/*.a; do \
|
||||
grep "^\!to" $${f} >/dev/null && $(ACME) $${f}; \
|
||||
done
|
||||
asmfx: preconditions md
|
||||
$(PARALLEL) 'if grep -q "^!to" "{}"; then $(ACME) "{}"; fi' ::: src/fx/*.a
|
||||
|
||||
asmprelaunch: preconditions md
|
||||
$(PARALLEL) 'if grep -q "^!to" "{}"; then $(ACME) "{}"; fi' ::: src/prelaunch/*.a
|
||||
|
||||
asmproboot: md
|
||||
$(ACME) -r build/proboothd.lst src/proboothd/proboothd.a
|
||||
|
||||
#
|
||||
# |compress| and |attract| must be called separately because they are slow.
|
||||
# They create files in the repository which can then be checked in.
|
||||
#
|
||||
compress: md
|
||||
for f in res/ACTION.HGR.UNCOMPRESSED/*; do o=res/ACTION.HGR/$$(basename $$f); [ -f "$$o" ] || ${EXOMIZER} "$$f"@0x4000 -o "$$o" >>build/log; done
|
||||
for f in res/ACTION.DHGR.UNCOMPRESSED/*; do o=res/ACTION.DHGR/$$(basename $$f); [ -f "$$o" ] || ${EXOMIZER} "$$f"@0x4000 -o "$$o" >>build/log; done
|
||||
for f in res/ARTWORK.SHR.UNCOMPRESSED/*; do o=res/ARTWORK.SHR/$$(basename $$f); [ -f "$$o" ] || ${EXOMIZER} "$$f"@0x2000 -o "$$o" >>build/log; done
|
||||
compress: preconditions md
|
||||
$(PARALLEL) '[ -f "res/ACTION.HGR/{/}" ] || ${EXOMIZER} "{}"@0x4000 -o "res/ACTION.HGR/{/}"' ::: res/ACTION.HGR.UNCOMPRESSED/*
|
||||
$(PARALLEL) '[ -f "res/ACTION.DHGR/{/}" ] || ${EXOMIZER} "{}"@0x4000 -o "res/ACTION.DHGR/{/}"' ::: res/ACTION.DHGR.UNCOMPRESSED/*
|
||||
$(PARALLEL) '[ -f "res/ARTWORK.SHR/{/}" ] || ${EXOMIZER} "{}"@0x2000 -o "res/ARTWORK.SHR/{/}"' ::: res/ARTWORK.SHR.UNCOMPRESSED/*
|
||||
$(PARALLEL) '[ -f "res/TITLE.HGR/{/}" ] || bin/packhgrfile.py "{}" "res/TITLE.HGR/{/}"' ::: res/TITLE.HGR.UNPACKED/*
|
||||
|
||||
#
|
||||
# |attract| must be called separately because it is slow and
|
||||
# only needs to be run when a new game or demo is added.
|
||||
# It create files in the repository which can then be checked in.
|
||||
#
|
||||
attract: compress
|
||||
bin/check-attract-mode.sh
|
||||
bin/generate-mini-attract-mode.sh
|
||||
|
||||
cache: preconditions md
|
||||
$(PARALLEL) ::: \
|
||||
'awk -F= '"'"'/^00/ { print $$2 }'"'"' < res/GAMES.CONF | bin/buildcache.py > build/cache00.a' \
|
||||
'awk -F= '"'"'/^0/ { print $$2 }'"'"' < res/GAMES.CONF | bin/buildcache.py > build/cache01.a' \
|
||||
'awk -F= '"'"'/^.0/ { print $$2 }'"'"' < res/GAMES.CONF | bin/buildcache.py > build/cache10.a' \
|
||||
'awk -F= '"'"'!/^$$|^#|^\[/ { print $$2 }'"'"' < res/GAMES.CONF | bin/buildcache.py > build/cache11.a'
|
||||
$(PARALLEL) ::: \
|
||||
'$(ACME) -o res/CACHE00.IDX build/cache00.a' \
|
||||
'$(ACME) -o res/CACHE01.IDX build/cache01.a' \
|
||||
'$(ACME) -o res/CACHE10.IDX build/cache10.a' \
|
||||
'$(ACME) -o res/CACHE11.IDX build/cache11.a'
|
||||
|
||||
mount: dsk
|
||||
osascript bin/V2Make.scpt "`pwd`" bin/4cade.vii build/"$(DISK)"
|
||||
|
||||
md:
|
||||
mkdir -p build/X build/FX.INDEXED build/FX build/PRELAUNCH.INDEXED build/PRELAUNCH build/ATTRACT build/SS build/GAMEHELP
|
||||
mkdir -p build/X build/X.INDEXED build/FX build/FX.INDEXED build/PRELAUNCH build/PRELAUNCH.INDEXED build/ATTRACT build/SS build/GAMEHELP build/DEMO
|
||||
touch build/log
|
||||
|
||||
clean:
|
||||
rm -rf build/ || rm -rf build
|
||||
|
||||
preconditions:
|
||||
@$(ACME) --version | grep -q "ACME, release" || (echo "ACME is not installed" && exit 1)
|
||||
@$(CADIUS) | grep -q "cadius v" || (echo "Cadius is not installed" && exit 1)
|
||||
@$(PARALLEL) --version | grep -q "GNU" || (echo "GNU Parallel is not installed" && exit 1)
|
||||
@$(PYTHON) --version | grep -q "Python 3" || (echo "Python 3 is not installed" && exit 1)
|
||||
|
||||
all: clean dsk mount
|
||||
|
||||
al: all
|
||||
|
|
63
README.md
63
README.md
|
@ -7,10 +7,18 @@
|
|||
## Mac OS X
|
||||
|
||||
You will need
|
||||
- [Xcode command line tools](https://www.google.com/search?q=xcode+command+line+tools)
|
||||
- [Xcode command line tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html)
|
||||
- [ACME](https://sourceforge.net/projects/acme-crossass/)
|
||||
- [Parallel](https://www.gnu.org/software/parallel/)
|
||||
- [Cadius](https://github.com/mach-kernel/cadius)
|
||||
|
||||
As of this writing, all of the non-Xcode programs are installable via [Homebrew](https://brew.sh/).
|
||||
|
||||
``` shell
|
||||
$ brew tap lifepillar/appleii
|
||||
$ brew install acme parallel mach-kernel-cadius
|
||||
```
|
||||
|
||||
Then open a terminal window and type
|
||||
|
||||
``` shell
|
||||
|
@ -22,7 +30,7 @@ If all goes well, the `build/` subdirectory will contain a `4cade.hdv` image whi
|
|||
|
||||
If all does not go well, try doing a clean build (`make clean dsk`)
|
||||
|
||||
If that fails, perhaps you have out-of-date versions of one of the required tools? The [Makefile](https://github.com/a2-4am/4cade/blob/master/Makefile) lists, but does not enforce, the minimum version requirements of each third-party tool.
|
||||
If that fails, perhaps you have out-of-date versions of one of the required tools? The [Makefile](https://github.com/a2-4am/4cade/blob/main/Makefile) lists, but does not enforce, the minimum version requirements of each third-party tool.
|
||||
|
||||
If that fails, please [file a bug](https://github.com/a2-4am/4cade/issues/new).
|
||||
|
||||
|
@ -37,55 +45,60 @@ You will need
|
|||
Then open a `CMD.EXE` window and type
|
||||
|
||||
```
|
||||
C:\> CD 4CADE
|
||||
C:\4cade> WINMAKE
|
||||
C:\> cd 4cade
|
||||
C:\4cade> winmake dsk
|
||||
```
|
||||
If all goes well, the `BUILD\` subdirectory will contain a `4CADE.HDV` image which can be mounted in emulators like [AppleWin](https://github.com/AppleWin/AppleWin).
|
||||
If all goes well, the `build\` subdirectory will contain a `4cade.hdv` image which can be mounted in emulators like [AppleWin](https://github.com/AppleWin/AppleWin) or [MAME](http://www.mamedev.org).
|
||||
|
||||
If all does not go well, try doing a clean build (`winmake clean`, `winmake dsk`)
|
||||
|
||||
If that fails, perhaps you have out-of-date versions of one of the required tools? The [winmake](https://github.com/a2-4am/4cade/blob/main/winmake.bat) lists, but does not enforce, the minimum version requirements of each third-party tool.
|
||||
|
||||
If that fails, please [file a bug](https://github.com/a2-4am/4cade/issues/new).
|
||||
|
||||
# Navigating the code
|
||||
|
||||
## Initialization
|
||||
|
||||
[`4cade.a`](https://github.com/a2-4am/4cade/blob/master/src/4cade.a) is the main assembler target. It builds the launcher itself. Launcher code is split into code that can be run once from main memory then discarded, and code which is relocated to the language card and persists throughout the lifetime of the launcher. As the language card is only 16KB and will also need to store some persistent data structures, memory is precious and tightly managed.
|
||||
[`4cade.a`](https://github.com/a2-4am/4cade/blob/main/src/4cade.a) is the main assembler target. It builds the launcher itself. Launcher code is split into code that can be run once from main memory then discarded, and code which is relocated to the language card and persists throughout the lifetime of the launcher. As the language card is only 16KB and will also need to store some persistent data structures, memory is precious and tightly managed.
|
||||
|
||||
[`4cade.init.a`](https://github.com/a2-4am/4cade/blob/master/src/4cade.init.a) contains the code that is run once at program startup. First, we do some hardware detection, like how much memory you have, whether you have a joystick, and whether you have a IIgs. Then we relocate selected code to the language card. [`constants.a`](https://github.com/a2-4am/4cade/blob/master/src/constants.a) has a rough map of what ends up where, within the language card and its overlapping memory regions. Then we load and parse the global preferences file ([`PREFS.CONF`](https://github.com/a2-4am/4cade/blob/master/res/prefs.conf)) and master game list ([`GAMES.CONF`](https://github.com/a2-4am/4cade/blob/master/res/games.conf)) and store the results in the language card. Finally, we jump to the main entry point (`Reenter`). The launcher is initialized; anything left in main memory is discarded.
|
||||
[`4cade.init.a`](https://github.com/a2-4am/4cade/blob/main/src/4cade.init.a) contains the code that is run once at program startup. First, we do some hardware detection, like how much memory you have, whether you have a joystick, and whether you have a IIgs. Then we relocate selected code to the language card and load the appropriate search index. (For example, if you do not have a joystick, games that require a joystick will not appear in search results.) [`constants.a`](https://github.com/a2-4am/4cade/blob/main/src/constants.a) has a rough map of what ends up where, within the language card and its overlapping memory regions. Then we load and parse the global preferences file ([`PREFS.CONF`](https://github.com/a2-4am/4cade/blob/main/res/prefs.conf)) and store the results in the language card. Finally, we jump to the main entry point (`Reenter`). The launcher is initialized; anything left in main memory is discarded.
|
||||
|
||||
## Search mode
|
||||
|
||||
There are three major modes in the launcher: search mode, browse mode, and mega-attract mode. Search mode is the default, and it is always the first mode you enter when launching the program. [`ui.search.mode.a`](https://github.com/a2-4am/4cade/blob/master/src/ui.search.mode.a) tracks your keystrokes to determine the best match within the game list for the keys you have typed, then loads the game's title screenshot and displays the game name and other information at the bottom of the screen. If you have not yet typed any keys, it displays the title page and welcome message instead. The `InputKeys` table documents all other recognized keys.
|
||||
There are three major modes in the launcher: search mode, browse mode, and mega-attract mode. Search mode is the default, and it is always the first mode you enter when launching the program. [`ui.search.mode.a`](https://github.com/a2-4am/4cade/blob/main/src/ui.search.mode.a) tracks your keystrokes to determine the best match within the game list for the keys you have typed, then loads the game's title screenshot and displays the game name and other information at the bottom of the screen. If you have not yet typed any keys, it displays the title page and welcome message instead. The `InputKeys` table documents all other recognized keys.
|
||||
|
||||
The text ranking algorithm is in [`textrank.a`](https://github.com/a2-4am/4cade/blob/master/src/textrank.a). It was inspired by [Quicksilver](https://github.com/quicksilver/Quicksilver) but is an independent implementation.
|
||||
The text ranking algorithm is in [`textrank.a`](https://github.com/a2-4am/4cade/blob/main/src/textrank.a). It was inspired by [Quicksilver](https://github.com/quicksilver/Quicksilver) but is an independent implementation.
|
||||
|
||||
## Browse mode
|
||||
|
||||
The user enters browse mode by pressing the right or down arrow key. [`ui.browse.mode.a`](https://github.com/a2-4am/4cade/blob/master/src/ui.browse.mode.a) then watches for other arrow keys and displays the next or previous game in the game list. The `BrowseKeys` table documents all other recognized keys.
|
||||
The user enters browse mode by pressing the right or down arrow key. [`ui.browse.mode.a`](https://github.com/a2-4am/4cade/blob/main/src/ui.browse.mode.a) then watches for other arrow keys and displays the next or previous game in the game list. The `BrowseKeys` table documents all other recognized keys.
|
||||
|
||||
## Mega-Attract mode
|
||||
|
||||
If the user presses `Esc` from any other mode, or does not type anything for 30 seconds, the launcher goes into Mega-Attract mode, a.k.a. screensaver mode. [`ui.attract.mode.a`](https://github.com/a2-4am/4cade/blob/master/src/ui.attract.mode.a) manages loading and executing attract mode modules. An attract mode module can be a short slideshow, a self-running demo, or just a single screenshot. Modules are listed in [`ATTRACT.CONF`](https://github.com/a2-4am/4cade/blob/master/res/attract.conf) and are run in order until end-of-file, then it starts over from the beginning. The entire cycle is quite long (several hours), and some screenshots appear in multiple slideshows, but there is no actual randomness in selecting the next attract mode module.
|
||||
If the user presses `Esc` from any other mode, or does not type anything for 30 seconds, the launcher goes into Mega-Attract mode, a.k.a. screensaver mode. [`ui.attract.mode.a`](https://github.com/a2-4am/4cade/blob/main/src/ui.attract.mode.a) manages loading and executing attract mode modules. An attract mode module can be a short slideshow, a self-running demo, or just a single screenshot. Modules are listed in [`ATTRACT.CONF`](https://github.com/a2-4am/4cade/blob/main/res/attract.conf) and are run in order until end-of-file, then it starts over from the beginning. The entire cycle is quite long (several hours), and some screenshots appear in multiple slideshows, but there is no actual randomness in selecting the next attract mode module.
|
||||
|
||||
# Navigating the configuration files
|
||||
|
||||
## `GAMES.CONF`
|
||||
|
||||
[`GAMES.CONF`](https://github.com/a2-4am/4cade/blob/master/res/GAMES.CONF) is the master games list. It contains 1 record for every game in Total Replay. However, not every game is playable on every device, so each record also contains metadata, e.g. "this game requires a joystick," or "this game requires 128K," or "this game has a double hi-res title screen" (which is not identical to "this game requires 128K").
|
||||
[`GAMES.CONF`](https://github.com/a2-4am/4cade/blob/main/res/GAMES.CONF) is the master games list. It contains 1 record for every game in Total Replay. However, not every game is playable on every device, so each record also contains metadata, e.g. "this game requires a joystick," or "this game requires 128K," or "this game has a double hi-res title screen" (which is not identical to "this game requires 128K").
|
||||
|
||||
The format of the `GAMES.CONF` file has changed as new requirements have appeared, and it may change again in the future. There is up-to-date format information at the bottom of the file itself, which I will not duplicate here. However, in general, each record is 1 line and contains the name and flags for 1 game. The file is parsed once at program startup, and the (possibly filtered) list of available games is stored persistently in the language card.
|
||||
|
||||
Many records in `GAMES.CONF` do not list the game's display name, i.e. the mixed-case, human-readable name displayed in search mode, browse mode, and slideshows. Wherever possible, display names are calculated from a game's filename, so `WAVY.NAVY` is displayed as `Wavy Navy`, while `ARCHON.II` is displayed as `Archon II`, and so on.
|
||||
The format of the `GAMES.CONF` file has changed as new requirements have appeared, and it may change again in the future. There is up-to-date format information in comments in the file itself, which I will not duplicate here. However, in general, each record is 1 line and contains the name and flags for 1 game. The file is parsed during build and used to create the search indexes and other files which are stored on the final disk image.
|
||||
|
||||
Each game's filename is used as a "foreign key" (in database terms) to build directory paths, to locate files in subdirectories, and to reference the game in other configuration files.
|
||||
|
||||
- A game's main executable is always `X/FILENAME/FILENAME`
|
||||
- A game's HGR title screenshot is always `TITLE.HGR/FILENAME`
|
||||
- A game's super hi-res box art is always `ARTWORK.SHR/FILENAME`
|
||||
- A game's super hi-res box art is always `ARTWORK.SHR/FILENAME` (not all games have artwork)
|
||||
- A games's help page is always `GAMEHELP/FILENAME` (not all games have help)
|
||||
- A game's mini-attract mode configuration file is always `ATTRACT/FILENAME`
|
||||
- Games are included in other attract mode configuration files by `FILENAME`
|
||||
- The source disk image of a game (in [`res/dsk`](https://github.com/a2-4am/4cade/tree/master/res/dsk)) must have a volume name of `FILENAME`, and there must be a file in the disk image's root directory also named `FILENAME` which is the game's main executable
|
||||
- The source disk image of a game (in [`res/dsk`](https://github.com/a2-4am/4cade/tree/main/res/dsk)) must have a volume name of `FILENAME`, and there must be a file in the disk image's root directory also named `FILENAME` which is the game's main executable
|
||||
|
||||
## `ATTRACT.CONF`
|
||||
|
||||
[`ATTRACT.CONF`](https://github.com/a2-4am/4cade/blob/master/res/ATTRACT.CONF) is the master configuration file for Mega-Attract mode. There is up-to-date format information at the bottom of the file itself, which I will not duplicate here. In general, each record is the name of an attract module, which can be a slideshow, self-running demo, or even a single screenshot. Each attract module corresponds to a file in a separate directory; see format information for details. So the record `FAVORITES2.CONF=1` corresponds to [`a real file`](https://github.com/a2-4am/4cade/blob/master/res/SS/FAVORITES2.CONF) that contains details about that particular hi-res slideshow.
|
||||
[`ATTRACT.CONF`](https://github.com/a2-4am/4cade/blob/main/res/ATTRACT.CONF) is the master configuration file for Mega-Attract mode. There is up-to-date format information in comments in the file itself, which I will not duplicate here. In general, each record is the name of an attract module, which can be a slideshow, self-running demo, or even a single screenshot. Each attract module corresponds to a file in a separate directory; see format information for details. So the record `FAVORITES2.CONF=1` corresponds to [`a real file`](https://github.com/a2-4am/4cade/blob/main/res/SS/FAVORITES2.CONF) that contains details about that particular hi-res slideshow. `ATTRACT.CONF` and the linked slideshow configuration files are parsed at build time and stored in a custom format on the final disk image.
|
||||
|
||||
Attract modules are loosely divided into sets that have a loosely similar mix of hi-res, double hi-res, super hi-res, and self-running demos. The `ATTRACT.CONF` file is maintained by hand and changes frequently as we add games, split up slideshows, or reorder things on a whim.
|
||||
|
||||
|
@ -98,13 +111,13 @@ $ make attract
|
|||
|
||||
## `FX.CONF`, `DFX.CONF`
|
||||
|
||||
[`FX.CONF`](https://github.com/a2-4am/4cade/blob/master/res/FX.CONF) and its sister [`DFX.CONF`](https://github.com/a2-4am/4cade/blob/master/res/DFX.CONF) list the HGR and DHGR transition effects used in hi-res and double hi-res slideshows. Each record is a filename of a transition effect file, which is an executable file [assembled at build time](https://github.com/a2-4am/4cade/tree/master/src/fx) and stored on disk in a custom format. At the beginning of each slideshow, we query the global preferences to find the filename of the FX or DFX file, then update the global preferences with the next filename (wrapping around to the beginning of the list). If you watch the Mega-Attract mode long enough, you will eventually see all the transition effects, and since the cycle of transition effects is separate from the cycle of slideshows, you will eventually see the same slideshow with different transition effects.
|
||||
[`FX.CONF`](https://github.com/a2-4am/4cade/blob/main/res/FX.CONF) and its sister [`DFX.CONF`](https://github.com/a2-4am/4cade/blob/main/res/DFX.CONF) list the HGR and DHGR transition effects used in hi-res and double hi-res slideshows. Each record is a filename of a transition effect file, which is an executable file [assembled at build time](https://github.com/a2-4am/4cade/tree/main/src/fx) and stored on final disk image in a custom format. At the beginning of each slideshow, we query the global preferences to find the filename of the FX or DFX file, then update the global preferences with the next filename (wrapping around to the beginning of the list). If you watch the Mega-Attract mode long enough, you will eventually see all the transition effects, and since the cycle of transition effects is separate from the cycle of slideshows, you will eventually see the same slideshow with different transition effects.
|
||||
|
||||
These files are parsed at build time and stored on disk in a binary format, then read from disk every time they are needed. Due to memory restrictions, the parsed data is not persisted.
|
||||
These files are parsed at build time and stored on the final disk image in a binary format, then read from disk every time they are needed. Due to memory restrictions, the parsed data is not persisted.
|
||||
|
||||
## `PREFS.CONF`
|
||||
|
||||
[`PREFS.CONF`](https://github.com/a2-4am/4cade/blob/master/res/PREFS.CONF) contains persistent global state, including Mega-Attract mode state and whether cheats are enabled. There is up-to-date format information in the file itself.
|
||||
[`PREFS.CONF`](https://github.com/a2-4am/4cade/blob/main/res/PREFS.CONF) contains persistent global state, including Mega-Attract mode state and whether cheats are enabled. There is up-to-date format information in comments in the file itself.
|
||||
|
||||
This file is read and parsed once at program startup, and the parsed data is stored persistently in the language card. It is written to disk every time global state changes, which is often during Mega-Attract mode, or if the user toggles cheat mode.
|
||||
|
||||
|
@ -112,13 +125,13 @@ This file is read and parsed once at program startup, and the parsed data is sto
|
|||
|
||||
Many files in Total Replay are stored in a compressed format, then decompressed at run-time. The compression and decompression is handled by [Exomizer](https://bitbucket.org/magli143/exomizer/wiki/Home), which targets 8-bit platforms. Compressed files include
|
||||
|
||||
- [hi-res action screenshots](https://github.com/a2-4am/4cade/tree/master/res/ACTION.HGR)
|
||||
- [double hi-res action screenshots](https://github.com/a2-4am/4cade/tree/master/res/ACTION.DHGR)
|
||||
- [super hi-res box art](https://github.com/a2-4am/4cade/tree/master/res/ARTWORK.SHR)
|
||||
- [hi-res action screenshots](https://github.com/a2-4am/4cade/tree/main/res/ACTION.HGR)
|
||||
- [double hi-res action screenshots](https://github.com/a2-4am/4cade/tree/main/res/ACTION.DHGR)
|
||||
- [super hi-res box art](https://github.com/a2-4am/4cade/tree/main/res/ARTWORK.SHR)
|
||||
|
||||
Both the compressed and uncompressed files are stored in the repository, so you do not need Exomizer installed to build Total Replay. You only need it if you add new graphics.
|
||||
|
||||
To add a new compressed graphic file, add the uncompressed original file to the appropriate directory ([`ACTION.HGR.UNCOMPRESSED`](https://github.com/a2-4am/4cade/tree/master/res/ACTION.HGR.UNCOMPRESSED), [`ACTION.DHGR.UNCOMPRESSED`](https://github.com/a2-4am/4cade/tree/master/res/ACTION.DHGR.UNCOMPRESSED), or [`ARTWORK.SHR.UNCOMPRESSED`](https://github.com/a2-4am/4cade/tree/master/res/ARTWORK.SHR.UNCOMPRESSED) respectively), then run
|
||||
To add a new compressed graphic file, add the uncompressed original file to the appropriate directory ([`ACTION.HGR.UNCOMPRESSED`](https://github.com/a2-4am/4cade/tree/main/res/ACTION.HGR.UNCOMPRESSED), [`ACTION.DHGR.UNCOMPRESSED`](https://github.com/a2-4am/4cade/tree/main/res/ACTION.DHGR.UNCOMPRESSED), or [`ARTWORK.SHR.UNCOMPRESSED`](https://github.com/a2-4am/4cade/tree/main/res/ARTWORK.SHR.UNCOMPRESSED) respectively), then run
|
||||
|
||||
``` shell
|
||||
$ cd 4cade/
|
||||
|
|
5
bin/addfile.js
Normal file
5
bin/addfile.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
a=new ActiveXObject("scripting.filesystemobject")
|
||||
offset=a.getfile("BUILD\\TOTAL.DATA").size
|
||||
new ActiveXObject("wscript.shell").run('cmd /c copy /b /y BUILD\\TOTAL.DATA + ' + WScript.Arguments(0) + ' BUILD\\TOTAL.DATA', 0, 1)
|
||||
size=a.getfile(WScript.Arguments(0)).size
|
||||
a.createtextfile(WScript.Arguments(1)).write(";\r\n; Index record for " + WScript.Arguments(0).replace(/\\/, "/") + "\r\n;\r\n; This file is automatically generated\r\n;\r\n !byte 0\r\n !be24 " + offset + "\r\n !le16 " + " ".substr(0, 8 - size.toString().length) + size + "\r\n")
|
19
bin/addfile.sh
Executable file
19
bin/addfile.sh
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
# parameters
|
||||
# 1 - input file
|
||||
# 2 - output filename for data file
|
||||
# stdout - source code of index record
|
||||
|
||||
touch "$2"
|
||||
size=$(wc -c < "$1")
|
||||
offset=$(wc -c < "$2")
|
||||
cat "$1" >> "$2"
|
||||
echo ";"
|
||||
echo "; Index record for $1"
|
||||
echo ";"
|
||||
echo "; This file is automatically generated"
|
||||
echo ";"
|
||||
echo " !byte 0"
|
||||
echo " !be24 $offset"
|
||||
echo " !le16 $size"
|
60
bin/buildcache.js
Normal file
60
bin/buildcache.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
a = new ActiveXObject("scripting.filesystemobject")
|
||||
b = a.opentextfile("res\\GAMES.CONF")
|
||||
f00 = a.createtextfile("build\\filter00.txt")
|
||||
f01 = a.createtextfile("build\\filter01.txt")
|
||||
f10 = a.createtextfile("build\\filter10.txt")
|
||||
f11 = a.createtextfile("build\\filter11.txt")
|
||||
|
||||
while (!b.atendofstream)
|
||||
{
|
||||
c = b.readline()
|
||||
|
||||
d = c.indexOf("#")
|
||||
|
||||
if (d >= 0)
|
||||
{
|
||||
c = c.substr(0, d)
|
||||
}
|
||||
|
||||
if (c.indexOf("[eof]") >= 0)
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (c.length == 0)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (c.substr(0, 2) == "00")
|
||||
{
|
||||
f00.writeline(c.substr(c.indexOf("=") + 1))
|
||||
}
|
||||
|
||||
if (c.substr(0, 1) == "0")
|
||||
{
|
||||
f01.writeline(c.substr(c.indexOf("=") + 1))
|
||||
}
|
||||
|
||||
if (c.substr(1, 1) == "0")
|
||||
{
|
||||
f10.writeline(c.substr(c.indexOf("=") + 1))
|
||||
}
|
||||
|
||||
f11.writeline(c.substr(c.indexOf("=") + 1))
|
||||
}
|
||||
|
||||
f11.close()
|
||||
f10.close()
|
||||
f01.close()
|
||||
f00.close()
|
||||
|
||||
x = new ActiveXObject("wscript.shell")
|
||||
x.run('cmd /c %python% bin\\buildcache.py < build\\filter00.txt > build\\cache00.a', 0, 1)
|
||||
x.run('cmd /c %python% bin\\buildcache.py < build\\filter01.txt > build\\cache01.a', 0, 1)
|
||||
x.run('cmd /c %python% bin\\buildcache.py < build\\filter10.txt > build\\cache10.a', 0, 1)
|
||||
x.run('cmd /c %python% bin\\buildcache.py < build\\filter11.txt > build\\cache11.a', 0, 1)
|
||||
x.run('cmd /c %acme% -o res\\CACHE00.IDX build\\cache00.a', 0, 1)
|
||||
x.run('cmd /c %acme% -o res\\CACHE01.IDX build\\cache01.a', 0, 1)
|
||||
x.run('cmd /c %acme% -o res\\CACHE10.IDX build\\cache10.a', 0, 1)
|
||||
x.run('cmd /c %acme% -o res\\CACHE11.IDX build\\cache11.a', 0, 1)
|
126
bin/buildcache.py
Executable file
126
bin/buildcache.py
Executable file
|
@ -0,0 +1,126 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from collections import OrderedDict
|
||||
from pprint import pprint
|
||||
from string import ascii_lowercase
|
||||
from sys import stdin
|
||||
|
||||
def score(inputbuffer, displayname):
|
||||
if len(inputbuffer) > len(displayname):
|
||||
return 0, False
|
||||
likely = True
|
||||
startat = 0
|
||||
score = 0
|
||||
for c in inputbuffer:
|
||||
x = 10
|
||||
y = displayname[startat:].find(c)
|
||||
if y < 0:
|
||||
return 0, False
|
||||
if y == 0:
|
||||
x = 80
|
||||
elif (startat > 0) and (displayname[startat+y-1] == " "):
|
||||
x = 90
|
||||
else:
|
||||
likely = False
|
||||
score += x
|
||||
startat += y + 1
|
||||
score = int(score/len(displayname) + (score/len(inputbuffer)) + 0.99)/2
|
||||
if (inputbuffer[0] == displayname[0]) and (score < 85):
|
||||
score += 15
|
||||
return score, likely
|
||||
|
||||
def best(keys, games):
|
||||
gameindex = 0
|
||||
bestscore = -1
|
||||
bestindex = -1
|
||||
bestlikely = False
|
||||
for game in games:
|
||||
gamescore, likely = score(keys, game)
|
||||
if (gamescore > bestscore):
|
||||
bestscore = gamescore
|
||||
bestindex = gameindex
|
||||
bestlikely = likely
|
||||
gameindex += 1
|
||||
if not bestlikely:
|
||||
return 0
|
||||
return bestindex
|
||||
|
||||
def main():
|
||||
games = [line.strip().lower() for line in stdin]
|
||||
cache = OrderedDict()
|
||||
for a in ascii_lowercase:
|
||||
index1 = best(a, games)
|
||||
if not index1: continue
|
||||
cache[a] = OrderedDict()
|
||||
cache[a][" "] = index1
|
||||
for b in ascii_lowercase:
|
||||
index2 = best(a+b, games)
|
||||
if not index2: continue
|
||||
cache[a][b] = OrderedDict()
|
||||
if index2 != index1:
|
||||
cache[a][b][" "] = index2
|
||||
for c in ascii_lowercase:
|
||||
index3 = best(a+b+c, games)
|
||||
if not index3: continue
|
||||
cache[a][b][c] = OrderedDict()
|
||||
if index3 != index2:
|
||||
cache[a][b][c][" "] = index3
|
||||
for d in ascii_lowercase:
|
||||
index4 = best(a+b+c+d, games)
|
||||
if not index4: continue
|
||||
if index4 != index3:
|
||||
cache[a][b][c][d] = index4
|
||||
if not cache[a][b][c]:
|
||||
del cache[a][b][c]
|
||||
if not cache[a][b]:
|
||||
del cache[a][b]
|
||||
if not cache[a]:
|
||||
del cache[a]
|
||||
|
||||
print('*=$A000')
|
||||
for a in cache:
|
||||
print(f' !text "{a}"')
|
||||
if type(cache[a]) == int:
|
||||
print(f' !word {cache[a]}')
|
||||
else:
|
||||
print(f' !word _{a}')
|
||||
print(' !byte 0')
|
||||
|
||||
for a in cache:
|
||||
if type(cache[a]) == int: continue
|
||||
print(f'_{a}')
|
||||
for b in cache[a]:
|
||||
print(f' !text "{b}"')
|
||||
if type(cache[a][b]) == int:
|
||||
print(f' !word {cache[a][b]}')
|
||||
else:
|
||||
print(f' !word _{a}{b}')
|
||||
print(' !byte 0')
|
||||
|
||||
for a in cache:
|
||||
if type(cache[a]) == int: continue
|
||||
for b in cache[a]:
|
||||
if type(cache[a][b]) == int: continue
|
||||
print(f'_{a}{b}')
|
||||
for c in cache[a][b]:
|
||||
print(f' !text "{c}"')
|
||||
if type(cache[a][b][c]) == int:
|
||||
print(f' !word {cache[a][b][c]}')
|
||||
else:
|
||||
print(f' !word _{a}{b}{c}')
|
||||
print(' !byte 0')
|
||||
|
||||
for a in cache:
|
||||
if type(cache[a]) == int: continue
|
||||
for b in cache[a]:
|
||||
if type(cache[a][b]) == int: continue
|
||||
for c in cache[a][b]:
|
||||
if type(cache[a][b][c]) == int: continue
|
||||
print(f'_{a}{b}{c}')
|
||||
for d in cache[a][b][c]:
|
||||
print(f' !text "{d}"')
|
||||
print(f' !word {cache[a][b][c][d]}')
|
||||
print(' !byte 0')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# usage:
|
||||
# builddisplaynames.py < build/GAMES.CONF > build/DISPLAY.CONF
|
||||
|
||||
import sys
|
||||
|
||||
for line in sys.stdin:
|
||||
if line.startswith("["): continue
|
||||
if "=" not in line:
|
||||
prefix, key = line.split(",")
|
||||
line = prefix + "," + key.strip() + "=" + key.replace(".", " ").title().replace(" Ii", " II")
|
||||
print(line, end="")
|
|
@ -1,31 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# make temp file with just the key/value pairs (strip blank lines, comments, eof marker)
|
||||
records=$(mktemp)
|
||||
awk '!/^$|^#|^\[/' > "$records"
|
||||
|
||||
# make temp assembly source file that represents the binary OKVS data structure
|
||||
source=$(mktemp)
|
||||
(echo "*=0" # dummy program counter for assembler
|
||||
echo "!le16 $(wc -l <"$records"), 0" # OKVS header
|
||||
while IFS="=" read -r key value; do
|
||||
dhgr=$(echo "$key" | cut -c3) # 'has DHGR title screen' flag (0 or 1)
|
||||
cheat=$(echo "$key" | cut -c4) # 'cheat category' (0..5)
|
||||
key=$(echo "$key" | cut -d"," -f2)
|
||||
echo "!byte ${#key}+${#value}+4" # OKVS record length
|
||||
echo "!byte ${#key}" # OKVS key length
|
||||
echo "!text \"$key\"" # OKVS key
|
||||
echo "!byte ${#value}+1" # OKVS value length
|
||||
echo "!text \"$value\"" # OKVS value
|
||||
echo "!byte $((dhgr*128))+$cheat"
|
||||
done < "$records") > "$source"
|
||||
|
||||
# assemble temp source file into binary OKVS data structure, then output that
|
||||
out=$(mktemp)
|
||||
acme -o "$out" "$source"
|
||||
cat "$out"
|
||||
|
||||
# clean up
|
||||
rm "$out"
|
||||
rm "$source"
|
||||
rm "$records"
|
|
@ -5,10 +5,11 @@
|
|||
# -p pad sizes within data file to next block size (default off)
|
||||
|
||||
# parameters
|
||||
# stdin - input containing list of effects (probably FX.CONF or DFX.CONF)
|
||||
# stdin - input containing list of files (e.g. FX.CONF)
|
||||
# stdout - binary OKVS data structure
|
||||
# 1 - output filename for data file
|
||||
# 2 - input directory of files to merge into data file
|
||||
# 3 - (optional) output filename for log of key,offset,size
|
||||
|
||||
pad=false
|
||||
append=false
|
||||
|
@ -29,6 +30,11 @@ if [ "$append" = false ]; then
|
|||
fi
|
||||
touch "$1"
|
||||
|
||||
if [ "${#3}" -ne "0" ]; then
|
||||
rm -f "$3"
|
||||
touch "$3"
|
||||
fi
|
||||
|
||||
# if there is a file called "STANDARD" in the input directory, add it now
|
||||
# because we will reuse it for any files that don't exist
|
||||
if [ -f "$2"/STANDARD ]; then
|
||||
|
@ -39,40 +45,44 @@ fi
|
|||
|
||||
# make temp file with list of lines that contain keys
|
||||
records=$(mktemp)
|
||||
awk '!/^$|^#|^\[/' > "$records"
|
||||
tr -d "\r" | awk '!/^$|^#|^\[/' > "$records"
|
||||
|
||||
# make temp assembly source file that represents the binary OKVS data structure
|
||||
source=$(mktemp)
|
||||
(echo "*=0" # dummy program counter for assembler
|
||||
echo "!le16 $(wc -l <"$records"), 0" # OKVS header
|
||||
while IFS="=" read -r key value; do
|
||||
echo "!byte ${#key}+7" # OKVS record length
|
||||
echo "!byte ${#key}" # OKVS key length
|
||||
echo "!text \"$key\"" # OKVS key
|
||||
if [ -f "$2/$key" ]; then # if file exists, determine offset and size
|
||||
(echo "*=0" # dummy program counter for assembler
|
||||
echo "!le16 $(wc -l <"$records"), 0" # OKVS header
|
||||
while IFS="=" read -r filename dummy; do
|
||||
key=$(echo "$filename" | awk -F'#' '{ print $1 }')
|
||||
addr=$(echo "$filename" | awk -F'#' '{ print $2 }')
|
||||
if [ "${#addr}" -ne "0" ]; then # if filename is in the form 'NAME#06ADDR' then create extended index record
|
||||
addr=$(echo "$addr" | cut -c3-) # trim '06' so we get just the starting address
|
||||
echo "!byte ${#key}+9" # OKVS record length
|
||||
else
|
||||
echo "!byte ${#key}+7" # OKVS record length
|
||||
fi
|
||||
echo "!byte ${#key}" # OKVS key length
|
||||
echo "!text \"$key\"" # OKVS key
|
||||
if [ ! -e "$2/$filename" ]; then # if file does not exist, use standard offset and size
|
||||
offset="$standardoffset"
|
||||
size="$standardsize"
|
||||
else # otherwise calculate offset and size from file and options
|
||||
offset=$(wc -c < "$1")
|
||||
echo "!be24 $offset" # offset into merged data file
|
||||
echo -n "!le16 "
|
||||
size=$(wc -c < "$2/$key")
|
||||
size=$(wc -c < "$2/$filename")
|
||||
if [ "$pad" = true ]; then
|
||||
# If offset+size does not cross a block boundary, use file's true size.
|
||||
# Otherwise, round up size to the next block boundary.
|
||||
# This padding does not get added to the file; it is just an
|
||||
# optimization to avoid a partial copy on the last block read.
|
||||
if [ $(($offset / 512)) -eq $((($offset + $size) / 512)) ]; then
|
||||
echo "$size"
|
||||
else
|
||||
echo "$(((($offset + $size + 511) & -512) - $offset))"
|
||||
if [ $(($offset / 512)) -ne $((($offset + $size) / 512)) ]; then
|
||||
size=$(((($offset + $size + 511) & -512) - $offset))
|
||||
fi
|
||||
else
|
||||
# Caller said never pad, so always use file's true size.
|
||||
echo "$size"
|
||||
fi
|
||||
cat "$2/$key" >> "$1" # append this file to the end of the merged data file
|
||||
else # if file does not exist, reuse STANDARD file
|
||||
echo "!be24 $standardoffset"
|
||||
echo "!le16 $standardsize"
|
||||
cat "$2/$filename" >> "$1" # append this file to the end of the merged data file
|
||||
fi
|
||||
echo "!be24 $offset"
|
||||
echo "!le16 $size"
|
||||
[ "${#addr}" -ne "0" ] && echo '!le16 $'"$addr"
|
||||
[ "${#3}" -ne "0" ] && echo "$key,$offset,$size" >> "$3"
|
||||
done < "$records") > "$source"
|
||||
|
||||
# assemble temp source file into binary OKVS data structure, then output that
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# make temp file with just the key/value pairs (strip blank lines, comments, eof marker)
|
||||
records=$(mktemp)
|
||||
awk '!/^$|^#|^\[/' > "$records"
|
||||
tr -d "\r" | awk '!/^$|^#|^\[/' > "$records"
|
||||
|
||||
# make temp assembly source file that represents the binary OKVS data structure
|
||||
source=$(mktemp)
|
||||
|
|
|
@ -32,7 +32,7 @@ for (i = 0; i < entries.length; i++)
|
|||
size = ((Math.floor(c / 512) == Math.floor((c + size) / 512)) ? size : (((c + size + 511) & -512) - c))
|
||||
}
|
||||
|
||||
groups += "!byte " + (1 + 1 + entries[i].length + 5) + "\n" + "!byte " + entries[i].length + "\n" + "!text \"" + entries[i] + "\"\n" + "!be24 " + c + "\n" + "!le16 " + size + "\n"
|
||||
groups += "!byte " + (1 + 1 + entries[i].length + 3 + 2) + "\n" + "!byte " + entries[i].length + "\n" + "!text \"" + entries[i] + "\"\n" + "!be24 " + c + "\n" + "!le16 " + size + "\n"
|
||||
}
|
||||
|
||||
f = a.createtextfile("build\\pre.tmp")
|
||||
|
|
|
@ -1,13 +1,75 @@
|
|||
a = new ActiveXObject("scripting.filesystemobject")
|
||||
x = new ActiveXObject("wscript.shell")
|
||||
b = x.exec('findstr /b \"' + WScript.Arguments(0) + '\" build\\DISPLAY.CONF')
|
||||
c = a.createtextfile("build\\search.txt")
|
||||
|
||||
entries = []
|
||||
|
||||
while (!b.stdout.atendofstream)
|
||||
{
|
||||
d = b.stdout.readline()
|
||||
c.writeline(d.substr(d.indexOf(",") + 1))
|
||||
entries.push(b.stdout.readline())
|
||||
}
|
||||
|
||||
c.close()
|
||||
x.run('cscript /nologo bin\\buildokvs.js build\\search.txt ' + WScript.Arguments(1), 0, 1)
|
||||
a.createtextfile(WScript.Arguments(1)).write(";\r\n; Game count\r\n;\r\n; This file is automatically generated\r\n;\r\n" + "!word " + " ".substr(0, 8 - entries.length.toString().length) + entries.length + "\r\n")
|
||||
|
||||
source = a.createtextfile("build\\search.a")
|
||||
source.writeline("*=$6000")
|
||||
source.writeline("!le16 " + entries.length)
|
||||
source.writeline("!word KeyLookup")
|
||||
|
||||
hgrlog = a.opentextfile("build\\HGR.TITLES.LOG").readall().replace(/\r\n/, "\n")
|
||||
dhgrlog = a.opentextfile("build\\DHGR.TITLES.LOG").readall().replace(/\r\n/, "\n")
|
||||
|
||||
for (i = 0; i < entries.length; i++)
|
||||
{
|
||||
bits = entries[i].indexOf(",")
|
||||
dhgr = entries[i].substr(2, 1)
|
||||
|
||||
if (WScript.Arguments(1).substr(WScript.Arguments(1).length - 3, 1) == "0")
|
||||
{
|
||||
dhgr = "0"
|
||||
}
|
||||
|
||||
cheat = entries[i].substr(3, 1)
|
||||
sng = entries[i].substr(4, 1)
|
||||
eq = entries[i].indexOf("=")
|
||||
key = ((eq >= 0) ? entries[i].substr(bits + 1, eq - bits - 1) : entries[i])
|
||||
value = ((eq >= 0) ? entries[i].substr(eq + 1) : "")
|
||||
source.writeline("!byte " + (key.length + value.length + 10).toString())
|
||||
source.writeline("Key" + (i + 1).toString())
|
||||
source.writeline("!byte " + key.length)
|
||||
source.writeline("!text \"" + key + "\"")
|
||||
source.writeline("!byte " + value.length)
|
||||
source.writeline("!text \"" + value + "\"")
|
||||
source.writeline("!byte 1")
|
||||
source.writeline("!byte " + ((dhgr * 128) + (sng * 64) + Number(cheat)))
|
||||
|
||||
if (dhgr != 0)
|
||||
{
|
||||
dname = dhgrlog.indexOf("\n" + key + ",") + key.length + 2
|
||||
dpos = dhgrlog.substr(dname).indexOf(",")
|
||||
dsize = dhgrlog.substr(dname + dpos + 1).indexOf("\n")
|
||||
dsize = dhgrlog.substr(dname + dpos + 1, dsize)
|
||||
dpos = dhgrlog.substr(dname, dpos)
|
||||
}
|
||||
else
|
||||
{
|
||||
dname = hgrlog.indexOf("\n" + key + ",") + key.length + 2
|
||||
dpos = hgrlog.substr(dname).indexOf(",")
|
||||
dsize = hgrlog.substr(dname + dpos + 1).indexOf("\n")
|
||||
dsize = hgrlog.substr(dname + dpos + 1, dsize)
|
||||
dpos = hgrlog.substr(dname, dpos)
|
||||
}
|
||||
|
||||
source.writeline("!be24 " + dpos)
|
||||
source.writeline("!le16 " + dsize)
|
||||
}
|
||||
|
||||
source.writeline("KeyLookup")
|
||||
|
||||
for (i = 0; i < entries.length; i++)
|
||||
{
|
||||
source.writeline("!word Key" + (i + 1))
|
||||
}
|
||||
|
||||
source.close()
|
||||
new ActiveXObject("wscript.shell").run('cmd /c %acme% -o ' + WScript.Arguments(2) + ' build\\search.a', 0, 1)
|
||||
|
|
77
bin/buildsearch.sh
Executable file
77
bin/buildsearch.sh
Executable file
|
@ -0,0 +1,77 @@
|
|||
#!/bin/bash
|
||||
|
||||
# parameters
|
||||
# stdin - input containing list of game metadata, filename, display name (e.g. GAMES.CONF or some subset of it)
|
||||
# stdout - binary OKVS data structure
|
||||
# 1 - output filename for game count in assembler code format
|
||||
# 2 - input filename of HGR titles, offsets, and sizes
|
||||
# 3 - input filename of DHGR titles, offsets, and sizes
|
||||
|
||||
# make temp file with just the key/value pairs (strip blank lines, comments, eof marker)
|
||||
records=$(mktemp)
|
||||
tr -d "\r" | awk '!/^$|^#|^\[/' > "$records"
|
||||
|
||||
# read logs of offsets & sizes for HGR and DHGR titles
|
||||
# that were generated by an earlier script
|
||||
hgrlog=$(< "$2")
|
||||
dhgrlog=$(< "$3")
|
||||
|
||||
# generate source file with game count
|
||||
(echo ";"
|
||||
echo "; Game count"
|
||||
echo ";"
|
||||
echo "; This file is automatically generated"
|
||||
echo ";"
|
||||
echo "!word $(wc -l < "$records")") > "$1"
|
||||
|
||||
# make temp assembly source file that represents the binary OKVS data structure
|
||||
source=$(mktemp)
|
||||
(echo '*=$6000'
|
||||
echo "!le16 $(wc -l <"$records")" # OKVS header
|
||||
echo "!word KeyLookup"
|
||||
count=0
|
||||
while IFS="=" read -r key value; do
|
||||
count=$((count+1))
|
||||
if [ -z "$dhgrlog" ]; then
|
||||
dhgr="0"
|
||||
else
|
||||
dhgr=$(echo "$key" | cut -c3) # 'has DHGR title screen' flag (0 or 1)
|
||||
fi
|
||||
cheat=$(echo "$key" | cut -c4) # 'cheat category' (0..7)
|
||||
single=$(echo "$key" | cut -c5) # 'single-load' flag (0 or 1)
|
||||
key=$(echo "$key" | cut -d"," -f2)
|
||||
if [ "$dhgr" -eq "0" ]; then
|
||||
offset=$hgrlog
|
||||
size=$hgrlog
|
||||
else
|
||||
offset=$dhgrlog
|
||||
size=$dhgrlog
|
||||
fi
|
||||
offset=$(echo "$offset" | awk -F, '/^'"$key"',/ { print $2 }')
|
||||
size=$(echo "$size" | awk -F, '/^'"$key"',/ { print $3 }')
|
||||
echo "!byte ${#key}+${#value}+10" # OKVS record length
|
||||
echo "Key${count}"
|
||||
echo "!byte ${#key}" # OKVS key length
|
||||
echo "!text \"$key\"" # OKVS key (filename)
|
||||
echo "!byte ${#value}" # OKVS value length
|
||||
echo "!text \"$value\"" # OKVS value (display name)
|
||||
echo "!byte 1"
|
||||
echo "!byte $((dhgr*128))+$((single*64))+$cheat"
|
||||
echo "!be24 $offset"
|
||||
echo "!le16 $size"
|
||||
done < "$records"
|
||||
echo "KeyLookup"
|
||||
for i in $(seq $count); do
|
||||
echo "!word Key$i"
|
||||
done
|
||||
) > "$source"
|
||||
|
||||
# assemble temp source file into binary OKVS data structure, then output that
|
||||
out=$(mktemp)
|
||||
acme -o "$out" "$source"
|
||||
cat "$out"
|
||||
|
||||
# clean up
|
||||
rm "$out"
|
||||
rm "$source"
|
||||
rm "$records"
|
52
bin/buildsingle.js
Normal file
52
bin/buildsingle.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
a = new ActiveXObject("scripting.filesystemobject")
|
||||
x = new ActiveXObject("wscript.shell")
|
||||
b = x.exec('findstr /b \"....1\" build\\DISPLAY.CONF')
|
||||
|
||||
entries = []
|
||||
|
||||
while (!b.stdout.atendofstream)
|
||||
{
|
||||
c = b.stdout.readline()
|
||||
c = c.substr(c.indexOf(",") + 1)
|
||||
c = c.substr(0, c.indexOf("="))
|
||||
entries.push(c)
|
||||
}
|
||||
|
||||
for (i = 0; i < entries.length; i++)
|
||||
{
|
||||
x.run('cmd /c move /y build\\X\\' + entries[i] + ' ' + WScript.Arguments(0), 0, 1)
|
||||
}
|
||||
|
||||
groups = "*=0\n" + "!le16 " + entries.length + ", 0\n"
|
||||
sng_off = a.getfile(WScript.Arguments(2)).size
|
||||
b = a.createtextfile("build\\sng.lst")
|
||||
|
||||
for (i = 0; i < entries.length; i++)
|
||||
{
|
||||
c = sng_off
|
||||
item = (new Enumerator(a.GetFolder(WScript.Arguments(0) + "\\" + entries[i]).files)).item()
|
||||
name = a.GetFileName(item)
|
||||
key = name.substr(0,name.indexOf("#"))
|
||||
addr = name.substr(name.indexOf("#") + 3)
|
||||
b.writeline(key + "\\" + name)
|
||||
size = item.size
|
||||
sng_off += size
|
||||
|
||||
if (WScript.Arguments.length == 4)
|
||||
{
|
||||
// if offset+size does not cross a block boundary, use the size
|
||||
// otherwise adjust size until it ends at the next block boundary to avoid a partial copy on the last block
|
||||
size = ((Math.floor(c / 512) == Math.floor((c + size) / 512)) ? size : (((c + size + 511) & -512) - c))
|
||||
}
|
||||
|
||||
groups += "!byte " + (1 + 1 + key.length + 3 + 2 + 2) + "\n" + "!byte " + key.length + "\n" + "!text \"" + key + "\"\n" + "!be24 " + c + "\n" + "!le16 " + size + "\n" + "!le16 $" + addr + "\n"
|
||||
}
|
||||
|
||||
b.close()
|
||||
|
||||
f = a.createtextfile("build\\sng.tmp")
|
||||
f.write(groups)
|
||||
f.close()
|
||||
x = new ActiveXObject("wscript.shell")
|
||||
x.run('cmd /c %acme% -o ' + WScript.Arguments(1) + ' build\\sng.tmp', 0, 1)
|
||||
x.run('cmd /c bin\\buildsngall.bat ' + WScript.Arguments(0) + ' ' + WScript.Arguments(2), 0, 1)
|
57
bin/buildslideshow.js
Normal file
57
bin/buildslideshow.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
a = new ActiveXObject("scripting.filesystemobject")
|
||||
|
||||
if (!a.fileexists(WScript.Arguments(1)) || a.getfile(WScript.Arguments(1)).datelastmodified < a.getFile(WScript.Arguments(0)).datelastmodified)
|
||||
{
|
||||
b = a.opentextfile(WScript.Arguments(0))
|
||||
|
||||
entries = []
|
||||
|
||||
while (!b.atendofstream)
|
||||
{
|
||||
c = b.readline()
|
||||
d = c.indexOf("#")
|
||||
|
||||
if (d >= 0)
|
||||
{
|
||||
c = c.substr(0, d)
|
||||
}
|
||||
|
||||
if (c.indexOf("[eof]") >= 0)
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (c.length > 0)
|
||||
{
|
||||
entries.push(c)
|
||||
}
|
||||
}
|
||||
|
||||
source = a.createtextfile("build\\okvs.tmp")
|
||||
source.writeline("*=0")
|
||||
source.writeline("!le16 " + entries.length + ", 0")
|
||||
q = a.opentextfile("build\\DISPLAY.CONF").readall().replace(/\r\n/g, "\n")
|
||||
|
||||
for (i = 0; i < entries.length; i++)
|
||||
{
|
||||
val = entries[i].indexOf("=")
|
||||
name = ((val >= 0) ? entries[i].substr(val + 1) : entries[i])
|
||||
bits = q.indexOf("," + name + "=") + 1
|
||||
name = q.substr(bits + name.length + 1)
|
||||
name = name.substr(0, name.indexOf("\n"))
|
||||
needsjoystick = q.substr(bits - 5, 1)
|
||||
needs128k = q.substr(bits - 4, 1)
|
||||
displayname = ((WScript.Arguments.length == 3) ? name : "")
|
||||
source.writeline("!byte " + (entries[i].length - ((val >= 0) ? 1 : 0) + displayname.length + 5))
|
||||
source.writeline("!byte " + ((val >= 0) ? val : entries[i].length))
|
||||
source.writeline("!text \"" + ((val >= 0) ? entries[i].substr(0, val) : entries[i]) + "\"")
|
||||
source.writeline("!byte " + ((val >= 0) ? (entries[i].length - (val + 1)) : 0))
|
||||
source.writeline("!text \"" + ((val >= 0) ? (entries[i].substr(val + 1)) : "") + "\"")
|
||||
source.writeline("!byte " + displayname.length)
|
||||
source.writeline("!text \"" + displayname + "\"")
|
||||
source.writeline("!byte " + ((needsjoystick * 128) + (Number(needs128k) * 64)))
|
||||
}
|
||||
|
||||
source.close()
|
||||
new ActiveXObject("wscript.shell").run('cmd /c %acme% -o ' + WScript.Arguments(1) + ' build\\okvs.tmp', 0, 1)
|
||||
}
|
58
bin/buildslideshow.sh
Executable file
58
bin/buildslideshow.sh
Executable file
|
@ -0,0 +1,58 @@
|
|||
#!/bin/bash
|
||||
|
||||
# flags
|
||||
# -d include game display name (default off = display name will be 0-length string)
|
||||
|
||||
# parameters
|
||||
# stdin - input containing slideshow (e.g. some file in res/SS/)
|
||||
# stdout - binary OKVS data structure
|
||||
# 1 - list of games with metadata (e.g. build/GAMES.CONF)
|
||||
|
||||
include_displayname=false
|
||||
while getopts ":d" opt; do
|
||||
case $opt in
|
||||
d) include_displayname=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
games=$(cat "$1")
|
||||
|
||||
# make temp file with just the key/value pairs (strip blank lines, comments, eof marker)
|
||||
records=$(mktemp)
|
||||
tr -d "\r" | awk '!/^$|^#|^\[/' > "$records"
|
||||
|
||||
# make temp assembly source file that represents the binary OKVS data structure
|
||||
source=$(mktemp)
|
||||
(echo "*=0" # dummy program counter for assembler
|
||||
echo "!le16 $(wc -l <"$records"), 0" # OKVS header
|
||||
while IFS="=" read -r key value; do
|
||||
[ -n "$value" ] && filename="$value" || filename="$key"
|
||||
line=$(echo "$games" | awk '/,'"$filename"'=/')
|
||||
needsjoystick=$(echo "$line" | cut -c1) # 'requires joystick' flag (0 or 1)
|
||||
needs128k=$(echo "$line" | cut -c2) # 'requires 128K' flag (0 or 1)
|
||||
if [ "$include_displayname" = false ]; then
|
||||
displayname=""
|
||||
else
|
||||
displayname=$(echo "$line" | tr -d "\r" | awk -F= '{ print $2 }')
|
||||
fi
|
||||
echo "!byte ${#key}+${#value}+${#displayname}+5" # OKVS record length
|
||||
echo "!byte ${#key}" # OKVS key length
|
||||
echo "!text \"$key\"" # OKVS key
|
||||
echo "!byte ${#value}" # OKVS value length
|
||||
echo "!text \"$value\"" # OKVS value
|
||||
echo "!byte ${#displayname}"
|
||||
echo "!text \"$displayname\""
|
||||
echo "!byte $((needsjoystick*128))+$((needs128k*64))"
|
||||
done < "$records") > "$source"
|
||||
|
||||
# assemble temp source file into binary OKVS data structure, then output that
|
||||
out=$(mktemp)
|
||||
acme -o "$out" "$source"
|
||||
cat "$out"
|
||||
|
||||
# clean up
|
||||
rm "$out"
|
||||
rm "$source"
|
||||
rm "$records"
|
2
bin/buildsngall.bat
Normal file
2
bin/buildsngall.bat
Normal file
|
@ -0,0 +1,2 @@
|
|||
@echo off
|
||||
for /f "tokens=*" %%a in (build\sng.lst) do 1>nul copy /b /y %2+%1\%%a %2
|
|
@ -28,23 +28,41 @@ entries.sort()
|
|||
f = a.createtextfile("build\\GAMES.SORTED")
|
||||
f.write(entries.toString().replace(/,/g, "\n"))
|
||||
f.close()
|
||||
ss_off = a.fileexists(WScript.Arguments(2)) ? a.getFile(WScript.Arguments(2)).size : 0
|
||||
ss_off = a.fileexists(WScript.Arguments(3)) ? a.getFile(WScript.Arguments(3)).size : 0
|
||||
groups = "*=0\n" + "!le16 " + entries.length + ", 0\n"
|
||||
|
||||
q = 0
|
||||
|
||||
if (WScript.Arguments(2) != "nul")
|
||||
{
|
||||
q = a.createtextfile(WScript.Arguments(2))
|
||||
q.writeline()
|
||||
}
|
||||
|
||||
for (i = 0; i < entries.length; i++)
|
||||
{
|
||||
size = a.getfile(p + "\\" + entries[i]).size
|
||||
c = ss_off
|
||||
ss_off += size
|
||||
|
||||
if (WScript.Arguments.length == 5)
|
||||
if (WScript.Arguments.length == 6)
|
||||
{
|
||||
// if offset+size does not cross a block boundary, use the size
|
||||
// otherwise adjust size until it ends at the next block boundary to avoid a partial copy on the last block
|
||||
size = ((Math.floor(c / 512) == Math.floor((c + size) / 512)) ? size : (((c + size + 511) & -512) - c))
|
||||
}
|
||||
|
||||
groups += "!byte " + (1 + 1 + entries[i].length + 5) + "\n" + "!byte " + entries[i].length + "\n" + "!text \"" + entries[i] + "\"\n" + "!be24 " + c + "\n" + "!le16 " + size + "\n"
|
||||
groups += "!byte " + (entries[i].length + 7) + "\n" + "!byte " + entries[i].length + "\n" + "!text \"" + entries[i] + "\"\n" + "!be24 " + c + "\n" + "!le16 " + size + "\n"
|
||||
|
||||
if (typeof(q) == "object")
|
||||
{
|
||||
q.writeline(entries[i] + "," + c + "," + size)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof(q) == "object")
|
||||
{
|
||||
q.close()
|
||||
}
|
||||
|
||||
f = a.createtextfile("build\\ss.tmp")
|
||||
|
@ -52,4 +70,4 @@ f.write(groups)
|
|||
f.close()
|
||||
x = new ActiveXObject("wscript.shell")
|
||||
x.run('cmd /c %acme% -o ' + WScript.Arguments(1) + ' build\\ss.tmp', 0, 1)
|
||||
x.run('cmd /c bin\\buildpreall.bat ' + p + ' ' + WScript.Arguments(2) + ' ' + WScript.Arguments(3), 0, 1)
|
||||
x.run('cmd /c bin\\buildpreall.bat ' + p + ' ' + WScript.Arguments(3) + ' ' + WScript.Arguments(4), 0, 1)
|
||||
|
|
|
@ -7,23 +7,11 @@ fatal_error() {
|
|||
exit 1
|
||||
}
|
||||
|
||||
check_title_slideshow() {
|
||||
check_slideshow() {
|
||||
[ -f "$1" ] ||
|
||||
fatal_error "Can't find HGR title slideshow" "$1"
|
||||
cat "$1" |
|
||||
grep -v "^#" |
|
||||
grep -v "^\[" |
|
||||
grep -v "^$" |
|
||||
while read ssline; do
|
||||
[ -f "$2"/"$ssline" ] ||
|
||||
fatal_error "Can't find title screenshot" "$ssline"
|
||||
done
|
||||
}
|
||||
|
||||
check_action_slideshow() {
|
||||
[ -f "$1" ] ||
|
||||
fatal_error "Can't find HGR action slideshow" "$1"
|
||||
fatal_error "Can't find slideshow" "$1"
|
||||
cat "$1" |
|
||||
tr -d "\r" |
|
||||
grep -v "^#" |
|
||||
grep -v "^\[" |
|
||||
grep -v "^$" |
|
||||
|
@ -33,23 +21,25 @@ check_action_slideshow() {
|
|||
gamename=$filename
|
||||
fi
|
||||
[ -f "$2"/"$filename" ] ||
|
||||
fatal_error "Can't find action screenshot" "$filename"
|
||||
fatal_error "Can't find screenshot" "$filename"
|
||||
grep "^$gamename$" /tmp/games >/dev/null ||
|
||||
fatal_error "Action screenshot links to non-existent game" "$gamename"
|
||||
fatal_error "Screenshot links to non-existent game" "$gamename"
|
||||
done
|
||||
}
|
||||
|
||||
# fatal error if an attract mode module is listed more than once
|
||||
dupes=$(cat res/ATTRACT.CONF |
|
||||
grep -v "^#" |
|
||||
grep -v "^$" |
|
||||
sort |
|
||||
uniq -d)
|
||||
tr -d "\r" |
|
||||
grep -v "^#" |
|
||||
grep -v "^$" |
|
||||
sort |
|
||||
uniq -d)
|
||||
if [[ $dupes ]]; then
|
||||
fatal_error "Duplicate ATTRACT.CONF module:" "$dupes"
|
||||
fi
|
||||
|
||||
cat res/GAMES.CONF |
|
||||
tr -d "\r" |
|
||||
grep -v "^#" |
|
||||
grep -v "^\[" |
|
||||
grep -v "^$" |
|
||||
|
@ -57,10 +47,8 @@ cat res/GAMES.CONF |
|
|||
cut -d"=" -f1 > /tmp/games
|
||||
|
||||
# warn about unused self-running demos
|
||||
cat res/DEMO/_FileInformation.txt |
|
||||
grep "Type(06)" |
|
||||
grep '^\!to' src/demo/*.a | cut -d'/' -f5-|cut -d'#' -f1 |
|
||||
grep -v "SPCARTOON" |
|
||||
cut -d"=" -f1 |
|
||||
while read f; do
|
||||
grep "$f=0" res/ATTRACT.CONF >/dev/null || echo "unused demo: $f";
|
||||
done
|
||||
|
@ -73,27 +61,30 @@ done
|
|||
cd ../..
|
||||
|
||||
cat res/ATTRACT.CONF |
|
||||
tr -d "\r" |
|
||||
grep "=" |
|
||||
grep -v "^#" |
|
||||
while read line; do
|
||||
IFS="=" read -r module_name module_type <<< "$line"
|
||||
# echo "$module_name" "$module_type"
|
||||
if [ "$module_type" = "0" ]; then
|
||||
[ -f res/DEMO/"$module_name" ] ||
|
||||
[ "${module_name%???}" = "SPCARTOON" ] ||
|
||||
fatal_error "Can't find demo" $module_name
|
||||
[ "${module_name%???}" = "SPCARTOON" ] && continue
|
||||
demo=$(grep 'to.*'"$module_name" src/demo/*.a)
|
||||
[ -n "$demo" ] || fatal_error "Can't find demo" $module_name
|
||||
elif [ "$module_type" = "1" ]; then
|
||||
check_title_slideshow res/SS/"$module_name" res/TITLE.HGR/
|
||||
check_slideshow res/SS/"$module_name" res/TITLE.HGR/
|
||||
elif [ "$module_type" = "2" ]; then
|
||||
check_action_slideshow res/SS/"$module_name" res/ACTION.HGR/
|
||||
check_slideshow res/SS/"$module_name" res/ACTION.HGR/
|
||||
elif [ "$module_type" = "3" ]; then
|
||||
check_title_slideshow res/SS/"$module_name" res/TITLE.DHGR/
|
||||
check_slideshow res/SS/"$module_name" res/TITLE.DHGR/
|
||||
elif [ "$module_type" = "4" ]; then
|
||||
check_action_slideshow res/SS/"$module_name" res/ACTION.DHGR/
|
||||
check_slideshow res/SS/"$module_name" res/ACTION.DHGR/
|
||||
elif [ "$module_type" = "5" ]; then
|
||||
check_title_slideshow res/SS/"$module_name" res/ARTWORK.SHR/
|
||||
check_slideshow res/SS/"$module_name" res/ARTWORK.SHR/
|
||||
elif [ "$module_type" = "6" ]; then
|
||||
check_action_slideshow res/SS/"$module_name" res/ACTION.GR/
|
||||
check_slideshow res/SS/"$module_name" res/ACTION.GR/
|
||||
elif [ "$module_type" = "7" ]; then
|
||||
check_slideshow res/SS/"$module_name" res/ACTION.DGR/
|
||||
else
|
||||
fatal_error "Unknown module type" $module_type
|
||||
fi
|
||||
|
|
2
bin/checkdate.js
Normal file
2
bin/checkdate.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
a = new ActiveXObject("scripting.filesystemobject")
|
||||
WScript.quit(Math.abs(!a.fileexists(WScript.Arguments(0)) || a.getfile(WScript.Arguments(0)).datelastmodified < a.getFile(WScript.Arguments(1)).datelastmodified))
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
tr "\*\~\<\>\$\%" "\020\021\010\025\016\017" < "$1" | \
|
||||
awk '!/^\[/ { printf "%c%s", length, $0 } END { printf "\xFF" }' > "$2"
|
||||
tr -d "\r" | awk '!/^\[/ { printf "%c%s", length, $0 } END { printf "\xFF" }' > "$2"
|
||||
|
|
35
bin/forevershr.sh
Executable file
35
bin/forevershr.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
# directory of PNG files (assume they are properly sized and named)
|
||||
PNGS="$HOME/Dropbox/a2/4cade/artwork/cropped-and-named-320x200"
|
||||
|
||||
# Python 3
|
||||
export PYTHON="python"
|
||||
|
||||
# https://github.com/KrisKennaway/ii-pix/
|
||||
export CONVERT_PY="$HOME/Documents/a2/ii-pix/convert.py"
|
||||
|
||||
# directories within Total Replay repository
|
||||
export SHR_SCORES="./res/ARTWORK.SHR.SCORES"
|
||||
export SHR_UNCOMPRESSED="./res/ARTWORK.SHR.UNCOMPRESSED"
|
||||
|
||||
# convert.py flags:
|
||||
# --no-show-output to suppress focus-stealing popup window during conversion
|
||||
# --no-save-preview to suppress saving -preview.png file
|
||||
# --fixed-colours=1 to prevent visual glitches during transition from black
|
||||
# --show-final-score to get score so the score matching can work
|
||||
|
||||
while true; do
|
||||
parallel '
|
||||
tmp=$(mktemp)
|
||||
newscore=$("$PYTHON" "$CONVERT_PY" shr --no-show-output --no-save-preview --fixed-colours=1 --show-final-score {} "$tmp" | grep FINAL_SCORE | cut -d":" -f2)
|
||||
oldscore=$(<"$SHR_SCORES"/{/.})
|
||||
if [ -z "$oldscore" ]; then
|
||||
oldscore=10000
|
||||
fi
|
||||
if (( $(echo "$newscore < $oldscore" | bc) )); then
|
||||
cp "$tmp" "$SHR_UNCOMPRESSED/"{/.}
|
||||
echo "$newscore" > "$SHR_SCORES/"{/.}
|
||||
fi
|
||||
rm "$tmp"' ::: "$PNGS"/*.png
|
||||
done
|
|
@ -3,6 +3,7 @@
|
|||
# run from project root directory
|
||||
|
||||
cat res/GAMES.CONF |
|
||||
tr -d "\r" |
|
||||
grep "," |
|
||||
grep -v "^#" |
|
||||
cut -d"," -f2 |
|
||||
|
@ -12,11 +13,17 @@ cat res/GAMES.CONF |
|
|||
echo -e "#\n# Attract mode for $game\n# This file is automatically generated\n#\n" > /tmp/g
|
||||
|
||||
# add box art, if any
|
||||
[ -f res/ARTWORK.SHR/"$game" ] &&
|
||||
echo "$game=C" >> /tmp/g
|
||||
cat res/SS/SHR*.CONF |
|
||||
tr -d "\r" |
|
||||
egrep "(^|=)""$game""$" |
|
||||
cut -d"=" -f1 |
|
||||
sed -e "s/$/=C/g" |
|
||||
sort |
|
||||
uniq >> /tmp/g
|
||||
|
||||
# add DHGR action screenshots, if any
|
||||
cat res/SS/ACTDHGR*.CONF |
|
||||
tr -d "\r" |
|
||||
egrep "(^|=)""$game""$" |
|
||||
cut -d"=" -f1 |
|
||||
sed -e "s/$/=B/g" |
|
||||
|
@ -25,6 +32,7 @@ cat res/GAMES.CONF |
|
|||
|
||||
# add HGR action screenshots, if any
|
||||
cat res/SS/ACTION*.CONF |
|
||||
tr -d "\r" |
|
||||
egrep "(^|=)""$game""$" |
|
||||
cut -d"=" -f1 |
|
||||
sed -e "s/$/=A/g" |
|
||||
|
@ -33,24 +41,34 @@ cat res/GAMES.CONF |
|
|||
|
||||
# add GR action screenshots, if any
|
||||
cat res/SS/ACTGR*.CONF |
|
||||
tr -d "\r" |
|
||||
egrep "(^|=)""$game""$" |
|
||||
cut -d"=" -f1 |
|
||||
sed -e "s/^/ACTION.GR\//g" |
|
||||
sed -e "s/$/=D/g" |
|
||||
sort |
|
||||
uniq >> /tmp/g
|
||||
|
||||
# add DGR action screenshots, if any
|
||||
cat res/SS/ACTDGR*.CONF |
|
||||
tr -d "\r" |
|
||||
egrep "(^|=)""$game""$" |
|
||||
cut -d"=" -f1 |
|
||||
sed -e "s/$/=E/g" |
|
||||
sort |
|
||||
uniq >> /tmp/g
|
||||
|
||||
# add self-running demo, if any
|
||||
cat res/ATTRACT.CONF |
|
||||
tr -d "\r" |
|
||||
grep "^$game=0" >> /tmp/g
|
||||
|
||||
if [ "$game" == "SPARE.CHANGE" ]; then
|
||||
echo "SPCARTOON.1=0" >> /tmp/g
|
||||
echo "SPCARTOON.2=0" >> /tmp/g
|
||||
echo "SPCARTOON.3=0" >> /tmp/g
|
||||
echo "SPCARTOON.4=0" >> /tmp/g
|
||||
echo "SPCARTOON.5=0" >> /tmp/g
|
||||
echo "SPCARTOON.6=0" >> /tmp/g
|
||||
echo "SPCARTOON.1.=0" >> /tmp/g
|
||||
echo "SPCARTOON.2.=0" >> /tmp/g
|
||||
echo "SPCARTOON.3.=0" >> /tmp/g
|
||||
echo "SPCARTOON.4.=0" >> /tmp/g
|
||||
echo "SPCARTOON.5.=0" >> /tmp/g
|
||||
echo "SPCARTOON.6.=0" >> /tmp/g
|
||||
fi
|
||||
|
||||
if [ "$game" == "PRINCEUNP" ]; then
|
||||
|
|
28
bin/packhgrfile.py
Executable file
28
bin/packhgrfile.py
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
|
||||
infile = sys.argv[1]
|
||||
outfile = sys.argv[2]
|
||||
|
||||
i = open(infile,"rb")
|
||||
filedata = i.read()
|
||||
i.close
|
||||
|
||||
# If the file has a JMP in the last screen hole, the
|
||||
# game has an animated title, skip packing and copy
|
||||
# the file as is instead.
|
||||
if(len(filedata) >= 8192 and filedata[8189] == 0x4c):
|
||||
print (infile, "has animation, not packing")
|
||||
outdata = bytearray(filedata[0:8192])
|
||||
else:
|
||||
outdata = bytearray(filedata[0:7680])
|
||||
|
||||
for h in range(60):
|
||||
oh = h*128+120
|
||||
ih = h*8+7680+(int(h/15)*8)
|
||||
outdata[oh:oh+8] = filedata[ih:ih+8]
|
||||
|
||||
o = open(outfile,"wb")
|
||||
o.write(outdata)
|
||||
o.close
|
||||
|
17
bin/padto.js
17
bin/padto.js
|
@ -1,5 +1,14 @@
|
|||
a = new ActiveXObject("scripting.filesystemobject")
|
||||
b = a.opentextfile(WScript.Arguments(1))
|
||||
c = b.readall().replace(/\r\n/g, "\n")
|
||||
b.close()
|
||||
a.createtextfile(WScript.Arguments(1)).write(String(c + Array(512).join(String.fromCharCode(0))).substr(0, 512))
|
||||
|
||||
if (WScript.Arguments(1) == "build\\PREFS.CONF")
|
||||
{
|
||||
b = a.opentextfile(WScript.Arguments(1))
|
||||
c = b.readall().replace(/\r\n/g, "\n")
|
||||
b.close()
|
||||
b = a.createtextfile(WScript.Arguments(1))
|
||||
b.write(c)
|
||||
b.close()
|
||||
}
|
||||
|
||||
c = a.getfile(WScript.Arguments(1)).size
|
||||
b = a.opentextfile(WScript.Arguments(1), 8).write(Array((Math.floor((c + 511) / 512) * 512) - c + 1).join(String.fromCharCode(0)))
|
||||
|
|
10
bin/padto.sh
10
bin/padto.sh
|
@ -1,11 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
totalsize=$1
|
||||
outfile=$2
|
||||
# zero-pads $1 to a multiple of 512 bytes, in place
|
||||
|
||||
[[ "$OSTYPE" == "linux-gnu" ]] \
|
||||
&& filesize=$(stat -c "%s" "$outfile") \
|
||||
|| filesize=$(stat -f "%z" "$outfile")
|
||||
|
||||
padsize=$((512-$filesize))
|
||||
dd if=/dev/zero bs=1 count=$padsize 2>/dev/null >> "$outfile"
|
||||
dd if=/dev/null of="$1" bs=1 count=1 seek="$((($(wc -c < "$1") + 511) & -512))" 2>/dev/null
|
||||
|
|
34
bin/toshr.sh
Executable file
34
bin/toshr.sh
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Add or unconditionally replace SHR file with newly converted PNG file
|
||||
# Also saves final error score from conversion
|
||||
# Also removes old compressed asset of the same name, if any
|
||||
|
||||
# parameters
|
||||
# 1 - input file (PNG, must be properly sized and named)
|
||||
|
||||
# Python 3
|
||||
PYTHON="python"
|
||||
|
||||
# https://github.com/KrisKennaway/ii-pix/
|
||||
CONVERT_PY="$HOME/Documents/a2/ii-pix/convert.py"
|
||||
|
||||
# directories within Total Replay repository
|
||||
SHR_SCORES="./res/ARTWORK.SHR.SCORES"
|
||||
SHR_COMPRESSED="./res/ARTWORK.SHR"
|
||||
SHR_UNCOMPRESSED="./res/ARTWORK.SHR.UNCOMPRESSED"
|
||||
|
||||
inputname=$(basename "$1") # e.g. "ZAXXON.png"
|
||||
shr_name="${inputname%.*}" # e.g. "ZAXXON"
|
||||
|
||||
"$PYTHON" "$CONVERT_PY" shr \
|
||||
--no-show-output \
|
||||
--no-save-preview \
|
||||
--fixed-colours=1 \
|
||||
--show-final-score \
|
||||
"$1" \
|
||||
"$SHR_UNCOMPRESSED/$shr_name" | \
|
||||
grep FINAL_SCORE | \
|
||||
cut -d":" -f2 \
|
||||
> "$SHR_SCORES/$shr_name"
|
||||
rm -f "$SHR_COMPRESSED/$shr_name"
|
BIN
res/ACTION.DGR/BEJEWELED
Normal file
BIN
res/ACTION.DGR/BEJEWELED
Normal file
Binary file not shown.
BIN
res/ACTION.DGR/FLAPPLE.BIRD
Normal file
BIN
res/ACTION.DGR/FLAPPLE.BIRD
Normal file
Binary file not shown.
BIN
res/ACTION.DGR/FLAPPLE.BIRD2
Normal file
BIN
res/ACTION.DGR/FLAPPLE.BIRD2
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/CATACOMBS
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/CATACOMBS
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/CATACOMBS2
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/CATACOMBS2
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ10
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ10
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ2
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ2
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ4
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ4
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ6
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ6
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ8
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.GOES.NUTZ8
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.RETURNS
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.RETURNS
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.RETURNS2
Normal file
BIN
res/ACTION.DHGR.UNCOMPRESSED/DD.RETURNS2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
res/ACTION.DHGR/CATACOMBS
Normal file
BIN
res/ACTION.DHGR/CATACOMBS
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/CATACOMBS2
Normal file
BIN
res/ACTION.DHGR/CATACOMBS2
Normal file
Binary file not shown.
Binary file not shown.
BIN
res/ACTION.DHGR/DD.GOES.NUTZ
Normal file
BIN
res/ACTION.DHGR/DD.GOES.NUTZ
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/DD.GOES.NUTZ10
Normal file
BIN
res/ACTION.DHGR/DD.GOES.NUTZ10
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/DD.GOES.NUTZ2
Normal file
BIN
res/ACTION.DHGR/DD.GOES.NUTZ2
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/DD.GOES.NUTZ4
Normal file
BIN
res/ACTION.DHGR/DD.GOES.NUTZ4
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/DD.GOES.NUTZ6
Normal file
BIN
res/ACTION.DHGR/DD.GOES.NUTZ6
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/DD.GOES.NUTZ8
Normal file
BIN
res/ACTION.DHGR/DD.GOES.NUTZ8
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/DD.RETURNS
Normal file
BIN
res/ACTION.DHGR/DD.RETURNS
Normal file
Binary file not shown.
BIN
res/ACTION.DHGR/DD.RETURNS2
Normal file
BIN
res/ACTION.DHGR/DD.RETURNS2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user