diff --git a/README.md b/README.md index a132f38..c3cd787 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Ys V: Lost Kefin - Kingdom of Sand (PS2) English Translation -Currently using Sam Farron's translation from his [Translation Series](https://www.youtube.com/watch?v=LfZZPwIdhzg&list=PLoD4gkRCJkUcgfpU5puBqYy5DX-RJK--b) with permission - -# Current Progress -Slowly reverse-engineering the script files so I can make tools. +Currently using Sam Farron's translation from his [Translation Series](https://www.youtube.com/watch?v=LfZZPwIdhzg&list=PLoD4gkRCJkUcgfpU5puBqYy5DX-RJK--b) with permission + **If you want to help with the translation please [contact me!](https://kaisaan.github.io/pages/contact) (Knowing Japanese is not needed)** +# Current Progress +I am replacing the usage of [armips](https://github.com/Kingcom/armips) with [acbde](https://www.romhacking.net/utilities/1392/) for script extraction and insertion. Currently I have raw dumps only as I need to figure out all the control codes to get a full pointer dump + # Building -- Copy the contents of the game's .iso into the `extracted` and `translated` folders +- Use [Apache3](https://www.psx-place.com/threads/apache.19171/) to extract the contents of the game's .iso file +- Copy the contents to the `extracted` and `translated` folders - Run `build.bat` or manually run the commands # Hacking Notes @@ -15,20 +17,33 @@ Slowly reverse-engineering the script files so I can make tools. - Extracted .bin files with `_anm` in the filename are animation files with indexed 8BPP graphics and have the header `NAXA5010` - Extracted .HGB files are texture files with 32BPP RGBA graphics - Music files are `.hd` (header), `.bd` (header), and `.sq` (sequence) files +- See my notes file for more terribly organized notes # Extracting the DATA.BIN Files `extract.py` extracts all the files from DATA.BIN and its folders into a `DATA` folder but does not extract the files into their correct folders yet, a `logfile.txt` is also created for fixing issues with the script # Font info The game uses Shift-JIS encoding but I decided to make table files so I can include control codes -`font.py` extracts the fontmap from `SLPM_663.60` to create a quick `font.tbl` table file. Use `kefin.tbl` for corrected values and control codes (also used by `patch.asm`) +`font.py` extracts the fontmap from `SLPM_663.60` to create a quick `font.tbl` table file. Use `kefin.tbl` for corrected values and control codes In `SLPM_663.60` the font is located at $1A3E90 as 4BPP graphics, its palette is stored at $25E4C0, and the fontmap is at $1A31F0 +# Script Info +- Script files (named `stageXX.bin`) have the first $2000 bytes as a pointer table +- Each pointer first as an "index" number (4 bytes, little-endian) then the pointer value to the file (4 bytes, little-endian) +- Pointer value are calculated as `pointer + $2000` +- Changing the pointer seems to cause the game to freeze +Before running `script.py` copy the script files (as extracted from `DATA.BIN`) to the `scripts` folder. `script.py` will extract the pointer information for each file into a separate text file. The python script will also include info for control codes. +Before running `dump.bat` make sure perl is installed. On Windows I recommend isnstalling [Strawberry perl](https://www.lifebottle.org/#/./other/strawberry-perl/index) +The script can be dumped from `DATA.BIN` and into `scripts` after running `dump.bat`. Currently it is a raw dump because I have not figured out all the control codes, using a pointer dump will cause the scripts to be under-dumped. + # To do -- Updated extraction script to extract `DATA0.BIN`, `DATA1.BIN`, and `SLPM_663.60` -- Add more hacking notes (my notes.txt file is a mess so I haven't added it here) +- Figure out all the control codes properly +- Update the extraction script to extract `DATA0.BIN`, `DATA1.BIN`, and `SLPM_663.60` - Continue inserting the English script +# Game Manual Translation +In the `manual` folder are scans for the game's manual. They were originally from [landofys.narod.ru](https://landofys.narod.ru/) which is now landofys.com.ru(http://landofys.com.ru/) was scanned by Dragon. + # Links to Stuff - Translation of opening cutscene by [mziab](https://www.romhacking.net/forum/index.php?topic=28379.0) (I did not use this translation) - Hacking attempt by [Hectavus](https://zenhax.com/viewtopic.php@t=15249.html) with only `SLPM_663.60` being translated diff --git a/datacommands.txt b/datacommands.txt new file mode 100644 index 0000000..7037323 --- /dev/null +++ b/datacommands.txt @@ -0,0 +1,133 @@ +#GAME NAME:Ys V Lost Kefin + +#BLOCK NAME:stage00.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94BC800 +#SCRIPT STOP: $94CBD9F +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage01.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94CE000 +#SCRIPT STOP: $94D4292 +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage02.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94D6800 +#SCRIPT STOP: $94DDD40 +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage03.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94E0000 +#SCRIPT STOP: $94E155E +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage04.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94E3800 +#SCRIPT STOP: $94EB29C +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage05.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94ED800 +#SCRIPT STOP: $94F2E37 +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage06.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94F5000 +#SCRIPT STOP: $94FC64B +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage07.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94FE800 +#SCRIPT STOP: $95018AA +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage08.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $9504000 +#SCRIPT STOP: $950E73C +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage09.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $9510800 +#SCRIPT STOP: $951609F +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stagea0.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $9518800 +#SCRIPT STOP: $95188FC +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stageb0.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $951B000 +#SCRIPT STOP: $951C0F4 +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK \ No newline at end of file diff --git a/dump.bat b/dump.bat new file mode 100644 index 0000000..3c3844b --- /dev/null +++ b/dump.bat @@ -0,0 +1,3 @@ +perl scripts\abcde\abcde.pl -cm abcde::Cartographer "extracted\DATA.BIN" datacommands.txt "scripts\dump" -m + +@pause \ No newline at end of file diff --git a/extract.py b/extract.py index 3103f90..63f3eee 100644 --- a/extract.py +++ b/extract.py @@ -38,7 +38,7 @@ while fileptr < fileptrend: filename = filename[:filename.find(terminator)] filesectorstart = filesectorstart * sector - filesectorsize = filesectorstart * sector + filesectorsize = filesectorsize * sector datafile.seek(filesectorstart) filedata = datafile.read(filesize) diff --git a/kefin.tbl b/kefin.tbl index ce32ae0..f0a79e4 100644 --- a/kefin.tbl +++ b/kefin.tbl @@ -1,7 +1,8 @@ -0A=\n +0A=[LINE]\n 20= 21=! 22=" +23=# 27=' 28=( 29=) @@ -9,7 +10,7 @@ 2B=+ 2D=- 2E=. -2F=/ +!2F=,2 30=0 31=1 32=2 @@ -22,7 +23,9 @@ 39=9 3A=: 3B=; +3C={ 3D== +3E=} 3F=? 41=A 42=B @@ -79,1547 +82,1598 @@ 78=x 79=y 7A=z -A2=¢ -A3=£ -A5=¥ -8140=@ -8141=A -8142=B -8143=C -8144=D -8145=E -8146=F -8148=H -8149=I -8158=X -815B=[ -815E=^ -8160=` -8163=c -8166=f -8167=g -8168=h -8169=i -816A=j -8175=u -8176=v -8177=w -8178=x -8179=y -817A=z -817B={ -817C=| -817E=~ -8180=€ -8181= -8183=ƒ -8184=„ -818F= -8190= -8193=“ -8194=” -8195=• -8196=– -8197=— -8199=™ -819A=š -819B=› -819C=œ -819D= -819E=ž -819F=Ÿ -81A0=  -81A1=¡ -81A2=¢ -81A3=£ -81A4=¤ -81A5=¥ -81A6=¦ -81A8=¨ -81A9=© -81AA=ª -81AB=« -824F=‚O -8250=‚P -8251=‚Q -8252=‚R -8253=‚S -8254=‚T -8255=‚U -8256=‚V -8257=‚W -8258=‚X -8260=‚` -8261=‚a -8262=‚b -8263=‚c -8264=‚d -8265=‚e -8266=‚f -8267=‚g -8268=‚h -8269=‚i -826A=‚j -826B=‚k -826C=‚l -826D=‚m -826E=‚n -826F=‚o -8270=‚p -8271=‚q -8272=‚r -8273=‚s -8274=‚t -8275=‚u -8276=‚v -8277=‚w -8278=‚x -8279=‚y -8281=‚ -8282=‚‚ -8283=‚ƒ -8284=‚„ -8285=‚… -8286=‚† -8287=‚‡ -8288=‚ˆ -8289=‚‰ -828A=‚Š -828B=‚‹ -828C=‚Œ -828D=‚ -828E=‚Ž -828F=‚ -8290=‚ -8291=‚‘ -8292=‚’ -8293=‚“ -8294=‚” -8295=‚• -8296=‚– -8297=‚— -8298=‚˜ -8299=‚™ -829A=‚š -829F=‚Ÿ -82A0=‚  -82A1=‚¡ -82A2=‚¢ -82A3=‚£ -82A4=‚¤ -82A5=‚¥ -82A6=‚¦ -82A7=‚§ -82A8=‚¨ -82A9=‚© -82AA=‚ª -82AB=‚« -82AC=‚¬ -82AD=‚­ -82AE=‚® -82AF=‚¯ -82B0=‚° -82B1=‚± -82B2=‚² -82B3=‚³ -82B4=‚´ -82B5=‚µ -82B6=‚¶ -82B7=‚· -82B8=‚¸ -82B9=‚¹ -82BA=‚º -82BB=‚» -82BC=‚¼ -82BD=‚½ -82BE=‚¾ -82BF=‚¿ -82C0=‚À -82C1=‚Á -82C2=‚ -82C3=‚à -82C4=‚Ä -82C5=‚Å -82C6=‚Æ -82C7=‚Ç -82C8=‚È -82C9=‚É -82CA=‚Ê -82CB=‚Ë -82CC=‚Ì -82CD=‚Í -82CE=‚Î -82CF=‚Ï -82D0=‚Ð -82D1=‚Ñ -82D2=‚Ò -82D3=‚Ó -82D4=‚Ô -82D5=‚Õ -82D6=‚Ö -82D7=‚× -82D8=‚Ø -82D9=‚Ù -82DA=‚Ú -82DB=‚Û -82DC=‚Ü -82DD=‚Ý -82DE=‚Þ -82DF=‚ß -82E0=‚à -82E1=‚á -82E2=‚â -82E3=‚ã -82E4=‚ä -82E5=‚å -82E6=‚æ -82E7=‚ç -82E8=‚è -82E9=‚é -82EA=‚ê -82EB=‚ë -82ED=‚í -82F0=‚ð -82F1=‚ñ -8340=ƒ@ -8341=ƒA -8342=ƒB -8343=ƒC -8344=ƒD -8345=ƒE -8346=ƒF -8347=ƒG -8348=ƒH -8349=ƒI -834A=ƒJ -834B=ƒK -834C=ƒL -834D=ƒM -834E=ƒN -834F=ƒO -8350=ƒP -8351=ƒQ -8352=ƒR -8353=ƒS -8354=ƒT -8355=ƒU -8356=ƒV -8357=ƒW -8358=ƒX -8359=ƒY -835A=ƒZ -835B=ƒ[ -835C=ƒ\ -835D=ƒ] -835E=ƒ^ -835F=ƒ_ -8360=ƒ` -8361=ƒa -8362=ƒb -8363=ƒc -8364=ƒd -8365=ƒe -8366=ƒf -8367=ƒg -8368=ƒh -8369=ƒi -836A=ƒj -836B=ƒk -836C=ƒl -836D=ƒm -836E=ƒn -836F=ƒo -8370=ƒp -8371=ƒq -8372=ƒr -8373=ƒs -8374=ƒt -8375=ƒu -8376=ƒv -8377=ƒw -8378=ƒx -8379=ƒy -837A=ƒz -837B=ƒ{ -837C=ƒ| -837D=ƒ} -837E=ƒ~ -8380=ƒ€ -8381=ƒ -8382=ƒ‚ -8383=ƒƒ -8384=ƒ„ -8385=ƒ… -8386=ƒ† -8387=ƒ‡ -8388=ƒˆ -8389=ƒ‰ -838A=ƒŠ -838B=ƒ‹ -838C=ƒŒ -838D=ƒ -838F=ƒ -8392=ƒ’ -8393=ƒ“ -8394=ƒ” -8395=ƒ• -8396=ƒ– -849F=„Ÿ -8754=‡T -8755=‡U -8756=‡V -8757=‡W -8758=‡X -8759=‡Y -875A=‡Z -875B=‡[ -875C=‡\ -875D=‡] -889F=ˆŸ -88A2=ˆ¢ -88A3=ˆ£ -88A4=ˆ¤ -88AB=ˆ« -88B5=ˆµ -88B6=ˆ¶ -88C0=ˆÀ -88C3=ˆÃ -88C4=ˆÄ -88C5=ˆÅ -88C8=ˆÈ -88CB=ˆË -88CC=ˆÌ -88CD=ˆÍ -88D0=ˆÐ -88D3=ˆÓ -88D5=ˆÕ -88D9=ˆÙ -88DA=ˆÚ -88DB=ˆÛ -88E1=ˆá -88E2=ˆâ -88E4=ˆä -88E6=ˆæ -88E7=ˆç -88EA=ˆê -88F3=ˆó -88F5=ˆõ -88F6=ˆö -88F8=ˆø -88F9=ˆù -8942=‰B -8945=‰E -8948=‰H -894A=‰J -8951=‰Q -8959=‰Y -895C=‰\ -895E=‰^ -8965=‰e -8968=‰h -8969=‰i -8970=‰p -8971=‰q -8973=‰s -8979=‰y -897A=‰z -897E=‰~ -8980=‰€ -8984=‰„ -8987=‰‡ -898A=‰Š -8993=‰“ -899B=‰› -899C=‰œ -899E=‰ž -899F=‰Ÿ -89A1=‰¡ -89A4=‰¤ -89A9=‰© -89AE=‰® -89AF=‰¯ -89B4=‰´ -89B6=‰¶ -89B8=‰¸ -89B9=‰¹ -89BA=‰º -89BB=‰» -89BC=‰¼ -89BD=‰½ -89BF=‰¿ -89C1=‰Á -89C2=‰Â -89C3=‰Ã -89C6=‰Æ -89CA=‰Ê -89CC=‰Ì -89CD=‰Í -89CE=‰Î -89D2=‰Ò -89D4=‰Ô -89D7=‰× -89D8=‰Ø -89DB=‰Û -89DF=‰ß -89E4=‰ä -89E6=‰æ -89EB=‰ë -89EC=‰ì -89EE=‰î -89EF=‰ï -89F0=‰ð -89F1=‰ñ -89F3=‰ó -89F6=‰ö -89F7=‰÷ -89F9=‰ù -89FC=‰ü -8A42=ŠB -8A43=ŠC -8A45=ŠE -8A46=ŠF -8A47=ŠG -8A4A=ŠJ -8A4B=ŠK -8A4F=ŠO -8A51=ŠQ -8A52=ŠR -8A58=ŠX -8A5A=ŠZ -8A5F=Š_ -8A65=Še -8A69=Ši -8A6A=Šj -8A6D=Šm -8A6F=Šo -8A70=Šp -8A75=Šu -8A77=Šw -8A79=Šy -8A7A=Šz -8A7C=Š| -8A7E=Š~ -8A84=Š„ -8A88=Šˆ -8A89=Љ -8A8A=ŠŠ -8A8B=Š‹ -8A90=Š -8A94=Š” -8A9A=Šš -8AA3=Š£ -8AA8=Ѝ -8AA9=Š© -8AAA=Šª -8AAE=Š® -8AB0=а -8AB1=б -8AB2=в -8AB4=Š´ -8AB5=е -8AB7=Š· -8ABE=о -8AC7=ŠÇ -8AC8=ŠÈ -8AC9=ŠÉ -8AD1=ŠÑ -8AD2=ŠÒ -8AD4=ŠÔ -8AD5=ŠÕ -8AD6=ŠÖ -8AD9=ŠÙ -8ADC=ŠÜ -8AE1=Šá -8AE2=Šâ -8AE6=Šæ -8AE7=Šç -8AE8=Šè -8AE9=Šé -8AEB=Šë -8AEC=Šì -8AED=Ší -8AEE=Šî -8AEF=Šï -8AF1=Šñ -8AF3=Šó -8AF6=Šö -8AFA=Šú -8B40=‹@ -8B41=‹A -8B43=‹C -8B46=‹F -8B47=‹G -8B4B=‹K -8B4C=‹L -8B4D=‹M -8B4E=‹N -8B50=‹P -8B53=‹S -8B55=‹U -8B56=‹V -8B5A=‹Z -8B5D=‹] -8B5E=‹^ -8B60=‹` -8B63=‹c -8B67=‹g -8B6C=‹l -8B70=‹p -8B71=‹q -8B72=‹r -8B74=‹t -8B76=‹v -8B78=‹x -8B79=‹y -8B7A=‹z -8B7B=‹{ -8B7D=‹} -8B7E=‹~ -8B80=‹€ -8B81=‹ -8B83=‹ƒ -8B85=‹… -8B86=‹† -8B8B=‹‹ -8B8E=‹Ž -8B8F=‹ -8B90=‹ -8B92=‹’ -8B96=‹– -8B97=‹— -8B9B=‹› -8B9F=‹Ÿ -8BA3=‹£ -8BA4=‹¤ -8BA5=‹¥ -8BA6=‹¦ -8BAB=‹« -8BAD=‹­ -8BB0=‹° -8BB3=‹³ -8BB4=‹´ -8BB6=‹¶ -8BBA=‹º -8BBB=‹» -8BBD=‹½ -8BBE=‹¾ -8BBF=‹¿ -8BC1=‹Á -8BC3=‹Ã -8BC5=‹Å -8BC6=‹Æ -8BC8=‹È -8BC9=‹É -8BCA=‹Ê -8BD6=‹Ö -8BDF=‹ß -8BE0=‹à -8BE2=‹â -8BE5=‹å -8BE6=‹æ -8BEA=‹ê -8BEC=‹ì -8BEF=‹ï -8BF0=‹ð -8BF2=‹ò -8BF3=‹ó -8BF4=‹ô -8BFC=‹ü -8C40=Œ@ -8C41=ŒA -8C49=ŒI -8C4A=ŒJ -8C4E=ŒN -8C51=ŒQ -8C52=ŒR -8C57=ŒW -8C58=ŒX -8C5A=ŒZ -8C5C=Œ\ -8C5F=Œ_ -8C60=Œ` -8C62=Œb -8C66=Œf -8C67=Œg -8C69=Œi -8C6B=Œk -8C6F=Œo -8C71=Œq -8C76=Œv -8C78=Œx -8C79=Œy -8C7D=Œ} -8C7E=Œ~ -8C80=Œ€ -8C82=Œ‚ -8C83=Œƒ -8C84=Œ„ -8C87=Œ‡ -8C88=Œˆ -8C8A=ŒŠ -8C8B=Œ‹ -8C8C=ŒŒ -8C8E=ŒŽ -8C8F=Œ -8C92=Œ’ -8C95=Œ• -8C96=Œ– -8C9A=Œš -8CA0=Œ  -8CA2=Œ¢ -8CA4=Œ¤ -8CA8=Œ¨ -8CA9=Œ© -8CAB=Œ« -8CAE=Œ® -8CAF=Œ¯ -8CB1=Œ± -8CB3=Œ³ -8CB4=Œ´ -8CB5=Œµ -8CB6=Œ¶ -8CB8=Œ¸ -8CB9=Œ¹ -8CBB=Œ» -8CBE=Œ¾ -8CC0=ŒÀ -8CC2=ŒÂ -8CC3=ŒÃ -8CC4=ŒÄ -8CC5=ŒÅ -8CC7=ŒÇ -8CC8=ŒÈ -8CC9=ŒÉ -8CCB=ŒË -8CD6=ŒÖ -8CD9=ŒÙ -8CDB=ŒÛ -8CDC=ŒÜ -8CDD=ŒÝ -8CE1=Œá -8CE3=Œã -8CE4=Œä -8CE5=Œå -8CEA=Œê -8CEC=Œì -8CF0=Œð -8CF3=Œó -8CF5=Œõ -8CF6=Œö -8CF7=Œ÷ -8CF8=Œø -8CFA=Œú -8CFB=Œû -8CFC=Œü -8D41=A -8D44=D -8D46=F -8D47=G -8D48=H -8D49=I -8D4B=K -8D4C=L -8D4E=N -8D52=R -8D55=U -8D58=X -8D5C=\ -8D5F=_ -8D60=` -8D62=b -8D64=d -8D67=g -8D6C=l -8D71=q -8D72=r -8D73=s -8D77=w -8D7A=z -8D7C=| -8D7E=~ -8D81= -8D82=‚ -8D84=„ -8D85=… -8D87=‡ -8D8B=‹ -8D8E=Ž -8D8F= -8D90= -8D91=‘ -8D95=• -8D98=˜ -8D9C=œ -8D9E=ž -8DA0=  -8DA1=¡ -8DA2=¢ -8DA5=¥ -8DAA=ª -8DAC=¬ -8DAD=­ -8DB0=° -8DB2=² -8DB6=¶ -8DB7=· -8DB8=¸ -8DBB=» -8DBD=½ -8DC0=À -8DC4=Ä -8DC5=Å -8DC7=Ç -8DC8=È -8DCC=Ì -8DCE=Î -8DCF=Ï -8DD0=Ð -8DD5=Õ -8DD7=× -8DD9=Ù -8DDB=Û -8DDD=Ý -8DDE=Þ -8DDF=ß -8DE0=à -8DE7=ç -8DE8=è -8DEC=ì -8DF0=ð -8DF4=ô -8DF5=õ -8DFB=û -8E40=Ž@ -8E43=ŽC -8E45=ŽE -8E47=ŽG -8E4F=ŽO -8E51=ŽQ -8E52=ŽR -8E53=ŽS -8E55=ŽU -8E59=ŽY -8E61=Ža -8E63=Žc -8E64=Žd -8E67=Žg -8E68=Žh -8E69=Ži -8E6A=Žj -8E6C=Žl -8E6D=Žm -8E6E=Žn -8E6F=Žo -8E70=Žp -8E71=Žq -8E73=Žs -8E74=Žt -8E75=Žu -8E76=Žv -8E77=Žw -8E78=Žx -8E7B=Ž{ -8E7E=Ž~ -8E80=Ž€ -8E81=Ž -8E84=Ž„ -8E85=Ž… -8E86=ކ -8E87=އ -8E88=Žˆ -8E8A=ŽŠ -8E8D=Ž -8E8E=ŽŽ -8E91=Ž‘ -8E94=Ž” -8E95=Ž• -8E96=Ž– -8E97=Ž— -8E99=Ž™ -8E9A=Žš -8E9C=Žœ -8E9D=Ž -8E9E=Žž -8E9F=ŽŸ -8EA1=Ž¡ -8EA6=ަ -8EA8=ލ -8EA9=Ž© -8EAE=Ž® -8EAF=ޝ -8EB7=Ž· -8EB8=ޏ -8EBA=Žº -8EBD=޽ -8EBF=Ž¿ -8EC0=ŽÀ -8EC5=ŽÅ -8ECA=ŽÊ -8ECC=ŽÌ -8ECE=ŽÎ -8ED0=ŽÐ -8ED2=ŽÒ -8ED3=ŽÓ -8ED5=ŽÕ -8ED7=Ž× -8ED8=ŽØ -8EDC=ŽÜ -8EE1=Žá -8EE3=Žã -8EE5=Žå -8EE6=Žæ -8EE7=Žç -8EE8=Žè -8EEA=Žê -8EEC=Žì -8EED=Ží -8EEF=Žï -8EF0=Žð -8EF1=Žñ -8EF3=Žó -8EF5=Žõ -8EF7=Ž÷ -8EFA=Žú -8EFB=Žû -8EFC=Žü -8F43=C -8F44=D -8F45=E -8F47=G -8F48=H -8F49=I -8F4B=K -8F4F=O -8F50=P -8F52=R -8F54=T -8F56=V -8F57=W -8F5A=Z -8F5C=\ -8F61=a -8F62=b -8F63=c -8F64=d -8F66=f -8F68=h -8F6A=j -8F6B=k -8F6E=n -8F6F=o -8F70=p -8F74=t -8F75=u -8F80=€ -8F82=‚ -8F83=ƒ -8F87=‡ -8F88=ˆ -8F89=‰ -8F8A=Š -8F8B=‹ -8F8F= -8F91=‘ -8F94=” -8F95=• -8F97=— -8F98=˜ -8F9C=œ -8F9D= -8F9F=Ÿ -8FA0=  -8FA2=¢ -8FA4=¤ -8FAC=¬ -8FAD=­ -8FB3=³ -8FB8=¸ -8FB9=¹ -8FBA=º -8FBB=» -8FC0=À -8FC1=Á -8FC2= -8FC4=Ä -8FC5=Å -8FC6=Æ -8FCD=Í -8FCE=Î -8FD0=Ð -8FD5=Õ -8FD8=Ø -8FDA=Ú -8FDB=Û -8FDF=ß -8FE3=ã -8FE4=ä -8FE6=æ -8FE7=ç -8FE9=é -8FEA=ê -8FED=í -8FEE=î -8FF0=ð -8FF1=ñ -8FF2=ò -8FF3=ó -8FFC=ü -9041=A -9043=C -9044=D -9045=E -9046=F -9047=G -9048=H -904D=M -904E=N -9051=Q -9052=R -9053=S -9054=T -9055=U -9056=V -9058=X -905B=[ -905C=\ -905E=^ -905F=_ -9062=b -9063=c -9065=e -9067=g -9069=i -906A=j -906C=l -906E=n -9073=s -907B={ -907D=} -9081= -9084=„ -9085=… -9088=ˆ -908A=Š -908B=‹ -908F= -9090= -9094=” -90A2=¢ -90A5=¥ -90A7=§ -90A8=¨ -90AA=ª -90AB=« -90AC=¬ -90AD=­ -90AE=® -90AF=¯ -90B3=³ -90B5=µ -90B6=¶ -90B7=· -90B8=¸ -90B9=¹ -90BA=º -90BB=» -90BC=¼ -90BF=¿ -90C2= -90C3=à -90C8=È -90C9=É -90CC=Ì -90CE=Î -90CF=Ï -90D1=Ñ -90D4=Ô -90D5=Õ -90D8=Ø -90DA=Ú -90DC=Ü -90DD=Ý -90DF=ß -90E0=à -90E2=â -90E6=æ -90E7=ç -90E8=è -90EA=ê -90EC=ì -90ED=í -90F3=ó -90F4=ô -90F5=õ -90F6=ö -90F9=ù -9144=‘D -9147=‘G -9149=‘I -914F=‘O -9150=‘P -9152=‘R -9153=‘S -915F=‘_ -9166=‘f -9167=‘g -916E=‘n -9171=‘q -917A=‘z -917C=‘| -917D=‘} -9180=‘€ -9181=‘ -9187=‘‡ -9188=‘ˆ -918A=‘Š -918D=‘ -9190=‘ -9193=‘“ -9195=‘• -9196=‘– -9197=‘— -919B=‘› -919C=‘œ -919D=‘ -91A0=‘  -91A1=‘¡ -91A2=‘¢ -91A3=‘£ -91A4=‘¤ -91A6=‘¦ -91A7=‘§ -91A9=‘© -91AA=‘ª -91AB=‘« -91AC=‘¬ -91AE=‘® -91AF=‘¯ -91B0=‘° -91B1=‘± -91B6=‘¶ -91B7=‘· -91BA=‘º -91BC=‘¼ -91BD=‘½ -91BE=‘¾ -91C5=‘Å -91CA=‘Ê -91CC=‘Ì -91CE=‘Î -91CF=‘Ï -91D1=‘Ñ -91D2=‘Ò -91D4=‘Ô -91D6=‘Ö -91D7=‘× -91DC=‘Ü -91DD=‘Ý -91DE=‘Þ -91E0=‘à -91E3=‘ã -91E4=‘ä -91E5=‘å -91E6=‘æ -91E8=‘è -91EA=‘ê -91F0=‘ð -91FC=‘ü -9240=’@ -9242=’B -9244=’D -9245=’E -9249=’I -924A=’J -924E=’N -9250=’P -9253=’S -9254=’T -9255=’U -9258=’X -925A=’Z -925B=’[ -9261=’a -9262=’b -9263=’c -9265=’e -9266=’f -9269=’i -926A=’j -926B=’k -926C=’l -926D=’m -926E=’n -9270=’p -9272=’r -9275=’u -9276=’v -9278=’x -927A=’z -927C=’| -927E=’~ -9281=’ -9283=’ƒ -9285=’… -9286=’† -9287=’‡ -9289=’‰ -928B=’‹ -928D=’ -928E=’Ž -9298=’˜ -9299=’™ -92A0=’  -92A3=’£ -92A4=’¤ -92A5=’¥ -92A7=’§ -92A9=’© -92AA=’ª -92AC=’¬ -92AE=’® -92B2=’² -92B7=’· -92B8=’¸ -92B9=’¹ -92BC=’¼ -92BF=’¿ -92C1=’Á -92C3=’à -92C7=’Ç -92C9=’É -92CA=’Ê -92CE=’Î -92D4=’Ô -92D7=’× -92DE=’Þ -92E0=’à -92E1=’á -92E8=’è -92E9=’é -92EB=’ë -92EC=’ì -92ED=’í -92EF=’ï -92F1=’ñ -92F6=’ö -92F7=’÷ -9345=“E -9347=“G -9349=“I -934B=“K -934F=“O -9353=“S -9356=“V -9358=“X -935D=“] -935F=“_ -9360=“` -9361=“a -9363=“c -9364=“d -9366=“f -9368=“h -9369=“i -936B=“k -936E=“n -936F=“o -9371=“q -9372=“r -9373=“s -9378=“x -9379=“y -937A=“z -937B=“{ -937C=“| -937D=“} -9381=“ -9383=“ƒ -9387=“‡ -938A=“Š -938C=“Œ -9390=“ -9394=“” -9396=“– -9399=“™ -939A=“š -939D=“ -939E=“ž -93A1=“¡ -93A2=“¢ -93A5=“¥ -93A6=“¦ -93AA=“ª -93AC=“¬ -93AD=“­ -93AE=“® -93AF=“¯ -93B0=“° -93B1=“± -93B2=“² -93B4=“´ -93B5=“µ -93B9=“¹ -93BA=“º -93BE=“¾ -93BF=“¿ -93C1=“Á -93C5=“Å -93C6=“Æ -93C7=“Ç -93CB=“Ë -93CD=“Í -93D6=“Ö -93DB=“Û -93DD=“Ý -93DF=“ß -93E0=“à -93E3=“ã -93E4=“ä -93EC=“ì -93EF=“ï -93F1=“ñ -93F5=“õ -93F7=“÷ -93F8=“ø -93FA=“ú -93FB=“û -93FC=“ü -9440=”@ -9443=”C -9445=”E -9446=”F -944D=”M -944E=”N -944F=”O -9452=”R -9456=”V -945C=”\ -9467=”g -9468=”h -946A=”j -946B=”k -946E=”n -9470=”p -9471=”q -9472=”r -9473=”s -9474=”t -9477=”w -9479=”y -947A=”z -947D=”} -947E=”~ -9483=”ƒ -9484=”„ -9489=”‰ -948D=” -9491=”‘ -9492=”’ -9496=”– -9499=”™ -949A=”š -94A0=”  -94A8=”¨ -94AD=”­ -94AF=”¯ -94B0=”° -94B2=”² -94BB=”» -94BC=”¼ -94BD=”½ -94C2=” -94C5=”Å -94C6=”Æ -94C7=”Ç -94C9=”É -94CA=”Ê -94CC=”Ì -94CD=”Í -94D1=”Ñ -94D3=”Ó -94D4=”Ô -94DB=”Û -94DE=”Þ -94DF=”ß -94E0=”à -94E3=”ã -94E4=”ä -94E6=”æ -94E7=”ç -94E8=”è -94E9=”é -94ED=”í -94F0=”ð -94F1=”ñ -94F2=”ò -94F5=”õ -94F7=”÷ -94FC=”ü -9543=•C -9545=•E -9548=•H -954B=•K -9550=•P -9553=•S -9557=•W -9558=•X -955C=•\ -955D=•] -9560=•` -9561=•a -9569=•i -956E=•n -9571=•q -9573=•s -9574=•t -9576=•v -9578=•x -957C=•| -957E=•~ -9581=• -9582=•‚ -9583=•ƒ -9589=•‰ -9590=• -9591=•‘ -9594=•” -9595=•• -9597=•— -959C=•œ -959D=• -959E=•ž -959F=•Ÿ -95A0=•  -95A1=•¡ -95A2=•¢ -95A5=•¥ -95A8=•¨ -95AA=•ª -95AC=•¬ -95B1=•± -95B5=•µ -95B6=•¶ -95B7=•· -95BA=•º -95BD=•½ -95BF=•¿ -95C2=• -95C7=•Ç -95CA=•Ê -95CF=•Ï -95D0=•Ð -95D2=•Ò -95D3=•Ó -95D4=•Ô -95D6=•Ö -95D9=•Ù -95DB=•Û -95DF=•ß -95E0=•à -95E2=•â -95E9=•é -95EA=•ê -95EF=•ï -95F1=•ñ -95F3=•ó -95F4=•ô -95F6=•ö -95F8=•ø -95FA=•ú -95FB=•û -9640=–@ -9641=–A -964B=–K -964C=–L -964F=–O -9652=–R -9653=–S -9656=–V -9659=–Y -965A=–Z -965B=–[ -965C=–\ -965D=–] -9660=–` -9664=–d -9666=–f -9668=–h -966B=–k -966C=–l -9676=–v -9678=–x -967B=–{ -9681=– -9682=–‚ -9683=–ƒ -9684=–„ -9685=–… -9687=–‡ -9688=–ˆ -968B=–‹ -9696=–– -969C=–œ -969E=–ž -96A1=–¡ -96A2=–¢ -96A7=–§ -96AC=–¬ -96AD=–­ -96AF=–¯ -96B0=–° -96B2=–² -96B3=–³ -96B6=–¶ -96BA=–º -96BC=–¼ -96BD=–½ -96BE=–¾ -96C0=–À -96C2=– -96C5=–Å -96CA=–Ê -96CD=–Í -96CE=–Î -96D1=–Ñ -96D2=–Ò -96D3=–Ó -96D4=–Ô -96D7=–× -96D8=–Ø -96D9=–Ù -96DA=–Ú -96DF=–ß -96E2=–â -96E4=–ä -96E5=–å -96E7=–ç -96E8=–è -96E9=–é -96EA=–ê -96EC=–ì -96EE=–î -96EF=–ï -96F0=–ð -96F1=–ñ -96F2=–ò -96F3=–ó -96F4=–ô -96F5=–õ -96FC=–ü -9742=—B -9744=—D -9745=—E -9746=—F -9748=—H -974C=—L -9752=—R -9754=—T -9755=—U -9756=—V -9759=—Y -975A=—Z -975B=—[ -975C=—\ -975D=—] -975E=—^ -975F=—_ -9761=—a -9764=—d -9765=—e -976C=—l -976D=—m -976E=—n -9770=—p -9772=—r -9774=—t -9776=—v -9779=—y -977A=—z -977B=—{ -977D=—} -977E=—~ -9782=—‚ -9783=—ƒ -9786=—† -9788=—ˆ -978A=—Š -978E=—Ž -9790=— -9792=—’ -9797=—— -9798=—˜ -979D=— -97A0=—  -97A3=—£ -97A4=—¤ -97A7=—§ -97AA=—ª -97AC=—¬ -97AF=—¯ -97B2=—² -97B3=—³ -97B6=—¶ -97B7=—· -97B9=—¹ -97BC=—¼ -97BF=—¿ -97C1=—Á -97C6=—Æ -97C7=—Ç -97CA=—Ê -97CC=—Ì -97CD=—Í -97CE=—Î -97D1=—Ñ -97D6=—Ö -97D7=—× -97D8=—Ø -97DE=—Þ -97DF=—ß -97E1=—á -97E7=—ç -97E9=—é -97EC=—ì -97ED=—í -97F0=—ð -97F4=—ô -97F6=—ö -97FB=—û -9841=˜A -9842=˜B -9846=˜F -9848=˜H -984A=˜J -984C=˜L -9853=˜S -9854=˜T -9855=˜U -9856=˜V -9859=˜Y -985E=˜^ -985F=˜_ -9861=˜a -9862=˜b -9866=˜f -9867=˜g -9870=˜p -9872=˜r -98EB=˜ë -9B9B=›› -9C9C=œœ -E163=ác -E183=რ-E1BF=á¿ -E1D5=áÕ -E359=ãY -E3A9=ã© -E4BB=ä» -E5E1=åá -E6CB=æË -E6D1=æÑ -E6D2=æÒ -E748=çH -E84A=èJ -FFFD=[WAIT] -3C4B333E= -3C4B303E= \ No newline at end of file +A2=ï½¢ +A3=ï½£ +A5=ï½¥ +8140=  +8141=〠+8142=。 +8143=, +8144=. +8145=・ +8146=: +8148=? +8149=ï¼ +8158=々 +815B=ー +815E=ï¼ +8160=~ +8163=… +8166=’ +8167=“ +8168=†+8169=( +816A=) +8175=「 +8176=〠+8177=『 +8178=〠+8179=〠+817A=】 +817B=+ +817C=ï¼ +817E=× +8180=÷ +8181=ï¼ +8183=< +8184=> +818F=ï¿¥ +8190=$ +8193=ï¼… +8194=# +8195=& +8196=* +8197=ï¼  +8199=☆ +819A=★ +819B=â—‹ +819C=â— +819D=â—Ž +819E=â—‡ +819F=â—† +81A0=â–¡ +81A1=â–  +81A2=â–³ +81A3=â–² +81A4=â–½ +81A5=â–¼ +81A6=※ +81A8=→ +81A9=↠+81AA=↑ +81AB=↓ +824F=ï¼ +8250=1 +8251=ï¼’ +8252=3 +8253=ï¼” +8254=5 +8255=ï¼– +8256=ï¼— +8257=8 +8258=ï¼™ +8260=A +8261=ï¼¢ +8262=ï¼£ +8263=D +8264=ï¼¥ +8265=F +8266=ï¼§ +8267=H +8268=I +8269=J +826A=K +826B=L +826C=ï¼­ +826D=ï¼® +826E=O +826F=ï¼° +8270=ï¼± +8271=ï¼² +8272=ï¼³ +8273=ï¼´ +8274=ï¼µ +8275=ï¼¶ +8276=ï¼· +8277=X +8278=ï¼¹ +8279=Z +8281=ï½ +8282=b +8283=c +8284=d +8285=ï½… +8286=f +8287=g +8288=h +8289=i +828A=j +828B=k +828C=l +828D=ï½ +828E=n +828F=ï½ +8290=ï½ +8291=q +8292=ï½’ +8293=s +8294=ï½” +8295=u +8296=ï½– +8297=ï½— +8298=x +8299=ï½™ +829A=z +829F=ã +82A0=ã‚ +82A1=ム+82A2=ã„ +82A3=ã… +82A4=ㆠ+82A5=㇠+82A6=㈠+82A7=㉠+82A8=㊠+82A9=ã‹ +82AA=㌠+82AB=ã +82AC=㎠+82AD=ã +82AE=ã +82AF=ã‘ +82B0=ã’ +82B1=ã“ +82B2=ã” +82B3=ã• +82B4=ã– +82B5=ã— +82B6=㘠+82B7=ã™ +82B8=ãš +82B9=ã› +82BA=㜠+82BB=ã +82BC=ãž +82BD=㟠+82BE=ã  +82BF=ã¡ +82C0=㢠+82C1=㣠+82C2=㤠+82C3=㥠+82C4=㦠+82C5=ã§ +82C6=㨠+82C7=ã© +82C8=㪠+82C9=ã« +82CA=㬠+82CB=ã­ +82CC=ã® +82CD=㯠+82CE=ã° +82CF=ã± +82D0=ã² +82D1=ã³ +82D2=ã´ +82D3=ãµ +82D4=ã¶ +82D5=ã· +82D6=㸠+82D7=ã¹ +82D8=㺠+82D9=ã» +82DA=ã¼ +82DB=ã½ +82DC=ã¾ +82DD=ã¿ +82DE=ã‚€ +82DF=ã‚ +82E0=ã‚‚ +82E1=ゃ +82E2=ã‚„ +82E3=ã‚… +82E4=ゆ +82E5=ょ +82E6=よ +82E7=ら +82E8=り +82E9=ã‚‹ +82EA=れ +82EB=ã‚ +82ED=ã‚ +82F0=ã‚’ +82F1=ã‚“ +8340=ã‚¡ +8341=ã‚¢ +8342=ã‚£ +8343=イ +8344=ã‚¥ +8345=ウ +8346=ã‚§ +8347=エ +8348=ã‚© +8349=オ +834A=ã‚« +834B=ガ +834C=ã‚­ +834D=ã‚® +834E=ク +834F=ã‚° +8350=ケ +8351=ゲ +8352=コ +8353=ã‚´ +8354=サ +8355=ã‚¶ +8356=ã‚· +8357=ジ +8358=ス +8359=ズ +835A=ã‚» +835B=ゼ +835C=ソ +835D=ゾ +835E=ã‚¿ +835F=ダ +8360=ム+8361=ヂ +8362=ッ +8363=ツ +8364=ヅ +8365=テ +8366=デ +8367=ト +8368=ド +8369=ナ +836A=ニ +836B=ヌ +836C=ム+836D=ノ +836E=ム+836F=ム+8370=パ +8371=ヒ +8372=ビ +8373=ピ +8374=フ +8375=ブ +8376=プ +8377=ヘ +8378=ベ +8379=ペ +837A=ホ +837B=ボ +837C=ム+837D=マ +837E=ミ +8380=ム +8381=メ +8382=モ +8383=ャ +8384=ヤ +8385=ュ +8386=ユ +8387=ョ +8388=ヨ +8389=ラ +838A=リ +838B=ル +838C=レ +838D=ロ +838F=ワ +8392=ヲ +8393=ン +8394=ヴ +8395=ヵ +8396=ヶ +849F=─ +8754=â…  +8755=â…¡ +8756=â…¢ +8757=â…£ +8758=â…¤ +8759=â…¥ +875A=â…¦ +875B=â…§ +875C=â…¨ +875D=â…© +889F=亜 +88A2=阿 +88A3=å“€ +88A4=æ„› +88AB=悪 +88B5=扱 +88B6=å®› +88C0=安 +88C3=æš— +88C4=案 +88C5=é—‡ +88C8=以 +88CB=ä¾ +88CC=å‰ +88CD=囲 +88D0=å¨ +88D3=æ„ +88D5=易 +88D9=ç•° +88DA=ç§» +88DB=ç¶­ +88E1=é• +88E2=éº +88E4=井 +88E6=域 +88E7=育 +88EA=一 +88F3=å° +88F5=å“¡ +88F6=å›  +88F8=引 +88F9=飲 +8942=éš  +8945=å³ +8948=ç¾½ +894A=雨 +8951=渦 +8959=浦 +895C=噂 +895E=é‹ +8965=å½± +8968=æ „ +8969=æ°¸ +8970=英 +8971=è¡› +8973=é‹­ +8979=è¬ +897A=è¶Š +897E=円 +8980=園 +8984=å»¶ +8987=æ´ +898A=炎 +8993=é  +899B=央 +899C=奥 +899E=応 +899F=押 +89A1=横 +89A4=王 +89A9=黄 +89AE=屋 +89AF=憶 +89B4=俺 +89B6=æ© +89B8=ç© +89B9=音 +89BA=下 +89BB=化 +89BC=ä»® +89BD=何 +89BF=価 +89C1=加 +89C2=å¯ +89C3=嘉 +89C6=å®¶ +89CA=æžœ +89CC=æ­Œ +89CD=æ²³ +89CE=ç« +89D2=稼 +89D4=花 +89D7=è· +89D8=è¯ +89DB=課 +89DF=éŽ +89E4=我 +89E6=ç”» +89EB=é›… +89EC=餓 +89EE=介 +89EF=会 +89F0=è§£ +89F1=回 +89F3=壊 +89F6=怪 +89F7=æ‚” +89F9=æ‡ +89FC=改 +8A42=械 +8A43=æµ· +8A45=界 +8A46=皆 +8A47=çµµ +8A4A=é–‹ +8A4B=階 +8A4F=外 +8A51=害 +8A52=å´– +8A58=è¡— +8A5A=鎧 +8A5F=垣 +8A65=å„ +8A69=æ ¼ +8A6A=æ ¸ +8A6D=確 +8A6F=覚 +8A70=è§’ +8A75=éš” +8A77=å­¦ +8A79=楽 +8A7A=é¡ +8A7C=掛 +8A7E=樫 +8A84=割 +8A88=æ´» +8A89=渇 +8A8A=滑 +8A8B=è‘› +8A90=å¶ +8A94=æ ª +8A9A=å™› +8AA3=ä¹¾ +8AA8=勘 +8AA9=å‹§ +8AAA=å·» +8AAE=完 +8AB0=寛 +8AB1=å¹² +8AB2=å¹¹ +8AB4=感 +8AB5=æ…£ +8AB7=æ› +8ABE=æ±— +8AC7=管 +8AC8=ç°¡ +8AC9=ç·© +8AD1=貫 +8AD2=é‚„ +8AD4=é–“ +8AD5=é–‘ +8AD6=é–¢ +8AD9=館 +8ADC=å« +8AE1=眼 +8AE2=岩 +8AE6=é ‘ +8AE7=é¡” +8AE8=願 +8AE9=ä¼ +8AEB=å± +8AEC=å–œ +8AED=器 +8AEE=基 +8AEF=奇 +8AF1=寄 +8AF3=希 +8AF6=æ® +8AFA=期 +8B40=機 +8B41=帰 +8B43=æ°— +8B46=祈 +8B47=å­£ +8B4B=è¦ +8B4C=記 +8B4D=è²´ +8B4E=èµ· +8B50=è¼ +8B53=鬼 +8B55=å½ +8B56=å„€ +8B5A=技 +8B5D=犠 +8B5E=ç–‘ +8B60=義 +8B63=è­° +8B67=å‰ +8B6C=è©° +8B70=å´ +8B71=客 +8B72=脚 +8B74=逆 +8B76=ä¹… +8B78=休 +8B79=åŠ +8B7A=å¸ +8B7B=å®® +8B7D=急 +8B7E=æ•‘ +8B80=朽 +8B81=求 +8B83=æ³£ +8B85=çƒ +8B86=ç©¶ +8B8B=給 +8B8E=去 +8B8F=å±… +8B90=å·¨ +8B92=æ‹  +8B96=許 +8B97=è· +8B9B=é­š +8B9F=ä¾› +8BA3=ç«¶ +8BA4=å…± +8BA5=凶 +8BA6=å” +8BAB=境 +8BAD=å¼· +8BB0=æ +8BB3=æ•™ +8BB4=æ©‹ +8BB6=ç‹‚ +8BBA=è„… +8BBB=興 +8BBD=郷 +8BBE=é¡ +8BBF=響 +8BC1=驚 +8BC3=å‡ +8BC5=æš +8BC6=業 +8BC8=曲 +8BC9=極 +8BCA=玉 +8BD6=ç¦ +8BDF=è¿‘ +8BE0=金 +8BE2=銀 +8BE5=å¥ +8BE6=区 +8BEA=苦 +8BEC=駆 +8BEF=å…· +8BF0=愚 +8BF2=å–° +8BF3=空 +8BF4=å¶ +8BFC=屈 +8C40=掘 +8C41=窟 +8C49=æ — +8C4A=ç¹° +8C4E=å› +8C51=群 +8C52=è» +8C57=ä¿‚ +8C58=傾 +8C5A=å…„ +8C5C=圭 +8C5F=契 +8C60=å½¢ +8C62=æµ +8C66=掲 +8C67=æº +8C69=景 +8C6B=渓 +8C6F=経 +8C71=繋 +8C76=計 +8C78=è­¦ +8C79=軽 +8C7D=迎 +8C7E=鯨 +8C80=劇 +8C82=æ’ƒ +8C83=æ¿€ +8C84=éš™ +8C87=欠 +8C88=決 +8C8A=ç©´ +8C8B=çµ +8C8C=è¡€ +8C8E=月 +8C8F=ä»¶ +8C92=å¥ +8C95=剣 +8C96=å–§ +8C9A=建 +8CA0=権 +8CA2=犬 +8CA4=ç ” +8CA8=è‚© +8CA9=見 +8CAB=è³¢ +8CAE=éµ +8CAF=険 +8CB1=験 +8CB3=å…ƒ +8CB4=原 +8CB5=厳 +8CB6=å¹» +8CB8=減 +8CB9=æº +8CBB=ç¾ +8CBE=言 +8CC0=é™ +8CC2=個 +8CC3=å¤ +8CC4=呼 +8CC5=固 +8CC7=å­¤ +8CC8=å·± +8CC9=庫 +8CCB=戸 +8CD6=誇 +8CD9=雇 +8CDB=鼓 +8CDC=五 +8CDD=互 +8CE1=å¾ +8CE3=後 +8CE4=御 +8CE5=悟 +8CEA=語 +8CEC=è­· +8CF0=交 +8CF3=候 +8CF5=å…‰ +8CF6=å…¬ +8CF7=功 +8CF8=効 +8CFA=厚 +8CFB=å£ +8CFC=å‘ +8D41=å–‰ +8D44=好 +8D46=å­ +8D47=å® +8D48=å·¥ +8D49=å·§ +8D4B=幸 +8D4C=広 +8D4E=康 +8D52=抗 +8D55=æ”» +8D58=æ›´ +8D5C=æ§‹ +8D5F=浩 +8D60=港 +8D62=甲 +8D64=硬 +8D67=ç´… +8D6C=考 +8D71=航 +8D72=è’ +8D73=行 +8D77=è³¼ +8D7A=鉱 +8D7C=鋼 +8D7E=é™ +8D81=香 +8D82=高 +8D84=剛 +8D85=劫 +8D87=åˆ +8D8B=豪 +8D8E=å…‹ +8D8F=刻 +8D90=告 +8D91=国 +8D95=é»’ +8D98=è…° +8D9C=骨 +8D9E=è¾¼ +8DA0=é ƒ +8DA1=今 +8DA2=å›° +8DA5=婚 +8DAA=æ ¹ +8DAC=æ·· +8DAD=ç—• +8DB0=é­‚ +8DB2=ä½ +8DB6=å·¦ +8DB7=å·® +8DB8=査 +8DBB=ç ‚ +8DBD=鎖 +8DC0=座 +8DC4=å† +8DC5=最 +8DC7=塞 +8DC8=妻 +8DCC=採 +8DCE=æ­³ +8DCF=済 +8DD0=ç½ +8DD5=祭 +8DD7=ç´° +8DD9=è£ +8DDB=éš› +8DDD=在 +8DDE=æ +8DDF=罪 +8DE0=財 +8DE7=å’² +8DE8=å´Ž +8DEC=作 +8DF0=昨 +8DF4=ç­– +8DF5=ç´¢ +8DFB=冊 +8E40=察 +8E43=擦 +8E45=殺 +8E47=雑 +8E4F=三 +8E51=å‚ +8E52=å±± +8E53=惨 +8E55=æ•£ +8E59=産 +8E61=æ–¬ +8E63=残 +8E64=仕 +8E67=使 +8E68=刺 +8E69=å¸ +8E6A=å² +8E6C=å›› +8E6D=士 +8E6E=å§‹ +8E6F=姉 +8E70=å§¿ +8E71=å­ +8E73=市 +8E74=師 +8E75=å¿— +8E76=æ€ +8E77=指 +8E78=支 +8E7B=æ–½ +8E7E=æ­¢ +8E80=æ­» +8E81=æ° +8E84=ç§ +8E85=糸 +8E86=ç´™ +8E87=ç´« +8E88=è‚¢ +8E8A=至 +8E8D=è©© +8E8E=試 +8E91=資 +8E94=飼 +8E95=æ­¯ +8E96=事 +8E97=ä¼¼ +8E99=å… +8E9A=å­— +8E9C=æ…ˆ +8E9D=æŒ +8E9E=時 +8E9F=次 +8EA1=æ²» +8EA6=示 +8EA8=耳 +8EA9=自 +8EAE=å¼ +8EAF=è­˜ +8EB7=執 +8EB8=失 +8EBA=室 +8EBD=漆 +8EBF=質 +8EC0=実 +8EC5=èŠ +8ECA=写 +8ECC=æ¨ +8ECE=æ–œ +8ED0=社 +8ED2=者 +8ED3=è¬ +8ED5=é® +8ED7=邪 +8ED8=借 +8EDC=ç¼ +8EE1=è‹¥ +8EE3=å¼± +8EE5=主 +8EE6=å– +8EE7=守 +8EE8=手 +8EEA=殊 +8EEC=ç  +8EED=種 +8EEF=è¶£ +8EF0=é…’ +8EF1=首 +8EF3=å— +8EF5=寿 +8EF7=樹 +8EFA=囚 +8EFB=åŽ +8EFC=周 +8F43=ä¿® +8F44=æ„ +8F45=拾 +8F47=ç§€ +8F48=ç§‹ +8F49=終 +8F4B=ç¿’ +8F4F=衆 +8F50=襲 +8F52=è¹´ +8F54=週 +8F56=é…¬ +8F57=集 +8F5A=ä½ +8F5C=å +8F61=渋 +8F62=ç£ +8F63=縦 +8F64=é‡ +8F66=å” +8F68=宿 +8F6A=ç¥ +8F6B=縮 +8F6E=熟 +8F6F=出 +8F70=è¡“ +8F74=春 +8F75=瞬 +8F80=準 +8F82=盾 +8F83=ç´” +8F87=é † +8F88=処 +8F89=åˆ +8F8A=所 +8F8B=æš‘ +8F8F=ç·’ +8F91=書 +8F94=諸 +8F95=助 +8F97=女 +8F98=åº +8F9C=除 +8F9D=å‚· +8F9F=å‹ +8FA0=匠 +8FA2=å¬ +8FA4=商 +8FAC=å° +8FAD=å°‘ +8FB3=承 +8FB8=昇 +8FB9=昌 +8FBA=昭 +8FBB=æ™¶ +8FC0=æ²¼ +8FC1=消 +8FC2=渉 +8FC4=焼 +8FC5=焦 +8FC6=ç…§ +8FCD=ç«  +8FCE=笑 +8FD0=ç´¹ +8FD5=è¡ +8FD8=証 +8FDA=詳 +8FDB=象 +8FDF=é¾ +8FE3=上 +8FE4=丈 +8FE6=ä¹— +8FE7=冗 +8FE9=城 +8FEA=å ´ +8FED=常 +8FEE=情 +8FF0=æ¡ +8FF1=æ– +8FF2=浄 +8FF3=状 +8FFC=飾 +9041=æ¤ +9043=燭 +9044=ç¹” +9045=è· +9046=色 +9047=触 +9048=食 +904D=ä¿¡ +904E=ä¾µ +9051=å¯ +9052=審 +9053=心 +9054=æ…Ž +9055=振 +9056=æ–° +9058=森 +905B=æ·± +905C=申 +905E=真 +905F=神 +9062=臣 +9063=芯 +9065=親 +9067=身 +9069=進 +906A=é‡ +906C=人 +906E=刃 +9073=å°½ +907B=é ˆ +907D=図 +9081=å¹ +9084=推 +9085=æ°´ +9088=粋 +908A=è¡° +908B=é‚ +908F=éš +9090=瑞 +9094=æ•° +90A2=世 +90A5=是 +90A7=制 +90A8=å‹¢ +90AA=å¾ +90AB=性 +90AC=æˆ +90AD=政 +90AE=æ•´ +90AF=星 +90B3=æ­£ +90B5=牲 +90B6=生 +90B7=ç›› +90B8=ç²¾ +90B9=è– +90BA=声 +90BB=製 +90BC=西 +90BF=è«‹ +90C2=é’ +90C3=é™ +90C8=席 +90C9=惜 +90CC=昔 +90CE=石 +90CF=ç© +90D1=績 +90D4=赤 +90D5=è·¡ +90D8=切 +90DA=接 +90DC=折 +90DD=設 +90DF=節 +90E0=説 +90E2=çµ¶ +90E6=å…ˆ +90E7=åƒ +90E8=å  +90EA=å°‚ +90EC=å· +90ED=戦 +90F3=æµ… +90F4=æ´— +90F5=染 +90F6=潜 +90F9=æ—‹ +9144=船 +9147=賎 +9149=é¸ +914F=å‰ +9150=å–„ +9152=ç„¶ +9153=å…¨ +915F=ç‹™ +9166=ç´  +9167=組 +916E=創 +9171=倉 +917A=想 +917C=掃 +917D=挿 +9180=æ“ +9181=æ—© +9187=燥 +9188=争 +918A=相 +918D=ç· +9190=è‰ +9193=è’¼ +9195=装 +9196=èµ° +9197=é€ +919B=騒 +919C=åƒ +919D=増 +91A0=蔵 +91A1=è´ˆ +91A2=造 +91A3=促 +91A4=å´ +91A6=å³ +91A7=æ¯ +91A9=æŸ +91AA=測 +91AB=è¶³ +91AC=速 +91AE=属 +91AF=賊 +91B0=æ— +91B1=ç¶š +91B6=å­˜ +91B7=å­« +91BA=æ‘ +91BC=ä»– +91BD=多 +91BE=太 +91C5=打 +91CA=é§„ +91CC=体 +91CE=対 +91CF=è€ +91D1=帯 +91D2=å¾… +91D4=æ…‹ +91D6=替 +91D7=æ³° +91DC=袋 +91DD=貸 +91DE=退 +91E0=隊 +91E3=代 +91E4=å° +91E5=大 +91E6=第 +91E8=題 +91EA=æ» +91F0=択 +91FC=åª +9240=å© +9242=é” +9244=奪 +9245=脱 +9249=棚 +924A=è°· +924E=誰 +9250=å˜ +9253=æ‹… +9254=探 +9255=æ—¦ +9258=æ¹› +925A=短 +925B=端 +9261=誕 +9262=é› +9263=団 +9265=å¼¾ +9266=æ–­ +9269=段 +926A=ç”· +926B=談 +926C=値 +926D=知 +926E=地 +9270=æ¥ +9272=æ±  +9275=ç½® +9276=致 +9278=é… +927A=築 +927C=竹 +927E=è“„ +9281=ç§© +9283=茶 +9285=ç€ +9286=中 +9287=仲 +9289=å¿  +928B=昼 +928D=注 +928E=虫 +9298=è‘— +9299=貯 +92A0=帳 +92A3=å¼µ +92A4=彫 +92A5=å¾´ +92A7=挑 +92A9=æœ +92AA=æ½® +92AC=町 +92AE=è´ +92B2=調 +92B7=é•· +92B8=é ‚ +92B9=é³¥ +92BC=ç›´ +92BF=ç +92C1=鎮 +92C3=æ´¥ +92C7=追 +92C9=ç—› +92CA=通 +92CE=æ§» +92D4=ç¶´ +92D7=æ½° +92DE=釣 +92E0=亭 +92E1=低 +92E8=定 +92E9=å¸ +92EB=庭 +92EC=å»· +92ED=弟 +92EF=抵 +92F1=æ +92F6=程 +92F7=ç·  +9345=摘 +9347=敵 +9349=çš„ +934B=é© +934F=å¾¹ +9353=鉄 +9356=天 +9358=店 +935D=転 +935F=点 +9360=ä¼ +9361=殿 +9363=ç”° +9364=é›» +9366=å +9368=å¡— +9369=妬 +936B=å¾’ +936E=渡 +936F=ç™» +9371=è³­ +9372=途 +9373=都 +9378=度 +9379=土 +937A=奴 +937B=怒 +937C=倒 +937D=å…š +9381=刀 +9383=å¡” +9387=å³¶ +938A=投 +938C=æ± +9390=ç›— +9394=ç¯ +9396=当 +9399=ç­‰ +939A=ç­” +939D=çµ± +939E=到 +93A1=è—¤ +93A2=討 +93A5=è¸ +93A6=逃 +93AA=é ­ +93AC=é—˜ +93AD=åƒ +93AE=å‹• +93AF=åŒ +93B0=å ‚ +93B1=å°Ž +93B2=憧 +93B4=æ´ž +93B5=çž³ +93B9=é“ +93BA=銅 +93BE=å¾— +93BF=å¾³ +93C1=特 +93C5=毒 +93C6=独 +93C7=読 +93CB=çª +93CD=届 +93D6=敦 +93DB=å‘‘ +93DD=éˆ +93DF=é‚£ +93E0=内 +93E3=è–™ +93E4=謎 +93EC=å— +93EF=難 +93F1=二 +93F5=匂 +93F7=肉 +93F8=虹 +93FA=æ—¥ +93FB=ä¹³ +93FC=å…¥ +9440=如 +9443=ä»» +9445=å¿ +9446=èª +944D=熱 +944E=å¹´ +944F=念 +9452=燃 +9456=之 +945C=能 +9467=æ³¢ +9468=æ´¾ +946A=ç ´ +946B=婆 +946E=馬 +9470=廃 +9471=æ‹ +9472=排 +9473=æ•— +9474=æ¯ +9477=背 +9479=輩 +947A=é… +947D=媒 +947E=梅 +9483=è²· +9484=売 +9489=秤 +948D=剥 +9491=泊 +9492=白 +9496=è–„ +9499=æ¼  +949A=爆 +94A0=ç®± +94A8=ç•‘ +94AD=発 +94AF=髪 +94B0=ä¼ +94B2=抜 +94BB=判 +94BC=åŠ +94BD=å +94C2=æ¿ +94C5=版 +94C6=犯 +94C7=ç­ +94C9=ç¹ +94CA=般 +94CC=販 +94CD=範 +94D1=飯 +94D3=晩 +94D4=番 +94DB=å¦ +94DE=å½¼ +94DF=悲 +94E0=扉 +94E3=æ– +94E4=比 +94E6=ç–² +94E7=çš® +94E8=碑 +94E9=秘 +94ED=被 +94F0=é¿ +94F1=éž +94F2=飛 +94F5=å‚™ +94F7=å¾® +94FC=美 +9543=匹 +9545=é«­ +9548=è± +954B=å¿… +9550=å§« +9553=百 +9557=標 +9558=æ°· +955C=表 +955D=è©• +9560=æ +9561=ç—… +9569=å“ +956E=è²§ +9571=æ• +9573=ä¸ +9574=付 +9576=夫 +9578=富 +957C=怖 +957E=æ•· +9581=æ™® +9582=æµ® +9583=父 +9589=è²  +9590=æ­¦ +9591=舞 +9594=部 +9595=å° +9597=風 +959C=復 +959D=å¹… +959E=æœ +959F=ç¦ +95A0=è…¹ +95A1=複 +95A2=覆 +95A5=払 +95A8=物 +95AA=分 +95AC=å™´ +95B1=奮 +95B5=é›° +95B6=æ–‡ +95B7=èž +95BA=å…µ +95BD=å¹³ +95BF=柄 +95C2=é–‰ +95C7=å£ +95CA=別 +95CF=変 +95D0=片 +95D2=ç·¨ +95D3=辺 +95D4=è¿” +95D6=便 +95D9=å¼ +95DB=ä¿ +95DF=æ• +95E0=æ­© +95E2=補 +95E9=æš® +95EA=æ¯ +95EF=包 +95F1=å ± +95F3=å® +95F4=å³° +95F6=å´© +95F8=抱 +95FA=放 +95FB=æ–¹ +9640=法 +9641=泡 +964B=訪 +964C=豊 +964F=飽 +9652=ä¹ +9653=亡 +9656=åŠ +9659=忘 +965A=å¿™ +965B=房 +965C=æš´ +965D=望 +9660=冒 +9664=謀 +9666=貿 +9668=防 +966B=北 +966C=僕 +9676=没 +9678=å € +967B=本 +9681=磨 +9682=é­” +9683=麻 +9684=埋 +9685=妹 +9687=æžš +9688=毎 +968B=幕 +9696=末 +969C=万 +969E=満 +96A1=味 +96A2=未 +96A7=密 +96AC=脈 +96AD=妙 +96AF=æ°‘ +96B0=眠 +96B2=夢 +96B3=ç„¡ +96B6=霧 +96BA=娘 +96BC=å +96BD=命 +96BE=明 +96C0=è¿· +96C2=é³´ +96C5=æ»… +96CA=é¢ +96CD=模 +96CE=茂 +96D1=毛 +96D2=猛 +96D3=盲 +96D4=ç¶² +96D7=儲 +96D8=木 +96D9=é»™ +96DA=ç›® +96DF=戻 +96E2=å• +96E4=ç´‹ +96E5=é–€ +96E7=也 +96E8=冶 +96E9=夜 +96EA=爺 +96EC=野 +96EE=矢 +96EF=厄 +96F0=å½¹ +96F1=ç´„ +96F2=è–¬ +96F3=訳 +96F4=èº +96F5=é– +96FC=ç™’ +9742=唯 +9744=優 +9745=勇 +9746=å‹ +9748=å¹½ +974C=有 +9752=ç”± +9754=裕 +9755=誘 +9756=éŠ +9759=雄 +975A=èž +975B=夕 +975C=予 +975D=ä½™ +975E=与 +975F=誉 +9761=é  +9764=妖 +9765=容 +976C=様 +976D=æ´‹ +976E=溶 +9770=用 +9772=羊 +9774=葉 +9776=è¦ +9779=é¥ +977A=陽 +977B=養 +977D=抑 +977E=欲 +9782=翌 +9783=翼 +9786=螺 +9788=æ¥ +978A=é ¼ +978E=è½ +9790=ä¹± +9792=åµ +9797=覧 +9798=利 +979D=ç† +97A0=è£ +97A3=離 +97A4=陸 +97A7=ç«‹ +97AA=ç•¥ +97AC=æµ +97AF=ç•™ +97B2=隆 +97B3=竜 +97B6=æ…® +97B7=æ—… +97B9=了 +97BC=両 +97BF=æ–™ +97C1=æ¶¼ +97C6=ç³§ +97C7=良 +97CA=é‡ +97CC=é ˜ +97CD=力 +97CE=ç·‘ +97D1=æž— +97D6=輪 +97D7=隣 +97D8=é±— +97DE=類 +97DF=令 +97E1=例 +97E7=礼 +97E9=鈴 +97EC=霊 +97ED=麗 +97F0=æ­´ +97F4=裂 +97F6=æ‹ +97FB=ç·´ +9841=連 +9842=錬 +9846=炉 +9848=è·¯ +984A=労 +984C=廊 +9853=牢 +9854=狼 +9855=篭 +9856=è€ +9859=郎 +985E=録 +985F=è«– +9861=å’Œ +9862=話 +9866=惑 +9867=æž  +9870=æ¹¾ +9872=è…• +98EB=俯 +9B9B=å± +9C9C=惧 +E163=ç•¶ +E183=ç—º +E1BF=眩 +E1D5=çž° +E359=綺 +E3A9=ç½  +E4BB=莉 +E5E1=裔 +E6CB=賤 +E6D1=è´„ +E6D2=è´… +E748=踪 +E84A=é® + +FFFD=[WAIT]\n + + +38FF=[IDK1]\n +B0FF=[IDK2]\n +B4FF=[IDK3]\n +CEFF=[IDK4]\n +ECFF=[IDK5]\n +9CFF=[IDK6]\n +10FF=[IDK7]\n +F6FF=[IDK8]\n +C4FF=[IDK9]\n +A6FF=[IDKA]\n +88FF=[IDKB]\n +D8FF=[IDKC]\n +B5FF=[IDKD]\n +E2FF=[IDKE]\n +60FF=[IDKF]\n +F8FF=[IDKG]\n +A1FF=[IDKH]\n +B1FF=[IDKI]\n +1FFF=[IDKJ]\n +FBFF=[IDKK]\n +15FF=[IDKL]\n + +47FF=[idkG]\n +4CFF=[idkL]\n +58FF=[idkX]\n +42FF=[idkB]\n +6FFF=[idko]\n +44FF=[idkD]\n +51FF=[idkQ]\n +6AFF=[idkj]\n +57FF=[idkW]\n + +/01FF=[END01]\n +/02FF=[END02]\n +/04FF=[END04]\n +/06FF=[END06]\n +/07FF=[END07]\n +/11FF=[END11]\n +/32FF=[END32]\n +/4EFF=[END4E]\n +/55FF=[END55]\n +#56FF=[END56]\n +/64FF=[END64]\n +#A5FF=[ENDA5]\n + +/000000FF=[ENDa]\n +/0000FF=[ENDb]\n +/00FF=[ENDc]\n + +/FF=[ENDFF] \ No newline at end of file diff --git a/manual/Ys5_-_0001.jpg b/manual/Ys5_-_0001.jpg new file mode 100644 index 0000000..e89a695 Binary files /dev/null and b/manual/Ys5_-_0001.jpg differ diff --git a/manual/Ys5_-_0002.jpg b/manual/Ys5_-_0002.jpg new file mode 100644 index 0000000..9e9aa67 Binary files /dev/null and b/manual/Ys5_-_0002.jpg differ diff --git a/manual/Ys5_-_0003.jpg b/manual/Ys5_-_0003.jpg new file mode 100644 index 0000000..746b5c3 Binary files /dev/null and b/manual/Ys5_-_0003.jpg differ diff --git a/manual/Ys5_-_0004.jpg b/manual/Ys5_-_0004.jpg new file mode 100644 index 0000000..64d622e Binary files /dev/null and b/manual/Ys5_-_0004.jpg differ diff --git a/manual/Ys5_-_0005.jpg b/manual/Ys5_-_0005.jpg new file mode 100644 index 0000000..9d1f830 Binary files /dev/null and b/manual/Ys5_-_0005.jpg differ diff --git a/manual/Ys5_-_0006.jpg b/manual/Ys5_-_0006.jpg new file mode 100644 index 0000000..96ebee8 Binary files /dev/null and b/manual/Ys5_-_0006.jpg differ diff --git a/manual/Ys5_-_0007.jpg b/manual/Ys5_-_0007.jpg new file mode 100644 index 0000000..c507c0f Binary files /dev/null and b/manual/Ys5_-_0007.jpg differ diff --git a/manual/Ys5_-_0008.jpg b/manual/Ys5_-_0008.jpg new file mode 100644 index 0000000..01228f3 Binary files /dev/null and b/manual/Ys5_-_0008.jpg differ diff --git a/manual/Ys5_-_0009.jpg b/manual/Ys5_-_0009.jpg new file mode 100644 index 0000000..8720111 Binary files /dev/null and b/manual/Ys5_-_0009.jpg differ diff --git a/manual/Ys5_-_0010.jpg b/manual/Ys5_-_0010.jpg new file mode 100644 index 0000000..38d5586 Binary files /dev/null and b/manual/Ys5_-_0010.jpg differ diff --git a/manual/Ys5_-_0011.jpg b/manual/Ys5_-_0011.jpg new file mode 100644 index 0000000..5c0ea54 Binary files /dev/null and b/manual/Ys5_-_0011.jpg differ diff --git a/manual/Ys5_-_0012.jpg b/manual/Ys5_-_0012.jpg new file mode 100644 index 0000000..28e2b22 Binary files /dev/null and b/manual/Ys5_-_0012.jpg differ diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..c0f44eb --- /dev/null +++ b/notes.txt @@ -0,0 +1,338 @@ +Text seems to be loaded into $00F6A150 in memory +and also at $00EF6580 + +stage00.bin is loaded at $0139BA00 (data starts at $0139DA00) + +stagea0.bin +$00015F91 $00000000 +$00015F92 $00000024 +$00015F93 $00000048 +$00015F94 $00000075 +$00015F95 $000000A2 +$00015F96 $000000CF + +the latter values map directly to the start of each string (pointer?) + +$00EF6660 has the value $00EF65D0 +$00EF65D0 has the value $00F69E00 +$00F69E00 has the value $01B08660 + +loading text is at $0025FD30 +$0A is newline + +stage00.bin +5A 00 5B 14 01 3A 02 $6005 + +THE TEXT IS IN SHIFT JIS THANK YOU FALCOM BLESS FEENA REAH ELDEEN EVERYONE I LOVE YOU FALCOM + +Filename table for SLPM_663.60 +0x00246240 Start +0x00246258 + Base pointer -> 003461D8 file start +0x0024B690 Folder start -> 0034B610 + +from vo1010101.bd to vo4030202.bd + +1829D0 -> 00282950 Start of file info +0x001875E0 Start of folder info +4 bytes: Pointer to folder name/location +4 bytes: File count start? +4 bytes: File count + +3DDFD0 -> 2DE050 + +003461D8 + 1D4D30 -> 41 AF88 -> 31 B008 + +What is 1D4D30? (D4DB0) + +At 2879b4(187A34) is a pointer to 0282950 (1829D0) which points to 246258 which points to + +0x00187A40 has 0034be10 (24BE90) which points the filename of stuff in DATA.BIN + +at 0x00187A28 is 00287560 (1875E0) + +what is 003DF4F0 -> 2DF570 ? + +filename for bmg01.hd is checked at 0012ED74 + +bgm01.hd +filename location is at 0x002462D8 -> 346258 +data file is 0000 09d0 +file start is 11BD +file stop is 02 + +bgm01.sq info: 0x00182F50 -> 282ED0 +filename location is at 0x002467D8 -> 346758 +data file is 1120 +file start is 3EDF +file stop is 03 +file length is 10F2 +file data start is at 0x01F6F800 +file data stop is at 0x01F71000 +file data length is 1800 + +ys3bgm01.sq +filename location is at 246A58 -> 3469D8 +data file is 1120 +file start is 3FE6 +file stop is 03 +file length is 1F1E +file data start is at 0x01FF4800 +file data stop is at 0x01FF6800 +file data length is 2000 + +first seq file is at 1F6F800 + +001342E8 in Ghidra: +At 4 breakpoints, first character is printed +At 8 breakpoints, second +at 12, third +at 14, v0 is 8000 +at 15, v0 is C000 +at 16, fourth +17, fifth +18, 14000 + +lw v1,0x4(v1) +slt at,v0,v1 +bne at,zero,0x001342FC +nop +subu a2,v1,a1 + +When the bne is false +00014000 is v0 +000115B0 is v1 +002879C0 is a0 +000115B0 is a1 +00002A50 is a2 +00402FF4 is a3 + +z_un_00134100 + +In DATA.BIN +0x0024BE80 File names +0x0024BE90 + FFF80 -> 0034BE10 -> 10BE3400 + +0x00187A40 + FFF80 -> 002879C0 start + +0x0018E7CF -> 0028e74f end + +003d2808 + +0x00187A40 is the file table the format is +4 bytes: Pointer to file name (add base pointer) (in little endian) +4 bytes: +4 bytes: Start of file offset +4 bytes: File length + +vo1010101.bd +file length is 500 +data file is 0115B0 +file data start is at 0x001D73F0 + +B0150100 -> 000115B0 + FFF80 + +003DF4F0 + +0x01F6F800 to 0x01F70900 is 1100 + +Main text set is 094BC800, so with pointer it's 0139DA00 + +The text after the opening cutscene is at $094BCE12 + +The text at the opening cutscene is at $094BC862 or $094BC85E or $094BC85A or $094BC858 +0x094BC800 +094BC89B + +095BC7DA -> DAC75B09 + +094BC85E - 0139DA5E = 0811EE00 + +Ghidra pointer is 187A40 or 1879C0 002879C0 +Base pointer is $FFF80 + +Before the text is the expected string length then $80 + +This is loaded from the routine at $001971E8 + +opening cutscene text in hex: + +82A082F182BD814182A0 + +location in memory (eeMemory.bin) + +EF6588 +F6A158 +139DA62 + +true start is at 139DA5A + +look into 0019DCF0 + +from 0x094BC800 to 0x094CBDA0 -> F5A0 + +text routine +0012D23C: +lbu v0,0x0(a1) +addiu a2,a2,-0x1 +addiu a1,a1,0x1 +sb v0,0x0(v1) +addiu v1,v1,0x1 +bne a2,a0,0x0012D23C +nop +jr ra + +first string is 55 dec or $37 (true $36) +second string is 83 dec or $53 (true $52) +third is true $8E + +v0 holds character value +v1 holds memory address +a0 holds 8080808080808080FFFFFFFFFFFFFFFF (negative 1) +a1 holds character address +a2 holds string length +ra holds 00197224 + +0012D23C: +lbu v0,0x0(a1) // The value at (a1+0x0) is stored at v0 +addiu a2,a2,-0x1 // Decrement string length +addiu a1,a1,0x1 // Increment character address +sb v0,0x0(v1) // The value in v0 is stored at (v1+0x0) +addiu v1,v1,0x1 // Increment address of memory +bne a2,a0,0x0012D23C // If a2 != a0, then loop back, so stop looping when string length is done +nop +jr ra // Return + +ghidra output: + + for (; iVar5 != -1; iVar5 = iVar5 + -1) { + uVar1 = *(undefined *)param_2; + param_2 = (undefined8 *)((int)param_2 + 1); + *(undefined *)puVar6 = uVar1; + puVar6 = (undefined8 *)((int)puVar6 + 1); + } + return param_1; + +The character address is stored at 003D2F00 in memory + +GP is 003DA7F0? + +Function at 001bf260 + +void FUN_001bf260(int searchvalue) + +{ + int *pointer; + int counter; + + counter = 0; + uRam003d2ed8 = uRam00f6c054; + uRam003d2ed4 = uRam00f6c058; + uRam003d2ed0 = uRam00f6c068; + pointer = piRam003d2f04; + do { + if (searchvalue == *pointer) goto LAB_001bf2e0; + if ((counter != 0) && (*pointer == 0)) break; + counter = counter + 1; + pointer = pointer + 2; + } while (counter < 0x400); + FUN_0012e570(0x368bf0,uRam003d2edc); + counter = -1; +LAB_001bf2e0: + if (counter != -1) { + uRam003d2ef0 = 1; + FUN_001484a0(uRam00f53d94,0x61,0); + FUN_001484a0(uRam00f53d94,0x3a,0x80); + FUN_001bf0e0((int)piRam003d2f04 + piRam003d2f04[counter * 2 + 1] + 0x2000); + FUN_00103d70(0xf53cd0,0xf53cf0); + } + return; +} + +counter is s0 +searchvalue is v0 +pointer is v1 + +when counter is equal to searchvalue ($01), it is true + +003D2EDC is 00000000 +003D2ED8 is 4016CBE4 +003D2ED4 is 3ED67748 +003D2ED0 is 44DD5FFB +00F53D94 is 0118CB90 +003D2F04 is 0139BA00 + +003d2f04 has $0139BA00 (start of stage00.bin) + +00368bf0 + + +f53cd0 + +loading screen text is at 0x0025FD30 -> 0x0035FCB0 in exe + + +graphics file format +8h: Header starts with NAXA5010 +4h: Usually $100 but sometimes $10 +4h: Always $200 +4h: pointer? +4h: pointer? +4h: idk +4h: nothing +the rest: idk + +There's just raw graphics at 0x0023C180 in slpm +2 dimensional, 32bpp (ARGB) + +anm.bin animation, indexed 8bpp +.hgb texture file, 32bpp rgba +.hgk 3d model file? +.hd music header +.sq music sequence +.bd music header 2 + +0x0019D000 -> 29 CF80 some pointer table + +the font graphic is at $1A3E90 -> 2A3E10 +font map is at 0x001A31F0 -> 2A3170 +palette is at 0x0025E4C0 + +FUN_0014f370 is to search the index of a character + +0035FE30 (conv) is No Ys 3 Data +0035FDF0 (conv) is Ys Data Found +00360AF0 (conv) is Ys 3 Data search + +FUN_0017b900 checks for save data with link option + +stage90.bin has the text for the titlescreen cutscene + +cartographer stuff + +#BLOCK NAME:stage00.bin +#TYPE: NORMAL +#METHOD: POINTER_RELATIVE +#POINTER ENDIAN: LITTLE +#POINTER TABLE START: $94BA804 +#POINTER TABLE STOP: $94BB410 +#POINTER SIZE: $04 +#POINTER SPACE: $04 +#ATLAS PTRS: Yes +#BASE POINTER: $94BC800 +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + +#BLOCK NAME:stage00.bin RAW +#TYPE: NORMAL +#METHOD: RAW +#SCRIPT START: $94BC800 +#SCRIPT STOP: $94CBD9F +#TABLE: kefin.tbl +#COMMENTS: No +#SHOW END ADDRESS: No +#TRIM TRAILING NEWLINES: No +#END BLOCK + diff --git a/script.py b/script.py new file mode 100644 index 0000000..886440e --- /dev/null +++ b/script.py @@ -0,0 +1,71 @@ +def extract(stagefile, logfile, data): + script = open(f"scripts/{stagefile}", "rb") + + log = open(f"scripts/{logfile}", "w") + log.write(f"{stagefile} header info\n") + + currentread = 0x0 + + endcode = 0x0 + endsize = 0x2 + + count = 0x0 + val1 = 0x0 + val2 = 0x0 + trueoffset = 0x0 + dataoffset = data + + offset = 0x2000 + + known = [b'\x00\xff', b'\x32\xff', b'\x11\xff', b'\x02\xff', b'\x4E\xff', b'\x01\xff', b'\x64\xff', b'\x04\xff', b'\x55\xff', b'\x07\xff', b'\x06\xff', b'\x56\xff'] + ignore = [b'\xa5\xff'] + + #known = [b'\x00\x00\x00\xff', b'\x02\x00\x00\xff', b'\x04\x00\x00\xff', b'\x00\x4E\x4E\xff'] + #ignore = [b'\x68\x81\xa5\xff', b'\x49\x81\xa5\xff', b'\x42\x81\xa5\xff', b'\x48\x81\xa5\xff',] + + isknown = "" + + while count < 0x400: + + script.seek(currentread) + + val1 = script.read(4) + val2 = script.read(4) + + val1 = int.from_bytes(val1, "little") + val2 = int.from_bytes(val2, "little") + + trueoffset = val2 + offset + dataoffset = dataoffset + trueoffset + + script.seek(trueoffset - endsize) + endcode = script.read(endsize) + + if endcode in known: + isknown = "KNOWN" + elif endcode in ignore: + isknown = "ignore" + else: + isknown = "NEW" + + if val1 == val2 == 0: + break + + log.write(f"Entry Order {count:X}\tEntry Order Offset {currentread:X}\tEntry Number {val1:X}\tOffset {val2:X}\tTrue Offset {trueoffset:X}\tDATA.BIN Offset {dataoffset:X}\tEnd code {endcode}\t{isknown}\n") + + count = count + 1 + + currentread = currentread + 0x08 + +extract("stage00.bin", "script00.txt", 0x94BA800) +extract("stage10.bin", "script10.txt", 0x94CC000) +extract("stage20.bin", "script20.txt", 0x94D4800) +extract("stage30.bin", "script30.txt", 0x94DE000) +extract("stage40.bin", "script40.txt", 0x94E1800) +extract("stage50.bin", "script50.txt", 0x94EB800) +extract("stage60.bin", "script60.txt", 0x94F3000) +extract("stage70.bin", "script70.txt", 0x94FC800) +extract("stage80.bin", "script80.txt", 0x9502000) +extract("stage90.bin", "script90.txt", 0x950E800) +extract("stagea0.bin", "scripta0.txt", 0x9516800) +extract("stageb0.bin", "scriptb0.txt", 0x9519000) \ No newline at end of file diff --git a/scripts/abcde/abcde.pl b/scripts/abcde/abcde.pl new file mode 100644 index 0000000..0ee3cac --- /dev/null +++ b/scripts/abcde/abcde.pl @@ -0,0 +1,268 @@ +#!/usr/bin/perl + +# abw's basic custom data encoder + +package abcde; + +use strict; +use warnings; + +my $usage = < [-cm []] + +In its most basic form, this program reads data from STDIN, translates it according to the provided table files and +other general options, and writes it to STDOUT. This form is useful for integration into other programs (e.g. hex +editors, (dis)assemblers, etc.) and for examining the translation process in detail, but is unlikely to be of much +interest to the average user as its scope is limited to the translation of data that should be translated and makes +no attempt to e.g. update pointers or exclude portions of the input data from translation. + +The average user is more likely to be interested in the command modules. Currently, varying levels of support for Atlas +and Cartographer command files have been implemented; see those modules' documentation for more details. + +Available required options: +-m / --mode : select operation mode; value can be either 'bin2text', in which case binary data on + STDIN is translated to text on STDOUT, or 'text2bin', in which case text data on STDIN is translated to binary + data on STDOUT. +-t / --table
: specify the file name of a table file to use in translation. Include this option + once for each table file to be used in translation. Note that when provided on the command line, relative + paths are assumed to be anchored at the current directory. + +Available optional options: +-g / --group: instead of normal output, print the output grouped by token (primarily used for debug, but also available + for interest's sake). +-h / --help: print this help text and exit; if used in conjunction with -cm , instead print help + text for the specified command module and exit. +-brp / --base-relative-path : sets the base relative path used by command modules to instead of the + current directory; see command module documentation for details including any special values. +-s / --stats: after normal output, print some statistics to STDERR. +--artificial-end-token
) { + $line =~ s/\R\z//; # strip newline + if ($. == 1) { + # strip out Unicode BOM if present + $line =~ s/^\x{EF}\x{BB}\x{BF}//; + } + next if ($line eq ''); + next if (substr($line, 0, 1) eq '#'); # ignore comments + $line = eval { Encode::decode('UTF-8', $line, 1); }; # check to see whether $line is valid UTF-8 + if ($@) { + die("error: $@ when reading $fileName line $.\n"); + } + $line = Unicode::Normalize::NFD($line) if ($abcde::options{unicode_normalization}); + if ($line =~ /^@([^$abcde::reserved_chars->{open}$abcde::reserved_chars->{close}]+)$/) { + # table id: @tableId + my $id = $1; + if (defined($table->{id})) { + if ($abcde::options{allowMultipleTablesPerFile}) { + # start a new table + $table = bless ({ + fileName => $fileName, + id => $id, + }, $class); + push(@tables, $table); + } else { + die("too many table IDs at '$fileName' line $.!\nIn order to use multi-table files, you need to add the switch --multi-table-files to your abcde command\n"); + } + } else { + $table->{id} = $id; + } + } else { + my $token = abcde::Table::Token->parseLine($table, $line, $.); + if (defined($table->{tokensByBin}->{$token->{bin}})) { + # In cases like hiragana he vs. katakana he or normal kana vs. small kana, it might be useful to allow different text entries to have the same hex; + # this idea is currently filed under "more trouble than it's worth". + die("duplicate binary value at '$fileName' lines $table->{tokensByBin}->{$token->{bin}}->{lineNum} and $.!\n"); + } + $table->{tokensByBin}->{$token->{bin}} = $token; + if ($token->{params}) { + push(@{$table->{switchTokensByBin}}, $token); + } + if ($token->{flags}->{isEndToken}) { + $table->{canReachEndToken} = 1; + } + } + } + close(TABLE); + + return \@tables; +} + +sub finalize { + my ($table) = @_; + + return if ($table->{finalized}); + $table->{participatesInSwitching} //= 0; + if ($table->{switchTokensByBin}) { + $table->{participatesInSwitching} = 1; + $table->{switchTokensByBin} = [sort {$a->{bin} cmp $b->{bin}} @{$table->{switchTokensByBin}}]; # sort to encourage determinism + foreach my $token (@{$table->{switchTokensByBin}}) { + my @paramStack = (); + foreach my $num (0..scalar(@{$token->{params}}) - 1) { + my $param = $token->{params}->[$num]; + # add direct references to each parameter's table, defaulting parameters with no table ID to $abcde::rawTable + $param->{table} = (defined($param->{table_id}) ? $abcde::tablesByID{$param->{table_id}} : ($param->{rawType} eq 'bin' ? $abcde::rawBitTable : $abcde::rawTable)); + if (!$param->{table}) { + die("table '$table->{fileName}' contains a control code table switch parameter to non-existant table '$param->{table_id}' (did you forget to load whatever file contains that table?)"); + } + push(@{$table->{child_tables}}, $param->{table}); + $param->{table}->{participatesInSwitching} = 1; + # setup stack requirements for insertion + push(@paramStack, {%$param}); + $table->{switchTokens}->{$param->{table}} ||= abcde::Table::Token->create($table, {S => 1}, '', 0, ''); # token for switching from this table to $param->{table} + } + $token->{paramStack} = \@paramStack; + } + } + if ($table ne $abcde::rawTable && $table ne $abcde::rawBitTable) { + $table->{switchTokens}->{$abcde::rawTable} ||= abcde::Table::Token->create($table, {S => 1}, '', 0, ''); # token for switching from this table to $abcde::rawTable + $table->{rawTableSwitchToken} = abcde::Table::Token->create($table, {}, '', 0, ''); + $table->{rawTableSwitchToken}->{params} = [{table => $abcde::rawTable, requiredCount => 1}]; # the actual switch parameter + } + + # sort by descending length so that we try matching longer left-hand sides before shorter left-hand sides + $table->{binPat} = join('|', sort {length($b) <=> length($a)} keys %{$table->{tokensByBin}}); + $table->{binPat} = ($table->{binPat} eq '' ? qr/^$/ : qr/$table->{binPat}/); + + # determine which binary suffixes can be added to each of our tokens to turn them into one of our other tokens + # determine maxBinLength for use in bin2text and allTokensHaveSameBinLength for use in text2bin + $table->{maxBinLength} = 0; + $table->{allTokensHaveSameBinLength} = 1; + my $tableBinLength; + my @bins = sort keys %{$table->{tokensByBin}}; + for (my $i = 0; $i <= $#bins; $i++) { + my $token = $table->{tokensByBin}->{$bins[$i]}; + my $binLength = length($bins[$i]); + for (my $j = 1; $j <= $#bins - $i; $j++) { + if ($bins[$i] eq substr($bins[$i + $j], 0, $binLength)) { + $token->{unusableSuffixes}->{substr($bins[$i + $j], $binLength)} = $table->{tokensByBin}->{$bins[$i + $j]}; + } else { + last; + } + } + if ($table->{allTokensHaveSameBinLength}) { + $tableBinLength //= $binLength; + if ($binLength != $tableBinLength) { + $table->{allTokensHaveSameBinLength} = 0; + } + } + $table->{maxBinLength} = List::Util::max($table->{maxBinLength}, $binLength); + next if ($token->{text} eq ''); + push(@{$table->{tokensByFirstChar}->{substr($token->{text}, 0, 1)}}, $token); + $abcde::minBinPerText = List::Util::min($abcde::minBinPerText, $token->{binLength} / $token->{textLength}); # A* cost heuristic factor + } + + $table->{finalized} = 1; +} + +sub canReachEndToken { + my ($self, $seen) = @_; + + $seen->{$self} = 1; # prevent infinite loop + foreach my $table (@{$self->{child_tables}}) { + if ($seen->{$table}) { + $self->{canReachEndToken} ||= $table->{canReachEndToken}; + next; + } + $table->canReachEndToken($seen); + $self->{canReachEndToken} ||= $table->{canReachEndToken}; + } +} + +sub getAllTextMatches { + my ($self, $stringRef, $pos) = @_; + + my @tokenList = (); + my $char = substr($$stringRef, $pos, 1); + foreach my $token (@{$self->{tokensByFirstChar}->{$char}}) { + if (substr($$stringRef, $pos, $token->{textLength}) eq $token->{text}) { + push(@tokenList, $token); + } + } + + return \@tokenList; +} + +# in order to save memory, all the raw bit/byte entries we use will be references to entries in this table +sub generateRawTable { + my ($class) = @_; + + my $self = bless ({ + participatesInSwitching => 1, + }, $class); + foreach my $num (0..255) { + my $token = abcde::Table::Token->create($self, {B => 1}, '%'.sprintf('%08b', $num), 1, $abcde::reserved_chars->{open}.'$'.sprintf('%02X', $num).$abcde::reserved_chars->{close}); + $self->{tokensByBin}->{$token->{bin}} = $token; + } + foreach my $num (0..1) { + my $token = abcde::Table::Token->create($self, {B => 1}, "%$num", 1, $abcde::reserved_chars->{open}.'%'.$num.$abcde::reserved_chars->{close}); + $self->{tokensByBin}->{$token->{bin}} = $token; + } + + return $self; +} + +sub generateRawBitTable { + my ($class) = @_; + + my $self = bless ({ + participatesInSwitching => 1, + }, $class); + foreach my $num (0..1) { + my $token = abcde::Table::Token->create($self, {B => 1}, "%$num", 1, $abcde::reserved_chars->{open}.'%'.$num.$abcde::reserved_chars->{close}); + $self->{tokensByBin}->{$token->{bin}} = $token; + } + + return $self; +} + +# Translates a hex string to text based on the current table. +# In order to translate properly, we need to know which bits to translate and which bits to ignore. +# This function handles the most common case, where +# 1) the start address is known (usually via pointer logic) +# 2) the end address is one of +# a) a known number of bits after the start address +# b) a known number of tokens (either in the current table only or including sub-tables as per the table switch token's definition) after the start address +# c) the last bit of the first end token encountered +# 3) all of the bits in between the start and end addresses are intended to be translated +# +# $binRef: reference to raw binary to translate (copying extremely large scalars like $abcde::data around has definite performance impacts!) +# $startPos: bit offset from beginning of $binRef indicating where to begin translation +# $options: hashref containing other translation configurations: +# autoJumps: arrayref of hashrefs, where the hashrefs have keys "start" and "stop" with integer values and the arrayref is sorted by the hashrefs' "start" values; when position "start" has been read, the read position will be changed to "stop" +# endTokenTerminated: if true, translation will stop when an end token has been read +# endAddress: if >= 0, translation will stop when this address is reached +# numTokens: arrayref, if any value > 0, translation will stop when that many tokens have been read +# param: if defined, the parameter that triggered switching to this table +# stringEndReAlignMultiple: if defined, a positive integer that will be used along with stringEndReAlignOffset to update the current read position after matching an end token +# stringEndReAlignOffset: if defined, a positive integer that will be used along with stringEndReAlignMultiple to update the current read position after matching an end token +# $previousTable: if defined, the previous table on the stack +# +# Returns an array of tokens representing $$binRef between the calculated start and end addresses. +sub bin2text { + my ($self, $binRef, $startPos, $options, $previousTable) = @_; + + my $curPos = $startPos; + my @tokenList = (); + my $endTokensSeen = 0; + my $numTokens = $options->{numTokens} || []; + +my $debug = 0; +print STDERR "bin2text in ".($self->{fileName} || $abcde::reserved_chars->{open}.'internal table'.$abcde::reserved_chars->{close})." (startPos=$startPos, endAddress=".($options->{endAddress}||'').", numTokens=".$abcde::reserved_chars->{open}.join(',', @$numTokens).$abcde::reserved_chars->{close}.", endTokenTerminated=$options->{endTokenTerminated})\n" if ($debug); +TABLE: + while (1) { + my $prevPos = $curPos; # remember where we started from in case we need to revert an incomplete table switch + + # figure out what string we're going to try matching against, considering potential autoJumps + my $matchBin = ''; + my @autoJumps = (); + if ($options->{autoJumps} && scalar(@{$options->{autoJumps}})) { + my $matchPos = $curPos; + my $matchLength = $self->{maxBinLength}; + foreach my $autoJump (@{$options->{autoJumps}}) { + if ($matchPos <= $autoJump->{start} && $autoJump->{start} < $matchPos + $matchLength) { + # in order to correctly match the next token, we're going to have to glue two sections of $$binRef together + my $initLength = $autoJump->{start} - $matchPos; + $matchBin .= substr($$binRef, $matchPos, $initLength); + $matchPos = $autoJump->{stop}; + $matchLength -= $initLength; + push(@autoJumps, $autoJump); + } + } + $matchBin .= substr($$binRef, $matchPos, $matchLength); + } else { + my $readLength = $self->{maxBinLength} || 8; # || 8 in case table has no entries! + die("Attempt to read beyond end of ROM!") if ($abcde::options{errorEOF} && $curPos + $readLength > length($$binRef)); + $matchBin = substr($$binRef, $curPos, $readLength); # || 8 in case table has no entries! + } + if (defined($options->{endAddress}) && $options->{endAddress} >= 0) { + $matchBin = substr($matchBin, 0, $options->{endAddress} - $curPos); + } + + if (!defined($matchBin) || $matchBin eq '') { + # if there's nothing to match, we're all done with this table + last; + } + + # try to match a token against that string + my $token; + if (length($matchBin) && defined($options->{param}) && defined($options->{param}->{FFToken}) && $matchBin =~ m/^($options->{param}->{FFToken}->{bin})/) { + $token = $options->{param}->{FFToken}; + } elsif (length($matchBin) && $matchBin =~ m/^($self->{binPat})/) { + $token = $self->{tokensByBin}->{$1}; + } else { + # couldn't match another token - either we we have reached the end of $$binRef, we have encountered an unparseable token, or we have no tokens in the first place + if ($curPos == length($$binRef)) { + # if we've reached the end of $$binRef, we're all done with this string + last; + # otherwise, it's not one of our tokens, so switch to $abcde::rawTable and continue matching there + } else { + warn ("unable to match another token in the current table at $curPos; are you sure you really understand how the text is encoded?") if ($debug); + $token = $self->{rawTableSwitchToken}; +# TBD: unexpected raw token match should still count towards numTokens + } + } + push(@tokenList, $token); + + # figure out where we ended up after crossing any autoJumps + if (scalar(@autoJumps)) { + my $matchLength = $token->{binLength}; + foreach my $autoJump (@autoJumps) { + if ($curPos <= $autoJump->{start} && $autoJump->{start} < $curPos + $matchLength) { + $matchLength -= $autoJump->{start} - $curPos; # amount of token that was consumed before jumping + $curPos = $autoJump->{stop}; + } + } + $curPos += $matchLength; + } else { + $curPos += $token->{binLength}; + } + + # update the status of some options + for (my $i = 0; $i < scalar(@$numTokens); $i++) { + $numTokens->[$i] -= $token->{numTokens}; + } + + # if we matched the forced fallback token, we're all done + if (defined($options->{param}) && defined($options->{param}->{FFToken}) && $token eq $options->{param}->{FFToken}) { + last; + } + + # handle any table switches + if ($token->{params}) { + foreach my $param (@{$token->{params}}) { + if ($param->{requiredCount} eq '-1') { + # fallback to previous table + push(@tokenList, $abcde::internalTokens{FF}); + last TABLE; + } elsif ($curPos == length($$binRef)) { + # we're trying to switch to another table, but the string has already ended, which means the control code token is invalid + warn("binary string ended before all control code parameters could be matched!"); + last; + } + # switch tables then increment pos by however many bits the sub-table matched + my %newOptions = %$options; # most options apply to the entire string; update options that differ for the sub-table + $newOptions{numTokens} = ($param->{addNumTokens} ? $numTokens : []), + push(@{$newOptions{numTokens}}, $param->{requiredCount}) if ($param->{requiredCount}); + $newOptions{param} = $param; + if (!$param->{FFToken}) { + if ($param->{table} eq $abcde::rawTable) { + $newOptions{endAddress} = $curPos + 8 * ($param->{requiredCount} // 1) + 1; + } elsif ($param->{table} eq $abcde::rawBitTable) { + $newOptions{endAddress} = $curPos + ($param->{requiredCount} // 1) + 1; + } + } + (my $subTokens, $curPos, my $subEndTokens) = $param->{table}->bin2text($binRef, $curPos, \%newOptions, $self); + $endTokensSeen += $subEndTokens; + push(@tokenList, $self->{switchTokens}->{$param->{table}}, @$subTokens); + } + } # else: nothing more to do here + + if ($options->{endTokenTerminated} && $token->{flags}->{isEndToken}) { + $endTokensSeen++; + if (defined($options->{stringEndReAlignMultiple}) && $options->{stringEndReAlignMultiple} > 0) { + # re-align read position to the next multiple of $options->{stringEndReAlignMultiple} starting from $options->{stringEndReAlignOffset} + $curPos = $options->{stringEndReAlignMultiple} * POSIX::ceil(($curPos - $options->{stringEndReAlignOffset}) / $options->{stringEndReAlignMultiple}) + ($options->{stringEndReAlignOffset}||0); + } + } + if ($options->{endTokenTerminated} && $endTokensSeen) { + # if we've reached one of the end conditions, kick all the way out, which will fall back to parent table if we're a sub table + last; + } + for (my $i = 0; $i < scalar(@$numTokens); $i++) { + if ($numTokens->[$i] == 0) { + # push appropriate FC token + push(@tokenList, $abcde::internalTokens{FC}); + last TABLE; + } + } + } + + return (\@tokenList, $curPos, $endTokensSeen); +} + +# determining end of $$stringRef is caller's responsibility +# caller is also responsible for newline stripping (newlines must be ignored for insertion purposes) +# TBD: pre-process string to condense substrings with only one possible tokenization into a single node to avoid re-computing unique paths from different starting states (e.g. Pascal string tables) +sub text2bin { + my ($startTable, $stringRef) = @_; + + # text2bin implements an A* graph search algorithm with a couple of tweaks to avoid exploring redundant tokenizations; + # at a high level, the algorithm looks like this: + # + # create priority queue + # enqueue empty root node for ^ + # loop: + # curNode = dequeue lowest priority node + # discover accessible nodes from curNode + # for each accessible node newNode loop: + # if newNode's tokenization is equivalent (same string position + same pending table switch conditions) to any previously examined node with lower or equal cost, discard newNode + # else if newNode is end of string and satisfies acceptability criteria (is an end token or has no pending table switch conditions) + # return list of tokens by following newNode's parent pointers all the way back to root node + # else + # enqueue newNode with priority = A* cost heuristic + # add newNode to list of previously examined nodes + # return error + + # some things to watch out for: + # + infinite table switch loops + # + need to keep track of number of tokens per table for table switch tokens requiring a specific number of tokens in the destination table + # + need to keep track of table switch stack + # + sequences of tokens whose concatenated binary would be interpreted as a different sequence of tokens by the (longest-leftmost) extraction algorithm, e.g. (a)(b) when table contains a token for (ab) + # + branches that rejoin - e.g. assuming binary cost and table stack conditions are the same, tokenization (a)(bc) is equivalent to tokenization (ab)(c) and we don't want to repeat investigating paths from the end of c + + $Table::text2bin_stringRef = $stringRef; + $Table::text2bin_stringRef_length = length($$stringRef); + my @nodesByPos = (); + $#nodesByPos = $Table::text2bin_stringRef_length + 1; # pre-extend array to avoid repetitive copying during automatic resizing + foreach my $table (@abcde::allTables) { + delete $table->{tokensByPos}; # make sure there's nothing left over from a previous invocation + } + delete $abcde::rawTable->{tokensByPos}; # make sure there's nothing left over from a previous invocation + delete $abcde::rawBitTable->{tokensByPos}; # make sure there's nothing left over from a previous invocation + my $root = abcde::Table::AStarNode->create(undef, 0, [{table => $startTable, requiredCount => 0, currentCount => 0, FFToken => undef}], undef); # ($parent, $pos, $stack, $token) + my $activeNodes = Hash::PriorityQueue->new(); + $activeNodes->insert($root, $root->{minCost}); + my $farthestNode = $root; + my @tokenization = (); +SEARCHING: + while (my $node = $activeNodes->pop()) { + my $newNodes = $node->discoverNodes(); + foreach my $newNode (@$newNodes) { +#print STDERR __LINE__.": newNode: pos:$newNode->{pos}, stackStr:'$newNode->{stackStr}', nodesByPos:".(defined($nodesByPos[$newNode->{pos}]->{$newNode->{stackStr}})).", unusableSuffixes:".scalar(keys(%{$newNode->{unusableSuffixes}}))."\n"; + next if ($nodesByPos[$newNode->{pos}]->{$newNode->{stackStr}} && scalar(keys(%{$newNode->{unusableSuffixes}})) == 0); # once we're sure that the existing tokenization is stable, skip nodes that are just equivalent tokenizations of things we've already seen + if ($farthestNode->{pos} < $newNode->{pos}) { + $farthestNode = $newNode; +#print STDERR "reached pos $newNode->{pos}\n"; + } + if ($newNode->{pos} == $Table::text2bin_stringRef_length) { + # if we have reached the end of the string and the current token is an end token or there are no unfulfilled table stack conditions, we're done + my $unfulfilled = 0; + foreach my $stack (@{$newNode->{tableStack}}) { + if ($stack->{requiredCount} && (!$stack->{currentCount} || $stack->{requiredCount} > $stack->{currentCount})) { + $unfulfilled = 1; + } + } + + if (!$unfulfilled || $newNode->{token}->{flags}->{isEndToken}) { + while ($newNode->{parent}) { + push(@tokenization, $newNode->{token}); + $newNode = $newNode->{parent}; + } + last SEARCHING; + } + } + $nodesByPos[$newNode->{pos}]->{$newNode->{stackStr}} = 1; # remember that we've seen a tokenization that reaches this pos with this stack + $activeNodes->insert($newNode, $newNode->{minCost}); + } + } + + if (!@tokenization) { + #TBD: die makes us not print stats :( + my $farthestPos = $farthestNode->{pos}; + while ($farthestNode->{parent}) { + push(@tokenization, $farthestNode->{token}); + $farthestNode = $farthestNode->{parent}; + } +# print STDERR join("\n", map {"(".($_->{table}->{fileName} // '').",[".join(',', sort keys %{$_->{flags}})."]:$_->{bin}/$_->{text})"} reverse(@tokenization))."\n"; + my $context = 20; + my $start = ($farthestPos > $context ? $farthestPos - $context : 0); + my $pre_context_length = $farthestPos - $start; + die("unable to tokenize; best attempt failed at input position $farthestPos at ^ indicator in\n" + .($pre_context_length == 0 ? " " : "") + .substr($$stringRef, $start, $pre_context_length + $context)."\n" + .substr($$stringRef, $start, $pre_context_length)."^\n" + ."(does your table file contain a \"".substr($$stringRef, $farthestPos, 1)."\"?)\n"); + } + +#print STDERR join("\n", map {"($_->{table}->{fileName},"$abcde::reserved_chars->{open}.join(',', sort keys %{$_->{flags}}).$abcde::reserved_chars->{close}":$_->{bin}/$_->{text})"} reverse(@tokenization))."\n"; + return [reverse(@tokenization)]; +} + + +1; diff --git a/scripts/abcde/abcde/Table/Token.pm b/scripts/abcde/abcde/Table/Token.pm new file mode 100644 index 0000000..93cc321 --- /dev/null +++ b/scripts/abcde/abcde/Table/Token.pm @@ -0,0 +1,119 @@ +package abcde::Table::Token; + +use strict; +use warnings; + +sub create { + my ($class, $table, $flags, $bin, $numTokens, $text, $line, $lineNum) = @_; + + if (defined($text)) { + if ($abcde::options{mode} eq 'bin2text') { + $text =~ s/\\n/\n/g; + } elsif ($abcde::options{mode} eq 'text2bin') { + $text =~ s/\\n//g; + } + } + + $bin = (substr($bin, 0, 1) eq '%' ? substr($bin, 1) : unpack('B'.(length($bin)*4), pack('H'.length($bin), $bin))); # if $bin has a leading %, it's already in binary form, otherwise it's in hexadecimal form + my $self = { + bin => $bin, + binLength => length($bin), + flags => $flags, + line => $line || $text, + lineNum => $lineNum || 'N/A', + numTokens => $numTokens, + table => $table, + text => $text, + textLength => length($text), + }; + + return bless ($self, $class); +} + +sub parseLine { + my ($class, $table, $line, $lineNum) = @_; + + pos($line) = 0; + my ($flags, $prefixes, $bin, $numTokens, $text) = ({}, '', '', 1, ''); + if ($line =~ m/\G([!\/]+)/gc) { # check for ! and / + $prefixes = $1; + } + if ($prefixes =~ s/\///) { + $flags->{isEndToken} = 1; + } + if ($prefixes =~ s/!//) { + $flags->{hasSwitchToken} = 1; # the documentation refers to these as switch tokens, but the switching doesn't actually happen until the start of each parameter, so we'll name the variable to reflect that + } + if ($prefixes ne '') { # extra unrecognized prefixes + die("unrecognized table entry '$line' at '$table->{fileName}' line $lineNum (unrecognized prefix '$prefixes')\n"); + } + if ($line =~ m/\G(%[01]+|[0-9A-Fa-f]+)/gc) { # binary or hex string + $bin = $1; + } else { + die("unrecognized table entry '$line' at '$table->{fileName}' line $lineNum (not a binary or hexadecimal string)\n"); + } + if ($line =~ m/\G$abcde::reserved_chars->{open}(-?(?:0|[1-9][0-9]*))$abcde::reserved_chars->{close}/gc) { # match count modifier + $numTokens = $1; + } + die("unrecognized table entry '$line' at '$table->{fileName}' line $lineNum (no '=' separator)\n") unless ($line =~ m/\G=/gc); # = separating lhs from rhs + my $token; + if ($flags->{hasSwitchToken}) { + my $label = ''; + if ($line =~ m/\G$abcde::reserved_chars->{open}([^\$$abcde::reserved_chars->{open}$abcde::reserved_chars->{close}][^$abcde::reserved_chars->{open}$abcde::reserved_chars->{close}]*)$abcde::reserved_chars->{close}/gc) { #