mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-09-25 07:58:04 +03:00
Compare commits
88
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82c8b76a58 | ||
|
|
1918350b19 | ||
|
|
9504ee7b65 | ||
|
|
f033a507d3 | ||
|
|
fbeb9a780e | ||
|
|
8c69f53073 | ||
|
|
cc96c85381 | ||
|
|
a2618319d9 | ||
|
|
30fd5768da | ||
|
|
15a769d83c | ||
|
|
253de6adc8 | ||
|
|
a0daa3261c | ||
|
|
98e9d8bcfb | ||
|
|
b7854aaec1 | ||
|
|
905eb34590 | ||
|
|
8f22566adb | ||
|
|
48ded43e2a | ||
|
|
571bec63a2 | ||
|
|
345c017c22 | ||
|
|
205004086b | ||
|
|
6820bcfcb8 | ||
|
|
5ce1494b59 | ||
|
|
dd45e566f6 | ||
|
|
1ccc7630c1 | ||
|
|
6456f59c37 | ||
|
|
f748e8f678 | ||
|
|
a9e23508b7 | ||
|
|
c3bd978f02 | ||
|
|
50a6b17c5e | ||
|
|
0d49619366 | ||
|
|
da3cc5d900 | ||
|
|
1785e93fcc | ||
|
|
a77e849f82 | ||
|
|
978dbdbc3b | ||
|
|
e3c168c5a6 | ||
|
|
9f8c2af842 | ||
|
|
5d8b1c5632 | ||
|
|
30188c3a4f | ||
|
|
a627a8ea3d | ||
|
|
0cf9c1fe8d | ||
|
|
0887c44292 | ||
|
|
27a0c89a73 | ||
|
|
5c827225ab | ||
|
|
bc37ba6256 | ||
|
|
ab4bc2d8d1 | ||
|
|
f26321c5e0 | ||
|
|
1d897c72d0 | ||
|
|
172c76b4e2 | ||
|
|
100584f896 | ||
|
|
975f618b53 | ||
|
|
0c8bab0c64 | ||
|
|
0192fd3d8e | ||
|
|
d69fc5c6a3 | ||
|
|
68a39843e2 | ||
|
|
e3d7b60785 | ||
|
|
2bb891ada8 | ||
|
|
f109fe11f5 | ||
|
|
73b3377b77 | ||
|
|
9400572502 | ||
|
|
a1e063c4b2 | ||
|
|
602c55a5e5 | ||
|
|
9624192a41 | ||
|
|
5c7436e2b1 | ||
|
|
6c9844697f | ||
|
|
210c0a13e4 | ||
|
|
3ebb1faece | ||
|
|
286f150510 | ||
|
|
a194cf10a6 | ||
|
|
9587d350ec | ||
|
|
02f62d51bb | ||
|
|
54b98ec3e4 | ||
|
|
8cde827ee6 | ||
|
|
a5d67b067c | ||
|
|
5cb70110b9 | ||
|
|
e3dcadd5dd | ||
|
|
ff31d03153 | ||
|
|
63886d7d00 | ||
|
|
c119c2f969 | ||
|
|
fb63d42ec1 | ||
|
|
6f631d073d | ||
|
|
49dca57fbd | ||
|
|
c8987da470 | ||
|
|
0dfb3eb378 | ||
|
|
269132fede | ||
|
|
651fc21a19 | ||
|
|
03f86bc4d7 | ||
|
|
4ffab8e4e9 | ||
|
|
1593452146 |
@@ -15,7 +15,7 @@ jobs:
|
|||||||
- name: Install Deps
|
- name: Install Deps
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libportmidi-dev libcjson-dev asciidoctor
|
sudo apt install libsdl2-dev libfreetype-dev libsdl2-mixer-dev libwebp-dev libportmidi-dev libcjson-dev asciidoctor gettext
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
@@ -27,3 +27,16 @@ jobs:
|
|||||||
- name: Test
|
- name: Test
|
||||||
run: ctest --output-on-failure
|
run: ctest --output-on-failure
|
||||||
working-directory: out/${{ matrix.build-type }}
|
working-directory: out/${{ matrix.build-type }}
|
||||||
|
|
||||||
|
- name: Verify xsystem35.pot is up to date
|
||||||
|
if: matrix.build-type == 'Debug'
|
||||||
|
run: |
|
||||||
|
xgettext --default-domain=xsystem35 --directory=. \
|
||||||
|
--keyword=_ --keyword=N_ \
|
||||||
|
--files-from=po/POTFILES.in \
|
||||||
|
--output=/tmp/fresh.pot
|
||||||
|
if ! diff <(grep '^msgid' po/xsystem35.pot | sort) \
|
||||||
|
<(grep '^msgid' /tmp/fresh.pot | sort); then
|
||||||
|
echo "::error::po/xsystem35.pot is out of date. Build the 'pot' target and commit the changes under po/."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
msystem: ${{ matrix.sys }}
|
msystem: ${{ matrix.sys }}
|
||||||
pacboy: >-
|
pacboy: >-
|
||||||
SDL2:p
|
SDL2:p
|
||||||
SDL2_ttf:p
|
freetype:p
|
||||||
SDL2_mixer:p
|
SDL2_mixer:p
|
||||||
libwebp:p
|
libwebp:p
|
||||||
${{ matrix.deps }}
|
${{ matrix.deps }}
|
||||||
|
|||||||
@@ -1,5 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2.20.0 - 2026-09-11
|
||||||
|
- Improved font rendering to more closely match the original engine. On
|
||||||
|
Windows, MS Gothic and MS Mincho are now used by default when available.
|
||||||
|
- The experimental `enable_zb` option has been removed. (#44)
|
||||||
|
- SACT: Message skipping now also skips text animation, effects, waits, and
|
||||||
|
related input waits.
|
||||||
|
- SACT: BGM now honors the loop count specified by the game.
|
||||||
|
- SACT: Fixed timer handling in 楽園行.
|
||||||
|
- The popup menu and dialogs can now be operated with the keyboard.
|
||||||
|
- Fixed mouse coordinates changing unexpectedly when automatic mouse movement
|
||||||
|
is disabled in System 3.8/3.9 games.
|
||||||
|
- Android: The status bar now stays hidden after returning to the game. (#81)
|
||||||
|
- Debugger: Added an `info cache` command for viewing cache usage and hit rates.
|
||||||
|
|
||||||
|
## 2.19.1 - 2026-08-02
|
||||||
|
- Fixed an issue that prevented moving upward during battles in Rance 4.
|
||||||
|
|
||||||
|
## 2.19.0 - 2026-07-19
|
||||||
|
- Replaced the GTK-based popup menu and dialogs with a pure-SDL implementation.
|
||||||
|
- On Android, the popup menu opens with a three-finger tap.
|
||||||
|
- Android: Added installation directly from CD-ROM images.
|
||||||
|
- Implemented volume control panel.
|
||||||
|
- Added `mute_on_unfocus` option to mute audio while the window is unfocused.
|
||||||
|
|
||||||
## 2.18.0 - 2026-06-23
|
## 2.18.0 - 2026-06-23
|
||||||
- Added support for the intro demo of Daiakuji.
|
- Added support for the intro demo of Daiakuji.
|
||||||
- Replaced the bundled mincho font with IPA Mincho.
|
- Replaced the bundled mincho font with IPA Mincho.
|
||||||
|
|||||||
+25
-22
@@ -5,7 +5,7 @@ set(CMAKE_C_STANDARD 99)
|
|||||||
enable_testing()
|
enable_testing()
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||||
|
|
||||||
set(XSYSTEM35_VERSION "2.18.0")
|
set(XSYSTEM35_VERSION "2.20.0")
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
@@ -55,6 +55,8 @@ check_symbol_exists(mmap "sys/mman.h" HAVE_MMAP)
|
|||||||
check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION)
|
check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION)
|
||||||
|
|
||||||
if (EMSCRIPTEN)
|
if (EMSCRIPTEN)
|
||||||
|
option(JSPI "Use JavaScript Promise Integration instead of Asyncify" OFF)
|
||||||
|
|
||||||
function(add_emscripten_library name option)
|
function(add_emscripten_library name option)
|
||||||
add_library(${name} INTERFACE)
|
add_library(${name} INTERFACE)
|
||||||
set_target_properties(${name} PROPERTIES
|
set_target_properties(${name} PROPERTIES
|
||||||
@@ -63,14 +65,14 @@ if (EMSCRIPTEN)
|
|||||||
endfunction()
|
endfunction()
|
||||||
add_emscripten_library(zlib -sUSE_ZLIB=1)
|
add_emscripten_library(zlib -sUSE_ZLIB=1)
|
||||||
add_emscripten_library(sdl2 -sUSE_SDL=2)
|
add_emscripten_library(sdl2 -sUSE_SDL=2)
|
||||||
add_emscripten_library(sdl2_ttf -sUSE_SDL_TTF=2)
|
add_emscripten_library(freetype2 -sUSE_FREETYPE=1)
|
||||||
set(DEFAULT_FONT_PATH /fonts/)
|
set(DEFAULT_FONT_PATH /fonts/)
|
||||||
fetch_webp()
|
fetch_webp()
|
||||||
set(HAVE_WEBP 1)
|
set(HAVE_WEBP 1)
|
||||||
|
|
||||||
elseif (ANDROID)
|
elseif (ANDROID)
|
||||||
add_library(sdl2 ALIAS SDL2)
|
add_library(sdl2 ALIAS SDL2)
|
||||||
add_library(sdl2_ttf ALIAS SDL2_ttf)
|
add_library(freetype2 ALIAS freetype)
|
||||||
add_library(sdl2_mixer ALIAS SDL2_mixer)
|
add_library(sdl2_mixer ALIAS SDL2_mixer)
|
||||||
find_library(ndk_log log)
|
find_library(ndk_log log)
|
||||||
find_library(ndk_zlib z)
|
find_library(ndk_zlib z)
|
||||||
@@ -87,24 +89,18 @@ else() # non-emscripten, non-android
|
|||||||
add_library(zlib ALIAS ZLIB::ZLIB)
|
add_library(zlib ALIAS ZLIB::ZLIB)
|
||||||
|
|
||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
optional_pkg_check_modules(GTK3 IMPORTED_TARGET gtk+-3.0)
|
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2>=2.18.0)
|
||||||
if (GTK3_FOUND)
|
pkg_check_modules(FREETYPE REQUIRED IMPORTED_TARGET freetype2)
|
||||||
set(ENABLE_GTK 1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
|
|
||||||
pkg_check_modules(SDL2TTF REQUIRED IMPORTED_TARGET SDL2_ttf)
|
|
||||||
pkg_check_modules(SDL2MIXER REQUIRED IMPORTED_TARGET SDL2_mixer)
|
pkg_check_modules(SDL2MIXER REQUIRED IMPORTED_TARGET SDL2_mixer)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
add_static_library(sdl2 SDL2)
|
add_static_library(sdl2 SDL2)
|
||||||
add_static_library(sdl2_ttf SDL2TTF)
|
add_static_library(freetype2 FREETYPE)
|
||||||
# Workaround for linking error
|
# harfbuzz and graphite2, which the static freetype depends on, are C++ libraries.
|
||||||
set_property(TARGET sdl2_ttf PROPERTY INTERFACE_LINK_LIBRARIES
|
target_link_libraries(freetype2 INTERFACE -lstdc++)
|
||||||
$<LINK_GROUP:RESCAN,${SDL2TTF_STATIC_LIBRARIES} -lstdc++>)
|
|
||||||
add_static_library(sdl2_mixer SDL2MIXER)
|
add_static_library(sdl2_mixer SDL2MIXER)
|
||||||
else()
|
else()
|
||||||
add_library(sdl2 ALIAS PkgConfig::SDL2)
|
add_library(sdl2 ALIAS PkgConfig::SDL2)
|
||||||
add_library(sdl2_ttf ALIAS PkgConfig::SDL2TTF)
|
add_library(freetype2 ALIAS PkgConfig::FREETYPE)
|
||||||
add_library(sdl2_mixer ALIAS PkgConfig::SDL2MIXER)
|
add_library(sdl2_mixer ALIAS PkgConfig::SDL2MIXER)
|
||||||
set(DEFAULT_FONT_PATH ${CMAKE_INSTALL_PREFIX}/share/xsystem35/fonts/)
|
set(DEFAULT_FONT_PATH ${CMAKE_INSTALL_PREFIX}/share/xsystem35/fonts/)
|
||||||
endif()
|
endif()
|
||||||
@@ -153,14 +149,19 @@ else() # non-emscripten, non-android
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Menu
|
# i18n support
|
||||||
|
#
|
||||||
|
# Translate via libintl if available; otherwise fall back to a built-in catalog
|
||||||
|
# compiled from the .po files.
|
||||||
|
#
|
||||||
|
# To add a language, create po/<lang>.po and list <lang> here.
|
||||||
|
set(NLS_LANGUAGES ja)
|
||||||
|
|
||||||
if (ENABLE_GTK)
|
if (NOT EMSCRIPTEN AND NOT ANDROID AND NOT WIN32)
|
||||||
# i18n support (currently only menus are translated)
|
|
||||||
include(FindIntl)
|
include(FindIntl)
|
||||||
include(FindGettext)
|
include(FindGettext)
|
||||||
if (Intl_FOUND AND GETTEXT_FOUND)
|
if (Intl_FOUND AND GETTEXT_FOUND)
|
||||||
set(ENABLE_NLS 1)
|
set(HAVE_LIBINTL 1)
|
||||||
add_compile_definitions(LOCALEDIR="${CMAKE_INSTALL_PREFIX}/share/locale")
|
add_compile_definitions(LOCALEDIR="${CMAKE_INSTALL_PREFIX}/share/locale")
|
||||||
include_directories(${Intl_INCLUDE_DIRS})
|
include_directories(${Intl_INCLUDE_DIRS})
|
||||||
link_libraries(${Intl_LIBRARIES})
|
link_libraries(${Intl_LIBRARIES})
|
||||||
@@ -227,9 +228,11 @@ add_subdirectory(fonts)
|
|||||||
if (NOT ANDROID AND NOT EMSCRIPTEN)
|
if (NOT ANDROID AND NOT EMSCRIPTEN)
|
||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
endif()
|
endif()
|
||||||
if (ENABLE_NLS)
|
add_subdirectory(po)
|
||||||
add_subdirectory(po)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_subdirectory(modules)
|
add_subdirectory(modules)
|
||||||
target_link_libraries(xsystem35 PRIVATE modules)
|
target_link_libraries(xsystem35 PRIVATE modules)
|
||||||
|
|
||||||
|
if (NOT ANDROID AND NOT EMSCRIPTEN)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ See [xsystem35 command manual](doc/xsystem35.6.adoc) for detailed usage.
|
|||||||
### Linux (Debian / Ubuntu)
|
### Linux (Debian / Ubuntu)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ sudo apt install build-essential cmake libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libportmidi-dev libcjson-dev asciidoctor
|
$ sudo apt install build-essential cmake libsdl2-dev libsdl2-mixer-dev libfreetype-dev libwebp-dev libportmidi-dev libcjson-dev asciidoctor
|
||||||
$ mkdir -p out/debug
|
$ mkdir -p out/debug
|
||||||
$ cd out/debug
|
$ cd out/debug
|
||||||
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
||||||
@@ -117,7 +117,7 @@ $ make && make install
|
|||||||
[Homebrew](https://brew.sh/) is required.
|
[Homebrew](https://brew.sh/) is required.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ brew install cmake pkg-config sdl2 sdl2_mixer sdl2_ttf webp portmidi cjson asciidoctor
|
$ brew install cmake pkg-config sdl2 sdl2_mixer freetype webp portmidi cjson asciidoctor
|
||||||
$ mkdir -p out/debug
|
$ mkdir -p out/debug
|
||||||
$ cd out/debug
|
$ cd out/debug
|
||||||
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
||||||
@@ -129,7 +129,7 @@ $ make && make install
|
|||||||
[MSYS2](https://www.msys2.org) is required.
|
[MSYS2](https://www.msys2.org) is required.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ pacman -S cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-SDL2_ttf mingw-w64-ucrt-x86_64-SDL2_mixer mingw-w64-ucrt-x86_64-libwebp mingw-w64-ucrt-x86_64-portmidi mingw-w64-ucrt-x86_64-cjson
|
$ pacman -S cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-freetype mingw-w64-ucrt-x86_64-SDL2_mixer mingw-w64-ucrt-x86_64-libwebp mingw-w64-ucrt-x86_64-portmidi mingw-w64-ucrt-x86_64-cjson
|
||||||
$ mkdir -p out/debug
|
$ mkdir -p out/debug
|
||||||
$ cd out/debug
|
$ cd out/debug
|
||||||
$ cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug ../../
|
$ cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug ../../
|
||||||
|
|||||||
+22
-2
@@ -16,13 +16,31 @@ Alternatively, you can install `xsystem35-sdl2` using [Obtainium](https://github
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
### Basic Usage
|
### Basic Usage
|
||||||
|
You can install games either from a prepared ZIP file or directly from a CD-ROM
|
||||||
|
image.
|
||||||
|
|
||||||
|
#### Installing from a ZIP
|
||||||
1. Create a ZIP file containing all the game files and BGM files (see
|
1. Create a ZIP file containing all the game files and BGM files (see
|
||||||
[below](#preparing-a-zip) for details), and transfer it to your device.
|
[below](#preparing-a-zip) for details), and transfer it to your device.
|
||||||
2. Open the app. Tap the option menu (three dots in the top right corner) and
|
2. Open the app. Tap the option menu (three dots in the top right corner) and
|
||||||
select "Install from ZIP".
|
select "Install from ZIP".
|
||||||
3. Select the ZIP file you created in step 1.
|
3. Select the ZIP file you created in step 1.
|
||||||
4. The game will start. To simulate a right-click, tap the black bars on either
|
4. The game will start.
|
||||||
the left or right, or top or bottom of the screen.
|
|
||||||
|
#### Installing from a CD image
|
||||||
|
1. Transfer the CD image file(s) to your device.
|
||||||
|
2. Open the app. Tap the option menu and select "Install from CD image".
|
||||||
|
3. Select the image file and, when needed, the matching metadata file at the
|
||||||
|
same time. The supported combinations are:
|
||||||
|
- `.iso`
|
||||||
|
- `.bin` or `.img` with matching `.cue`
|
||||||
|
- `.bin` or `.img` with matching `.ccd`
|
||||||
|
- `.mdf` with matching `.mds`
|
||||||
|
|
||||||
|
In many Android file pickers, tapping a file immediately selects only that
|
||||||
|
one file. Long-press a file first to enter multi-select mode, then select
|
||||||
|
both the image file and its metadata file.
|
||||||
|
4. The game will start.
|
||||||
|
|
||||||
### Preparing a ZIP
|
### Preparing a ZIP
|
||||||
- Include all files from the `GAMEDATA` folder (such as `.ALD` files and
|
- Include all files from the `GAMEDATA` folder (such as `.ALD` files and
|
||||||
@@ -41,6 +59,8 @@ Note: This ZIP format is also compatible with
|
|||||||
[Kichikuou on Web](http://kichikuou.github.io/web/).
|
[Kichikuou on Web](http://kichikuou.github.io/web/).
|
||||||
|
|
||||||
### Miscellaneous
|
### Miscellaneous
|
||||||
|
- To simulate a right-click, tap the black bars on either the left or right,
|
||||||
|
or top or bottom of the screen.
|
||||||
- You can export or import save files via the game list's option menu.
|
- You can export or import save files via the game list's option menu.
|
||||||
- To uninstall a game, long-tap its title in the game list.
|
- To uninstall a game, long-tap its title in the game list.
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ android {
|
|||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 36
|
versionCode 36
|
||||||
versionName "2.18.0" + gitRevision()
|
versionName "2.20.0" + gitRevision()
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
arguments "-DANDROID_APP_PLATFORM=android-19", "-DANDROID_STL=c++_static"
|
arguments "-DANDROID_APP_PLATFORM=android-19", "-DANDROID_STL=c++_static"
|
||||||
@@ -85,6 +85,7 @@ dependencies {
|
|||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
|
||||||
|
testImplementation 'junit:junit:4.13.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
static String gitRevision() {
|
static String gitRevision() {
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ FetchContent_Declare(
|
|||||||
URL_HASH SHA1=ce98fa93e31836a751feca374ab28a0770b63c16
|
URL_HASH SHA1=ce98fa93e31836a751feca374ab28a0770b63c16
|
||||||
)
|
)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
SDL_ttf
|
freetype
|
||||||
URL https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.22.0/SDL2_ttf-2.22.0.tar.gz
|
URL https://downloads.sourceforge.net/project/freetype/freetype2/2.14.3/freetype-2.14.3.tar.gz
|
||||||
URL_HASH SHA1=da5e86b601ad299a697878fab1af6f3be47b529d
|
https://download.savannah.gnu.org/releases/freetype/freetype-2.14.3.tar.gz
|
||||||
|
URL_HASH SHA1=a911f65c6355ddcf7aaba46e250dbc00f67e1678
|
||||||
)
|
)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
SDL_mixer
|
SDL_mixer
|
||||||
@@ -21,9 +22,12 @@ FetchContent_Declare(
|
|||||||
URL_HASH SHA1=a58c69f9d00e44833b9e00e1adb58d85759ca499
|
URL_HASH SHA1=a58c69f9d00e44833b9e00e1adb58d85759ca499
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SDL2TTF_SAMPLES OFF CACHE BOOL "Build the SDL2_ttf sample program(s)" FORCE)
|
# Only FreeType's own rasterizer is needed, none of its optional dependencies.
|
||||||
set(SDL2TTF_INSTALL OFF CACHE BOOL "Enable SDL2_ttf install target" FORCE)
|
set(FT_DISABLE_ZLIB ON CACHE BOOL "Disable use of system zlib" FORCE)
|
||||||
set(SDL2TTF_VENDORED ON CACHE BOOL "Use vendored third-party libraries" FORCE)
|
set(FT_DISABLE_BZIP2 ON CACHE BOOL "Disable use of system libbz2" FORCE)
|
||||||
|
set(FT_DISABLE_PNG ON CACHE BOOL "Disable use of system libpng" FORCE)
|
||||||
|
set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "Disable use of harfbuzz" FORCE)
|
||||||
|
set(FT_DISABLE_BROTLI ON CACHE BOOL "Disable use of brotli" FORCE)
|
||||||
|
|
||||||
set(SDL2MIXER_OPUS OFF CACHE BOOL "Enable Opus music" FORCE)
|
set(SDL2MIXER_OPUS OFF CACHE BOOL "Enable Opus music" FORCE)
|
||||||
set(SDL2MIXER_FLAC OFF CACHE BOOL "Enable FLAC music" FORCE)
|
set(SDL2MIXER_FLAC OFF CACHE BOOL "Enable FLAC music" FORCE)
|
||||||
@@ -33,7 +37,7 @@ set(SDL2MIXER_WAVPACK OFF CACHE BOOL "Enable WavPack music" FORCE)
|
|||||||
set(SDL2MIXER_SAMPLES OFF CACHE BOOL "Build the SDL2_mixer sample program(s)" FORCE)
|
set(SDL2MIXER_SAMPLES OFF CACHE BOOL "Build the SDL2_mixer sample program(s)" FORCE)
|
||||||
set(SDL2MIXER_INSTALL OFF CACHE BOOL "Enable SDL2_mixer install target" FORCE)
|
set(SDL2MIXER_INSTALL OFF CACHE BOOL "Enable SDL2_mixer install target" FORCE)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(SDL SDL_ttf SDL_mixer)
|
FetchContent_MakeAvailable(SDL freetype SDL_mixer)
|
||||||
|
|
||||||
# The main CMakeLists.txt of xsystem35
|
# The main CMakeLists.txt of xsystem35
|
||||||
add_subdirectory(${PROJECT_ROOT_DIR} xsystem35)
|
add_subdirectory(${PROJECT_ROOT_DIR} xsystem35)
|
||||||
@@ -47,8 +51,7 @@ file(COPY_FILE ${PROJECT_ROOT_DIR}/COPYING ${ASSETS_DIR}/licenses/xsystem35)
|
|||||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/licenses/MTLc3m.txt ${ASSETS_DIR}/licenses/MTLc3m)
|
file(COPY_FILE ${PROJECT_ROOT_DIR}/licenses/MTLc3m.txt ${ASSETS_DIR}/licenses/MTLc3m)
|
||||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/licenses/mincho.txt ${ASSETS_DIR}/licenses/mincho)
|
file(COPY_FILE ${PROJECT_ROOT_DIR}/licenses/mincho.txt ${ASSETS_DIR}/licenses/mincho)
|
||||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/licenses/nanojpeg.txt ${ASSETS_DIR}/licenses/nanojpeg)
|
file(COPY_FILE ${PROJECT_ROOT_DIR}/licenses/nanojpeg.txt ${ASSETS_DIR}/licenses/nanojpeg)
|
||||||
|
file(COPY_FILE ${PROJECT_ROOT_DIR}/licenses/microui.txt ${ASSETS_DIR}/licenses/microui)
|
||||||
file(COPY_FILE ${sdl_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL)
|
file(COPY_FILE ${sdl_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL)
|
||||||
file(COPY_FILE ${sdl_ttf_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL_ttf)
|
file(COPY_FILE ${freetype_SOURCE_DIR}/docs/GPLv2.TXT ${ASSETS_DIR}/licenses/freetype)
|
||||||
file(COPY_FILE ${sdl_ttf_SOURCE_DIR}/external/freetype/docs/GPLv2.TXT ${ASSETS_DIR}/licenses/freetype)
|
|
||||||
file(COPY_FILE ${sdl_ttf_SOURCE_DIR}/external/harfbuzz/COPYING ${ASSETS_DIR}/licenses/harfbuzz)
|
|
||||||
file(COPY_FILE ${sdl_mixer_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL_mixer)
|
file(COPY_FILE ${sdl_mixer_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL_mixer)
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
<!-- Example of setting SDL hints from AndroidManifest.xml:
|
<!-- Example of setting SDL hints from AndroidManifest.xml:
|
||||||
<meta-data android:name="SDL_ENV.SDL_ACCELEROMETER_AS_JOYSTICK" android:value="0"/>
|
<meta-data android:name="SDL_ENV.SDL_ACCELEROMETER_AS_JOYSTICK" android:value="0"/>
|
||||||
-->
|
-->
|
||||||
|
<meta-data android:name="SDL_ENV.SDL_IOS_ORIENTATIONS" android:value="LandscapeLeft LandscapeRight"/>
|
||||||
|
|
||||||
<activity android:name=".LauncherActivity"
|
<activity android:name=".LauncherActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
@@ -78,6 +79,7 @@
|
|||||||
|
|
||||||
<activity android:name=".GameActivity"
|
<activity android:name=".GameActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:process=":game"
|
||||||
android:alwaysRetainTaskState="true"
|
android:alwaysRetainTaskState="true"
|
||||||
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
|
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
|
|||||||
@@ -0,0 +1,566 @@
|
|||||||
|
/* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package io.github.kichikuou.xsystem35
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
|
import android.os.ParcelFileDescriptor
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.io.EOFException
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.channels.FileChannel
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
internal class CdImageReader private constructor(
|
||||||
|
private val image: RandomAccessImage,
|
||||||
|
private val tracks: List<TrackInfo?>,
|
||||||
|
) : Closeable {
|
||||||
|
fun readSector(sector: Int, buffer: ByteArray) {
|
||||||
|
readDataFully(sector.toLong() * ISO_SECTOR_SIZE, buffer, 0, ISO_SECTOR_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readDataFully(offset: Long, buffer: ByteArray, bufferOffset: Int, length: Int) {
|
||||||
|
// ISO9660 always sees logical 2048-byte data sectors even when the
|
||||||
|
// image stores each sector as a raw 2352-byte CD-ROM block.
|
||||||
|
var logicalOffset = offset
|
||||||
|
var outOffset = bufferOffset
|
||||||
|
var remaining = length
|
||||||
|
val sectorBuffer = ByteArray(ISO_SECTOR_SIZE)
|
||||||
|
while (remaining > 0) {
|
||||||
|
val sector = (logicalOffset / ISO_SECTOR_SIZE).toInt()
|
||||||
|
val offsetInSector = (logicalOffset % ISO_SECTOR_SIZE).toInt()
|
||||||
|
val count = minOf(remaining, ISO_SECTOR_SIZE - offsetInSector)
|
||||||
|
readSectorPayload(sector, sectorBuffer)
|
||||||
|
sectorBuffer.copyInto(buffer, outOffset, offsetInSector, offsetInSector + count)
|
||||||
|
logicalOffset += count
|
||||||
|
outOffset += count
|
||||||
|
remaining -= count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun audioTracks(): List<Int> {
|
||||||
|
return tracks.mapIndexedNotNull { trackNumber, track ->
|
||||||
|
if (track?.isAudio == true) trackNumber else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun extractAudioTrack(trackNumber: Int, output: OutputStream) {
|
||||||
|
val track = tracks.getOrNull(trackNumber)
|
||||||
|
if (track?.isAudio != true) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
val dataSize = track.numSectors.toLong() * RAW_AUDIO_SECTOR_SIZE
|
||||||
|
// CD-DA sectors are already 44.1kHz stereo 16-bit PCM; wrapping the
|
||||||
|
// raw sector stream in a WAV header makes it playable by SDL_mixer.
|
||||||
|
writeWaveHeader(output, dataSize)
|
||||||
|
val buffer = ByteArray(track.blockSize * 16)
|
||||||
|
var sector = 0
|
||||||
|
while (sector < track.numSectors) {
|
||||||
|
val sectorsToRead = minOf(16, track.numSectors - sector)
|
||||||
|
val bytesToRead = sectorsToRead * track.blockSize
|
||||||
|
image.readFully(track.offset + sector.toLong() * track.blockSize, buffer, 0, bytesToRead)
|
||||||
|
output.write(buffer, 0, sectorsToRead * RAW_AUDIO_SECTOR_SIZE)
|
||||||
|
sector += sectorsToRead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
image.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readSectorPayload(sector: Int, buffer: ByteArray) {
|
||||||
|
val track = findDataTrack(sector)
|
||||||
|
val offset = track.offset + (sector - track.startSector).toLong() * track.blockSize + track.blockOffset
|
||||||
|
image.readFully(offset, buffer, 0, ISO_SECTOR_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findDataTrack(sector: Int): TrackInfo {
|
||||||
|
for (track in tracks) {
|
||||||
|
if (track == null || track.isAudio) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (sector >= track.startSector && sector < track.startSector + track.numSectors) {
|
||||||
|
return track
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw InstallFailureException(R.string.invalid_iso9660_image)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ISO_SECTOR_SIZE = 2048
|
||||||
|
private const val RAW_AUDIO_SECTOR_SIZE = 2352
|
||||||
|
private const val WAVE_HEADER_SIZE = 44
|
||||||
|
private const val MDS_MODE_AUDIO = 0xa9
|
||||||
|
private const val MDS_MODE_MODE1 = 0xaa
|
||||||
|
|
||||||
|
fun open(
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
files: List<SelectedInstallFile>,
|
||||||
|
tempDir: File,
|
||||||
|
): CdImageReader {
|
||||||
|
val selected = selectImageFiles(files)
|
||||||
|
val image = RandomAccessImage.open(contentResolver, selected.image, tempDir)
|
||||||
|
try {
|
||||||
|
if (selected.metadata == null) {
|
||||||
|
return CdImageReader(image, listOf(null, TrackInfo.iso(image.size)))
|
||||||
|
}
|
||||||
|
val metadataName = selected.metadata.displayName.lowercase(Locale.US)
|
||||||
|
val tracks = when {
|
||||||
|
metadataName.endsWith(".cue") -> {
|
||||||
|
val cueText = readMetadataText(contentResolver, selected.metadata)
|
||||||
|
parseCue(cueText, image.size)
|
||||||
|
}
|
||||||
|
metadataName.endsWith(".ccd") -> {
|
||||||
|
val ccdText = readMetadataText(contentResolver, selected.metadata)
|
||||||
|
parseCcd(ccdText, image.size)
|
||||||
|
}
|
||||||
|
metadataName.endsWith(".mds") -> {
|
||||||
|
val mdsBytes = readMetadataBytes(contentResolver, selected.metadata)
|
||||||
|
parseMds(mdsBytes)
|
||||||
|
}
|
||||||
|
else -> throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
return CdImageReader(image, tracks)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
image.close()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun openForFile(
|
||||||
|
imageFile: File,
|
||||||
|
metadataName: String? = null,
|
||||||
|
metadataBytes: ByteArray? = null,
|
||||||
|
): CdImageReader {
|
||||||
|
val image = RandomAccessImage.open(imageFile)
|
||||||
|
try {
|
||||||
|
if (metadataName == null) {
|
||||||
|
return CdImageReader(image, listOf(null, TrackInfo.iso(image.size)))
|
||||||
|
}
|
||||||
|
val tracks = when {
|
||||||
|
metadataName.lowercase(Locale.US).endsWith(".cue") -> {
|
||||||
|
parseCue(metadataBytes?.toString(Charsets.UTF_8) ?: "", image.size)
|
||||||
|
}
|
||||||
|
metadataName.lowercase(Locale.US).endsWith(".ccd") -> {
|
||||||
|
parseCcd(metadataBytes?.toString(Charsets.UTF_8) ?: "", image.size)
|
||||||
|
}
|
||||||
|
metadataName.lowercase(Locale.US).endsWith(".mds") -> {
|
||||||
|
parseMds(metadataBytes ?: ByteArray(0))
|
||||||
|
}
|
||||||
|
else -> throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
return CdImageReader(image, tracks)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
image.close()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectImageFiles(files: List<SelectedInstallFile>): SelectedImageFiles {
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
val isoFiles = files.filter { it.displayName.lowercase(Locale.US).endsWith(".iso") }
|
||||||
|
if (isoFiles.size == 1 && files.size == 1) {
|
||||||
|
return SelectedImageFiles(isoFiles.single(), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val imageFiles = files.filter {
|
||||||
|
val name = it.displayName.lowercase(Locale.US)
|
||||||
|
name.endsWith(".bin") || name.endsWith(".img") || name.endsWith(".mdf")
|
||||||
|
}
|
||||||
|
val metadataFiles = files.filter {
|
||||||
|
val name = it.displayName.lowercase(Locale.US)
|
||||||
|
name.endsWith(".cue") || name.endsWith(".ccd") || name.endsWith(".mds")
|
||||||
|
}
|
||||||
|
if (imageFiles.size == 1 && metadataFiles.isEmpty() && files.size == 1 ||
|
||||||
|
imageFiles.isEmpty() && metadataFiles.size == 1 && files.size == 1
|
||||||
|
) {
|
||||||
|
throw InstallFailureException(R.string.missing_cd_image_metadata)
|
||||||
|
}
|
||||||
|
if (imageFiles.size != 1 || metadataFiles.size != 1 || files.size != 2) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
val imageBase = imageFiles.single().baseName()
|
||||||
|
val metadataBase = metadataFiles.single().baseName()
|
||||||
|
if (imageBase != metadataBase) {
|
||||||
|
throw InstallFailureException(R.string.missing_cd_image_metadata)
|
||||||
|
}
|
||||||
|
if (!isSupportedMetadataForImage(imageFiles.single(), metadataFiles.single())) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
return SelectedImageFiles(imageFiles.single(), metadataFiles.single())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSupportedMetadataForImage(
|
||||||
|
image: SelectedInstallFile,
|
||||||
|
metadata: SelectedInstallFile,
|
||||||
|
): Boolean {
|
||||||
|
val imageName = image.displayName.lowercase(Locale.US)
|
||||||
|
val metadataName = metadata.displayName.lowercase(Locale.US)
|
||||||
|
return if (imageName.endsWith(".mdf")) {
|
||||||
|
metadataName.endsWith(".mds")
|
||||||
|
} else {
|
||||||
|
metadataName.endsWith(".cue") || metadataName.endsWith(".ccd")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readMetadataText(
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
file: SelectedInstallFile,
|
||||||
|
): String {
|
||||||
|
return contentResolver.openInputStream(file.uri)?.bufferedReader()?.use {
|
||||||
|
it.readText()
|
||||||
|
} ?: throw InstallFailureException(R.string.cd_image_read_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readMetadataBytes(
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
file: SelectedInstallFile,
|
||||||
|
): ByteArray {
|
||||||
|
return contentResolver.openInputStream(file.uri)?.use {
|
||||||
|
it.readBytes()
|
||||||
|
} ?: throw InstallFailureException(R.string.cd_image_read_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseCue(cueText: String, imageSize: Long): List<TrackInfo?> {
|
||||||
|
val cueTracks = mutableListOf<CueTrack?>()
|
||||||
|
var currentTrack: Int? = null
|
||||||
|
for (line in cueText.lines()) {
|
||||||
|
val fields = line.trim().split(Regex("\\s+"))
|
||||||
|
if (fields.isEmpty()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
when (fields[0].uppercase(Locale.US)) {
|
||||||
|
"TRACK" -> {
|
||||||
|
if (fields.size < 3) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
currentTrack = fields[1].toIntOrNull()
|
||||||
|
?: throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
while (cueTracks.size <= currentTrack) {
|
||||||
|
cueTracks.add(null)
|
||||||
|
}
|
||||||
|
cueTracks[currentTrack] = when (fields[2].uppercase(Locale.US)) {
|
||||||
|
"MODE1/2048" -> CueTrack(false, 2048, 0)
|
||||||
|
"MODE1/2352" -> CueTrack(false, 2352, 16)
|
||||||
|
"AUDIO" -> CueTrack(true, 2352, 0)
|
||||||
|
else -> throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"INDEX" -> {
|
||||||
|
val trackNumber = currentTrack ?: continue
|
||||||
|
if (fields.size < 3) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
val indexNumber = fields[1].toIntOrNull()
|
||||||
|
?: throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
cueTracks[trackNumber]?.index?.put(indexNumber, indexToSector(fields[2]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return makeTrackInfo(cueTracks, imageSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseCcd(ccdText: String, imageSize: Long): List<TrackInfo?> {
|
||||||
|
val cueTracks = mutableListOf<CueTrack?>()
|
||||||
|
var currentTrack: Int? = null
|
||||||
|
for (line in ccdText.lines()) {
|
||||||
|
val trimmed = line.trim()
|
||||||
|
val trackMatch = Regex("""\[TRACK ([0-9]+)]""").matchEntire(trimmed)
|
||||||
|
if (trackMatch != null) {
|
||||||
|
currentTrack = trackMatch.groupValues[1].toInt()
|
||||||
|
while (cueTracks.size <= currentTrack) {
|
||||||
|
cueTracks.add(null)
|
||||||
|
}
|
||||||
|
cueTracks[currentTrack] = CueTrack(false, 2352, 16)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val trackNumber = currentTrack ?: continue
|
||||||
|
val keyValue = trimmed.split("=", limit = 2)
|
||||||
|
if (keyValue.size != 2) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
when (keyValue[0].uppercase(Locale.US)) {
|
||||||
|
"MODE" -> if (keyValue[1] == "0") {
|
||||||
|
cueTracks[trackNumber] = CueTrack(true, 2352, 0, cueTracks[trackNumber]?.index ?: mutableMapOf())
|
||||||
|
}
|
||||||
|
"INDEX 0" -> cueTracks[trackNumber]?.index?.put(
|
||||||
|
0,
|
||||||
|
keyValue[1].toIntOrNull() ?: throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
)
|
||||||
|
"INDEX 1" -> cueTracks[trackNumber]?.index?.put(
|
||||||
|
1,
|
||||||
|
keyValue[1].toIntOrNull() ?: throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return makeTrackInfo(cueTracks, imageSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseMds(mdsBytes: ByteArray): List<TrackInfo?> {
|
||||||
|
if (mdsBytes.size < 0x70 ||
|
||||||
|
String(mdsBytes, 0, 16, Charsets.US_ASCII).trimEnd('\u0000') != "MEDIA DESCRIPTOR"
|
||||||
|
) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
val entries = mdsBytes[0x62].toInt() and 0xff
|
||||||
|
if (0x70 + entries * 0x58 > mdsBytes.size) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
|
||||||
|
val tracks = MutableList<TrackInfo?>(100) { null }
|
||||||
|
for (i in 0 until entries) {
|
||||||
|
val trackOffset = 0x70 + i * 0x50
|
||||||
|
val extraOffset = 0x70 + entries * 0x50 + i * 8
|
||||||
|
val mode = mdsBytes[trackOffset].toInt() and 0xff
|
||||||
|
val trackNumber = mdsBytes[trackOffset + 0x04].toInt() and 0xff
|
||||||
|
val sectorSize = readLittleEndianShort(mdsBytes, trackOffset + 0x10)
|
||||||
|
// MDS offsets are treated as 32-bit file offsets, so images
|
||||||
|
// beyond 4GB are unsupported.
|
||||||
|
val imageOffset = readLittleEndianInt(mdsBytes, trackOffset + 0x28)
|
||||||
|
val sectors = readLittleEndianInt(mdsBytes, extraOffset + 0x04).toInt()
|
||||||
|
if (trackNumber >= tracks.size) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tracks[trackNumber] = when (mode) {
|
||||||
|
MDS_MODE_AUDIO -> TrackInfo(
|
||||||
|
isAudio = true,
|
||||||
|
offset = imageOffset,
|
||||||
|
blockSize = sectorSize,
|
||||||
|
blockOffset = 0,
|
||||||
|
startSector = 0,
|
||||||
|
numSectors = sectors,
|
||||||
|
)
|
||||||
|
MDS_MODE_MODE1 -> TrackInfo(
|
||||||
|
isAudio = false,
|
||||||
|
offset = imageOffset,
|
||||||
|
blockSize = sectorSize,
|
||||||
|
blockOffset = 16,
|
||||||
|
startSector = 0,
|
||||||
|
numSectors = sectors,
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tracks.getOrNull(1)?.isAudio != false) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
return tracks
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeTrackInfo(cueTracks: List<CueTrack?>, imageSize: Long): List<TrackInfo?> {
|
||||||
|
val tracks = MutableList<TrackInfo?>(cueTracks.size) { null }
|
||||||
|
var offset = 0L
|
||||||
|
var startSector = 0
|
||||||
|
for (trackNumber in 1 until cueTracks.size) {
|
||||||
|
val cueTrack = cueTracks[trackNumber] ?: continue
|
||||||
|
val index1 = cueTrack.index[1]
|
||||||
|
?: throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
// INDEX 0 describes a pregap, but a zero INDEX 0 is treated as absent.
|
||||||
|
cueTrack.index[0]?.takeIf { it != 0 }?.let { index0 ->
|
||||||
|
val gap = index1 - index0
|
||||||
|
if (gap > 0) {
|
||||||
|
startSector += gap
|
||||||
|
offset += gap.toLong() * cueTrack.blockSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val nextTrack = cueTracks.drop(trackNumber + 1).firstOrNull { it != null }
|
||||||
|
val nextStart = nextTrack?.let { it.index[0]?.takeIf { index -> index != 0 } ?: it.index[1] }
|
||||||
|
val numSectors = if (nextStart != null) {
|
||||||
|
nextStart - index1
|
||||||
|
} else {
|
||||||
|
((imageSize - offset) / cueTrack.blockSize).toInt()
|
||||||
|
}
|
||||||
|
if (numSectors <= 0) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
tracks[trackNumber] = TrackInfo(
|
||||||
|
isAudio = cueTrack.isAudio,
|
||||||
|
offset = offset,
|
||||||
|
blockSize = cueTrack.blockSize,
|
||||||
|
blockOffset = cueTrack.blockOffset,
|
||||||
|
startSector = startSector,
|
||||||
|
numSectors = numSectors,
|
||||||
|
)
|
||||||
|
startSector += numSectors
|
||||||
|
offset += numSectors.toLong() * cueTrack.blockSize
|
||||||
|
}
|
||||||
|
return tracks
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun indexToSector(index: String): Int {
|
||||||
|
val parts = index.split(":").map {
|
||||||
|
it.toIntOrNull() ?: throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
if (parts.size != 3) {
|
||||||
|
throw InstallFailureException(R.string.unsupported_cd_image)
|
||||||
|
}
|
||||||
|
return parts[0] * 60 * 75 + parts[1] * 75 + parts[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeWaveHeader(output: OutputStream, dataSize: Long) {
|
||||||
|
val header = ByteArray(WAVE_HEADER_SIZE)
|
||||||
|
writeAscii(header, 0, "RIFF")
|
||||||
|
writeLittleEndianInt(header, 4, dataSize + 36)
|
||||||
|
writeAscii(header, 8, "WAVE")
|
||||||
|
writeAscii(header, 12, "fmt ")
|
||||||
|
writeLittleEndianInt(header, 16, 16)
|
||||||
|
writeLittleEndianShort(header, 20, 1)
|
||||||
|
writeLittleEndianShort(header, 22, 2)
|
||||||
|
writeLittleEndianInt(header, 24, 44100)
|
||||||
|
writeLittleEndianInt(header, 28, 44100 * 2 * 2)
|
||||||
|
writeLittleEndianShort(header, 32, 2 * 2)
|
||||||
|
writeLittleEndianShort(header, 34, 16)
|
||||||
|
writeAscii(header, 36, "data")
|
||||||
|
writeLittleEndianInt(header, 40, dataSize)
|
||||||
|
output.write(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeAscii(buffer: ByteArray, offset: Int, value: String) {
|
||||||
|
value.toByteArray(Charsets.US_ASCII).copyInto(buffer, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeLittleEndianShort(buffer: ByteArray, offset: Int, value: Int) {
|
||||||
|
buffer[offset] = value.toByte()
|
||||||
|
buffer[offset + 1] = (value shr 8).toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeLittleEndianInt(buffer: ByteArray, offset: Int, value: Long) {
|
||||||
|
buffer[offset] = value.toByte()
|
||||||
|
buffer[offset + 1] = (value shr 8).toByte()
|
||||||
|
buffer[offset + 2] = (value shr 16).toByte()
|
||||||
|
buffer[offset + 3] = (value shr 24).toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readLittleEndianShort(buffer: ByteArray, offset: Int): Int {
|
||||||
|
return (buffer[offset].toInt() and 0xff) or
|
||||||
|
((buffer[offset + 1].toInt() and 0xff) shl 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readLittleEndianInt(buffer: ByteArray, offset: Int): Long {
|
||||||
|
return (buffer[offset].toLong() and 0xff) or
|
||||||
|
((buffer[offset + 1].toLong() and 0xff) shl 8) or
|
||||||
|
((buffer[offset + 2].toLong() and 0xff) shl 16) or
|
||||||
|
((buffer[offset + 3].toLong() and 0xff) shl 24)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class SelectedImageFiles(
|
||||||
|
val image: SelectedInstallFile,
|
||||||
|
val metadata: SelectedInstallFile?,
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class CueTrack(
|
||||||
|
val isAudio: Boolean,
|
||||||
|
val blockSize: Int,
|
||||||
|
val blockOffset: Int,
|
||||||
|
val index: MutableMap<Int, Int> = mutableMapOf(),
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class TrackInfo(
|
||||||
|
val isAudio: Boolean,
|
||||||
|
val offset: Long,
|
||||||
|
val blockSize: Int,
|
||||||
|
val blockOffset: Int,
|
||||||
|
val startSector: Int,
|
||||||
|
val numSectors: Int,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun iso(imageSize: Long): TrackInfo {
|
||||||
|
return TrackInfo(
|
||||||
|
isAudio = false,
|
||||||
|
offset = 0,
|
||||||
|
blockSize = CdImageReader.ISO_SECTOR_SIZE,
|
||||||
|
blockOffset = 0,
|
||||||
|
startSector = 0,
|
||||||
|
numSectors = (imageSize / CdImageReader.ISO_SECTOR_SIZE).toInt(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RandomAccessImage private constructor(
|
||||||
|
private val channel: FileChannel,
|
||||||
|
private val descriptor: ParcelFileDescriptor?,
|
||||||
|
private val tempFile: File?,
|
||||||
|
) : Closeable {
|
||||||
|
val size: Long = channel.size()
|
||||||
|
|
||||||
|
fun readFully(offset: Long, buffer: ByteArray, bufferOffset: Int, length: Int) {
|
||||||
|
val byteBuffer = ByteBuffer.wrap(buffer, bufferOffset, length)
|
||||||
|
var pos = offset
|
||||||
|
while (byteBuffer.hasRemaining()) {
|
||||||
|
val read = channel.read(byteBuffer, pos)
|
||||||
|
if (read < 0) {
|
||||||
|
throw EOFException("Unexpected end of CD image")
|
||||||
|
}
|
||||||
|
pos += read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
channel.close()
|
||||||
|
descriptor?.close()
|
||||||
|
tempFile?.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal fun open(file: File): RandomAccessImage {
|
||||||
|
return RandomAccessImage(FileInputStream(file).channel, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun open(
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
file: SelectedInstallFile,
|
||||||
|
tempDir: File,
|
||||||
|
): RandomAccessImage {
|
||||||
|
val descriptor = contentResolver.openFileDescriptor(file.uri, "r")
|
||||||
|
?: throw InstallFailureException(R.string.cd_image_read_error)
|
||||||
|
try {
|
||||||
|
val channel = FileInputStream(descriptor.fileDescriptor).channel
|
||||||
|
channel.size()
|
||||||
|
return RandomAccessImage(channel, descriptor, null)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
descriptor.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some SAF providers expose the URI as a pipe. Copy those to an
|
||||||
|
// app-private temp file so the CD reader can use positional reads.
|
||||||
|
val tempFile = File.createTempFile("cdimage-", ".img", tempDir)
|
||||||
|
try {
|
||||||
|
contentResolver.openInputStream(file.uri)?.use { input ->
|
||||||
|
tempFile.outputStream().buffered().use { output ->
|
||||||
|
input.copyTo(output)
|
||||||
|
}
|
||||||
|
} ?: throw InstallFailureException(R.string.cd_image_read_error)
|
||||||
|
return RandomAccessImage(FileInputStream(tempFile).channel, null, tempFile)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
tempFile.delete()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SelectedInstallFile.baseName(): String {
|
||||||
|
return displayName.substringBeforeLast('.').lowercase(Locale.US)
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ package io.github.kichikuou.xsystem35
|
|||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.media.MediaPlayer
|
import android.media.MediaPlayer
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Process
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
@@ -44,6 +45,8 @@ class GameActivity : SDLActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
gameRoot = File(intent.getStringExtra(EXTRA_GAME_ROOT)!!)
|
gameRoot = File(intent.getStringExtra(EXTRA_GAME_ROOT)!!)
|
||||||
|
// Workaround for https://github.com/libsdl-org/SDL/issues/8995
|
||||||
|
SDLActivity.setWindowStyle(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
@@ -56,18 +59,26 @@ class GameActivity : SDLActivity() {
|
|||||||
midi.onActivityResume()
|
midi.onActivityResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
try {
|
||||||
|
super.onDestroy()
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
midi.release()
|
||||||
|
} finally {
|
||||||
|
Process.killProcess(Process.myPid())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getLibraries(): Array<String> {
|
override fun getLibraries(): Array<String> {
|
||||||
return arrayOf("SDL2", "xsystem35")
|
return arrayOf("SDL2", "xsystem35")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getArguments(): Array<String> {
|
override fun getArguments(): Array<String> {
|
||||||
val args = mutableListOf(
|
return arrayOf(
|
||||||
"-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!,
|
"-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!,
|
||||||
"-savedir", intent.getStringExtra(EXTRA_SAVE_DIRECTORY)!!)
|
"-savedir", intent.getStringExtra(EXTRA_SAVE_DIRECTORY)!!)
|
||||||
val prefs = getSharedPreferences(Launcher.PREFS_NAME, MODE_PRIVATE)
|
|
||||||
if (prefs.getBoolean(Launcher.PREF_VIRTUAL_POINTER, false))
|
|
||||||
args.add("-virtualpointer")
|
|
||||||
return args.toTypedArray()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTitle(title: CharSequence?) {
|
override fun setTitle(title: CharSequence?) {
|
||||||
@@ -79,7 +90,6 @@ class GameActivity : SDLActivity() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
File(gameRoot, Launcher.TITLE_FILE).writeText(str)
|
File(gameRoot, Launcher.TITLE_FILE).writeText(str)
|
||||||
Launcher.updateGameList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun textInputDialog(msg: String, oldVal: String, maxLen: Int, result: Array<String?>) {
|
private fun textInputDialog(msg: String, oldVal: String, maxLen: Int, result: Array<String?>) {
|
||||||
@@ -158,11 +168,21 @@ class GameActivity : SDLActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class MidiPlayer {
|
private class MidiPlayer {
|
||||||
|
private enum class State {
|
||||||
|
STOPPED,
|
||||||
|
PLAYING,
|
||||||
|
PAUSED,
|
||||||
|
RELEASED,
|
||||||
|
}
|
||||||
|
|
||||||
private val player = MediaPlayer()
|
private val player = MediaPlayer()
|
||||||
private var playing = false
|
private var state = State.STOPPED
|
||||||
private var playerPaused = false
|
|
||||||
|
|
||||||
fun start(path: String, loop: Boolean) {
|
fun start(path: String, loop: Boolean) {
|
||||||
|
if (state == State.RELEASED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state = State.STOPPED
|
||||||
try {
|
try {
|
||||||
player.apply {
|
player.apply {
|
||||||
reset()
|
reset()
|
||||||
@@ -171,7 +191,7 @@ private class MidiPlayer {
|
|||||||
prepare()
|
prepare()
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
playing = true
|
state = State.PLAYING
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Log.e("midiStart", "Cannot play midi", e)
|
Log.e("midiStart", "Cannot play midi", e)
|
||||||
player.reset()
|
player.reset()
|
||||||
@@ -179,27 +199,41 @@ private class MidiPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
if (playing && player.isPlaying) {
|
when (state) {
|
||||||
player.stop()
|
State.PLAYING, State.PAUSED -> {
|
||||||
playing = false
|
player.stop()
|
||||||
|
state = State.STOPPED
|
||||||
|
}
|
||||||
|
State.STOPPED, State.RELEASED -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun currentPosition(): Int {
|
fun currentPosition(): Int {
|
||||||
return if (playing) player.currentPosition else 0
|
return when (state) {
|
||||||
|
State.PLAYING, State.PAUSED -> player.currentPosition
|
||||||
|
State.STOPPED, State.RELEASED -> 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onActivityStop() {
|
fun onActivityStop() {
|
||||||
if (playing && player.isPlaying) {
|
if (state == State.PLAYING && player.isPlaying) {
|
||||||
player.pause()
|
player.pause()
|
||||||
playerPaused = true
|
state = State.PAUSED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onActivityResume() {
|
fun onActivityResume() {
|
||||||
if (playerPaused) {
|
if (state == State.PAUSED) {
|
||||||
player.start()
|
player.start()
|
||||||
playerPaused = false
|
state = State.PLAYING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun release() {
|
||||||
|
if (state == State.RELEASED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state = State.RELEASED
|
||||||
|
player.release()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
/* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package io.github.kichikuou.xsystem35
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.UTFDataFormatException
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
|
data class SelectedInstallFile(
|
||||||
|
val uri: Uri,
|
||||||
|
val displayName: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
class GameInstaller(private val store: GameStore) {
|
||||||
|
suspend fun installZip(input: InputStream, progressCallback: suspend (String) -> Unit): File {
|
||||||
|
val dir = store.createDirForGame()
|
||||||
|
var committed = false
|
||||||
|
try {
|
||||||
|
val gameDir = extractFiles(input, dir, progressCallback)
|
||||||
|
committed = true
|
||||||
|
return gameDir
|
||||||
|
} finally {
|
||||||
|
if (!committed && !dir.deleteRecursively()) {
|
||||||
|
Log.w("launcher", "Failed to delete incomplete install directory: $dir")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun installCdImage(
|
||||||
|
files: List<SelectedInstallFile>,
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
tempDir: File,
|
||||||
|
progressCallback: suspend (String) -> Unit
|
||||||
|
): File {
|
||||||
|
val dir = store.createDirForGame()
|
||||||
|
var committed = false
|
||||||
|
try {
|
||||||
|
val gameDir = extractCdImage(files, contentResolver, tempDir, dir, progressCallback)
|
||||||
|
committed = true
|
||||||
|
return gameDir
|
||||||
|
} finally {
|
||||||
|
if (!committed && !dir.deleteRecursively()) {
|
||||||
|
Log.w("launcher", "Failed to delete incomplete install directory: $dir")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun installCdImageForTest(
|
||||||
|
cdImage: CdImageReader,
|
||||||
|
progressCallback: suspend (String) -> Unit
|
||||||
|
): File {
|
||||||
|
val dir = store.createDirForGame()
|
||||||
|
var committed = false
|
||||||
|
try {
|
||||||
|
val gameDir = extractCdImage(cdImage, dir, progressCallback)
|
||||||
|
committed = true
|
||||||
|
return gameDir
|
||||||
|
} finally {
|
||||||
|
if (!committed && !dir.deleteRecursively()) {
|
||||||
|
Log.w("launcher", "Failed to delete incomplete install directory: $dir")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun extractFiles(
|
||||||
|
input: InputStream,
|
||||||
|
outDir: File,
|
||||||
|
progressCallback: suspend (String) -> Unit
|
||||||
|
): File {
|
||||||
|
val configWriter = GameConfigWriter()
|
||||||
|
val hadDecodeError = forEachZipEntrySuspending(input) { zipEntry, zip ->
|
||||||
|
Log.i("extractFiles", zipEntry.name)
|
||||||
|
if (zipEntry.isDirectory)
|
||||||
|
return@forEachZipEntrySuspending
|
||||||
|
val resolvedPath = resolveOutputPath(outDir, zipEntry.name)
|
||||||
|
val path = resolvedPath.file
|
||||||
|
path.parentFile?.mkdirs()
|
||||||
|
progressCallback(resolvedPath.relativePath)
|
||||||
|
FileOutputStream(path).buffered().use {
|
||||||
|
zip.copyTo(it)
|
||||||
|
}
|
||||||
|
configWriter.maybeAdd(resolvedPath.relativePath)
|
||||||
|
}
|
||||||
|
if (!configWriter.ready) {
|
||||||
|
if (hadDecodeError)
|
||||||
|
throw InstallFailureException(R.string.unsupported_zip)
|
||||||
|
throw InstallFailureException(R.string.cannot_find_ald)
|
||||||
|
}
|
||||||
|
configWriter.write(outDir)
|
||||||
|
return configWriter.gameDir?.let { File(outDir, it) } ?: outDir
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun extractCdImage(
|
||||||
|
files: List<SelectedInstallFile>,
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
tempDir: File,
|
||||||
|
outDir: File,
|
||||||
|
progressCallback: suspend (String) -> Unit
|
||||||
|
): File {
|
||||||
|
progressCallback("metadata parsing")
|
||||||
|
CdImageReader.open(contentResolver, files, tempDir).use { cdImage ->
|
||||||
|
return extractCdImage(cdImage, outDir, progressCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun extractCdImage(
|
||||||
|
cdImage: CdImageReader,
|
||||||
|
outDir: File,
|
||||||
|
progressCallback: suspend (String) -> Unit
|
||||||
|
): File {
|
||||||
|
val fs = Iso9660FileSystem(cdImage)
|
||||||
|
val gameData = fs.findGameDataDirectory()
|
||||||
|
?: throw InstallFailureException(R.string.cannot_find_game_data_directory)
|
||||||
|
var foundAld = false
|
||||||
|
fs.extractDirectory(gameData, "GAMEDATA") { path, input ->
|
||||||
|
val resolvedPath = resolveOutputPath(outDir, path)
|
||||||
|
resolvedPath.file.parentFile?.mkdirs()
|
||||||
|
progressCallback(resolvedPath.relativePath)
|
||||||
|
FileOutputStream(resolvedPath.file).buffered().use {
|
||||||
|
input.copyTo(it)
|
||||||
|
}
|
||||||
|
if (File(path).name.matches(""".*?s[a-z]\.ald""".toRegex(RegexOption.IGNORE_CASE))) {
|
||||||
|
foundAld = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundAld) {
|
||||||
|
throw InstallFailureException(R.string.cannot_find_ald)
|
||||||
|
}
|
||||||
|
File(outDir, Launcher.GAMEDIR_FILE).writeText("GAMEDATA")
|
||||||
|
extractAudioTracks(cdImage, File(outDir, "GAMEDATA"), progressCallback)
|
||||||
|
return File(outDir, "GAMEDATA")
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun extractAudioTracks(
|
||||||
|
cdImage: CdImageReader,
|
||||||
|
gameDir: File,
|
||||||
|
progressCallback: suspend (String) -> Unit
|
||||||
|
) {
|
||||||
|
val audioTracks = cdImage.audioTracks()
|
||||||
|
if (audioTracks.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val cddaDir = File(gameDir, "cdda")
|
||||||
|
cddaDir.mkdirs()
|
||||||
|
val playlist = arrayOfNulls<String>(audioTracks.maxOrNull() ?: 0)
|
||||||
|
for (track in audioTracks) {
|
||||||
|
val relativePath = "cdda/track%02d.wav".format(track)
|
||||||
|
val outputFile = File(gameDir, relativePath)
|
||||||
|
progressCallback(relativePath)
|
||||||
|
FileOutputStream(outputFile).buffered().use {
|
||||||
|
cdImage.extractAudioTrack(track, it)
|
||||||
|
}
|
||||||
|
playlist[track - 1] = relativePath
|
||||||
|
}
|
||||||
|
File(gameDir, Launcher.PLAYLIST_FILE).writeText(playlist.joinToString("\n") { it ?: "" }.trimEnd('\n'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class InstallFailureException(val msgId: Int) : Exception()
|
||||||
|
|
||||||
|
// A helper class which generates GAMEDIR_FILE and PLAYLIST_FILE.
|
||||||
|
private class GameConfigWriter {
|
||||||
|
var ready = false
|
||||||
|
private set
|
||||||
|
var gameDir: String? = null
|
||||||
|
private set
|
||||||
|
private val aldRegex = """.*?s[a-z]\.ald""".toRegex(RegexOption.IGNORE_CASE)
|
||||||
|
private val audioRegex = """((\d+).*|.*?(\d+))\.(wav|mp3|ogg)""".toRegex(RegexOption.IGNORE_CASE)
|
||||||
|
private val audioFiles: Array<String?> = arrayOfNulls(100)
|
||||||
|
|
||||||
|
fun maybeAdd(path: String) {
|
||||||
|
val name = File(path).name
|
||||||
|
aldRegex.matchEntire(name)?.let {
|
||||||
|
gameDir = File(path).parent
|
||||||
|
ready = true
|
||||||
|
}
|
||||||
|
audioRegex.matchEntire(name)?.let {
|
||||||
|
val track = it.groupValues[2].toIntOrNull() ?: it.groupValues[3].toInt()
|
||||||
|
if (0 < track && track <= audioFiles.size)
|
||||||
|
audioFiles[track - 1] = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun write(outDir: File) {
|
||||||
|
// Generate GAMEDIR_FILE
|
||||||
|
gameDir?.let {
|
||||||
|
File(outDir, Launcher.GAMEDIR_FILE).writeText(it)
|
||||||
|
}
|
||||||
|
// Generate PLAYLIST_FILE
|
||||||
|
val absGameDir = gameDir?.let { File(outDir, it) } ?: outDir
|
||||||
|
val playlistFile = File(absGameDir, Launcher.PLAYLIST_FILE)
|
||||||
|
if (!playlistFile.exists()) {
|
||||||
|
val prefixToRemove = gameDir?.let { "$it/" } ?: ""
|
||||||
|
val playlist = audioFiles.joinToString("\n") {
|
||||||
|
it?.removePrefix(prefixToRemove) ?: ""
|
||||||
|
}.trimEnd('\n')
|
||||||
|
playlistFile.writeText(playlist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property file Safe canonical output path.
|
||||||
|
* @property relativePath Path relative to the install root after canonicalization.
|
||||||
|
*/
|
||||||
|
internal data class ResolvedOutputPath(val file: File, val relativePath: String)
|
||||||
|
|
||||||
|
internal fun resolveOutputPath(baseDir: File, relativePath: String): ResolvedOutputPath {
|
||||||
|
if (File(relativePath).isAbsolute) {
|
||||||
|
throw IOException("Output path is absolute: $relativePath")
|
||||||
|
}
|
||||||
|
val canonicalBase = baseDir.canonicalFile
|
||||||
|
val file = File(canonicalBase, relativePath).canonicalFile
|
||||||
|
if (!isFileInsideDirectory(file, canonicalBase)) {
|
||||||
|
throw IOException("Output path is outside target directory: $relativePath")
|
||||||
|
}
|
||||||
|
val basePath = canonicalBase.path + File.separator
|
||||||
|
val canonicalRelativePath = file.path.removePrefix(basePath)
|
||||||
|
return ResolvedOutputPath(file, canonicalRelativePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isFileInsideDirectory(file: File, directory: File): Boolean {
|
||||||
|
return file.path.startsWith(directory.path + File.separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun forEachZipEntry(input: InputStream, action: (ZipEntry, ZipInputStream) -> Unit): Boolean =
|
||||||
|
runBlocking {
|
||||||
|
forEachZipEntrySuspending(input) { zipEntry, zip ->
|
||||||
|
action(zipEntry, zip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun forEachZipEntrySuspending(
|
||||||
|
input: InputStream,
|
||||||
|
action: suspend (ZipEntry, ZipInputStream) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
val zip = if (Build.VERSION.SDK_INT >= 24) {
|
||||||
|
ZipInputStream(input.buffered(), Charset.forName("Shift_JIS"))
|
||||||
|
} else {
|
||||||
|
ZipInputStream(input.buffered())
|
||||||
|
}
|
||||||
|
var hadDecodeError = false
|
||||||
|
zip.use {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
val zipEntry = zip.nextEntry ?: break
|
||||||
|
action(zipEntry, zip)
|
||||||
|
} catch (e: UTFDataFormatException) {
|
||||||
|
// Attempted to read Shift_JIS zip in Android < 7
|
||||||
|
Log.w("forEachZipEntry", "UTFDataFormatException: skipping a zip entry")
|
||||||
|
zip.closeEntry()
|
||||||
|
hadDecodeError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hadDecodeError
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package io.github.kichikuou.xsystem35
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.UTFDataFormatException
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
|
class GameStore(private val rootDir: File) {
|
||||||
|
data class Entry(val path: File, val title: String, val timestamp: Long)
|
||||||
|
|
||||||
|
private val gameList = arrayListOf<Entry>()
|
||||||
|
val games: List<Entry>
|
||||||
|
get() = gameList
|
||||||
|
val titles: List<String>
|
||||||
|
get() = gameList.map(Entry::title)
|
||||||
|
|
||||||
|
init {
|
||||||
|
updateGameList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun uninstall(id: Int) {
|
||||||
|
gameList[id].path.deleteRecursively()
|
||||||
|
gameList.removeAt(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateGameList() {
|
||||||
|
var saveDirFound = false
|
||||||
|
gameList.clear()
|
||||||
|
for (path in rootDir.listFiles() ?: emptyArray()) {
|
||||||
|
if (!path.isDirectory)
|
||||||
|
continue
|
||||||
|
if (path.name == Launcher.SAVE_DIR) {
|
||||||
|
saveDirFound = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val gameDirFile = File(path, Launcher.GAMEDIR_FILE)
|
||||||
|
val gamePath = if (gameDirFile.exists()) File(path, gameDirFile.readText()) else path
|
||||||
|
val titleFile = File(gamePath, Launcher.TITLE_FILE)
|
||||||
|
val title = titleFile.readText()
|
||||||
|
gameList.add(Entry(gamePath, title, titleFile.lastModified()))
|
||||||
|
migratePlaylist(path)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
// Incomplete game installation. Delete it.
|
||||||
|
path.deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gameList.sortByDescending(Entry::timestamp)
|
||||||
|
if (!saveDirFound) {
|
||||||
|
File(rootDir, Launcher.SAVE_DIR).mkdir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDirForGame(): File {
|
||||||
|
var i = 0
|
||||||
|
while (true) {
|
||||||
|
val f = File(rootDir, i++.toString())
|
||||||
|
if (!f.exists() && f.mkdir()) {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throws IOException
|
||||||
|
fun exportSaveData(output: OutputStream) {
|
||||||
|
ZipOutputStream(output.buffered()).use { zip ->
|
||||||
|
for (path in File(rootDir, Launcher.SAVE_DIR).listFiles() ?: emptyArray()) {
|
||||||
|
if (path.isDirectory || path.name.endsWith(".asd."))
|
||||||
|
continue
|
||||||
|
val pathInZip = "${Launcher.SAVE_DIR}/${path.name}"
|
||||||
|
Log.i("exportSaveData", pathInZip)
|
||||||
|
zip.putNextEntry(ZipEntry(pathInZip))
|
||||||
|
path.inputStream().buffered().use {
|
||||||
|
it.copyTo(zip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun importSaveData(input: InputStream): Int? {
|
||||||
|
try {
|
||||||
|
var imported = false
|
||||||
|
forEachZipEntry(input) { zipEntry, zip ->
|
||||||
|
// Process only files directly under save/
|
||||||
|
if (zipEntry.isDirectory || !zipEntry.name.startsWith("save/") ||
|
||||||
|
zipEntry.name.count{it == '/'} != 1)
|
||||||
|
return@forEachZipEntry
|
||||||
|
val path = resolveOutputPath(rootDir, zipEntry.name).file
|
||||||
|
Log.i("importSaveData", zipEntry.name)
|
||||||
|
FileOutputStream(path).buffered().use {
|
||||||
|
zip.copyTo(it)
|
||||||
|
}
|
||||||
|
imported = true
|
||||||
|
}
|
||||||
|
return if (imported) null else R.string.no_data_to_import
|
||||||
|
} catch (e: UTFDataFormatException) {
|
||||||
|
// Attempted to read Shift_JIS zip in Android < 7
|
||||||
|
return R.string.unsupported_zip
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e("launcher", "Failed to extract ZIP", e)
|
||||||
|
return R.string.zip_extraction_error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearSaveData(): Boolean {
|
||||||
|
var success = true
|
||||||
|
File(rootDir, Launcher.SAVE_DIR).listFiles()?.forEach { file ->
|
||||||
|
if (!file.deleteRecursively()) success = false
|
||||||
|
}
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
// Xsystem35-sdl2 2.3.0 - 2.11.1 used playlist2.txt. Rename it to playlist.txt.
|
||||||
|
private fun migratePlaylist(dir: File) {
|
||||||
|
val oldPlaylist = File(dir, Launcher.OLD_PLAYLIST_FILE)
|
||||||
|
if (oldPlaylist.exists()) {
|
||||||
|
oldPlaylist.renameTo(File(dir, Launcher.PLAYLIST_FILE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
/* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package io.github.kichikuou.xsystem35
|
||||||
|
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
internal class Iso9660FileSystem(private val image: CdImageReader) {
|
||||||
|
private val descriptor = readBestVolumeDescriptor()
|
||||||
|
|
||||||
|
data class Entry(
|
||||||
|
val name: String,
|
||||||
|
val extent: Int,
|
||||||
|
val size: Int,
|
||||||
|
val isDirectory: Boolean,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun findGameDataDirectory(): Entry? {
|
||||||
|
return listDirectory(descriptor.rootDirectory).firstOrNull {
|
||||||
|
it.isDirectory && it.name.uppercase(Locale.US) == "GAMEDATA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun extractDirectory(
|
||||||
|
directory: Entry,
|
||||||
|
outputPath: String,
|
||||||
|
writeFile: suspend (String, InputStream) -> Unit,
|
||||||
|
) {
|
||||||
|
for (entry in listDirectory(directory)) {
|
||||||
|
val childPath = "$outputPath/${entry.name}"
|
||||||
|
if (entry.isDirectory) {
|
||||||
|
extractDirectory(entry, childPath, writeFile)
|
||||||
|
} else {
|
||||||
|
writeFile(childPath, fileInputStream(entry))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listDirectory(directory: Entry): List<Entry> {
|
||||||
|
val bytes = ByteArray(directory.size)
|
||||||
|
image.readDataFully(
|
||||||
|
directory.extent.toLong() * CdImageReader.ISO_SECTOR_SIZE,
|
||||||
|
bytes,
|
||||||
|
0,
|
||||||
|
bytes.size
|
||||||
|
)
|
||||||
|
val entries = mutableListOf<Entry>()
|
||||||
|
var offset = 0
|
||||||
|
while (offset < bytes.size) {
|
||||||
|
val length = bytes[offset].toInt() and 0xff
|
||||||
|
if (length == 0) {
|
||||||
|
offset = ((offset / CdImageReader.ISO_SECTOR_SIZE) + 1) * CdImageReader.ISO_SECTOR_SIZE
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parseDirectoryRecord(bytes, offset, length)?.let { entries.add(it) }
|
||||||
|
offset += length
|
||||||
|
}
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseDirectoryRecord(bytes: ByteArray, offset: Int, length: Int): Entry? {
|
||||||
|
if (length < 34) {
|
||||||
|
throw InstallFailureException(R.string.invalid_iso9660_image)
|
||||||
|
}
|
||||||
|
val nameLength = bytes[offset + 32].toInt() and 0xff
|
||||||
|
if (33 + nameLength > length) {
|
||||||
|
throw InstallFailureException(R.string.invalid_iso9660_image)
|
||||||
|
}
|
||||||
|
val rawName = bytes.copyOfRange(offset + 33, offset + 33 + nameLength)
|
||||||
|
if (rawName.size == 1 && (rawName[0].toInt() == 0 || rawName[0].toInt() == 1)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val name = descriptor.decodeName(rawName)
|
||||||
|
val extent = readLittleEndianInt(bytes, offset + 2)
|
||||||
|
val size = readLittleEndianInt(bytes, offset + 10)
|
||||||
|
val flags = bytes[offset + 25].toInt() and 0xff
|
||||||
|
return Entry(name, extent, size, flags and 0x02 != 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fileInputStream(entry: Entry): InputStream {
|
||||||
|
return object : InputStream() {
|
||||||
|
private var pos = 0
|
||||||
|
|
||||||
|
override fun read(): Int {
|
||||||
|
val buffer = ByteArray(1)
|
||||||
|
val read = read(buffer, 0, 1)
|
||||||
|
return if (read < 0) -1 else buffer[0].toInt() and 0xff
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(buffer: ByteArray, offset: Int, length: Int): Int {
|
||||||
|
if (pos >= entry.size) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
val count = minOf(length, entry.size - pos)
|
||||||
|
image.readDataFully(
|
||||||
|
entry.extent.toLong() * CdImageReader.ISO_SECTOR_SIZE + pos,
|
||||||
|
buffer,
|
||||||
|
offset,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
pos += count
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readBestVolumeDescriptor(): VolumeDescriptor {
|
||||||
|
var primary: VolumeDescriptor? = null
|
||||||
|
var joliet: VolumeDescriptor? = null
|
||||||
|
val sector = ByteArray(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
var sectorNumber = 0x10
|
||||||
|
while (true) {
|
||||||
|
image.readSector(sectorNumber++, sector)
|
||||||
|
if (String(sector, 1, 5, Charsets.US_ASCII) != "CD001") {
|
||||||
|
throw InstallFailureException(R.string.invalid_iso9660_image)
|
||||||
|
}
|
||||||
|
when (sector[0].toInt() and 0xff) {
|
||||||
|
1 -> primary = VolumeDescriptor(parseRootDirectory(sector), false)
|
||||||
|
2 -> if (isJolietDescriptor(sector)) {
|
||||||
|
joliet = VolumeDescriptor(parseRootDirectory(sector), true)
|
||||||
|
}
|
||||||
|
255 -> return joliet ?: primary
|
||||||
|
?: throw InstallFailureException(R.string.invalid_iso9660_image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseRootDirectory(sector: ByteArray): Entry {
|
||||||
|
return Entry(
|
||||||
|
name = "",
|
||||||
|
extent = readLittleEndianInt(sector, 156 + 2),
|
||||||
|
size = readLittleEndianInt(sector, 156 + 10),
|
||||||
|
isDirectory = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isJolietDescriptor(sector: ByteArray): Boolean {
|
||||||
|
return sector[88] == 0x25.toByte() &&
|
||||||
|
sector[89] == 0x2f.toByte() &&
|
||||||
|
(sector[90] == 0x40.toByte() || sector[90] == 0x43.toByte() || sector[90] == 0x45.toByte())
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class VolumeDescriptor(
|
||||||
|
val rootDirectory: Entry,
|
||||||
|
val joliet: Boolean,
|
||||||
|
) {
|
||||||
|
fun decodeName(rawName: ByteArray): String {
|
||||||
|
val charset = if (joliet) Charsets.UTF_16BE else Charset.forName("Shift_JIS")
|
||||||
|
return String(rawName, charset).substringBefore(";")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readLittleEndianInt(bytes: ByteArray, offset: Int): Int {
|
||||||
|
return (bytes[offset].toInt() and 0xff) or
|
||||||
|
((bytes[offset + 1].toInt() and 0xff) shl 8) or
|
||||||
|
((bytes[offset + 2].toInt() and 0xff) shl 16) or
|
||||||
|
((bytes[offset + 3].toInt() and 0xff) shl 24)
|
||||||
|
}
|
||||||
@@ -17,18 +17,15 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.kichikuou.xsystem35
|
package io.github.kichikuou.xsystem35
|
||||||
|
|
||||||
import android.os.Build
|
import android.content.ContentResolver
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.nio.charset.Charset
|
|
||||||
import java.util.zip.ZipEntry
|
|
||||||
import java.util.zip.ZipInputStream
|
|
||||||
import java.util.zip.ZipOutputStream
|
|
||||||
|
|
||||||
private var gLauncher: Launcher? = null
|
private var gLauncher: Launcher? = null
|
||||||
|
|
||||||
@@ -39,11 +36,18 @@ interface LauncherObserver {
|
|||||||
fun onInstallFailure(msgId: Int)
|
fun onInstallFailure(msgId: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Launcher private constructor(private val rootDir: File) {
|
sealed class InstallState {
|
||||||
|
object Idle : InstallState()
|
||||||
|
data class Installing(val progress: String?) : InstallState()
|
||||||
|
data class Succeeded(val path: File, val archiveName: String?) : InstallState()
|
||||||
|
data class Failed(val msgId: Int) : InstallState()
|
||||||
|
}
|
||||||
|
|
||||||
|
data class InstallResult(val path: File, val archiveName: String?)
|
||||||
|
|
||||||
|
class Launcher private constructor(rootDir: File) {
|
||||||
companion object {
|
companion object {
|
||||||
const val SAVE_DIR = "save"
|
const val SAVE_DIR = "save"
|
||||||
const val PREFS_NAME = "settings"
|
|
||||||
const val PREF_VIRTUAL_POINTER = "virtual_pointer"
|
|
||||||
const val TITLE_FILE = "title.txt"
|
const val TITLE_FILE = "title.txt"
|
||||||
const val GAMEDIR_FILE = "game_directory.txt"
|
const val GAMEDIR_FILE = "game_directory.txt"
|
||||||
const val PLAYLIST_FILE = "playlist.txt"
|
const val PLAYLIST_FILE = "playlist.txt"
|
||||||
@@ -56,234 +60,118 @@ class Launcher private constructor(private val rootDir: File) {
|
|||||||
return gLauncher!!
|
return gLauncher!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateGameList() {
|
|
||||||
gLauncher?.updateGameList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Entry(val path: File, val title: String, val timestamp: Long)
|
private val store = GameStore(rootDir)
|
||||||
val games = arrayListOf<Entry>()
|
private val installer = GameInstaller(store)
|
||||||
|
val games: List<GameStore.Entry>
|
||||||
|
get() = store.games
|
||||||
val titles: List<String>
|
val titles: List<String>
|
||||||
get() = games.map(Entry::title)
|
get() = store.titles
|
||||||
var observer: LauncherObserver? = null
|
var observer: LauncherObserver? = null
|
||||||
var isInstalling = false
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||||
|
private var installJob: Job? = null
|
||||||
|
var installState: InstallState = InstallState.Idle
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
fun installZip(input: InputStream, archiveName: String?) {
|
||||||
updateGameList()
|
if (installJob?.isActive == true) {
|
||||||
}
|
input.close()
|
||||||
|
return
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
}
|
||||||
fun install(input: InputStream, archiveName: String?) {
|
startInstallJob {
|
||||||
val dir = createDirForGame()
|
val gameDir = withContext(Dispatchers.IO) {
|
||||||
isInstalling = true
|
input.use {
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
installer.installZip(it) { msg ->
|
||||||
try {
|
withContext(Dispatchers.Main) {
|
||||||
val gameDir = withContext(Dispatchers.IO) {
|
setInstallProgress(msg)
|
||||||
extractFiles(input, dir) { msg ->
|
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
|
||||||
observer?.onInstallProgress(msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
observer?.onInstallSuccess(gameDir, archiveName)
|
|
||||||
} catch (e: InstallFailureException) {
|
|
||||||
observer?.onInstallFailure(e.msgId)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("launcher", "Failed to extract ZIP", e)
|
|
||||||
observer?.onInstallFailure(R.string.zip_extraction_error)
|
|
||||||
}
|
}
|
||||||
isInstalling = false
|
InstallResult(gameDir, archiveName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun installCdImage(
|
||||||
|
files: List<SelectedInstallFile>,
|
||||||
|
contentResolver: ContentResolver,
|
||||||
|
tempDir: File,
|
||||||
|
) {
|
||||||
|
if (installJob?.isActive == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
startInstallJob {
|
||||||
|
val gameDir = withContext(Dispatchers.IO) {
|
||||||
|
installer.installCdImage(files, contentResolver, tempDir) { msg ->
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
setInstallProgress(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InstallResult(gameDir, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startInstallJob(block: suspend () -> InstallResult) {
|
||||||
|
if (installJob?.isActive == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
installState = InstallState.Installing(null)
|
||||||
|
installJob = scope.launch {
|
||||||
|
try {
|
||||||
|
val result = block()
|
||||||
|
setInstallSucceeded(result)
|
||||||
|
} catch (e: InstallFailureException) {
|
||||||
|
setInstallFailed(e.msgId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("launcher", "Failed to install game", e)
|
||||||
|
setInstallFailed(R.string.install_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun consumeInstallResult() {
|
||||||
|
if (installState is InstallState.Succeeded || installState is InstallState.Failed) {
|
||||||
|
installState = InstallState.Idle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setInstallProgress(progress: String) {
|
||||||
|
installState = InstallState.Installing(progress)
|
||||||
|
observer?.onInstallProgress(progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setInstallSucceeded(result: InstallResult) {
|
||||||
|
installState = InstallState.Succeeded(result.path, result.archiveName)
|
||||||
|
observer?.onInstallSuccess(result.path, result.archiveName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setInstallFailed(msgId: Int) {
|
||||||
|
installState = InstallState.Failed(msgId)
|
||||||
|
observer?.onInstallFailure(msgId)
|
||||||
|
}
|
||||||
|
|
||||||
fun uninstall(id: Int) {
|
fun uninstall(id: Int) {
|
||||||
games[id].path.deleteRecursively()
|
store.uninstall(id)
|
||||||
games.removeAt(id)
|
|
||||||
observer?.onGameListChange()
|
observer?.onGameListChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateGameList() {
|
fun refreshGameList() {
|
||||||
var saveDirFound = false
|
store.updateGameList()
|
||||||
games.clear()
|
|
||||||
for (path in rootDir.listFiles() ?: emptyArray()) {
|
|
||||||
if (!path.isDirectory)
|
|
||||||
continue
|
|
||||||
if (path.name == SAVE_DIR) {
|
|
||||||
saveDirFound = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
val gameDirFile = File(path, GAMEDIR_FILE)
|
|
||||||
val gamePath = if (gameDirFile.exists()) File(path, gameDirFile.readText()) else path
|
|
||||||
val titleFile = File(gamePath, TITLE_FILE)
|
|
||||||
val title = titleFile.readText()
|
|
||||||
games.add(Entry(gamePath, title, titleFile.lastModified()))
|
|
||||||
migratePlaylist(path)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Incomplete game installation. Delete it.
|
|
||||||
path.deleteRecursively()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
games.sortByDescending(Entry::timestamp)
|
|
||||||
if (!saveDirFound) {
|
|
||||||
File(rootDir, SAVE_DIR).mkdir()
|
|
||||||
}
|
|
||||||
observer?.onGameListChange()
|
observer?.onGameListChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDirForGame(): File {
|
|
||||||
var i = 0
|
|
||||||
while (true) {
|
|
||||||
val f = File(rootDir, i++.toString())
|
|
||||||
if (!f.exists() && f.mkdir()) {
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throws IOException
|
// Throws IOException
|
||||||
fun exportSaveData(output: OutputStream) {
|
fun exportSaveData(output: OutputStream) {
|
||||||
ZipOutputStream(output.buffered()).use { zip ->
|
store.exportSaveData(output)
|
||||||
for (path in File(rootDir, SAVE_DIR).listFiles() ?: emptyArray()) {
|
|
||||||
if (path.isDirectory || path.name.endsWith(".asd."))
|
|
||||||
continue
|
|
||||||
val pathInZip = "${SAVE_DIR}/${path.name}"
|
|
||||||
Log.i("exportSaveData", pathInZip)
|
|
||||||
zip.putNextEntry(ZipEntry(pathInZip))
|
|
||||||
path.inputStream().buffered().use {
|
|
||||||
it.copyTo(zip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun importSaveData(input: InputStream): Int? {
|
fun importSaveData(input: InputStream): Int? {
|
||||||
try {
|
return store.importSaveData(input)
|
||||||
var imported = false
|
|
||||||
forEachZipEntry(input) { zipEntry, zip ->
|
|
||||||
// Process only files directly under save/
|
|
||||||
if (zipEntry.isDirectory || !zipEntry.name.startsWith("save/") ||
|
|
||||||
zipEntry.name.count{it == '/'} != 1)
|
|
||||||
return@forEachZipEntry
|
|
||||||
Log.i("importSaveData", zipEntry.name)
|
|
||||||
FileOutputStream(File(rootDir, zipEntry.name)).buffered().use {
|
|
||||||
zip.copyTo(it)
|
|
||||||
}
|
|
||||||
imported = true
|
|
||||||
}
|
|
||||||
return if (imported) null else R.string.no_data_to_import
|
|
||||||
} catch (e: UTFDataFormatException) {
|
|
||||||
// Attempted to read Shift_JIS zip in Android < 7
|
|
||||||
return R.string.unsupported_zip
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e("launcher", "Failed to extract ZIP", e)
|
|
||||||
return R.string.zip_extraction_error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractFiles(input: InputStream, outDir: File, progressCallback: (String) -> Unit): File {
|
|
||||||
val configWriter = GameConfigWriter()
|
|
||||||
val hadDecodeError = forEachZipEntry(input) { zipEntry, zip ->
|
|
||||||
Log.i("extractFiles", zipEntry.name)
|
|
||||||
val path = File(outDir, zipEntry.name)
|
|
||||||
if (zipEntry.isDirectory)
|
|
||||||
return@forEachZipEntry
|
|
||||||
path.parentFile?.mkdirs()
|
|
||||||
progressCallback(zipEntry.name)
|
|
||||||
FileOutputStream(path).buffered().use {
|
|
||||||
zip.copyTo(it)
|
|
||||||
}
|
|
||||||
configWriter.maybeAdd(zipEntry.name)
|
|
||||||
}
|
|
||||||
if (!configWriter.ready) {
|
|
||||||
if (hadDecodeError)
|
|
||||||
throw InstallFailureException(R.string.unsupported_zip)
|
|
||||||
throw InstallFailureException(R.string.cannot_find_ald)
|
|
||||||
}
|
|
||||||
configWriter.write(outDir)
|
|
||||||
return configWriter.gameDir?.let { File(outDir, it) } ?: outDir
|
|
||||||
}
|
|
||||||
|
|
||||||
// Xsystem35-sdl2 2.3.0 - 2.11.1 used playlist2.txt. Rename it to playlist.txt.
|
|
||||||
private fun migratePlaylist(dir: File) {
|
|
||||||
val oldPlaylist = File(dir, OLD_PLAYLIST_FILE)
|
|
||||||
if (oldPlaylist.exists()) {
|
|
||||||
oldPlaylist.renameTo(File(dir, PLAYLIST_FILE))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class InstallFailureException(val msgId: Int) : Exception()
|
|
||||||
|
|
||||||
// A helper class which generates GAMEDIR_FILE and PLAYLIST_FILE.
|
|
||||||
private class GameConfigWriter {
|
|
||||||
var ready = false
|
|
||||||
private set
|
|
||||||
var gameDir: String? = null
|
|
||||||
private set
|
|
||||||
private val aldRegex = """.*?s[a-z]\.ald""".toRegex(RegexOption.IGNORE_CASE)
|
|
||||||
private val audioRegex = """((\d+).*|.*?(\d+))\.(wav|mp3|ogg)""".toRegex(RegexOption.IGNORE_CASE)
|
|
||||||
private val audioFiles: Array<String?> = arrayOfNulls(100)
|
|
||||||
|
|
||||||
fun maybeAdd(path: String) {
|
|
||||||
val name = File(path).name
|
|
||||||
aldRegex.matchEntire(name)?.let {
|
|
||||||
gameDir = File(path).parent
|
|
||||||
ready = true
|
|
||||||
}
|
|
||||||
audioRegex.matchEntire(name)?.let {
|
|
||||||
val track = it.groupValues[2].toIntOrNull() ?: it.groupValues[3].toInt()
|
|
||||||
if (0 < track && track <= audioFiles.size)
|
|
||||||
audioFiles[track - 1] = path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun write(outDir: File) {
|
|
||||||
// Generate GAMEDIR_FILE
|
|
||||||
gameDir?.let {
|
|
||||||
File(outDir, GAMEDIR_FILE).writeText(it)
|
|
||||||
}
|
|
||||||
// Generate PLAYLIST_FILE
|
|
||||||
val absGameDir = gameDir?.let { File(outDir, it) } ?: outDir
|
|
||||||
val playlistFile = File(absGameDir, PLAYLIST_FILE)
|
|
||||||
if (!playlistFile.exists()) {
|
|
||||||
val prefixToRemove = gameDir?.let { "$it/" } ?: ""
|
|
||||||
val playlist = audioFiles.joinToString("\n") {
|
|
||||||
it?.removePrefix(prefixToRemove) ?: ""
|
|
||||||
}.trimEnd('\n')
|
|
||||||
playlistFile.writeText(playlist)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearSaveData(): Boolean {
|
fun clearSaveData(): Boolean {
|
||||||
var success = true
|
return store.clearSaveData()
|
||||||
File(rootDir, SAVE_DIR).listFiles()?.forEach { file ->
|
|
||||||
if (!file.deleteRecursively()) success = false
|
|
||||||
}
|
|
||||||
return success
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun forEachZipEntry(input: InputStream, action: (ZipEntry, ZipInputStream) -> Unit): Boolean {
|
|
||||||
val zip = if (Build.VERSION.SDK_INT >= 24) {
|
|
||||||
ZipInputStream(input.buffered(), Charset.forName("Shift_JIS"))
|
|
||||||
} else {
|
|
||||||
ZipInputStream(input.buffered())
|
|
||||||
}
|
|
||||||
var hadDecodeError = false
|
|
||||||
zip.use {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
val zipEntry = zip.nextEntry ?: break
|
|
||||||
action(zipEntry, zip)
|
|
||||||
} catch (e: UTFDataFormatException) {
|
|
||||||
// Attempted to read Shift_JIS zip in Android < 7
|
|
||||||
Log.w("forEachZipEntry", "UTFDataFormatException: skipping a zip entry")
|
|
||||||
zip.closeEntry()
|
|
||||||
hadDecodeError = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hadDecodeError
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ import android.widget.Toast
|
|||||||
import java.io.*
|
import java.io.*
|
||||||
|
|
||||||
private const val CONTENT_TYPE_ZIP = "application/zip"
|
private const val CONTENT_TYPE_ZIP = "application/zip"
|
||||||
private const val INSTALL_REQUEST = 1
|
private const val ZIP_INSTALL_REQUEST = 1
|
||||||
private const val SAVEDATA_EXPORT_REQUEST = 2
|
private const val SAVEDATA_EXPORT_REQUEST = 2
|
||||||
private const val SAVEDATA_IMPORT_REQUEST = 3
|
private const val SAVEDATA_IMPORT_REQUEST = 3
|
||||||
private const val STATE_PROGRESS_TEXT = "progressText"
|
private const val CD_IMAGE_INSTALL_REQUEST = 4
|
||||||
|
|
||||||
class LauncherActivity : Activity(), LauncherObserver {
|
class LauncherActivity : Activity(), LauncherObserver {
|
||||||
private lateinit var launcher: Launcher
|
private lateinit var launcher: Launcher
|
||||||
@@ -48,9 +48,7 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
|
|
||||||
launcher = Launcher.getInstance(filesDir)
|
launcher = Launcher.getInstance(filesDir)
|
||||||
launcher.observer = this
|
launcher.observer = this
|
||||||
if (launcher.isInstalling) {
|
renderInstallState(launcher.installState)
|
||||||
showProgressDialog(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
onGameListChange()
|
onGameListChange()
|
||||||
val listView = findViewById<ListView>(R.id.list)
|
val listView = findViewById<ListView>(R.id.list)
|
||||||
@@ -70,11 +68,9 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onResume() {
|
||||||
progressDialog?.let {
|
super.onResume()
|
||||||
outState.putCharSequence(STATE_PROGRESS_TEXT, it.findViewById<TextView>(R.id.text).text)
|
launcher.refreshGameList()
|
||||||
}
|
|
||||||
super.onSaveInstanceState(outState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onListItemClick(position: Int) {
|
private fun onListItemClick(position: Int) {
|
||||||
@@ -92,9 +88,6 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
menuInflater.inflate(R.menu.launcher_menu, menu)
|
menuInflater.inflate(R.menu.launcher_menu, menu)
|
||||||
val prefs = getSharedPreferences(Launcher.PREFS_NAME, MODE_PRIVATE)
|
|
||||||
menu.findItem(R.id.virtual_pointer).isChecked =
|
|
||||||
prefs.getBoolean(Launcher.PREF_VIRTUAL_POINTER, false)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +96,15 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
R.id.install_from_zip -> {
|
R.id.install_from_zip -> {
|
||||||
val i = Intent(Intent.ACTION_GET_CONTENT)
|
val i = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
i.type = CONTENT_TYPE_ZIP
|
i.type = CONTENT_TYPE_ZIP
|
||||||
startActivityForResult(Intent.createChooser(i, getString(R.string.choose_a_file)), INSTALL_REQUEST)
|
startActivityForResult(Intent.createChooser(i, getString(R.string.choose_a_file)), ZIP_INSTALL_REQUEST)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.install_from_cd_image -> {
|
||||||
|
val i = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
|
i.type = "*/*"
|
||||||
|
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||||
|
startActivityForResult(Intent.createChooser(i, getString(R.string.choose_cd_image_files)),
|
||||||
|
CD_IMAGE_INSTALL_REQUEST)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.export_savedata -> {
|
R.id.export_savedata -> {
|
||||||
@@ -146,13 +147,6 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.virtual_pointer -> {
|
|
||||||
val enabled = !item.isChecked
|
|
||||||
item.isChecked = enabled
|
|
||||||
getSharedPreferences(Launcher.PREFS_NAME, MODE_PRIVATE).edit()
|
|
||||||
.putBoolean(Launcher.PREF_VIRTUAL_POINTER, enabled).apply()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,14 +154,20 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
if (resultCode != RESULT_OK)
|
if (resultCode != RESULT_OK)
|
||||||
return
|
return
|
||||||
val uri = data?.data ?: return
|
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
INSTALL_REQUEST -> {
|
ZIP_INSTALL_REQUEST -> {
|
||||||
|
val uri = data?.data ?: return
|
||||||
val input = contentResolver.openInputStream(uri) ?: return
|
val input = contentResolver.openInputStream(uri) ?: return
|
||||||
showProgressDialog()
|
launcher.installZip(input, getArchiveName(uri))
|
||||||
launcher.install(input, getArchiveName(uri))
|
renderInstallState(launcher.installState)
|
||||||
|
}
|
||||||
|
CD_IMAGE_INSTALL_REQUEST -> {
|
||||||
|
val files = getSelectedInstallFiles(data)
|
||||||
|
launcher.installCdImage(files, contentResolver, cacheDir)
|
||||||
|
renderInstallState(launcher.installState)
|
||||||
}
|
}
|
||||||
SAVEDATA_EXPORT_REQUEST -> try {
|
SAVEDATA_EXPORT_REQUEST -> try {
|
||||||
|
val uri = data?.data ?: return
|
||||||
launcher.exportSaveData(contentResolver.openOutputStream(uri)!!)
|
launcher.exportSaveData(contentResolver.openOutputStream(uri)!!)
|
||||||
Toast.makeText(this, R.string.save_data_export_success, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.save_data_export_success, Toast.LENGTH_SHORT).show()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
@@ -175,6 +175,7 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
errorDialog(R.string.save_data_export_error)
|
errorDialog(R.string.save_data_export_error)
|
||||||
}
|
}
|
||||||
SAVEDATA_IMPORT_REQUEST -> {
|
SAVEDATA_IMPORT_REQUEST -> {
|
||||||
|
val uri = data?.data ?: return
|
||||||
val input = contentResolver.openInputStream(uri) ?: return
|
val input = contentResolver.openInputStream(uri) ?: return
|
||||||
val errMsgId = launcher.importSaveData(input)
|
val errMsgId = launcher.importSaveData(input)
|
||||||
if (errMsgId == null) {
|
if (errMsgId == null) {
|
||||||
@@ -194,17 +195,15 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onInstallProgress(path: String) {
|
override fun onInstallProgress(path: String) {
|
||||||
progressDialog?.findViewById<TextView>(R.id.text)?.text = getString(R.string.install_progress, path)
|
renderInstallState(launcher.installState)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInstallSuccess(path: File, archiveName: String?) {
|
override fun onInstallSuccess(path: File, archiveName: String?) {
|
||||||
dismissProgressDialog()
|
renderInstallState(launcher.installState)
|
||||||
startGame(path, archiveName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInstallFailure(msgId: Int) {
|
override fun onInstallFailure(msgId: Int) {
|
||||||
dismissProgressDialog()
|
renderInstallState(launcher.installState)
|
||||||
errorDialog(msgId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startGame(path: File, archiveName: String?) {
|
private fun startGame(path: File, archiveName: String?) {
|
||||||
@@ -220,16 +219,35 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
launcher.uninstall(id)
|
launcher.uninstall(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showProgressDialog(savedInstanceState: Bundle? = null) {
|
private fun renderInstallState(state: InstallState) {
|
||||||
progressDialog = Dialog(this)
|
when (state) {
|
||||||
progressDialog!!.apply {
|
InstallState.Idle -> dismissProgressDialog()
|
||||||
setTitle(R.string.install_dialog_title)
|
is InstallState.Installing -> showProgressDialog(state.progress)
|
||||||
setCancelable(false)
|
is InstallState.Succeeded -> {
|
||||||
setContentView(R.layout.progress_dialog)
|
dismissProgressDialog()
|
||||||
savedInstanceState?.let {
|
startGame(state.path, state.archiveName)
|
||||||
findViewById<TextView>(R.id.text)?.text = it.getCharSequence(STATE_PROGRESS_TEXT)
|
launcher.consumeInstallResult()
|
||||||
}
|
}
|
||||||
show()
|
is InstallState.Failed -> {
|
||||||
|
dismissProgressDialog()
|
||||||
|
errorDialog(state.msgId)
|
||||||
|
launcher.consumeInstallResult()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showProgressDialog(progress: String? = null) {
|
||||||
|
if (progressDialog == null) {
|
||||||
|
progressDialog = Dialog(this)
|
||||||
|
progressDialog!!.apply {
|
||||||
|
setTitle(R.string.install_dialog_title)
|
||||||
|
setCancelable(false)
|
||||||
|
setContentView(R.layout.progress_dialog)
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
progress?.let {
|
||||||
|
progressDialog?.findViewById<TextView>(R.id.text)?.text = getString(R.string.install_progress, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,13 +264,33 @@ class LauncherActivity : Activity(), LauncherObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getArchiveName(uri: Uri): String? {
|
private fun getArchiveName(uri: Uri): String? {
|
||||||
|
val fname = getDisplayName(uri) ?: return null
|
||||||
|
return if (fname.endsWith(".zip", true)) fname.dropLast(4) else fname
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSelectedInstallFiles(data: Intent?): List<SelectedInstallFile> {
|
||||||
|
val files = mutableListOf<SelectedInstallFile>()
|
||||||
|
val clipData = data?.clipData
|
||||||
|
if (clipData != null) {
|
||||||
|
for (i in 0 until clipData.itemCount) {
|
||||||
|
val uri = clipData.getItemAt(i).uri
|
||||||
|
files.add(SelectedInstallFile(uri, getDisplayName(uri) ?: uri.lastPathSegment ?: ""))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data?.data?.let { uri ->
|
||||||
|
files.add(SelectedInstallFile(uri, getDisplayName(uri) ?: uri.lastPathSegment ?: ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDisplayName(uri: Uri): String? {
|
||||||
val cursor = contentResolver.query(uri, null, null, null, null, null)
|
val cursor = contentResolver.query(uri, null, null, null, null, null)
|
||||||
cursor?.use {
|
cursor?.use {
|
||||||
if (it.moveToFirst()) {
|
if (it.moveToFirst()) {
|
||||||
val column = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
val column = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||||
if (column >= 0) {
|
if (column >= 0) {
|
||||||
val fname = it.getString(column)
|
return it.getString(column)
|
||||||
return if (fname.endsWith(".zip", true)) fname.dropLast(4) else fname
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,9 @@ class LicensesMenuActivity : Activity() {
|
|||||||
Entry("xsystem35-sdl2", "xsystem35", "https://github.com/kichikuou/xsystem35-sdl2"),
|
Entry("xsystem35-sdl2", "xsystem35", "https://github.com/kichikuou/xsystem35-sdl2"),
|
||||||
Entry("SDL", "SDL", "https://www.libsdl.org/"),
|
Entry("SDL", "SDL", "https://www.libsdl.org/"),
|
||||||
Entry("SDL_mixer", "SDL_mixer", "https://github.com/libsdl-org/SDL_mixer"),
|
Entry("SDL_mixer", "SDL_mixer", "https://github.com/libsdl-org/SDL_mixer"),
|
||||||
Entry("SDL_ttf", "SDL_ttf", "https://github.com/libsdl-org/SDL_ttf"),
|
|
||||||
Entry("NanoJPEG", "nanojpeg", "https://keyj.emphy.de/nanojpeg/"),
|
Entry("NanoJPEG", "nanojpeg", "https://keyj.emphy.de/nanojpeg/"),
|
||||||
|
Entry("microui", "microui", "https://github.com/rxi/microui"),
|
||||||
Entry("FreeType", "freetype", "https://freetype.org/"),
|
Entry("FreeType", "freetype", "https://freetype.org/"),
|
||||||
Entry("HarfBuzz", "harfbuzz", "https://harfbuzz.github.io/"),
|
|
||||||
Entry("MotoyaLCedar W3 mono", "MTLc3m", "https://github.com/aosp-mirror/platform_frameworks_base/tree/lollipop-release/data/fonts"),
|
Entry("MotoyaLCedar W3 mono", "MTLc3m", "https://github.com/aosp-mirror/platform_frameworks_base/tree/lollipop-release/data/fonts"),
|
||||||
Entry("IPA明朝", "mincho", "https://moji.or.jp/ipafont/"),
|
Entry("IPA明朝", "mincho", "https://moji.or.jp/ipafont/"),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
<item
|
<item
|
||||||
android:id="@+id/install_from_zip"
|
android:id="@+id/install_from_zip"
|
||||||
android:title="@string/action_install_from_zip" />
|
android:title="@string/action_install_from_zip" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/install_from_cd_image"
|
||||||
|
android:title="@string/action_install_from_cd_image" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/export_savedata"
|
android:id="@+id/export_savedata"
|
||||||
android:title="@string/action_export_save_data" />
|
android:title="@string/action_export_save_data" />
|
||||||
@@ -12,14 +15,10 @@
|
|||||||
<item
|
<item
|
||||||
android:id="@+id/clear_savedata"
|
android:id="@+id/clear_savedata"
|
||||||
android:title="@string/action_clear_save_data" />
|
android:title="@string/action_clear_save_data" />
|
||||||
<item
|
|
||||||
android:id="@+id/virtual_pointer"
|
|
||||||
android:checkable="true"
|
|
||||||
android:title="@string/action_virtual_pointer" />
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/help"
|
android:id="@+id/help"
|
||||||
android:title="@string/action_help" />
|
android:title="@string/action_help" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/licenses"
|
android:id="@+id/licenses"
|
||||||
android:title="@string/action_licenses" />
|
android:title="@string/action_licenses" />
|
||||||
</menu>
|
</menu>
|
||||||
|
|||||||
@@ -4,18 +4,24 @@
|
|||||||
<string name="action_export_save_data">セーブデータをエクスポート</string>
|
<string name="action_export_save_data">セーブデータをエクスポート</string>
|
||||||
<string name="action_help">使い方</string>
|
<string name="action_help">使い方</string>
|
||||||
<string name="action_import_save_data">セーブデータをインポート</string>
|
<string name="action_import_save_data">セーブデータをインポート</string>
|
||||||
|
<string name="action_install_from_cd_image">CDイメージからインストール</string>
|
||||||
<string name="action_install_from_zip">ZIPからインストール</string>
|
<string name="action_install_from_zip">ZIPからインストール</string>
|
||||||
<string name="action_licenses">オープンソースライセンス</string>
|
<string name="action_licenses">オープンソースライセンス</string>
|
||||||
<string name="action_clear_save_data">セーブデータをクリア</string>
|
<string name="action_clear_save_data">セーブデータをクリア</string>
|
||||||
<string name="action_virtual_pointer">仮想マウスポインタ</string>
|
|
||||||
<string name="cancel">キャンセル</string>
|
<string name="cancel">キャンセル</string>
|
||||||
<string name="cannot_find_ald">System 3.x のファイル (*.ald) が見つかりません。</string>
|
<string name="cannot_find_ald">System 3.x のファイル (*.ald) が見つかりません。</string>
|
||||||
|
<string name="cannot_find_game_data_directory">CDイメージ内に GAMEDATA ディレクトリが見つかりません。</string>
|
||||||
|
<string name="cd_image_read_error">選択された CD イメージファイルを読み取れません。</string>
|
||||||
<string name="choose_a_file">ファイルを選択</string>
|
<string name="choose_a_file">ファイルを選択</string>
|
||||||
|
<string name="choose_cd_image_files">CDイメージファイルを選択</string>
|
||||||
<string name="clear_save_data_confirm">セーブデータをすべて削除します。元には戻せません。本当によろしいですか?</string>
|
<string name="clear_save_data_confirm">セーブデータをすべて削除します。元には戻せません。本当によろしいですか?</string>
|
||||||
<string name="confirm">確認</string>
|
<string name="confirm">確認</string>
|
||||||
<string name="error_dialog_title">エラー</string>
|
<string name="error_dialog_title">エラー</string>
|
||||||
<string name="install_dialog_title">インストール中…</string>
|
<string name="install_dialog_title">インストール中…</string>
|
||||||
|
<string name="install_error">ゲームのインストールに失敗しました。</string>
|
||||||
<string name="install_progress">%s を展開中</string>
|
<string name="install_progress">%s を展開中</string>
|
||||||
|
<string name="invalid_iso9660_image">有効な ISO9660 イメージではありません。</string>
|
||||||
|
<string name="missing_cd_image_metadata">CD イメージファイルと対応するメタデータファイルを一緒に選択してください。ファイル選択画面ではファイルを長押しすると複数選択モードに入れます。</string>
|
||||||
<string name="no_data_to_import">ZIP アーカイブ中に save/ フォルダが見つかりません。</string>
|
<string name="no_data_to_import">ZIP アーカイブ中に save/ フォルダが見つかりません。</string>
|
||||||
<string name="save_data_export_error">セーブデータのエクスポートに失敗しました。</string>
|
<string name="save_data_export_error">セーブデータのエクスポートに失敗しました。</string>
|
||||||
<string name="save_data_export_success">エクスポートに成功しました。</string>
|
<string name="save_data_export_success">エクスポートに成功しました。</string>
|
||||||
@@ -23,6 +29,7 @@
|
|||||||
<string name="save_data_clear_success">セーブデータをクリアしました。</string>
|
<string name="save_data_clear_success">セーブデータをクリアしました。</string>
|
||||||
<string name="save_data_clear_error">セーブデータのクリアに失敗しました。</string>
|
<string name="save_data_clear_error">セーブデータのクリアに失敗しました。</string>
|
||||||
<string name="uninstall_dialog_message">「%s」をアンインストールしますか?</string>
|
<string name="uninstall_dialog_message">「%s」をアンインストールしますか?</string>
|
||||||
|
<string name="unsupported_cd_image">この CD イメージ形式にはまだ対応していません。現在は .iso、.bin/.img + .cue/.ccd、.mdf/.mds に対応しています。</string>
|
||||||
<string name="unsupported_zip">この形式の ZIP はサポートしていません。</string>
|
<string name="unsupported_zip">この形式の ZIP はサポートしていません。</string>
|
||||||
<string name="zip_extraction_error">ZIP の展開に失敗しました。</string>
|
<string name="zip_extraction_error">ZIP の展開に失敗しました。</string>
|
||||||
<string name="usage">
|
<string name="usage">
|
||||||
@@ -42,4 +49,4 @@
|
|||||||
<p>3. この画面の右上のメニューボタンをタップして「ZIPからインストール」を選択し、転送したZIPを選びます。</p>
|
<p>3. この画面の右上のメニューボタンをタップして「ZIPからインストール」を選択し、転送したZIPを選びます。</p>
|
||||||
]]>
|
]]>
|
||||||
</string>
|
</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -4,17 +4,23 @@
|
|||||||
<string name="action_export_save_data">Export Save Files</string>
|
<string name="action_export_save_data">Export Save Files</string>
|
||||||
<string name="action_help">Help</string>
|
<string name="action_help">Help</string>
|
||||||
<string name="action_import_save_data">Import Save Files</string>
|
<string name="action_import_save_data">Import Save Files</string>
|
||||||
|
<string name="action_install_from_cd_image">Install from CD image</string>
|
||||||
<string name="action_install_from_zip">Install from ZIP</string>
|
<string name="action_install_from_zip">Install from ZIP</string>
|
||||||
<string name="action_licenses">Open source licenses</string>
|
<string name="action_licenses">Open source licenses</string>
|
||||||
<string name="action_virtual_pointer">Virtual mouse pointer</string>
|
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
<string name="cannot_find_ald">Cannot find System 3.x game files (*.ald).</string>
|
<string name="cannot_find_ald">Cannot find System 3.x game files (*.ald).</string>
|
||||||
|
<string name="cannot_find_game_data_directory">Cannot find GAMEDATA directory in the CD image.</string>
|
||||||
|
<string name="cd_image_read_error">Cannot read the selected CD image file.</string>
|
||||||
<string name="choose_a_file">Choose a file</string>
|
<string name="choose_a_file">Choose a file</string>
|
||||||
|
<string name="choose_cd_image_files">Choose CD image files</string>
|
||||||
<string name="clear_save_data_confirm">Are you sure you want to clear all save files? This cannot be undone.</string>
|
<string name="clear_save_data_confirm">Are you sure you want to clear all save files? This cannot be undone.</string>
|
||||||
<string name="confirm">Confirm</string>
|
<string name="confirm">Confirm</string>
|
||||||
<string name="error_dialog_title">Error</string>
|
<string name="error_dialog_title">Error</string>
|
||||||
<string name="install_dialog_title">Installing…</string>
|
<string name="install_dialog_title">Installing…</string>
|
||||||
|
<string name="install_error">Failed to install game.</string>
|
||||||
<string name="install_progress">Extracting %s</string>
|
<string name="install_progress">Extracting %s</string>
|
||||||
|
<string name="invalid_iso9660_image">This file is not a valid ISO9660 image.</string>
|
||||||
|
<string name="missing_cd_image_metadata">Select a matching metadata file with the CD image file. In the file picker, long-press a file to enter multi-select mode.</string>
|
||||||
<string name="no_data_to_import">No save/ folder in the ZIP archive.</string>
|
<string name="no_data_to_import">No save/ folder in the ZIP archive.</string>
|
||||||
<string name="ok">OK</string>
|
<string name="ok">OK</string>
|
||||||
<string name="save_data_clear_error">Failed to clear save files.</string>
|
<string name="save_data_clear_error">Failed to clear save files.</string>
|
||||||
@@ -23,6 +29,7 @@
|
|||||||
<string name="save_data_import_success">Imported successfully.</string>
|
<string name="save_data_import_success">Imported successfully.</string>
|
||||||
<string name="save_data_export_success">Exported successfully.</string>
|
<string name="save_data_export_success">Exported successfully.</string>
|
||||||
<string name="uninstall_dialog_message">Uninstall \"%s\"?</string>
|
<string name="uninstall_dialog_message">Uninstall \"%s\"?</string>
|
||||||
|
<string name="unsupported_cd_image">This CD image format is not supported yet. Currently only .iso, .bin/.img + .cue/.ccd, and .mdf/.mds are supported.</string>
|
||||||
<string name="unsupported_zip">This type of ZIP is not supported.</string>
|
<string name="unsupported_zip">This type of ZIP is not supported.</string>
|
||||||
<string name="zip_extraction_error">Failed to extract ZIP.</string>
|
<string name="zip_extraction_error">Failed to extract ZIP.</string>
|
||||||
<string name="usage">
|
<string name="usage">
|
||||||
|
|||||||
@@ -0,0 +1,714 @@
|
|||||||
|
/* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package io.github.kichikuou.xsystem35
|
||||||
|
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Assert.assertArrayEquals
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Assert.fail
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
class Iso9660FileSystemTest {
|
||||||
|
@get:Rule
|
||||||
|
val tmp = TemporaryFolder()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun extractsGameDataDirectoryFromPrimaryDescriptor() = runBlocking {
|
||||||
|
val iso = SyntheticIsoBuilder()
|
||||||
|
.addGameDataFile("SA.ALD;1", "ald".toByteArray())
|
||||||
|
.addGameDataFile("SUB/FILE.TXT;1", "text".toByteArray())
|
||||||
|
.writeTo(tmp.newFile("game.iso"))
|
||||||
|
|
||||||
|
CdImageReader.openForFile(iso).use { reader ->
|
||||||
|
val fs = Iso9660FileSystem(reader)
|
||||||
|
val gameData = fs.findGameDataDirectory()
|
||||||
|
?: throw AssertionError("GAMEDATA directory was not found")
|
||||||
|
val extracted = mutableMapOf<String, ByteArray>()
|
||||||
|
|
||||||
|
fs.extractDirectory(gameData, "GAMEDATA") { path, input ->
|
||||||
|
extracted[path] = input.readBytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertArrayEquals("ald".toByteArray(), extracted["GAMEDATA/SA.ALD"])
|
||||||
|
assertArrayEquals("text".toByteArray(), extracted["GAMEDATA/SUB/FILE.TXT"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun decodesPrimaryDescriptorNamesAsShiftJis() = runBlocking {
|
||||||
|
val name = "表.TXT;1"
|
||||||
|
val iso = SyntheticIsoBuilder()
|
||||||
|
.addGameDataFile(name, "sjis".toByteArray())
|
||||||
|
.writeTo(tmp.newFile("sjis.iso"))
|
||||||
|
|
||||||
|
CdImageReader.openForFile(iso).use { reader ->
|
||||||
|
val fs = Iso9660FileSystem(reader)
|
||||||
|
val gameData = fs.findGameDataDirectory()
|
||||||
|
?: throw AssertionError("GAMEDATA directory was not found")
|
||||||
|
val extracted = mutableMapOf<String, ByteArray>()
|
||||||
|
|
||||||
|
fs.extractDirectory(gameData, "GAMEDATA") { path, input ->
|
||||||
|
extracted[path] = input.readBytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertArrayEquals("sjis".toByteArray(), extracted["GAMEDATA/表.TXT"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun prefersJolietDescriptorOverPrimaryDescriptor() = runBlocking {
|
||||||
|
val iso = SyntheticIsoBuilder()
|
||||||
|
.addGameDataFile("PRIMARY.TXT;1", "primary".toByteArray())
|
||||||
|
.addJolietGameDataFile("日本語.TXT;1", "joliet".toByteArray())
|
||||||
|
.writeTo(tmp.newFile("joliet.iso"))
|
||||||
|
|
||||||
|
CdImageReader.openForFile(iso).use { reader ->
|
||||||
|
val fs = Iso9660FileSystem(reader)
|
||||||
|
val gameData = fs.findGameDataDirectory()
|
||||||
|
?: throw AssertionError("GAMEDATA directory was not found")
|
||||||
|
val extracted = mutableMapOf<String, ByteArray>()
|
||||||
|
|
||||||
|
fs.extractDirectory(gameData, "GAMEDATA") { path, input ->
|
||||||
|
extracted[path] = input.readBytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(extracted.containsKey("GAMEDATA/PRIMARY.TXT"))
|
||||||
|
assertArrayEquals("joliet".toByteArray(), extracted["GAMEDATA/日本語.TXT"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rejectsInvalidVolumeDescriptorSignature() {
|
||||||
|
val iso = tmp.newFile("invalid.iso")
|
||||||
|
iso.writeBytes(ByteArray(18 * CdImageReader.ISO_SECTOR_SIZE))
|
||||||
|
|
||||||
|
val e = assertInstallFailure(R.string.invalid_iso9660_image) {
|
||||||
|
CdImageReader.openForFile(iso).use { Iso9660FileSystem(it) }
|
||||||
|
}
|
||||||
|
assertEquals(R.string.invalid_iso9660_image, e.msgId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CdImageReaderTest {
|
||||||
|
@get:Rule
|
||||||
|
val tmp = TemporaryFolder()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun readsIsoSectorAt2048ByteOffset() {
|
||||||
|
val sector0 = sectorFilledWith(0x10)
|
||||||
|
val sector1 = sectorFilledWith(0x20)
|
||||||
|
val image = tmp.newFile("plain.iso")
|
||||||
|
image.writeBytes(sector0 + sector1)
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image).use { reader ->
|
||||||
|
val buffer = ByteArray(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
|
||||||
|
reader.readSector(1, buffer)
|
||||||
|
|
||||||
|
assertArrayEquals(sector1, buffer)
|
||||||
|
assertTrue(reader.audioTracks().isEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cueMode12048ReadsDataSector() {
|
||||||
|
val payload = sectorFilledWith(0x31)
|
||||||
|
val image = tmp.newFile("mode2048.bin")
|
||||||
|
image.writeBytes(payload)
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image, "mode2048.cue", cue("MODE1/2048").toByteArray()).use { reader ->
|
||||||
|
val buffer = ByteArray(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
|
||||||
|
reader.readSector(0, buffer)
|
||||||
|
|
||||||
|
assertArrayEquals(payload, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cueMode12352ReadsPayloadAtOffset16() {
|
||||||
|
val payload = sectorFilledWith(0x42)
|
||||||
|
val image = tmp.newFile("mode2352.bin")
|
||||||
|
image.writeBytes(rawDataSector(payload, 0x11))
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image, "mode2352.cue", cue("MODE1/2352").toByteArray()).use { reader ->
|
||||||
|
val buffer = ByteArray(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
|
||||||
|
reader.readSector(0, buffer)
|
||||||
|
|
||||||
|
assertArrayEquals(payload, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cuePregapAdvancesDataTrackStart() {
|
||||||
|
val pregapPayload = sectorFilledWith(0x21)
|
||||||
|
val dataPayload = sectorFilledWith(0x22)
|
||||||
|
val image = tmp.newFile("pregap.bin")
|
||||||
|
image.writeBytes(rawDataSector(pregapPayload, 0x01) + rawDataSector(dataPayload, 0x02))
|
||||||
|
val metadata = """
|
||||||
|
FILE "pregap.bin" BINARY
|
||||||
|
TRACK 01 MODE1/2352
|
||||||
|
INDEX 00 00:00:00
|
||||||
|
INDEX 01 00:00:01
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image, "pregap.cue", metadata.toByteArray()).use { reader ->
|
||||||
|
val buffer = ByteArray(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
|
||||||
|
reader.readSector(1, buffer)
|
||||||
|
|
||||||
|
assertArrayEquals(dataPayload, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun extractsCueAudioTrackAsWav() {
|
||||||
|
val dataPayload = sectorFilledWith(0x33)
|
||||||
|
val audio = ByteArray(RAW_AUDIO_SECTOR_SIZE) { it.toByte() }
|
||||||
|
val image = tmp.newFile("audio.bin")
|
||||||
|
image.writeBytes(rawDataSector(dataPayload, 0) + audio)
|
||||||
|
val metadata = """
|
||||||
|
FILE "audio.bin" BINARY
|
||||||
|
TRACK 01 MODE1/2352
|
||||||
|
INDEX 01 00:00:00
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
INDEX 01 00:00:01
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image, "audio.cue", metadata.toByteArray()).use { reader ->
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
assertEquals(listOf(2), reader.audioTracks())
|
||||||
|
reader.extractAudioTrack(2, output)
|
||||||
|
|
||||||
|
val wav = output.toByteArray()
|
||||||
|
assertEquals("RIFF", wav.decodeAscii(0, 4))
|
||||||
|
assertEquals(RAW_AUDIO_SECTOR_SIZE + 36, wav.readLeInt(4))
|
||||||
|
assertEquals("WAVE", wav.decodeAscii(8, 4))
|
||||||
|
assertEquals("data", wav.decodeAscii(36, 4))
|
||||||
|
assertEquals(RAW_AUDIO_SECTOR_SIZE, wav.readLeInt(40))
|
||||||
|
assertEquals(44100, wav.readLeInt(24))
|
||||||
|
assertEquals(2, wav.readLeShort(22))
|
||||||
|
assertEquals(16, wav.readLeShort(34))
|
||||||
|
assertArrayEquals(audio, wav.copyOfRange(44, 44 + RAW_AUDIO_SECTOR_SIZE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rejectsUnsupportedCueMode() {
|
||||||
|
val image = tmp.newFile("unsupported.bin")
|
||||||
|
image.writeBytes(ByteArray(CdImageReader.ISO_SECTOR_SIZE))
|
||||||
|
|
||||||
|
assertInstallFailure(R.string.unsupported_cd_image) {
|
||||||
|
CdImageReader.openForFile(image, "unsupported.cue", cue("MODE2/2352").toByteArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun ccdUsesMode0ForAudioAndMode1PayloadOffsetForData() {
|
||||||
|
val dataPayload = sectorFilledWith(0x52)
|
||||||
|
val audio = ByteArray(RAW_AUDIO_SECTOR_SIZE) { (255 - it).toByte() }
|
||||||
|
val image = tmp.newFile("disc.img")
|
||||||
|
image.writeBytes(rawDataSector(dataPayload, 0x08) + audio)
|
||||||
|
val metadata = """
|
||||||
|
[TRACK 1]
|
||||||
|
MODE=1
|
||||||
|
INDEX 1=0
|
||||||
|
[TRACK 2]
|
||||||
|
MODE=0
|
||||||
|
INDEX 1=1
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image, "disc.ccd", metadata.toByteArray()).use { reader ->
|
||||||
|
val buffer = ByteArray(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
reader.readSector(0, buffer)
|
||||||
|
reader.extractAudioTrack(2, output)
|
||||||
|
|
||||||
|
assertArrayEquals(dataPayload, buffer)
|
||||||
|
assertEquals(listOf(2), reader.audioTracks())
|
||||||
|
assertArrayEquals(audio, output.toByteArray().copyOfRange(44, 44 + RAW_AUDIO_SECTOR_SIZE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun mdsMapsModeAAToDataAndModeA9ToAudio() {
|
||||||
|
val dataPayload = sectorFilledWith(0x61)
|
||||||
|
val audio = ByteArray(RAW_AUDIO_SECTOR_SIZE) { (it * 3).toByte() }
|
||||||
|
val image = tmp.newFile("disc.mdf")
|
||||||
|
image.writeBytes(rawDataSector(dataPayload, 0x09) + audio)
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image, "disc.mds", mds(track1Sectors = 1, track2Sectors = 1)).use { reader ->
|
||||||
|
val buffer = ByteArray(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
reader.readSector(0, buffer)
|
||||||
|
reader.extractAudioTrack(2, output)
|
||||||
|
|
||||||
|
assertArrayEquals(dataPayload, buffer)
|
||||||
|
assertEquals(listOf(2), reader.audioTracks())
|
||||||
|
assertArrayEquals(audio, output.toByteArray().copyOfRange(44, 44 + RAW_AUDIO_SECTOR_SIZE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rejectsMdsWithoutMediaDescriptorSignature() {
|
||||||
|
val image = tmp.newFile("bad.mdf")
|
||||||
|
image.writeBytes(ByteArray(RAW_AUDIO_SECTOR_SIZE))
|
||||||
|
|
||||||
|
assertInstallFailure(R.string.unsupported_cd_image) {
|
||||||
|
CdImageReader.openForFile(image, "bad.mds", ByteArray(0x70))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameInstallerCdImageTest {
|
||||||
|
@get:Rule
|
||||||
|
val tmp = TemporaryFolder()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun installsDataOnlyIso() = runBlocking {
|
||||||
|
val root = tmp.newFolder("root")
|
||||||
|
val iso = SyntheticIsoBuilder()
|
||||||
|
.addGameDataFile("SA.ALD;1", "ald".toByteArray())
|
||||||
|
.addGameDataFile("TITLE.TXT;1", "title".toByteArray())
|
||||||
|
.writeTo(tmp.newFile("game.iso"))
|
||||||
|
|
||||||
|
CdImageReader.openForFile(iso).use { reader ->
|
||||||
|
val gameDir = GameInstaller(GameStore(root)).installCdImageForTest(reader) {}
|
||||||
|
|
||||||
|
assertEquals(File(root, "0/GAMEDATA").canonicalFile, gameDir.canonicalFile)
|
||||||
|
assertEquals("GAMEDATA", File(root, "0/${Launcher.GAMEDIR_FILE}").readText())
|
||||||
|
assertEquals("ald", File(gameDir, "SA.ALD").readText())
|
||||||
|
assertEquals("title", File(gameDir, "TITLE.TXT").readText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun installsCueAudioTrackAndPlaylist() = runBlocking {
|
||||||
|
val root = tmp.newFolder("root")
|
||||||
|
val isoSector = SyntheticIsoBuilder()
|
||||||
|
.addGameDataFile("SA.ALD;1", "ald".toByteArray())
|
||||||
|
.toByteArray()
|
||||||
|
val dataSectors = isoSector.toList().chunked(CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
.joinToByteArray { rawDataSector(it.toByteArray(), 0) }
|
||||||
|
val audio = ByteArray(RAW_AUDIO_SECTOR_SIZE) { (it and 0x7f).toByte() }
|
||||||
|
val image = tmp.newFile("audio.bin")
|
||||||
|
image.writeBytes(dataSectors + audio)
|
||||||
|
val dataSectorCount = isoSector.size / CdImageReader.ISO_SECTOR_SIZE
|
||||||
|
val metadata = """
|
||||||
|
FILE "audio.bin" BINARY
|
||||||
|
TRACK 01 MODE1/2352
|
||||||
|
INDEX 01 00:00:00
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
INDEX 01 ${dataSectorCount.toMsf()}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
CdImageReader.openForFile(image, "audio.cue", metadata.toByteArray()).use { reader ->
|
||||||
|
val gameDir = GameInstaller(GameStore(root)).installCdImageForTest(reader) {}
|
||||||
|
|
||||||
|
val wav = File(gameDir, "cdda/track02.wav")
|
||||||
|
assertTrue(wav.exists())
|
||||||
|
assertEquals("\ncdda/track02.wav", File(gameDir, Launcher.PLAYLIST_FILE).readText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rejectsIsoWithoutGameDataDirectoryAndDeletesIncompleteInstall() = runBlocking {
|
||||||
|
val root = tmp.newFolder("root")
|
||||||
|
val iso = SyntheticIsoBuilder(includeGameData = false).writeTo(tmp.newFile("nogamedata.iso"))
|
||||||
|
|
||||||
|
CdImageReader.openForFile(iso).use { reader ->
|
||||||
|
assertInstallFailure(R.string.cannot_find_game_data_directory) {
|
||||||
|
runBlocking {
|
||||||
|
GameInstaller(GameStore(root)).installCdImageForTest(reader) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(File(root, "0").exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rejectsIsoWithoutAldAndDeletesIncompleteInstall() = runBlocking {
|
||||||
|
val root = tmp.newFolder("root")
|
||||||
|
val iso = SyntheticIsoBuilder()
|
||||||
|
.addGameDataFile("README.TXT;1", "readme".toByteArray())
|
||||||
|
.writeTo(tmp.newFile("noald.iso"))
|
||||||
|
|
||||||
|
CdImageReader.openForFile(iso).use { reader ->
|
||||||
|
assertInstallFailure(R.string.cannot_find_ald) {
|
||||||
|
runBlocking {
|
||||||
|
GameInstaller(GameStore(root)).installCdImageForTest(reader) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(File(root, "0").exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun resolveOutputPathRejectsTraversal() {
|
||||||
|
val base = tmp.newFolder("out")
|
||||||
|
|
||||||
|
assertThrowsIOException {
|
||||||
|
resolveOutputPath(base, "../evil")
|
||||||
|
}
|
||||||
|
assertThrowsIOException {
|
||||||
|
resolveOutputPath(base, File(base.parentFile, "evil").absolutePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SyntheticIsoBuilder(
|
||||||
|
private val includeGameData: Boolean = true,
|
||||||
|
) {
|
||||||
|
private val primaryFiles = mutableMapOf<String, ByteArray>()
|
||||||
|
private val jolietFiles = mutableMapOf<String, ByteArray>()
|
||||||
|
|
||||||
|
fun addGameDataFile(path: String, content: ByteArray): SyntheticIsoBuilder {
|
||||||
|
primaryFiles[path] = content
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addJolietGameDataFile(path: String, content: ByteArray): SyntheticIsoBuilder {
|
||||||
|
jolietFiles[path] = content
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeTo(file: File): File {
|
||||||
|
file.writeBytes(toByteArray())
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toByteArray(): ByteArray {
|
||||||
|
val sectors = MutableList(80) { ByteArray(CdImageReader.ISO_SECTOR_SIZE) }
|
||||||
|
var nextSector = 30
|
||||||
|
val primaryTree = buildTree(primaryFiles, Charset.forName("Shift_JIS"))
|
||||||
|
val primaryRoot = writeTree(sectors, primaryTree, ROOT_SECTOR, GAMEDATA_SECTOR, nextSector, false)
|
||||||
|
nextSector = primaryRoot.nextSector
|
||||||
|
|
||||||
|
writeVolumeDescriptor(sectors[16], 1, ROOT_SECTOR, CdImageReader.ISO_SECTOR_SIZE, false)
|
||||||
|
var terminatorSector = 17
|
||||||
|
if (jolietFiles.isNotEmpty()) {
|
||||||
|
val jolietTree = buildTree(jolietFiles, Charsets.UTF_16BE)
|
||||||
|
writeTree(sectors, jolietTree, JOLIET_ROOT_SECTOR, JOLIET_GAMEDATA_SECTOR, nextSector, true)
|
||||||
|
writeVolumeDescriptor(sectors[17], 2, JOLIET_ROOT_SECTOR, CdImageReader.ISO_SECTOR_SIZE, true)
|
||||||
|
terminatorSector = 18
|
||||||
|
}
|
||||||
|
writeTerminator(sectors[terminatorSector])
|
||||||
|
return sectors.flattenToByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildTree(files: Map<String, ByteArray>, charset: Charset): DirectoryNode {
|
||||||
|
val root = DirectoryNode("")
|
||||||
|
if (!includeGameData) {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
val gameData = DirectoryNode("GAMEDATA")
|
||||||
|
root.directories["GAMEDATA"] = gameData
|
||||||
|
for ((path, content) in files) {
|
||||||
|
var directory = gameData
|
||||||
|
val parts = path.split("/")
|
||||||
|
for (part in parts.dropLast(1)) {
|
||||||
|
directory = directory.directories.getOrPut(part.substringBefore(";")) {
|
||||||
|
DirectoryNode(part.substringBefore(";"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val rawName = parts.last().toByteArray(charset)
|
||||||
|
directory.files.add(FileNode(rawName, content))
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeTree(
|
||||||
|
sectors: MutableList<ByteArray>,
|
||||||
|
root: DirectoryNode,
|
||||||
|
rootSector: Int,
|
||||||
|
gameDataSector: Int,
|
||||||
|
firstFileSector: Int,
|
||||||
|
joliet: Boolean,
|
||||||
|
): TreeWriteResult {
|
||||||
|
var nextSector = firstFileSector
|
||||||
|
root.extent = rootSector
|
||||||
|
root.size = CdImageReader.ISO_SECTOR_SIZE
|
||||||
|
if (includeGameData) {
|
||||||
|
root.directories["GAMEDATA"]!!.extent = gameDataSector
|
||||||
|
root.directories["GAMEDATA"]!!.size = CdImageReader.ISO_SECTOR_SIZE
|
||||||
|
}
|
||||||
|
assignDirectorySectors(root, gameDataSector + 1)
|
||||||
|
nextSector = writeFileContents(sectors, root, nextSector)
|
||||||
|
writeDirectorySector(sectors[rootSector], root, root, joliet)
|
||||||
|
if (includeGameData) {
|
||||||
|
writeDirectorySectors(sectors, root.directories["GAMEDATA"]!!, root, joliet)
|
||||||
|
}
|
||||||
|
return TreeWriteResult(nextSector)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assignDirectorySectors(directory: DirectoryNode, nextDirectorySector: Int): Int {
|
||||||
|
var sector = nextDirectorySector
|
||||||
|
for (child in directory.directories.values) {
|
||||||
|
if (child.name == "GAMEDATA") {
|
||||||
|
sector = assignDirectorySectors(child, sector)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
child.extent = sector++
|
||||||
|
child.size = CdImageReader.ISO_SECTOR_SIZE
|
||||||
|
sector = assignDirectorySectors(child, sector)
|
||||||
|
}
|
||||||
|
return sector
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeFileContents(
|
||||||
|
sectors: MutableList<ByteArray>,
|
||||||
|
directory: DirectoryNode,
|
||||||
|
firstFileSector: Int,
|
||||||
|
): Int {
|
||||||
|
var sector = firstFileSector
|
||||||
|
for (child in directory.directories.values) {
|
||||||
|
sector = writeFileContents(sectors, child, sector)
|
||||||
|
}
|
||||||
|
for (file in directory.files) {
|
||||||
|
file.extent = sector
|
||||||
|
file.size = file.content.size
|
||||||
|
val sectorCount = (file.content.size + CdImageReader.ISO_SECTOR_SIZE - 1) /
|
||||||
|
CdImageReader.ISO_SECTOR_SIZE
|
||||||
|
for (i in 0 until sectorCount) {
|
||||||
|
file.content.copyInto(
|
||||||
|
sectors[sector + i],
|
||||||
|
0,
|
||||||
|
i * CdImageReader.ISO_SECTOR_SIZE,
|
||||||
|
minOf(file.content.size, (i + 1) * CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sector += maxOf(1, sectorCount)
|
||||||
|
}
|
||||||
|
return sector
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeDirectorySectors(
|
||||||
|
sectors: MutableList<ByteArray>,
|
||||||
|
directory: DirectoryNode,
|
||||||
|
parent: DirectoryNode,
|
||||||
|
joliet: Boolean,
|
||||||
|
) {
|
||||||
|
writeDirectorySector(sectors[directory.extent], directory, parent, joliet)
|
||||||
|
for (child in directory.directories.values) {
|
||||||
|
writeDirectorySectors(sectors, child, directory, joliet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeDirectorySector(
|
||||||
|
sector: ByteArray,
|
||||||
|
directory: DirectoryNode,
|
||||||
|
parent: DirectoryNode,
|
||||||
|
joliet: Boolean,
|
||||||
|
) {
|
||||||
|
var offset = 0
|
||||||
|
offset += writeRecord(sector, offset, byteArrayOf(0), directory.extent, directory.size, true)
|
||||||
|
offset += writeRecord(sector, offset, byteArrayOf(1), parent.extent, parent.size, true)
|
||||||
|
for (child in directory.directories.values) {
|
||||||
|
val name = if (joliet) child.name.toByteArray(Charsets.UTF_16BE) else child.name.toByteArray()
|
||||||
|
offset += writeRecord(sector, offset, name, child.extent, child.size, true)
|
||||||
|
}
|
||||||
|
for (file in directory.files) {
|
||||||
|
offset += writeRecord(sector, offset, file.rawName, file.extent, file.size, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeVolumeDescriptor(
|
||||||
|
sector: ByteArray,
|
||||||
|
type: Int,
|
||||||
|
rootExtent: Int,
|
||||||
|
rootSize: Int,
|
||||||
|
joliet: Boolean,
|
||||||
|
) {
|
||||||
|
sector[0] = type.toByte()
|
||||||
|
"CD001".toByteArray(Charsets.US_ASCII).copyInto(sector, 1)
|
||||||
|
sector[6] = 1
|
||||||
|
if (joliet) {
|
||||||
|
sector[88] = 0x25
|
||||||
|
sector[89] = 0x2f
|
||||||
|
sector[90] = 0x45
|
||||||
|
}
|
||||||
|
writeRecord(sector, 156, byteArrayOf(0), rootExtent, rootSize, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeTerminator(sector: ByteArray) {
|
||||||
|
sector[0] = 255.toByte()
|
||||||
|
"CD001".toByteArray(Charsets.US_ASCII).copyInto(sector, 1)
|
||||||
|
sector[6] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeRecord(
|
||||||
|
buffer: ByteArray,
|
||||||
|
offset: Int,
|
||||||
|
rawName: ByteArray,
|
||||||
|
extent: Int,
|
||||||
|
size: Int,
|
||||||
|
isDirectory: Boolean,
|
||||||
|
): Int {
|
||||||
|
val length = 33 + rawName.size + if (rawName.size % 2 == 0) 1 else 0
|
||||||
|
buffer[offset] = length.toByte()
|
||||||
|
buffer.writeLeInt(offset + 2, extent)
|
||||||
|
buffer.writeLeInt(offset + 10, size)
|
||||||
|
buffer[offset + 25] = if (isDirectory) 0x02 else 0x00
|
||||||
|
buffer[offset + 32] = rawName.size.toByte()
|
||||||
|
rawName.copyInto(buffer, offset + 33)
|
||||||
|
return length
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ROOT_SECTOR = 20
|
||||||
|
private const val GAMEDATA_SECTOR = 21
|
||||||
|
private const val JOLIET_ROOT_SECTOR = 24
|
||||||
|
private const val JOLIET_GAMEDATA_SECTOR = 25
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class DirectoryNode(
|
||||||
|
val name: String,
|
||||||
|
val directories: MutableMap<String, DirectoryNode> = linkedMapOf(),
|
||||||
|
val files: MutableList<FileNode> = mutableListOf(),
|
||||||
|
var extent: Int = 0,
|
||||||
|
var size: Int = 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class FileNode(
|
||||||
|
val rawName: ByteArray,
|
||||||
|
val content: ByteArray,
|
||||||
|
var extent: Int = 0,
|
||||||
|
var size: Int = 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class TreeWriteResult(val nextSector: Int)
|
||||||
|
|
||||||
|
private const val RAW_AUDIO_SECTOR_SIZE = 2352
|
||||||
|
|
||||||
|
private fun cue(mode: String): String = """
|
||||||
|
FILE "image.bin" BINARY
|
||||||
|
TRACK 01 $mode
|
||||||
|
INDEX 01 00:00:00
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
private fun mds(track1Sectors: Int, track2Sectors: Int): ByteArray {
|
||||||
|
val bytes = ByteArray(0x70 + 2 * 0x50 + 2 * 8)
|
||||||
|
"MEDIA DESCRIPTOR".toByteArray(Charsets.US_ASCII).copyInto(bytes, 0)
|
||||||
|
bytes[0x62] = 2
|
||||||
|
val track1 = 0x70
|
||||||
|
bytes[track1] = 0xaa.toByte()
|
||||||
|
bytes[track1 + 0x04] = 1
|
||||||
|
bytes.writeLeShort(track1 + 0x10, RAW_AUDIO_SECTOR_SIZE)
|
||||||
|
bytes.writeLeInt(track1 + 0x28, 0)
|
||||||
|
bytes.writeLeInt(0x70 + 2 * 0x50 + 0x04, track1Sectors)
|
||||||
|
val track2 = 0x70 + 0x50
|
||||||
|
bytes[track2] = 0xa9.toByte()
|
||||||
|
bytes[track2 + 0x04] = 2
|
||||||
|
bytes.writeLeShort(track2 + 0x10, RAW_AUDIO_SECTOR_SIZE)
|
||||||
|
bytes.writeLeInt(track2 + 0x28, track1Sectors * RAW_AUDIO_SECTOR_SIZE)
|
||||||
|
bytes.writeLeInt(0x70 + 2 * 0x50 + 8 + 0x04, track2Sectors)
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sectorFilledWith(value: Int): ByteArray {
|
||||||
|
return ByteArray(CdImageReader.ISO_SECTOR_SIZE) { value.toByte() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rawDataSector(payload: ByteArray, prefixValue: Int): ByteArray {
|
||||||
|
val sector = ByteArray(RAW_AUDIO_SECTOR_SIZE) { prefixValue.toByte() }
|
||||||
|
payload.copyInto(sector, 16, 0, CdImageReader.ISO_SECTOR_SIZE)
|
||||||
|
return sector
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Int.toMsf(): String {
|
||||||
|
val minutes = this / (60 * 75)
|
||||||
|
val seconds = this / 75 % 60
|
||||||
|
val frames = this % 75
|
||||||
|
return "%02d:%02d:%02d".format(minutes, seconds, frames)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Iterable<Byte>.toByteArray(): ByteArray {
|
||||||
|
val result = ByteArray(count())
|
||||||
|
forEachIndexed { index, byte -> result[index] = byte }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<ByteArray>.flattenToByteArray(): ByteArray {
|
||||||
|
val result = ByteArray(sumOf { it.size })
|
||||||
|
var offset = 0
|
||||||
|
for (bytes in this) {
|
||||||
|
bytes.copyInto(result, offset)
|
||||||
|
offset += bytes.size
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<List<Byte>>.joinToByteArray(transform: (List<Byte>) -> ByteArray): ByteArray {
|
||||||
|
return map(transform).flattenToByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ByteArray.decodeAscii(offset: Int, length: Int): String {
|
||||||
|
return String(this, offset, length, Charsets.US_ASCII)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ByteArray.readLeShort(offset: Int): Int {
|
||||||
|
return (this[offset].toInt() and 0xff) or ((this[offset + 1].toInt() and 0xff) shl 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ByteArray.readLeInt(offset: Int): Int {
|
||||||
|
return readLeShort(offset) or (readLeShort(offset + 2) shl 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ByteArray.writeLeShort(offset: Int, value: Int) {
|
||||||
|
this[offset] = value.toByte()
|
||||||
|
this[offset + 1] = (value shr 8).toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ByteArray.writeLeInt(offset: Int, value: Int) {
|
||||||
|
writeLeShort(offset, value)
|
||||||
|
writeLeShort(offset + 2, value shr 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertInstallFailure(expectedMsgId: Int, block: () -> Unit): InstallFailureException {
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} catch (e: InstallFailureException) {
|
||||||
|
assertEquals(expectedMsgId, e.msgId)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
fail("Expected InstallFailureException")
|
||||||
|
throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertThrowsIOException(block: () -> Unit) {
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fail("Expected IOException")
|
||||||
|
}
|
||||||
+1
-4
@@ -1,17 +1,14 @@
|
|||||||
#cmakedefine PACKAGE "@PACKAGE@"
|
#cmakedefine PACKAGE "@PACKAGE@"
|
||||||
#define VERSION "@XSYSTEM35_VERSION@"
|
#define VERSION "@XSYSTEM35_VERSION@"
|
||||||
|
|
||||||
#cmakedefine CACHE_TOTALSIZE @CACHE_TOTALSIZE@
|
|
||||||
|
|
||||||
#cmakedefine ENABLE_DEBUGGER @ENABLE_DEBUGGER@
|
#cmakedefine ENABLE_DEBUGGER @ENABLE_DEBUGGER@
|
||||||
#cmakedefine ENABLE_GTK @ENABLE_GTK@
|
|
||||||
#cmakedefine ENABLE_MIDI_SDLMIXER @ENABLE_MIDI_SDLMIXER@
|
#cmakedefine ENABLE_MIDI_SDLMIXER @ENABLE_MIDI_SDLMIXER@
|
||||||
#cmakedefine ENABLE_MIDI_PORTMIDI @ENABLE_MIDI_PORTMIDI@
|
#cmakedefine ENABLE_MIDI_PORTMIDI @ENABLE_MIDI_PORTMIDI@
|
||||||
#cmakedefine ENABLE_NLS @ENABLE_NLS@
|
|
||||||
|
|
||||||
#cmakedefine DEFAULT_PLAYLIST_PATH "@DEFAULT_PLAYLIST_PATH@"
|
#cmakedefine DEFAULT_PLAYLIST_PATH "@DEFAULT_PLAYLIST_PATH@"
|
||||||
#cmakedefine JOY_DEVICE "@JOY_DEVICE@"
|
#cmakedefine JOY_DEVICE "@JOY_DEVICE@"
|
||||||
|
|
||||||
|
#cmakedefine HAVE_LIBINTL @HAVE_LIBINTL@
|
||||||
#cmakedefine HAVE_GETLOGIN @HAVE_GETLOGIN@
|
#cmakedefine HAVE_GETLOGIN @HAVE_GETLOGIN@
|
||||||
#cmakedefine HAVE_MMAP @HAVE_MMAP@
|
#cmakedefine HAVE_MMAP @HAVE_MMAP@
|
||||||
#cmakedefine HAVE_SIGACTION @HAVE_SIGACTION@
|
#cmakedefine HAVE_SIGACTION @HAVE_SIGACTION@
|
||||||
|
|||||||
@@ -98,6 +98,9 @@ finds System 3.x game files (*.ALD) from the current directory.
|
|||||||
*-noimagecursor*::
|
*-noimagecursor*::
|
||||||
Disable custom mouse cursor images.
|
Disable custom mouse cursor images.
|
||||||
|
|
||||||
|
*-mute_on_unfocus*::
|
||||||
|
Mute audio while the game window is not in focus.
|
||||||
|
|
||||||
*-version*::
|
*-version*::
|
||||||
Print the version number and exit.
|
Print the version number and exit.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2024 rxi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -12,8 +12,8 @@ or in your `.xsys35rc` file. For example:
|
|||||||
xsystem35 -censor misc/censor/kichikuou.txt
|
xsystem35 -censor misc/censor/kichikuou.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
The list files contain image numbers (integers), one per line. Lines starting
|
The list files contain image numbers (integers), one per line. A `#` starts a
|
||||||
with `#` are treated as comments.
|
comment that continues to the end of the line.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Censor list for ランス -光をもとめて- (Rance: The Quest for Hikari)
|
||||||
|
# Images marked with a * might be allowed in an 18+ stream.
|
||||||
|
5
|
||||||
|
6
|
||||||
|
8
|
||||||
|
22
|
||||||
|
26
|
||||||
|
27
|
||||||
|
29
|
||||||
|
32
|
||||||
|
39
|
||||||
|
40
|
||||||
|
41
|
||||||
|
51
|
||||||
|
56
|
||||||
|
57
|
||||||
|
75
|
||||||
|
76
|
||||||
|
77
|
||||||
|
78 # *
|
||||||
|
80
|
||||||
|
82
|
||||||
|
89
|
||||||
|
91
|
||||||
|
96 # *
|
||||||
|
97 # *
|
||||||
|
98
|
||||||
|
99
|
||||||
|
101
|
||||||
|
208
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Censor list for ランスII (Rance II)
|
||||||
|
# Images marked with a * might be allowed in an 18+ stream.
|
||||||
|
26
|
||||||
|
39 # *
|
||||||
|
40
|
||||||
|
41
|
||||||
|
77
|
||||||
|
78
|
||||||
|
86
|
||||||
|
98
|
||||||
|
103
|
||||||
|
104
|
||||||
|
121
|
||||||
|
122
|
||||||
|
123
|
||||||
|
124
|
||||||
|
130
|
||||||
|
131
|
||||||
|
132
|
||||||
|
133
|
||||||
|
134
|
||||||
|
140
|
||||||
|
141
|
||||||
|
142
|
||||||
|
148
|
||||||
|
156
|
||||||
|
157
|
||||||
|
158
|
||||||
|
159
|
||||||
|
161
|
||||||
|
166
|
||||||
|
171
|
||||||
|
172
|
||||||
|
185
|
||||||
|
187
|
||||||
|
191
|
||||||
|
195
|
||||||
|
197
|
||||||
|
200
|
||||||
|
201
|
||||||
|
234
|
||||||
|
236
|
||||||
|
245
|
||||||
|
246
|
||||||
|
247
|
||||||
|
272
|
||||||
|
274
|
||||||
|
275
|
||||||
|
276
|
||||||
|
278
|
||||||
|
280
|
||||||
|
281
|
||||||
|
282
|
||||||
|
284
|
||||||
|
289
|
||||||
|
292
|
||||||
|
299
|
||||||
|
300
|
||||||
|
302
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# Censor list for Rance 3
|
||||||
|
# Images marked with a * might be allowed in an 18+ stream.
|
||||||
|
1 # *
|
||||||
|
2 # *
|
||||||
|
3
|
||||||
|
6
|
||||||
|
8
|
||||||
|
9
|
||||||
|
32 # *
|
||||||
|
53 # *
|
||||||
|
54
|
||||||
|
70
|
||||||
|
71
|
||||||
|
72
|
||||||
|
73
|
||||||
|
75
|
||||||
|
77 # *
|
||||||
|
78
|
||||||
|
79
|
||||||
|
112 # *
|
||||||
|
113
|
||||||
|
114
|
||||||
|
115
|
||||||
|
116
|
||||||
|
117
|
||||||
|
118 # *
|
||||||
|
150
|
||||||
|
151
|
||||||
|
152
|
||||||
|
153
|
||||||
|
154
|
||||||
|
155
|
||||||
|
166
|
||||||
|
167
|
||||||
|
180
|
||||||
|
181
|
||||||
|
183
|
||||||
|
184
|
||||||
|
185
|
||||||
|
186
|
||||||
|
187
|
||||||
|
188
|
||||||
|
189
|
||||||
|
190
|
||||||
|
195
|
||||||
|
196
|
||||||
|
208
|
||||||
|
209
|
||||||
|
210
|
||||||
|
211
|
||||||
|
212
|
||||||
|
213
|
||||||
|
215
|
||||||
|
216
|
||||||
|
217
|
||||||
|
218
|
||||||
|
219
|
||||||
|
231
|
||||||
|
232
|
||||||
|
233
|
||||||
|
234
|
||||||
|
235
|
||||||
|
236
|
||||||
|
238
|
||||||
|
239
|
||||||
|
260
|
||||||
|
261
|
||||||
|
263
|
||||||
|
264
|
||||||
|
265
|
||||||
|
266
|
||||||
|
268
|
||||||
|
269
|
||||||
|
330
|
||||||
|
331
|
||||||
|
332
|
||||||
|
334
|
||||||
|
335
|
||||||
|
336
|
||||||
|
337
|
||||||
|
338
|
||||||
|
339
|
||||||
|
420
|
||||||
|
421
|
||||||
|
422
|
||||||
|
423
|
||||||
|
424
|
||||||
|
425
|
||||||
|
426
|
||||||
|
427
|
||||||
|
428
|
||||||
|
429
|
||||||
|
440
|
||||||
|
441
|
||||||
|
442
|
||||||
|
443
|
||||||
|
444
|
||||||
|
445
|
||||||
|
447
|
||||||
|
473
|
||||||
|
474
|
||||||
|
475
|
||||||
|
476
|
||||||
|
477
|
||||||
|
479
|
||||||
|
519 # *
|
||||||
|
521 # *
|
||||||
|
523
|
||||||
|
524
|
||||||
|
525
|
||||||
|
526
|
||||||
|
530
|
||||||
|
533 # *
|
||||||
|
534
|
||||||
|
535
|
||||||
|
536
|
||||||
|
537
|
||||||
|
570
|
||||||
|
571
|
||||||
|
572
|
||||||
|
581
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
# Censor list for Rance IV
|
||||||
|
# Images marked with a * might be allowed in an 18+ stream.
|
||||||
|
1
|
||||||
|
2
|
||||||
|
10
|
||||||
|
20
|
||||||
|
26
|
||||||
|
28
|
||||||
|
29
|
||||||
|
30 # *
|
||||||
|
31
|
||||||
|
32
|
||||||
|
33
|
||||||
|
34
|
||||||
|
35
|
||||||
|
36
|
||||||
|
37
|
||||||
|
38
|
||||||
|
39 # *
|
||||||
|
40
|
||||||
|
41
|
||||||
|
42
|
||||||
|
43
|
||||||
|
44
|
||||||
|
45
|
||||||
|
46
|
||||||
|
48
|
||||||
|
49
|
||||||
|
75
|
||||||
|
76
|
||||||
|
77
|
||||||
|
78
|
||||||
|
79
|
||||||
|
122
|
||||||
|
126
|
||||||
|
140
|
||||||
|
142
|
||||||
|
148
|
||||||
|
149
|
||||||
|
162 # *
|
||||||
|
163
|
||||||
|
164
|
||||||
|
165 # *
|
||||||
|
166
|
||||||
|
167
|
||||||
|
168
|
||||||
|
169 # *
|
||||||
|
170
|
||||||
|
171
|
||||||
|
172
|
||||||
|
176
|
||||||
|
177
|
||||||
|
178
|
||||||
|
185
|
||||||
|
186
|
||||||
|
188
|
||||||
|
189
|
||||||
|
205
|
||||||
|
207
|
||||||
|
217 # *
|
||||||
|
220
|
||||||
|
221
|
||||||
|
222
|
||||||
|
223
|
||||||
|
228
|
||||||
|
241
|
||||||
|
242
|
||||||
|
251
|
||||||
|
252
|
||||||
|
253
|
||||||
|
254
|
||||||
|
260
|
||||||
|
261
|
||||||
|
262 # *
|
||||||
|
264 # *
|
||||||
|
265
|
||||||
|
266
|
||||||
|
267
|
||||||
|
268
|
||||||
|
269
|
||||||
|
280
|
||||||
|
281
|
||||||
|
283
|
||||||
|
284
|
||||||
|
285
|
||||||
|
286 # *
|
||||||
|
287
|
||||||
|
288
|
||||||
|
292
|
||||||
|
294
|
||||||
|
299
|
||||||
|
370
|
||||||
|
371
|
||||||
|
372
|
||||||
|
373
|
||||||
|
376
|
||||||
|
378
|
||||||
|
382
|
||||||
|
384
|
||||||
|
385 # *
|
||||||
|
386
|
||||||
|
387
|
||||||
|
388
|
||||||
|
389
|
||||||
|
414 # *
|
||||||
|
416
|
||||||
|
428 # *
|
||||||
|
531 # *
|
||||||
|
532
|
||||||
|
533
|
||||||
|
534 # *
|
||||||
|
535
|
||||||
|
550
|
||||||
|
551
|
||||||
|
552
|
||||||
|
553
|
||||||
|
554
|
||||||
|
555
|
||||||
|
562 # *
|
||||||
|
565
|
||||||
|
615
|
||||||
|
625
|
||||||
|
626
|
||||||
|
711
|
||||||
|
723
|
||||||
|
1055
|
||||||
|
1056
|
||||||
|
1057
|
||||||
|
1058
|
||||||
|
1059
|
||||||
|
1060
|
||||||
|
1061
|
||||||
|
1062
|
||||||
|
1545 # *
|
||||||
|
1546 # *
|
||||||
|
1547 # *
|
||||||
|
1548 # *
|
||||||
|
1549 # *
|
||||||
|
1653 # *
|
||||||
|
1654 # *
|
||||||
|
1655 # *
|
||||||
|
1656 # *
|
||||||
|
1657 # *
|
||||||
|
1658 # *
|
||||||
|
1659 # *
|
||||||
|
1660 # *
|
||||||
|
1661 # *
|
||||||
|
1662 # *
|
||||||
|
1663 # *
|
||||||
|
1664 # *
|
||||||
|
1665 # *
|
||||||
|
1728
|
||||||
|
1729
|
||||||
|
2004
|
||||||
|
2005
|
||||||
|
2006
|
||||||
|
2007
|
||||||
|
2008
|
||||||
|
2009
|
||||||
|
2010
|
||||||
|
2011
|
||||||
|
2012
|
||||||
|
2013
|
||||||
|
2014
|
||||||
|
2015
|
||||||
|
2016
|
||||||
|
2017
|
||||||
|
2018
|
||||||
@@ -12,7 +12,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue(); /* ISys3x */
|
int p1 = getCaliValue(); /* ISys3x */
|
||||||
int p2 = getCaliValue(); /* IWinMsg */
|
int p2 = getCaliValue(); /* IWinMsg */
|
||||||
int p3 = getCaliValue(); /* ITimer */
|
int p3 = getCaliValue(); /* ITimer */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ static void Init() {
|
|||||||
|
|
||||||
static void ExistKeyFile() {
|
static void ExistKeyFile() {
|
||||||
const char *p1 = sl_getString(0);
|
const char *p1 = sl_getString(0);
|
||||||
int *p2 = getCaliVariable();
|
vmvar_t *p2 = getCaliVariable();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ static void ExistKeyFile() {
|
|||||||
|
|
||||||
static void CheckProtectFile() {
|
static void CheckProtectFile() {
|
||||||
const char *p1 = sl_getString(0);
|
const char *p1 = sl_getString(0);
|
||||||
int *p2 = getCaliVariable();
|
vmvar_t *p2 = getCaliVariable();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ static void CheckProtectFile() {
|
|||||||
|
|
||||||
static void CreateKeyFile() {
|
static void CreateKeyFile() {
|
||||||
const char *p1 = sl_getString(0);
|
const char *p1 = sl_getString(0);
|
||||||
int *p2 = getCaliVariable();
|
vmvar_t *p2 = getCaliVariable();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -135,7 +135,7 @@ static void Create() {
|
|||||||
height: surface の高さ
|
height: surface の高さ
|
||||||
bpp : surface の深さ(24bppのみサポート)
|
bpp : surface の深さ(24bppのみサポート)
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int width = getCaliValue();
|
int width = getCaliValue();
|
||||||
int height = getCaliValue();
|
int height = getCaliValue();
|
||||||
int bpp = getCaliValue();
|
int bpp = getCaliValue();
|
||||||
@@ -162,7 +162,7 @@ static void CreatePixelOnly() {
|
|||||||
height: surface の高さ
|
height: surface の高さ
|
||||||
bpp : surface の深さ(24bpp only)
|
bpp : surface の深さ(24bpp only)
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int width = getCaliValue();
|
int width = getCaliValue();
|
||||||
int height = getCaliValue();
|
int height = getCaliValue();
|
||||||
int bpp = getCaliValue();
|
int bpp = getCaliValue();
|
||||||
@@ -188,7 +188,7 @@ static void CreateAMapOnly() {
|
|||||||
width : surface の幅
|
width : surface の幅
|
||||||
height: surface の高さ
|
height: surface の高さ
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int width = getCaliValue();
|
int width = getCaliValue();
|
||||||
int height = getCaliValue();
|
int height = getCaliValue();
|
||||||
surface_t *s;
|
surface_t *s;
|
||||||
@@ -214,7 +214,7 @@ static void IsSurface() {
|
|||||||
var : 結果を返す変数。surface ならば 1, !surface ならば 0
|
var : 結果を返す変数。surface ならば 1, !surface ならば 0
|
||||||
*/
|
*/
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = sf_get(p1) ? 1 : 0;
|
*var = sf_get(p1) ? 1 : 0;
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ static void IsPixel() {
|
|||||||
var : 結果を返す変数。pixel ならば 1, !pixel ならば 0
|
var : 結果を返す変数。pixel ならば 1, !pixel ならば 0
|
||||||
*/
|
*/
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
surface_t *s;
|
surface_t *s;
|
||||||
|
|
||||||
s = sf_get(p1);
|
s = sf_get(p1);
|
||||||
@@ -251,7 +251,7 @@ static void IsAlpha() {
|
|||||||
var : 結果を返す変数。alpha ならば 1, !alpha ならば 0
|
var : 結果を返す変数。alpha ならば 1, !alpha ならば 0
|
||||||
*/
|
*/
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
surface_t *s;
|
surface_t *s;
|
||||||
|
|
||||||
s = sf_get(p1);
|
s = sf_get(p1);
|
||||||
@@ -273,7 +273,7 @@ static void GetWidth() {
|
|||||||
var : 結果を返す変数。
|
var : 結果を返す変数。
|
||||||
*/
|
*/
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
surface_t *s;
|
surface_t *s;
|
||||||
|
|
||||||
s = sf_get(p1);
|
s = sf_get(p1);
|
||||||
@@ -295,7 +295,7 @@ static void GetHeight() {
|
|||||||
var : 結果を返す変数。
|
var : 結果を返す変数。
|
||||||
*/
|
*/
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
surface_t *s;
|
surface_t *s;
|
||||||
|
|
||||||
s = sf_get(p1);
|
s = sf_get(p1);
|
||||||
@@ -310,7 +310,7 @@ static void GetHeight() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetCreatedSurface() { /* not used ? */
|
static void GetCreatedSurface() { /* not used ? */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("Gpx.GetCreatedSurface %p:", var);
|
TRACE_UNIMPLEMENTED("Gpx.GetCreatedSurface %p:", var);
|
||||||
}
|
}
|
||||||
@@ -322,7 +322,7 @@ static void LoadCG() {
|
|||||||
var : 作成した surface の番号を返す変数
|
var : 作成した surface の番号を返す変数
|
||||||
p1 : 読み込む CG の番号
|
p1 : 読み込む CG の番号
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
|
|
||||||
*var = load_cg_main(p1 -1);
|
*var = load_cg_main(p1 -1);
|
||||||
@@ -331,14 +331,14 @@ static void LoadCG() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetCGPosX() { /* not useed ? */
|
static void GetCGPosX() { /* not useed ? */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("Gpx.GetCgPosX %p,%d:", var, p1);
|
TRACE_UNIMPLEMENTED("Gpx.GetCgPosX %p,%d:", var, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetCGPosY() { /* not useed ? */
|
static void GetCGPosY() { /* not useed ? */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("Gpx.GetCgPosY %p,%d:", var, p1);
|
TRACE_UNIMPLEMENTED("Gpx.GetCgPosY %p,%d:", var, p1);
|
||||||
@@ -1117,7 +1117,7 @@ static void EffectCopy() {
|
|||||||
int sw = getCaliValue();
|
int sw = getCaliValue();
|
||||||
int sh = getCaliValue();
|
int sh = getCaliValue();
|
||||||
int time = getCaliValue();
|
int time = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
TRACE("Gpx.EffectCopy %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%p:", no, dx, dy, ss1, sx1, sy1, ss2, sx2, sy2, sw, sh, time, var);
|
TRACE("Gpx.EffectCopy %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%p:", no, dx, dy, ss1, sx1, sy1, ss2, sx2, sy2, sw, sh, time, var);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ void gpx_effect(int no,
|
|||||||
surface_t *src, int sx, int sy,
|
surface_t *src, int sx, int sy,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
int time,
|
int time,
|
||||||
int *endtype) {
|
vmvar_t *endtype) {
|
||||||
surface_t *write = nact->ags.dib;
|
surface_t *write = nact->ags.dib;
|
||||||
if (!gr_clip(dst, &dx, &dy, &width, &height, write, &wx, &wy)) return;
|
if (!gr_clip(dst, &dx, &dy, &width, &height, write, &wx, &wy)) return;
|
||||||
if (!gr_clip(src, &sx, &sy, &width, &height, write, &wx, &wy)) return;
|
if (!gr_clip(src, &sx, &sy, &width, &height, write, &wx, &wy)) return;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef __GLEFFECTCOPY_H__
|
#ifndef __GLEFFECTCOPY_H__
|
||||||
#define __GLEFFECTCOPY_H__
|
#define __GLEFFECTCOPY_H__
|
||||||
|
|
||||||
|
#include "portab.h"
|
||||||
#include "surface.h"
|
#include "surface.h"
|
||||||
|
|
||||||
extern void gpx_effect(int no,
|
extern void gpx_effect(int no,
|
||||||
@@ -9,6 +10,6 @@ extern void gpx_effect(int no,
|
|||||||
surface_t *src, int sx, int sy,
|
surface_t *src, int sx, int sy,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
int time,
|
int time,
|
||||||
int *endtype);
|
vmvar_t *endtype);
|
||||||
|
|
||||||
#endif /* __GLEFFECTCOPY_H__ */
|
#endif /* __GLEFFECTCOPY_H__ */
|
||||||
|
|||||||
+2
-2
@@ -53,7 +53,7 @@ static void RandMTGet() {
|
|||||||
var: 結果を返す変数
|
var: 結果を返す変数
|
||||||
*/
|
*/
|
||||||
int num = getCaliValue();
|
int num = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
if (num == 0 || num == 1) {
|
if (num == 0 || num == 1) {
|
||||||
*var = num;
|
*var = num;
|
||||||
@@ -83,7 +83,7 @@ static void RandMTGetNumTable() {
|
|||||||
|
|
||||||
var: 乱数を格納する変数
|
var: 乱数を格納する変数
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = (int)(genrand() * numtblmax) + 1;
|
*var = (int)(genrand() * numtblmax) + 1;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ static bool valid;
|
|||||||
static int action;
|
static int action;
|
||||||
|
|
||||||
static void Init() {
|
static void Init() {
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int p2 = getCaliValue(); /* ISys3x */
|
int p2 = getCaliValue(); /* ISys3x */
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int p4 = getCaliValue();
|
int p4 = getCaliValue();
|
||||||
@@ -30,7 +30,7 @@ static void Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void Start() {
|
static void Start() {
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
|
|
||||||
char *fname_utf8 = sjis2utf(svar_get(p2));
|
char *fname_utf8 = sjis2utf(svar_get(p2));
|
||||||
@@ -52,7 +52,7 @@ static void SetValid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetValid() {
|
static void GetValid() {
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
*p1 = valid;
|
*p1 = valid;
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ static void SetAction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetAction() {
|
static void GetAction() {
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
*p1 = action;
|
*p1 = action;
|
||||||
|
|
||||||
|
|||||||
+25
-26
@@ -22,7 +22,7 @@ night_t nightprv;
|
|||||||
|
|
||||||
|
|
||||||
static void Init(void) { /* 0 */
|
static void Init(void) { /* 0 */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int p1 = getCaliValue(); /* ISys3xCG */
|
int p1 = getCaliValue(); /* ISys3xCG */
|
||||||
int p2 = getCaliValue(); /* ISys3xDIB */
|
int p2 = getCaliValue(); /* ISys3xDIB */
|
||||||
int p3 = getCaliValue(); /* ISys3xMsgString */
|
int p3 = getCaliValue(); /* ISys3xMsgString */
|
||||||
@@ -56,8 +56,7 @@ static void InitGame() { /* 1 */
|
|||||||
|
|
||||||
nact->msgout = ntmsg_add;
|
nact->msgout = ntmsg_add;
|
||||||
nact->ags.eventcb = ntev_callback;
|
nact->ags.eventcb = ntev_callback;
|
||||||
nact->callback = ntev_main;
|
|
||||||
|
|
||||||
nt_gr_init();
|
nt_gr_init();
|
||||||
ntmsg_init();
|
ntmsg_init();
|
||||||
nt_sstr_init();
|
nt_sstr_init();
|
||||||
@@ -214,7 +213,7 @@ static void SetSelMode(void) { /* 18 */
|
|||||||
|
|
||||||
// キー入力待ち後、改ページ
|
// キー入力待ち後、改ページ
|
||||||
static void AnalyzeMessage(void) { /* 19 */
|
static void AnalyzeMessage(void) { /* 19 */
|
||||||
int *var = getCaliVariable(); // 入力されたキー
|
vmvar_t *var = getCaliVariable(); // 入力されたキー
|
||||||
|
|
||||||
*var = ntmsg_ana();
|
*var = ntmsg_ana();
|
||||||
|
|
||||||
@@ -298,7 +297,7 @@ static void ScreenCG(void) { /* 27 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void RunGameMain(void) { /* 28 */
|
static void RunGameMain(void) { /* 28 */
|
||||||
int *p1 = getCaliVariable(); // result
|
vmvar_t *p1 = getCaliVariable(); // result
|
||||||
int p2 = getCaliValue(); // month
|
int p2 = getCaliValue(); // month
|
||||||
int p3 = getCaliValue(); // day
|
int p3 = getCaliValue(); // day
|
||||||
int p4 = getCaliValue(); // day of week
|
int p4 = getCaliValue(); // day of week
|
||||||
@@ -314,7 +313,7 @@ static void RunGameMain(void) { /* 28 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void CheckNewGame(void) { /* 29 */
|
static void CheckNewGame(void) { /* 29 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
*p1 = 0;
|
*p1 = 0;
|
||||||
|
|
||||||
@@ -348,9 +347,9 @@ static void SetDate(void) { /* 33 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetDate(void) { /* 34 */
|
static void GetDate(void) { /* 34 */
|
||||||
int *p1 = getCaliVariable(); // month
|
vmvar_t *p1 = getCaliVariable(); // month
|
||||||
int *p2 = getCaliVariable(); // day
|
vmvar_t *p2 = getCaliVariable(); // day
|
||||||
int *p3 = getCaliVariable(); // day of weeek
|
vmvar_t *p3 = getCaliVariable(); // day of weeek
|
||||||
|
|
||||||
*p1 = night.Month;
|
*p1 = night.Month;
|
||||||
*p2 = night.Day;
|
*p2 = night.Day;
|
||||||
@@ -364,7 +363,7 @@ static void SelectGameLevel(void) { /* 35 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void RunEventDungeon(void) { /* 36 */
|
static void RunEventDungeon(void) { /* 36 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
|
|
||||||
*p1 = 1;
|
*p1 = 1;
|
||||||
@@ -479,7 +478,7 @@ static void RunSoundMode(void) { /* 48 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void RunMapEditor(void) { /* 49 */
|
static void RunMapEditor(void) { /* 49 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.RunMapEditor %p:", p1);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.RunMapEditor %p:", p1);
|
||||||
}
|
}
|
||||||
@@ -496,21 +495,21 @@ static void VisualListAdd(void) { /* 51 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetLocalCountCG(void) { /* 52 */
|
static void GetLocalCountCG(void) { /* 52 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.GetLocalCountCG %p,%d:", p1, p2);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.GetLocalCountCG %p,%d:", p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PlayMemory(void) { /* 53 */
|
static void PlayMemory(void) { /* 53 */
|
||||||
int *p1 = getCaliVariable(); // 回想ページ
|
vmvar_t *p1 = getCaliVariable(); // 回想ページ
|
||||||
int *p2 = getCaliVariable(); // 回想RESULT
|
vmvar_t *p2 = getCaliVariable(); // 回想RESULT
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.PlayMemory %p,%p:", p1, p2);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.PlayMemory %p,%p:", p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetEventFlagTotal(void) { /* 54 */
|
static void GetEventFlagTotal(void) { /* 54 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.GetEventFlagTotal %p,%d:", p1, p2);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.GetEventFlagTotal %p,%d:", p1, p2);
|
||||||
@@ -529,25 +528,25 @@ static void GetPlayerName(void) { /* 56 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SaveGame(void) { /* 57 */
|
static void SaveGame(void) { /* 57 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.SaveGame %p:", p1);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.SaveGame %p:", p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadGame(void) { /* 58 */
|
static void LoadGame(void) { /* 58 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.LoadGame %p:", p1);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.LoadGame %p:", p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExistSaveData(void) { /* 59 */
|
static void ExistSaveData(void) { /* 59 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.ExistSaveData %p:", p1);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.ExistSaveData %p:", p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExistStartData(void) { /* 60 */
|
static void ExistStartData(void) { /* 60 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.ExistStartData %p:", p1);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.ExistStartData %p:", p1);
|
||||||
}
|
}
|
||||||
@@ -581,13 +580,13 @@ static void DebugScenario(void) { /* 66 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetDLLTime(void) { /* 67 */
|
static void GetDLLTime(void) { /* 67 */
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int *p2 = getCaliVariable();
|
vmvar_t *p2 = getCaliVariable();
|
||||||
int *p3 = getCaliVariable();
|
vmvar_t *p3 = getCaliVariable();
|
||||||
int *p4 = getCaliVariable();
|
vmvar_t *p4 = getCaliVariable();
|
||||||
int *p5 = getCaliVariable();
|
vmvar_t *p5 = getCaliVariable();
|
||||||
int *p6 = getCaliVariable();
|
vmvar_t *p6 = getCaliVariable();
|
||||||
int *p7 = getCaliVariable();
|
vmvar_t *p7 = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("NIGHTDLL.GetDLLTime %p,%p,%p,%p,%p,%p,%p:", p1, p2, p3, p4, p5, p6, p7);
|
TRACE_UNIMPLEMENTED("NIGHTDLL.GetDLLTime %p,%p,%p,%p,%p,%p,%p:", p1, p2, p3, p4, p5, p6, p7);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,11 +53,6 @@ static void cb_waitkey_selection(agsevent_t *e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ntev_callback(agsevent_t *e) {
|
void ntev_callback(agsevent_t *e) {
|
||||||
// menu open中は無視
|
|
||||||
if (nact->popupmenu_opened) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
||||||
night.waitskiplv = 2;
|
night.waitskiplv = 2;
|
||||||
night.waitkey = e->code;
|
night.waitkey = e->code;
|
||||||
@@ -90,16 +85,5 @@ void ntev_callback(agsevent_t *e) {
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
system35のメインループからで呼ばれるコールバック
|
|
||||||
*/
|
|
||||||
void ntev_main() {
|
|
||||||
// デフォルトのコールバックのうち、ここで必要なものだけ処理。
|
|
||||||
if (nact->popupmenu_opened) {
|
|
||||||
menu_gtkmainiteration();
|
|
||||||
if (nact->is_quit) sys_exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define __NT_EVENT_H__
|
#define __NT_EVENT_H__
|
||||||
|
|
||||||
extern void ntev_callback(agsevent_t *e);
|
extern void ntev_callback(agsevent_t *e);
|
||||||
extern void ntev_main();
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __NT_EVENT_H__ */
|
#endif /* __NT_EVENT_H__ */
|
||||||
|
|||||||
@@ -55,19 +55,17 @@ static void ntmain(struct _scoadr inadr) {
|
|||||||
while (!nact->is_quit && !is_yield_requested()) {
|
while (!nact->is_quit && !is_yield_requested()) {
|
||||||
scheduler_on_command();
|
scheduler_on_command();
|
||||||
//SACT_DEBUG("%d:%x", sl_getPage(), sl_getIndex());
|
//SACT_DEBUG("%d:%x", sl_getPage(), sl_getIndex());
|
||||||
if (!nact->popupmenu_opened) {
|
exec_command();
|
||||||
exec_command();
|
if (sl_getPage() == inadr.page &&
|
||||||
if (sl_getPage() == inadr.page &&
|
sl_getIndex() == inadr.index) {
|
||||||
sl_getIndex() == inadr.index) {
|
// ~E%05dからの戻り
|
||||||
// ~E%05dからの戻り
|
if (nact->fnc_return_value == 0) {
|
||||||
if (nact->fnc_return_value == 0) {
|
return;
|
||||||
return;
|
} else {
|
||||||
} else {
|
scono = nact->fnc_return_value;
|
||||||
scono = nact->fnc_return_value;
|
|
||||||
}
|
|
||||||
curadr = scene2adr(scono);
|
|
||||||
sl_callFar2(curadr.page -1, curadr.index);
|
|
||||||
}
|
}
|
||||||
|
curadr = scene2adr(scono);
|
||||||
|
sl_callFar2(curadr.page -1, curadr.index);
|
||||||
}
|
}
|
||||||
nact->callback();
|
nact->callback();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue(); /* ISys3x */
|
int p1 = getCaliValue(); /* ISys3x */
|
||||||
int p2 = getCaliValue(); /* IWinMsg */
|
int p2 = getCaliValue(); /* IWinMsg */
|
||||||
int p3 = getCaliValue(); /* ITimer */
|
int p3 = getCaliValue(); /* ITimer */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ static void Get() {
|
|||||||
var: 結果を返す変数
|
var: 結果を返す変数
|
||||||
*/
|
*/
|
||||||
int num = getCaliValue();
|
int num = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
if (num == 0 || num == 1) {
|
if (num == 0 || num == 1) {
|
||||||
*var = num;
|
*var = num;
|
||||||
@@ -65,7 +65,7 @@ static void Get() {
|
|||||||
static void GetNoOverlap() {
|
static void GetNoOverlap() {
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int n = getCaliValue();
|
int n = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = (int)(genrand() * n) + min;
|
*var = (int)(genrand() * n) + min;
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ static void CreateChannel(void) {
|
|||||||
static void Prepare(void) {
|
static void Prepare(void) {
|
||||||
int ch = getCaliValue();
|
int ch = getCaliValue();
|
||||||
int no = getCaliValue();
|
int no = getCaliValue();
|
||||||
int *result = getCaliVariable();
|
vmvar_t *result = getCaliVariable();
|
||||||
|
|
||||||
if (ch == 0) {
|
if (ch == 0) {
|
||||||
current_no = no;
|
current_no = no;
|
||||||
@@ -97,7 +97,7 @@ static void PlayPosSample(void) {
|
|||||||
|
|
||||||
static void IsPlay(void) {
|
static void IsPlay(void) {
|
||||||
int ch = getCaliValue();
|
int ch = getCaliValue();
|
||||||
int *result = getCaliVariable();
|
vmvar_t *result = getCaliVariable();
|
||||||
|
|
||||||
if (ch == 0) {
|
if (ch == 0) {
|
||||||
*result = current_no && musbgm_isplaying(current_no);
|
*result = current_no && musbgm_isplaying(current_no);
|
||||||
@@ -127,10 +127,10 @@ static void Restart(void) {
|
|||||||
|
|
||||||
static void GetPlayPos(void) {
|
static void GetPlayPos(void) {
|
||||||
int ch = getCaliValue();
|
int ch = getCaliValue();
|
||||||
int *hour = getCaliVariable();
|
vmvar_t *hour = getCaliVariable();
|
||||||
int *min = getCaliVariable();
|
vmvar_t *min = getCaliVariable();
|
||||||
int *sec = getCaliVariable();
|
vmvar_t *sec = getCaliVariable();
|
||||||
int *msec = getCaliVariable();
|
vmvar_t *msec = getCaliVariable();
|
||||||
if (ch == 0) {
|
if (ch == 0) {
|
||||||
int time = musbgm_getpos(current_no);
|
int time = musbgm_getpos(current_no);
|
||||||
*hour = time / 360000;
|
*hour = time / 360000;
|
||||||
@@ -149,8 +149,8 @@ static void GetPlayPos(void) {
|
|||||||
|
|
||||||
static void GetPlayPosSample(void) {
|
static void GetPlayPosSample(void) {
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int *var1 = getCaliVariable();
|
vmvar_t *var1 = getCaliVariable();
|
||||||
int *var2 = getCaliVariable();
|
vmvar_t *var2 = getCaliVariable();
|
||||||
TRACE_UNIMPLEMENTED("S3xMusic.GetPlayPosSample %d, %p, %p:", p1, var1, var2);
|
TRACE_UNIMPLEMENTED("S3xMusic.GetPlayPosSample %d, %p, %p:", p1, var1, var2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ static void FadeVolume(void) {
|
|||||||
|
|
||||||
static void IsFade(void) {
|
static void IsFade(void) {
|
||||||
int ch = getCaliValue();
|
int ch = getCaliValue();
|
||||||
int *result = getCaliVariable();
|
vmvar_t *result = getCaliVariable();
|
||||||
*result = 0;
|
*result = 0;
|
||||||
TRACE_UNIMPLEMENTED("S3xMusic.IsFade %d => %d:", ch, *result);
|
TRACE_UNIMPLEMENTED("S3xMusic.IsFade %d => %d:", ch, *result);
|
||||||
}
|
}
|
||||||
|
|||||||
+69
-60
@@ -33,6 +33,7 @@
|
|||||||
#include "portab.h"
|
#include "portab.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "ald_manager.h"
|
#include "ald_manager.h"
|
||||||
|
#include "audio_meta.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "msgskip.h"
|
#include "msgskip.h"
|
||||||
#include "xsystem35.h"
|
#include "xsystem35.h"
|
||||||
@@ -286,8 +287,11 @@ static void DrawEffect() {
|
|||||||
if (sact.version >= 110) {
|
if (sact.version >= 110) {
|
||||||
wEffectkey = getCaliValue();
|
wEffectkey = getCaliValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_eupdate(wType, wEffectTime, wEffectkey);
|
if (sact.waitskiplv > 1 || msgskip_isSkipping())
|
||||||
|
sp_update_all(true);
|
||||||
|
else
|
||||||
|
sp_eupdate(wType, wEffectTime, wEffectkey);
|
||||||
|
|
||||||
TRACE("SACT.DrawEffect %d,%d,%d:", wType, wEffectTime, wEffectkey);
|
TRACE("SACT.DrawEffect %d,%d,%d:", wType, wEffectTime, wEffectkey);
|
||||||
}
|
}
|
||||||
@@ -304,7 +308,10 @@ static void DrawEffectAlphaMap() {
|
|||||||
int wEffectTime = getCaliValue();
|
int wEffectTime = getCaliValue();
|
||||||
int wEffectKey = getCaliValue();
|
int wEffectKey = getCaliValue();
|
||||||
|
|
||||||
sp_eupdate_amap(nIndexAlphaMap, wEffectTime, wEffectKey);
|
if (sact.waitskiplv > 1 || msgskip_isSkipping())
|
||||||
|
sp_update_all(true);
|
||||||
|
else
|
||||||
|
sp_eupdate_amap(nIndexAlphaMap, wEffectTime, wEffectKey);
|
||||||
|
|
||||||
TRACE("SACT.DrawEffectAlphaMap %d,%d,%d:", nIndexAlphaMap, wEffectTime, wEffectKey);
|
TRACE("SACT.DrawEffectAlphaMap %d,%d,%d:", nIndexAlphaMap, wEffectTime, wEffectKey);
|
||||||
}
|
}
|
||||||
@@ -622,9 +629,10 @@ static void QuakeSprite() {
|
|||||||
if (sact.version >= 110) {
|
if (sact.version >= 110) {
|
||||||
nfKeyEnable = getCaliValue();
|
nfKeyEnable = getCaliValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_quake_sprite(wType, wAmplitudeX, wAmplitudeY, wCount, nfKeyEnable);
|
if (!msgskip_isSkipping())
|
||||||
|
sp_quake_sprite(wType, wAmplitudeX, wAmplitudeY, wCount, nfKeyEnable);
|
||||||
|
|
||||||
TRACE("SACT.QuakeSprite %d,%d,%d,%d:", wType, wAmplitudeX, wAmplitudeY, wCount);
|
TRACE("SACT.QuakeSprite %d,%d,%d,%d:", wType, wAmplitudeX, wAmplitudeY, wCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +644,7 @@ static void QuakeSprite() {
|
|||||||
*/
|
*/
|
||||||
static void QuerySpriteIsExist() {
|
static void QuerySpriteIsExist() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = sp_exists(wNum) ? 1 : 0;
|
*var = sp_exists(wNum) ? 1 : 0;
|
||||||
|
|
||||||
@@ -654,10 +662,10 @@ static void QuerySpriteIsExist() {
|
|||||||
*/
|
*/
|
||||||
static void QuerySpriteInfo() {
|
static void QuerySpriteInfo() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vType = getCaliVariable();
|
vmvar_t *vType = getCaliVariable();
|
||||||
int *vCG1 = getCaliVariable();
|
vmvar_t *vCG1 = getCaliVariable();
|
||||||
int *vCG2 = getCaliVariable();
|
vmvar_t *vCG2 = getCaliVariable();
|
||||||
int *vCG3 = getCaliVariable();
|
vmvar_t *vCG3 = getCaliVariable();
|
||||||
|
|
||||||
sp_query_info(wNum, vType, vCG1, vCG2, vCG3);
|
sp_query_info(wNum, vType, vCG1, vCG2, vCG3);
|
||||||
|
|
||||||
@@ -672,7 +680,7 @@ static void QuerySpriteInfo() {
|
|||||||
*/
|
*/
|
||||||
static void QuerySpriteShow() {
|
static void QuerySpriteShow() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vShow = getCaliVariable();
|
vmvar_t *vShow = getCaliVariable();
|
||||||
|
|
||||||
sp_query_show(wNum, vShow);
|
sp_query_show(wNum, vShow);
|
||||||
|
|
||||||
@@ -688,8 +696,8 @@ static void QuerySpriteShow() {
|
|||||||
*/
|
*/
|
||||||
static void QuerySpritePos() {
|
static void QuerySpritePos() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vX = getCaliVariable();
|
vmvar_t *vX = getCaliVariable();
|
||||||
int *vY = getCaliVariable();
|
vmvar_t *vY = getCaliVariable();
|
||||||
|
|
||||||
sp_query_pos(wNum, vX, vY);
|
sp_query_pos(wNum, vX, vY);
|
||||||
|
|
||||||
@@ -705,8 +713,8 @@ static void QuerySpritePos() {
|
|||||||
*/
|
*/
|
||||||
static void QuerySpriteSize() {
|
static void QuerySpriteSize() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vWidth = getCaliVariable();
|
vmvar_t *vWidth = getCaliVariable();
|
||||||
int *vHeight = getCaliVariable();
|
vmvar_t *vHeight = getCaliVariable();
|
||||||
|
|
||||||
sp_query_size(wNum, vWidth, vHeight);
|
sp_query_size(wNum, vWidth, vHeight);
|
||||||
|
|
||||||
@@ -722,8 +730,8 @@ static void QuerySpriteSize() {
|
|||||||
*/
|
*/
|
||||||
static void QueryTextPos() {
|
static void QueryTextPos() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vX = getCaliVariable();
|
vmvar_t *vX = getCaliVariable();
|
||||||
int *vY = getCaliVariable();
|
vmvar_t *vY = getCaliVariable();
|
||||||
|
|
||||||
sp_query_textpos(wNum, vX, vY);
|
sp_query_textpos(wNum, vX, vY);
|
||||||
|
|
||||||
@@ -762,7 +770,7 @@ static void CG_Reset() {
|
|||||||
*/
|
*/
|
||||||
static void CG_QueryType() {
|
static void CG_QueryType() {
|
||||||
int wNumCG = getCaliValue();
|
int wNumCG = getCaliValue();
|
||||||
int *vType = getCaliVariable();
|
vmvar_t *vType = getCaliVariable();
|
||||||
|
|
||||||
*vType = scg_querytype(wNumCG);
|
*vType = scg_querytype(wNumCG);
|
||||||
|
|
||||||
@@ -778,8 +786,8 @@ static void CG_QueryType() {
|
|||||||
*/
|
*/
|
||||||
static void CG_QuerySize() {
|
static void CG_QuerySize() {
|
||||||
int wNumCG = getCaliValue();
|
int wNumCG = getCaliValue();
|
||||||
int *vWidth = getCaliVariable();
|
vmvar_t *vWidth = getCaliVariable();
|
||||||
int *vHeight = getCaliVariable();
|
vmvar_t *vHeight = getCaliVariable();
|
||||||
|
|
||||||
scg_querysize(wNumCG, vWidth, vHeight);
|
scg_querysize(wNumCG, vWidth, vHeight);
|
||||||
|
|
||||||
@@ -794,7 +802,7 @@ static void CG_QuerySize() {
|
|||||||
*/
|
*/
|
||||||
static void CG_QueryBpp() {
|
static void CG_QueryBpp() {
|
||||||
int wNumCG = getCaliValue();
|
int wNumCG = getCaliValue();
|
||||||
int *vBpp = getCaliVariable();
|
vmvar_t *vBpp = getCaliVariable();
|
||||||
|
|
||||||
*vBpp = scg_querybpp(wNumCG);
|
*vBpp = scg_querybpp(wNumCG);
|
||||||
|
|
||||||
@@ -809,7 +817,7 @@ static void CG_QueryBpp() {
|
|||||||
*/
|
*/
|
||||||
static void CG_ExistAlphaMap() {
|
static void CG_ExistAlphaMap() {
|
||||||
int wNumCG = getCaliValue();
|
int wNumCG = getCaliValue();
|
||||||
int *vMask = getCaliVariable();
|
vmvar_t *vMask = getCaliVariable();
|
||||||
|
|
||||||
*vMask = scg_existalphamap(wNumCG) ? 1 : 0;
|
*vMask = scg_existalphamap(wNumCG) ? 1 : 0;
|
||||||
|
|
||||||
@@ -1021,7 +1029,7 @@ static void CG_PartCopy() {
|
|||||||
* @param vKey: 入力されたキー
|
* @param vKey: 入力されたキー
|
||||||
*/
|
*/
|
||||||
static void WaitKeySimple() {
|
static void WaitKeySimple() {
|
||||||
int *vKey = getCaliVariable();
|
vmvar_t *vKey = getCaliVariable();
|
||||||
|
|
||||||
TRACE("SACT.WaitKeySimple %d:", vKey);
|
TRACE("SACT.WaitKeySimple %d:", vKey);
|
||||||
|
|
||||||
@@ -1071,10 +1079,10 @@ static void WaitKeyMessage() {
|
|||||||
* @param vRsv2: 予約
|
* @param vRsv2: 予約
|
||||||
*/
|
*/
|
||||||
static void WaitKeySprite() {
|
static void WaitKeySprite() {
|
||||||
int *vOK = getCaliVariable();
|
vmvar_t *vOK = getCaliVariable();
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
int *vRsv1 = getCaliVariable();
|
vmvar_t *vRsv1 = getCaliVariable();
|
||||||
int *vRsv2 = getCaliVariable();
|
vmvar_t *vRsv2 = getCaliVariable();
|
||||||
|
|
||||||
TRACE("SACT.WaitKeySprite %p,%p,%p,%p:", vOK, vRND, vRsv1, vRsv2);
|
TRACE("SACT.WaitKeySprite %p,%p,%p,%p:", vOK, vRND, vRsv1, vRsv2);
|
||||||
|
|
||||||
@@ -1092,7 +1100,7 @@ static void WaitKeySprite() {
|
|||||||
static void PeekKey() {
|
static void PeekKey() {
|
||||||
static int prevKeyCode = NUM_KEYCODES;
|
static int prevKeyCode = NUM_KEYCODES;
|
||||||
int nKeyCode = getCaliValue();
|
int nKeyCode = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
|
|
||||||
// This function is called successively with different nKeyCodes.
|
// This function is called successively with different nKeyCodes.
|
||||||
// Only the first call hits the scheduler.
|
// Only the first call hits the scheduler.
|
||||||
@@ -1121,8 +1129,8 @@ static void WaitMsgSkipKeyUp() {
|
|||||||
* @param wTime: タイムアウト時間 (1/100sec)
|
* @param wTime: タイムアウト時間 (1/100sec)
|
||||||
*/
|
*/
|
||||||
static void WaitKeySimpleTimeOut() {
|
static void WaitKeySimpleTimeOut() {
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
int *vD03 = getCaliVariable();
|
vmvar_t *vD03 = getCaliVariable();
|
||||||
int wTime = getCaliValue();
|
int wTime = getCaliValue();
|
||||||
|
|
||||||
sact.waittype = KEYWAIT_SIMPLE;
|
sact.waittype = KEYWAIT_SIMPLE;
|
||||||
@@ -1153,11 +1161,11 @@ static void WaitKeySimpleTimeOut() {
|
|||||||
* @param wTime: タイムアウト時間 (1/100sec)
|
* @param wTime: タイムアウト時間 (1/100sec)
|
||||||
*/
|
*/
|
||||||
static void WaitKeySpriteTimeOut() {
|
static void WaitKeySpriteTimeOut() {
|
||||||
int *vOK = getCaliVariable();
|
vmvar_t *vOK = getCaliVariable();
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
int *vD01 = getCaliVariable();
|
vmvar_t *vD01 = getCaliVariable();
|
||||||
int *vD02 = getCaliVariable();
|
vmvar_t *vD02 = getCaliVariable();
|
||||||
int *vD03 = getCaliVariable();
|
vmvar_t *vD03 = getCaliVariable();
|
||||||
int wTime = getCaliValue();
|
int wTime = getCaliValue();
|
||||||
|
|
||||||
sp_keywait(vOK, vRND, vD01, vD02, vD03, wTime);
|
sp_keywait(vOK, vRND, vD01, vD02, vD03, wTime);
|
||||||
@@ -1171,7 +1179,7 @@ static void WaitKeySpriteTimeOut() {
|
|||||||
* @param vSkip:
|
* @param vSkip:
|
||||||
*/
|
*/
|
||||||
static void QueryMessageSkip() {
|
static void QueryMessageSkip() {
|
||||||
int *vSkip = getCaliVariable();
|
vmvar_t *vSkip = getCaliVariable();
|
||||||
|
|
||||||
*vSkip = msgskip_isSkipping() ? 1 : 0;
|
*vSkip = msgskip_isSkipping() ? 1 : 0;
|
||||||
|
|
||||||
@@ -1219,7 +1227,7 @@ static void MessageOutput() {
|
|||||||
int wMessageSpeed = getCaliValue();
|
int wMessageSpeed = getCaliValue();
|
||||||
int wMessageLineSpace = getCaliValue();
|
int wMessageLineSpace = getCaliValue();
|
||||||
int wMessageAlign = 0;
|
int wMessageAlign = 0;
|
||||||
int *vMessageLength = NULL;
|
vmvar_t *vMessageLength = NULL;
|
||||||
|
|
||||||
if (sact.version >= 110) {
|
if (sact.version >= 110) {
|
||||||
wMessageAlign = getCaliValue();
|
wMessageAlign = getCaliValue();
|
||||||
@@ -1266,7 +1274,7 @@ static void MessageOutputEx() {
|
|||||||
int wRubySize = getCaliValue();
|
int wRubySize = getCaliValue();
|
||||||
int wRubyFont = getCaliValue();
|
int wRubyFont = getCaliValue();
|
||||||
int wRubyLineSpace = getCaliValue();
|
int wRubyLineSpace = getCaliValue();
|
||||||
int *vLength = NULL;
|
vmvar_t *vLength = NULL;
|
||||||
|
|
||||||
if (sact.version >= 120) {
|
if (sact.version >= 120) {
|
||||||
vLength = getCaliVariable();
|
vLength = getCaliVariable();
|
||||||
@@ -1311,7 +1319,7 @@ static void MessageClear() {
|
|||||||
* @param wResult: 結果を返す変数
|
* @param wResult: 結果を返す変数
|
||||||
*/
|
*/
|
||||||
static void MessageIsEmpty() {
|
static void MessageIsEmpty() {
|
||||||
int *wResult = getCaliVariable();
|
vmvar_t *wResult = getCaliVariable();
|
||||||
|
|
||||||
*wResult = smsg_is_empty() ? 1 : 0;
|
*wResult = smsg_is_empty() ? 1 : 0;
|
||||||
|
|
||||||
@@ -1325,7 +1333,7 @@ static void MessageIsEmpty() {
|
|||||||
* @param nTopStringNum: バッファを取得する文字列変数の最初
|
* @param nTopStringNum: バッファを取得する文字列変数の最初
|
||||||
*/
|
*/
|
||||||
static void MessagePeek() {
|
static void MessagePeek() {
|
||||||
int *vCount = getCaliVariable();
|
vmvar_t *vCount = getCaliVariable();
|
||||||
int nTopStringNum = getCaliValue();
|
int nTopStringNum = getCaliValue();
|
||||||
|
|
||||||
*vCount = smsg_peek(nTopStringNum);
|
*vCount = smsg_peek(nTopStringNum);
|
||||||
@@ -1388,7 +1396,7 @@ static void MenuAdd() {
|
|||||||
* @param nAlign: 行そろえ (0:左, 1:中央, 2: 右) (1.1~)
|
* @param nAlign: 行そろえ (0:左, 1:中央, 2: 右) (1.1~)
|
||||||
*/
|
*/
|
||||||
static void MenuOpen() {
|
static void MenuOpen() {
|
||||||
int *wMenuResult = getCaliVariable();
|
vmvar_t *wMenuResult = getCaliVariable();
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int wChoiceSize = getCaliValue();
|
int wChoiceSize = getCaliValue();
|
||||||
int wMenuOutSpc = getCaliValue();
|
int wMenuOutSpc = getCaliValue();
|
||||||
@@ -1464,7 +1472,7 @@ static void Numeral_SetCG() {
|
|||||||
static void Numeral_GetCG() {
|
static void Numeral_GetCG() {
|
||||||
int nNum = getCaliValue();
|
int nNum = getCaliValue();
|
||||||
int nIndex = getCaliValue();
|
int nIndex = getCaliValue();
|
||||||
int *vCG = getCaliVariable();
|
vmvar_t *vCG = getCaliVariable();
|
||||||
|
|
||||||
sp_num_getcg(nNum, nIndex, vCG);
|
sp_num_getcg(nNum, nIndex, vCG);
|
||||||
|
|
||||||
@@ -1497,8 +1505,8 @@ static void Numeral_SetPos() {
|
|||||||
*/
|
*/
|
||||||
static void Numeral_GetPos() {
|
static void Numeral_GetPos() {
|
||||||
int nNum = getCaliValue();
|
int nNum = getCaliValue();
|
||||||
int *vX = getCaliVariable();
|
vmvar_t *vX = getCaliVariable();
|
||||||
int *vY = getCaliVariable();
|
vmvar_t *vY = getCaliVariable();
|
||||||
|
|
||||||
sp_num_getpos(nNum, vX, vY);
|
sp_num_getpos(nNum, vX, vY);
|
||||||
|
|
||||||
@@ -1528,7 +1536,7 @@ static void Numeral_SetSpan() {
|
|||||||
*/
|
*/
|
||||||
static void Numeral_GetSpan() {
|
static void Numeral_GetSpan() {
|
||||||
int nNum = getCaliValue();
|
int nNum = getCaliValue();
|
||||||
int *vSpan = getCaliVariable();
|
vmvar_t *vSpan = getCaliVariable();
|
||||||
|
|
||||||
sp_num_getspan(nNum, vSpan);
|
sp_num_getspan(nNum, vSpan);
|
||||||
|
|
||||||
@@ -1596,7 +1604,7 @@ static void TimerSet() {
|
|||||||
*/
|
*/
|
||||||
static void TimerGet() {
|
static void TimerGet() {
|
||||||
int wTimerID = getCaliValue();
|
int wTimerID = getCaliValue();
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
|
|
||||||
*vRND = stimer_get(wTimerID);
|
*vRND = stimer_get(wTimerID);
|
||||||
|
|
||||||
@@ -1615,7 +1623,7 @@ static void TimerWait() {
|
|||||||
|
|
||||||
int msec = (wCount - stimer_get(wTimerID)) * 10;
|
int msec = (wCount - stimer_get(wTimerID)) * 10;
|
||||||
if (msec > 0)
|
if (msec > 0)
|
||||||
sys_keywait(msec, KEYWAIT_CTRL_CANCELABLE);
|
sys_keywait(msec, KEYWAIT_CTRL_CANCELABLE | KEYWAIT_SKIPPABLE);
|
||||||
|
|
||||||
TRACE("SACT.TimerWait %d,%d:", wTimerID, wCount);
|
TRACE("SACT.TimerWait %d,%d:", wTimerID, wCount);
|
||||||
}
|
}
|
||||||
@@ -1628,7 +1636,7 @@ static void TimerWait() {
|
|||||||
static void Wait() {
|
static void Wait() {
|
||||||
int wCount = getCaliValue();
|
int wCount = getCaliValue();
|
||||||
|
|
||||||
sys_keywait(wCount * 10, KEYWAIT_CTRL_CANCELABLE);
|
sys_keywait(wCount * 10, KEYWAIT_CTRL_CANCELABLE | KEYWAIT_SKIPPABLE);
|
||||||
|
|
||||||
TRACE("SACT.Wait %d:", wCount);
|
TRACE("SACT.Wait %d:", wCount);
|
||||||
}
|
}
|
||||||
@@ -1696,7 +1704,7 @@ static void SoundWait() {
|
|||||||
*/
|
*/
|
||||||
static void SoundWaitKey() {
|
static void SoundWaitKey() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vKey = getCaliVariable();
|
vmvar_t *vKey = getCaliVariable();
|
||||||
|
|
||||||
ssnd_waitkey(wNum, vKey);
|
ssnd_waitkey(wNum, vKey);
|
||||||
|
|
||||||
@@ -1797,7 +1805,7 @@ static void SpriteSoundOB() {
|
|||||||
*/
|
*/
|
||||||
static void MusicCheck() {
|
static void MusicCheck() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
|
|
||||||
*vRND = ald_exists(DRIFILE_BGM, wNum - 1) ? 1 : 0;
|
*vRND = ald_exists(DRIFILE_BGM, wNum - 1) ? 1 : 0;
|
||||||
|
|
||||||
@@ -1812,7 +1820,7 @@ static void MusicCheck() {
|
|||||||
*/
|
*/
|
||||||
static void MusicGetLength() {
|
static void MusicGetLength() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
|
|
||||||
*vRND = musbgm_getlen(wNum);
|
*vRND = musbgm_getlen(wNum);
|
||||||
|
|
||||||
@@ -1827,7 +1835,7 @@ static void MusicGetLength() {
|
|||||||
*/
|
*/
|
||||||
static void MusicGetPos() {
|
static void MusicGetPos() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
|
|
||||||
*vRND = musbgm_getpos(wNum);
|
*vRND = musbgm_getpos(wNum);
|
||||||
|
|
||||||
@@ -1845,8 +1853,9 @@ static void MusicPlay() {
|
|||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int wFadeTime = getCaliValue();
|
int wFadeTime = getCaliValue();
|
||||||
int wVolume = getCaliValue();
|
int wVolume = getCaliValue();
|
||||||
|
bgi_t *bgi = bgi_find(wNum);
|
||||||
|
|
||||||
musbgm_play(wNum, wFadeTime, wVolume, 0);
|
musbgm_play(wNum, wFadeTime, wVolume, bgi ? bgi->loopno : 0);
|
||||||
|
|
||||||
TRACE("SACT.MusicPlay %d,%d,%d:", wNum, wFadeTime, wVolume);
|
TRACE("SACT.MusicPlay %d,%d,%d:", wNum, wFadeTime, wVolume);
|
||||||
}
|
}
|
||||||
@@ -1937,7 +1946,7 @@ static void MusicWaitPos() {
|
|||||||
*/
|
*/
|
||||||
static void SoundGetLinkNum() {
|
static void SoundGetLinkNum() {
|
||||||
int wNum = getCaliValue();
|
int wNum = getCaliValue();
|
||||||
int *vRND = getCaliVariable();
|
vmvar_t *vRND = getCaliVariable();
|
||||||
|
|
||||||
*vRND = ssnd_getlinknum(wNum);
|
*vRND = ssnd_getlinknum(wNum);
|
||||||
|
|
||||||
@@ -1957,7 +1966,7 @@ static void SoundGetLinkNum() {
|
|||||||
* pos = ((pos2-pos1) / (val2-val1)) * (val-val1) + pos1
|
* pos = ((pos2-pos1) / (val2-val1)) * (val-val1) + pos1
|
||||||
*/
|
*/
|
||||||
static void ChartPos() {
|
static void ChartPos() {
|
||||||
int *pos = getCaliVariable();
|
vmvar_t *pos = getCaliVariable();
|
||||||
int pos1 = getCaliValue();
|
int pos1 = getCaliValue();
|
||||||
int pos2 = getCaliValue();
|
int pos2 = getCaliValue();
|
||||||
int val1 = getCaliValue();
|
int val1 = getCaliValue();
|
||||||
@@ -2002,7 +2011,7 @@ static void Maze_Create() {
|
|||||||
* SACT.Maze_Get (1.0~)
|
* SACT.Maze_Get (1.0~)
|
||||||
*/
|
*/
|
||||||
static void Maze_Get() {
|
static void Maze_Get() {
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
|
|
||||||
@@ -2013,7 +2022,7 @@ static void Maze_Get() {
|
|||||||
* SACT.EncryptWORD (1.0~)
|
* SACT.EncryptWORD (1.0~)
|
||||||
*/
|
*/
|
||||||
static void EncryptWORD() {
|
static void EncryptWORD() {
|
||||||
int *array = getCaliVariable();
|
vmvar_t *array = getCaliVariable();
|
||||||
int num = getCaliValue();
|
int num = getCaliValue();
|
||||||
int key = getCaliValue();
|
int key = getCaliValue();
|
||||||
|
|
||||||
@@ -2026,7 +2035,7 @@ static void EncryptWORD() {
|
|||||||
* SACT.DecryptWORD (1.0~)
|
* SACT.DecryptWORD (1.0~)
|
||||||
*/
|
*/
|
||||||
static void DecryptWORD() {
|
static void DecryptWORD() {
|
||||||
int *array = getCaliVariable();
|
vmvar_t *array = getCaliVariable();
|
||||||
int num = getCaliValue();
|
int num = getCaliValue();
|
||||||
int key = getCaliValue();
|
int key = getCaliValue();
|
||||||
|
|
||||||
@@ -2092,7 +2101,7 @@ static void XMenuRegister() {
|
|||||||
*/
|
*/
|
||||||
static void XMenuGetNum() {
|
static void XMenuGetNum() {
|
||||||
int nRegiNum = getCaliValue();
|
int nRegiNum = getCaliValue();
|
||||||
int *vMenuID = getCaliVariable();
|
vmvar_t *vMenuID = getCaliVariable();
|
||||||
|
|
||||||
*vMenuID = spxm_getnum(nRegiNum);
|
*vMenuID = spxm_getnum(nRegiNum);
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
#include "portab.h"
|
#include "portab.h"
|
||||||
|
|
||||||
// グラフ用チャート作成
|
// グラフ用チャート作成
|
||||||
void schart_pos(int *pos, int pos1, int pos2, int val1, int val2, int val) {
|
void schart_pos(vmvar_t *pos, int pos1, int pos2, int val1, int val2, int val) {
|
||||||
if (val1 == val2) {
|
if (val1 == val2) {
|
||||||
*pos = 0;
|
*pos = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#ifndef __SACTCHART_H__
|
#ifndef __SACTCHART_H__
|
||||||
#define __SACTCHART_H__
|
#define __SACTCHART_H__
|
||||||
|
|
||||||
void schart_pos(int *pos, int pos1, int pos2, int val1, int val2, int val);
|
#include "portab.h"
|
||||||
|
|
||||||
|
void schart_pos(vmvar_t *pos, int pos1, int pos2, int val1, int val2, int val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
適当でいいとおもう
|
適当でいいとおもう
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void scryp_encrypt_word(int *array, int num, int key) {
|
void scryp_encrypt_word(vmvar_t *array, int num, int key) {
|
||||||
WARNING("NOT IMPLEMENTED");
|
WARNING("NOT IMPLEMENTED");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,9 @@
|
|||||||
#ifndef __SACTCRYPT_H__
|
#ifndef __SACTCRYPT_H__
|
||||||
#define __SACTCRYPT_H__
|
#define __SACTCRYPT_H__
|
||||||
|
|
||||||
void scryp_encrypt_word(int *array, int num, int key);
|
#include "portab.h"
|
||||||
|
|
||||||
|
void scryp_encrypt_word(vmvar_t *array, int num, int key);
|
||||||
void scryp_decrypt_word(int *array, int num, int key);
|
void scryp_decrypt_word(int *array, int num, int key);
|
||||||
void scryp_encrypt_str(int strno, int key);
|
void scryp_encrypt_str(int strno, int key);
|
||||||
void scryp_decrypt_str(int strno, int key);
|
void scryp_decrypt_str(int strno, int key);
|
||||||
|
|||||||
@@ -97,7 +97,11 @@ static void draw_log() {
|
|||||||
if (0 == strcmp(str, "\n")) {
|
if (0 == strcmp(str, "\n")) {
|
||||||
SDL_BlitSurface(hline, NULL, main_surface, &(SDL_Rect){0, y + FONTSIZE/2, main_surface->w, 3});
|
SDL_BlitSurface(hline, NULL, main_surface, &(SDL_Rect){0, y + FONTSIZE/2, main_surface->w, 3});
|
||||||
} else {
|
} else {
|
||||||
FontSpec font_spec = { .type = cur < 6 ? FONT_MINCHO : FONT_GOTHIC, .size = FONTSIZE };
|
FontSpec font_spec = {
|
||||||
|
.type = cur < 6 ? FONT_MINCHO : FONT_GOTHIC,
|
||||||
|
.weight = cur < 6 ? FONT_WEIGHT_NORMAL : FONT_WEIGHT_BOLD,
|
||||||
|
.size = FONTSIZE
|
||||||
|
};
|
||||||
gfx_drawString(0, y, str, 255, font_spec);
|
gfx_drawString(0, y, str, 255, font_spec);
|
||||||
}
|
}
|
||||||
y += FONTSIZE;
|
y += FONTSIZE;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "nact.h"
|
#include "nact.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "msgskip.h"
|
||||||
#include "sactsound.h"
|
#include "sactsound.h"
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "sact.h"
|
#include "sact.h"
|
||||||
@@ -112,7 +113,7 @@ void ssnd_wait(int no) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 指定の効果音が終了するか、キーが押されるまで待つ
|
// 指定の効果音が終了するか、キーが押されるまで待つ
|
||||||
void ssnd_waitkey(int no, int *res) {
|
void ssnd_waitkey(int no, vmvar_t *res) {
|
||||||
int slot = slt_find(no);
|
int slot = slt_find(no);
|
||||||
|
|
||||||
if (slot == -1) {
|
if (slot == -1) {
|
||||||
@@ -120,7 +121,7 @@ void ssnd_waitkey(int no, int *res) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sact.waitskiplv > 1) {
|
if (sact.waitskiplv > 1 || msgskip_isSkipping()) {
|
||||||
*res = SYS35KEY_RET;
|
*res = SYS35KEY_RET;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,13 @@
|
|||||||
#ifndef __SACTSOUND_H__
|
#ifndef __SACTSOUND_H__
|
||||||
#define __SACTSOUND_H__
|
#define __SACTSOUND_H__
|
||||||
|
|
||||||
|
#include "portab.h"
|
||||||
|
|
||||||
void ssnd_init(void);
|
void ssnd_init(void);
|
||||||
void ssnd_play(int no);
|
void ssnd_play(int no);
|
||||||
void ssnd_stop(int no, int fadetime);
|
void ssnd_stop(int no, int fadetime);
|
||||||
void ssnd_wait(int no);
|
void ssnd_wait(int no);
|
||||||
void ssnd_waitkey(int no, int *res);
|
void ssnd_waitkey(int no, vmvar_t *res);
|
||||||
void ssnd_prepare(int no);
|
void ssnd_prepare(int no);
|
||||||
void ssnd_prepareLRrev(int no);
|
void ssnd_prepareLRrev(int no);
|
||||||
void ssnd_playLRrev(int no);
|
void ssnd_playLRrev(int no);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "sacttimer.h"
|
#include "sacttimer.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#define MAX_TIMER 10
|
#define MAX_TIMER 128
|
||||||
#define TICKS_PER_CENTISECOND 10
|
#define TICKS_PER_CENTISECOND 10
|
||||||
|
|
||||||
uint32_t ticks_base[MAX_TIMER];
|
uint32_t ticks_base[MAX_TIMER];
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ bool sp_exists(int wNum) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// スプライトのタイプと何番のCGがセットされているかの取得
|
// スプライトのタイプと何番のCGがセットされているかの取得
|
||||||
bool sp_query_info(int wNum, int *vtype, int *vcg1, int *vcg2, int *vcg3) {
|
bool sp_query_info(int wNum, vmvar_t *vtype, vmvar_t *vcg1, vmvar_t *vcg2, vmvar_t *vcg3) {
|
||||||
sprite_t *sp;
|
sprite_t *sp;
|
||||||
|
|
||||||
if (wNum >= SPRITEMAX) goto errexit;
|
if (wNum >= SPRITEMAX) goto errexit;
|
||||||
@@ -479,7 +479,7 @@ bool sp_query_info(int wNum, int *vtype, int *vcg1, int *vcg2, int *vcg3) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// スプライトの表示状態の取得
|
// スプライトの表示状態の取得
|
||||||
bool sp_query_show(int wNum, int *vShow) {
|
bool sp_query_show(int wNum, vmvar_t *vShow) {
|
||||||
if (wNum >= SPRITEMAX) goto errexit;
|
if (wNum >= SPRITEMAX) goto errexit;
|
||||||
if (sact.sp[wNum]->type == SPRITE_NONE) goto errexit;
|
if (sact.sp[wNum]->type == SPRITE_NONE) goto errexit;
|
||||||
|
|
||||||
@@ -492,7 +492,7 @@ bool sp_query_show(int wNum, int *vShow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// スプライトの表示位置の取得
|
// スプライトの表示位置の取得
|
||||||
bool sp_query_pos(int wNum, int *vx, int *vy) {
|
bool sp_query_pos(int wNum, vmvar_t *vx, vmvar_t *vy) {
|
||||||
if (wNum >= SPRITEMAX) goto errexit;
|
if (wNum >= SPRITEMAX) goto errexit;
|
||||||
if (sact.sp[wNum]->type == SPRITE_NONE) goto errexit;
|
if (sact.sp[wNum]->type == SPRITE_NONE) goto errexit;
|
||||||
|
|
||||||
@@ -507,7 +507,7 @@ bool sp_query_pos(int wNum, int *vx, int *vy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// スプライトの大きさの取得
|
// スプライトの大きさの取得
|
||||||
bool sp_query_size(int wNum, int *vw, int *vh) {
|
bool sp_query_size(int wNum, vmvar_t *vw, vmvar_t *vh) {
|
||||||
sprite_t *sp;
|
sprite_t *sp;
|
||||||
|
|
||||||
if (wNum >= SPRITEMAX) goto errexit;
|
if (wNum >= SPRITEMAX) goto errexit;
|
||||||
@@ -528,7 +528,7 @@ bool sp_query_size(int wNum, int *vw, int *vh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// テキストスプライトの現在の文字表示位置の取得
|
// テキストスプライトの現在の文字表示位置の取得
|
||||||
bool sp_query_textpos(int wNum, int *vx, int *vy) {
|
bool sp_query_textpos(int wNum, vmvar_t *vx, vmvar_t *vy) {
|
||||||
if (wNum >= SPRITEMAX) goto errexit;
|
if (wNum >= SPRITEMAX) goto errexit;
|
||||||
sprite_t *sp = sact.sp[wNum];
|
sprite_t *sp = sact.sp[wNum];
|
||||||
if (sp->type != SPRITE_MSG) goto errexit;
|
if (sp->type != SPRITE_MSG) goto errexit;
|
||||||
@@ -551,7 +551,7 @@ void sp_num_setcg(int nNum, int nIndex, int nCG) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NumeralXXXのCGの取得
|
// NumeralXXXのCGの取得
|
||||||
void sp_num_getcg(int nNum, int nIndex, int *vCG) {
|
void sp_num_getcg(int nNum, int nIndex, vmvar_t *vCG) {
|
||||||
SP_ASSERT_NO(nNum);
|
SP_ASSERT_NO(nNum);
|
||||||
|
|
||||||
*vCG = sact.sp[nNum]->numeral.cg[nIndex];
|
*vCG = sact.sp[nNum]->numeral.cg[nIndex];
|
||||||
@@ -566,7 +566,7 @@ void sp_num_setpos(int nNum, int nX, int nY) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NumeralXXXの位置の取得
|
// NumeralXXXの位置の取得
|
||||||
void sp_num_getpos(int nNum, int *vX, int *vY) {
|
void sp_num_getpos(int nNum, vmvar_t *vX, vmvar_t *vY) {
|
||||||
SP_ASSERT_NO(nNum);
|
SP_ASSERT_NO(nNum);
|
||||||
|
|
||||||
*vX = sact.sp[nNum]->numeral.pos.x;
|
*vX = sact.sp[nNum]->numeral.pos.x;
|
||||||
@@ -581,7 +581,7 @@ void sp_num_setspan(int nNum, int nSpan) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NumeralXXXのスパンの取得
|
// NumeralXXXのスパンの取得
|
||||||
void sp_num_getspan(int nNum, int *vSpan) {
|
void sp_num_getspan(int nNum, vmvar_t *vSpan) {
|
||||||
SP_ASSERT_NO(nNum);
|
SP_ASSERT_NO(nNum);
|
||||||
|
|
||||||
*vSpan = sact.sp[nNum]->numeral.span;
|
*vSpan = sact.sp[nNum]->numeral.span;
|
||||||
|
|||||||
+11
-10
@@ -24,6 +24,7 @@
|
|||||||
#ifndef __SPRITE_H__
|
#ifndef __SPRITE_H__
|
||||||
#define __SPRITE_H__
|
#define __SPRITE_H__
|
||||||
|
|
||||||
|
#include "portab.h"
|
||||||
#include "sact.h"
|
#include "sact.h"
|
||||||
|
|
||||||
#define DEFAULT_UPDATE sp_draw
|
#define DEFAULT_UPDATE sp_draw
|
||||||
@@ -51,17 +52,17 @@ void sp_set_animeinterval(int wNum, int wTime);
|
|||||||
bool sp_is_insprite(sprite_t *sp, int x, int y);
|
bool sp_is_insprite(sprite_t *sp, int x, int y);
|
||||||
void sp_set_blendrate(int wNum, int wCount, int rate);
|
void sp_set_blendrate(int wNum, int wCount, int rate);
|
||||||
bool sp_exists(int wNum);
|
bool sp_exists(int wNum);
|
||||||
bool sp_query_info(int wNum, int *vtype, int *vcg1, int *vcg2, int *vcg3);
|
bool sp_query_info(int wNum, vmvar_t *vtype, vmvar_t *vcg1, vmvar_t *vcg2, vmvar_t *vcg3);
|
||||||
bool sp_query_show(int wNum, int *vShow);
|
bool sp_query_show(int wNum, vmvar_t *vShow);
|
||||||
bool sp_query_pos(int wNum, int *vx, int *vy);
|
bool sp_query_pos(int wNum, vmvar_t *vx, vmvar_t *vy);
|
||||||
bool sp_query_size(int wNum, int *vw, int *vh);
|
bool sp_query_size(int wNum, vmvar_t *vw, vmvar_t *vh);
|
||||||
bool sp_query_textpos(int wNum, int *vx, int *vy);
|
bool sp_query_textpos(int wNum, vmvar_t *vx, vmvar_t *vy);
|
||||||
void sp_num_setcg(int nNum, int nIndex, int nCG);
|
void sp_num_setcg(int nNum, int nIndex, int nCG);
|
||||||
void sp_num_getcg(int nNum, int nIndex, int *vCG);
|
void sp_num_getcg(int nNum, int nIndex, vmvar_t *vCG);
|
||||||
void sp_num_setpos(int nNum, int nX, int nY);
|
void sp_num_setpos(int nNum, int nX, int nY);
|
||||||
void sp_num_getpos(int nNum, int *vX, int *vY);
|
void sp_num_getpos(int nNum, vmvar_t *vX, vmvar_t *vY);
|
||||||
void sp_num_setspan(int nNum, int nSpan);
|
void sp_num_setspan(int nNum, int nSpan);
|
||||||
void sp_num_getspan(int nNUm, int *vSpan);
|
void sp_num_getspan(int nNUm, vmvar_t *vSpan);
|
||||||
void sp_exp_clear(void);
|
void sp_exp_clear(void);
|
||||||
void sp_exp_add(int nNumSP1, int nNumSP2);
|
void sp_exp_add(int nNumSP1, int nNumSP2);
|
||||||
void sp_exp_del(int wNum);
|
void sp_exp_del(int wNum);
|
||||||
@@ -85,7 +86,7 @@ void sp_draw_dmap(void* data, void* userdata);
|
|||||||
// in sprite_msg.c
|
// in sprite_msg.c
|
||||||
void smsg_add(const char *msg);
|
void smsg_add(const char *msg);
|
||||||
void smsg_newline(int wNum, int size);
|
void smsg_newline(int wNum, int size);
|
||||||
void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wFont, int wSpeed, int wLineSpace, int wAlign, int wRSize, int wRFont, int wRLineSpace, int *wLength);
|
void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wFont, int wSpeed, int wLineSpace, int wAlign, int wRSize, int wRFont, int wRLineSpace, vmvar_t *wLength);
|
||||||
void smsg_clear(int wNum);
|
void smsg_clear(int wNum);
|
||||||
bool smsg_is_empty();
|
bool smsg_is_empty();
|
||||||
int smsg_peek(int nTopStringNum);
|
int smsg_peek(int nTopStringNum);
|
||||||
@@ -133,7 +134,7 @@ void sp_eupdate(int type, int time, int key);
|
|||||||
void sp_quake_sprite(int wType, int wAmplitudeX, int wAmplitude, int wCount, int cancel);
|
void sp_quake_sprite(int wType, int wAmplitudeX, int wAmplitude, int wCount, int cancel);
|
||||||
|
|
||||||
// in sprite_keywait.c
|
// in sprite_keywait.c
|
||||||
void sp_keywait(int *vOK, int *vRND, int *vRsv1, int *vRsv2, int *vRsv3, int timeout);
|
void sp_keywait(vmvar_t *vOK, vmvar_t *vRND, vmvar_t *vRsv1, vmvar_t *vRsv2, vmvar_t *vRsv3, int timeout);
|
||||||
|
|
||||||
// in screen_quake.c
|
// in screen_quake.c
|
||||||
void sp_quake_screen(int type, int p1, int p2, int time, int cancel);
|
void sp_quake_screen(int type, int p1, int p2, int time, int cancel);
|
||||||
|
|||||||
@@ -39,11 +39,6 @@
|
|||||||
@param cancel: キー抜け(0:なし, 1:あり)
|
@param cancel: キー抜け(0:なし, 1:あり)
|
||||||
*/
|
*/
|
||||||
void sp_eupdate(int type, int time, int cancel) {
|
void sp_eupdate(int type, int time, int cancel) {
|
||||||
if (sact.waitskiplv > 1) {
|
|
||||||
sp_update_all(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sp_update_all(false);
|
sp_update_all(false);
|
||||||
|
|
||||||
enum effect_type effect = from_sact_effect(type);
|
enum effect_type effect = from_sact_effect(type);
|
||||||
|
|||||||
@@ -426,11 +426,6 @@ static void cb_waitkey_backlog(agsevent_t *e) {
|
|||||||
X|SDL のイベントディスパッチャからくる最初の場所
|
X|SDL のイベントディスパッチャからくる最初の場所
|
||||||
*/
|
*/
|
||||||
void spev_callback(agsevent_t *e) {
|
void spev_callback(agsevent_t *e) {
|
||||||
// menu open中は無視
|
|
||||||
if (nact->popupmenu_opened) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sact.waittype != KEYWAIT_BACKLOG) {
|
if (sact.waittype != KEYWAIT_BACKLOG) {
|
||||||
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
||||||
sact.waitskiplv = 2;
|
sact.waitskiplv = 2;
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ static bool waitcond(int endtime) {
|
|||||||
@param vD03: タイムアウトした場合=1, しない場合=0
|
@param vD03: タイムアウトした場合=1, しない場合=0
|
||||||
@param wTime: タイムアウト時間 (1/100sec)
|
@param wTime: タイムアウト時間 (1/100sec)
|
||||||
*/
|
*/
|
||||||
void sp_keywait(int *vOK, int *vRND, int *vD01, int *vD02, int *vD03, int timeout) {
|
void sp_keywait(vmvar_t *vOK, vmvar_t *vRND, vmvar_t *vD01, vmvar_t *vD02, vmvar_t *vD03, int timeout) {
|
||||||
int curtime, endtime;
|
int curtime, endtime;
|
||||||
|
|
||||||
// とりあえず全更新
|
// とりあえず全更新
|
||||||
@@ -171,4 +171,3 @@ void sp_keywait(int *vOK, int *vRND, int *vD01, int *vD02, int *vD03, int timeou
|
|||||||
sact.waittype = KEYWAIT_NONE;
|
sact.waittype = KEYWAIT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,11 @@
|
|||||||
#include "portab.h"
|
#include "portab.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "ags.h"
|
#include "ags.h"
|
||||||
|
#include "gfx.h"
|
||||||
#include "nact.h"
|
#include "nact.h"
|
||||||
#include "variable.h"
|
#include "variable.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "msgskip.h"
|
||||||
#include "sact.h"
|
#include "sact.h"
|
||||||
#include "sprite.h"
|
#include "sprite.h"
|
||||||
#include "drawtext.h"
|
#include "drawtext.h"
|
||||||
@@ -236,11 +238,12 @@ void smsg_newline(int wNum, int size) {
|
|||||||
@param wRLineSpace: ルビと本文の文字間隔
|
@param wRLineSpace: ルビと本文の文字間隔
|
||||||
@param vLength: ???
|
@param vLength: ???
|
||||||
*/
|
*/
|
||||||
void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wFont, int wSpeed, int wLineSpace, int wAlign, int wRSize, int wRFont, int wRLineSpace, int *wLength) {
|
void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wFont, int wSpeed, int wLineSpace, int wAlign, int wRSize, int wRFont, int wRLineSpace, vmvar_t *wLength) {
|
||||||
char *msg;
|
char *msg;
|
||||||
sprite_t *sp;
|
sprite_t *sp;
|
||||||
int len = 0; // 処理した文字数?
|
int len = 0; // 処理した文字数?
|
||||||
bool needupdate = false;
|
bool has_batched_output = false;
|
||||||
|
bool flush_batched_output = wSpeed > 0;
|
||||||
SDL_Rect uparea = {0,0,0,0};
|
SDL_Rect uparea = {0,0,0,0};
|
||||||
|
|
||||||
// wRSize == 0 -> ルビ無し(SACT.MessageOutputからの呼出)
|
// wRSize == 0 -> ルビ無し(SACT.MessageOutputからの呼出)
|
||||||
@@ -250,7 +253,7 @@ void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wF
|
|||||||
if (!is_messagesprite(wNum)) return;
|
if (!is_messagesprite(wNum)) return;
|
||||||
|
|
||||||
// MessageSkip中は文字送り速度を最大に
|
// MessageSkip中は文字送り速度を最大に
|
||||||
if (sact.waitskiplv > 1) wSpeed = 0;
|
if (sact.waitskiplv > 1 || msgskip_isSkipping()) wSpeed = 0;
|
||||||
|
|
||||||
// shortcut
|
// shortcut
|
||||||
sp = sact.sp[wNum];
|
sp = sact.sp[wNum];
|
||||||
@@ -302,7 +305,7 @@ void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wF
|
|||||||
mbuf,
|
mbuf,
|
||||||
wColorR, wColorG, wColorB);
|
wColorR, wColorG, wColorB);
|
||||||
|
|
||||||
needupdate = true;
|
has_batched_output = true;
|
||||||
|
|
||||||
append_to_log(mbuf);
|
append_to_log(mbuf);
|
||||||
|
|
||||||
@@ -313,7 +316,7 @@ void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wF
|
|||||||
cw,
|
cw,
|
||||||
wSize + wRSize + wRLineSpace);
|
wSize + wRSize + wRLineSpace);
|
||||||
sp_update_clipped();
|
sp_update_clipped();
|
||||||
needupdate = false;
|
has_batched_output = false;
|
||||||
|
|
||||||
// keywait
|
// keywait
|
||||||
delta = sys_get_ticks() - wcnt;
|
delta = sys_get_ticks() - wcnt;
|
||||||
@@ -333,11 +336,17 @@ void smsg_out(int wNum, int wSize, int wColorR, int wColorG, int wColorB, int wF
|
|||||||
// バッファリング中の文字のクリア
|
// バッファリング中の文字のクリア
|
||||||
sact.msgbuf[0] = '\0';
|
sact.msgbuf[0] = '\0';
|
||||||
|
|
||||||
// Waitなしの出力は最後にupdate
|
// Register the update area after rendering without waits.
|
||||||
if (needupdate) {
|
if (has_batched_output) {
|
||||||
uparea.w = sp->width;
|
uparea.w = sp->width;
|
||||||
uparea.h = min(sp->height, uparea.y - sp->u.msg.dspcur.y + wLineSpace + wLineSpace + wRSize);
|
uparea.h = min(sp->height - uparea.y,
|
||||||
|
sp->u.msg.dspcur.y - uparea.y + wSize + wRSize + wRLineSpace);
|
||||||
sp_updateme_part(sp, uparea.x, uparea.y, uparea.w, uparea.h);
|
sp_updateme_part(sp, uparea.x, uparea.y, uparea.w, uparea.h);
|
||||||
|
// Present now if waiting was skipped.
|
||||||
|
if (flush_batched_output) {
|
||||||
|
sp_update_clipped();
|
||||||
|
gfx_updateScreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ????
|
// ????
|
||||||
@@ -408,7 +417,7 @@ int smsg_keywait(int wNum1, int wNum2, int msglen) {
|
|||||||
struct markinfo minfo[6];
|
struct markinfo minfo[6];
|
||||||
int i = 0, j, maxstep;
|
int i = 0, j, maxstep;
|
||||||
|
|
||||||
if (sact.waitskiplv > 0) {
|
if (sact.waitskiplv > 0 || msgskip_isSkipping()) {
|
||||||
sys_getInputInfo();
|
sys_getInputInfo();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,11 +117,4 @@ void spev_main() {
|
|||||||
|
|
||||||
e.type = AGSEVENT_TIMER;
|
e.type = AGSEVENT_TIMER;
|
||||||
tevent_callback(&e);
|
tevent_callback(&e);
|
||||||
|
|
||||||
// デフォルトのコールバックのうち、ここで必要なものだけ
|
|
||||||
// 処理。(VAコマンドcallbackはなし)
|
|
||||||
if (nact->popupmenu_opened) {
|
|
||||||
menu_gtkmainiteration();
|
|
||||||
if (nact->is_quit) sys_exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+83
-83
@@ -43,10 +43,10 @@ static void GetAtArray(void) { /* 0 */
|
|||||||
type: 演算の種類
|
type: 演算の種類
|
||||||
vResult: 演算結果を返す変数
|
vResult: 演算結果を返す変数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int type = getCaliValue();
|
int type = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
TRACE("ShArray.GetAtArray %p,%d,%d,%p:", vAry, cnt, type, vResult);
|
TRACE("ShArray.GetAtArray %p,%d,%d,%p:", vAry, cnt, type, vResult);
|
||||||
@@ -88,8 +88,8 @@ static void AddAtArray(void) { /* 1 */
|
|||||||
vAry2: 配列2
|
vAry2: 配列2
|
||||||
cnt : 個数
|
cnt : 個数
|
||||||
*/
|
*/
|
||||||
int *vAry1 = getCaliVariable();
|
vmvar_t *vAry1 = getCaliVariable();
|
||||||
int *vAry2 = getCaliVariable();
|
vmvar_t *vAry2 = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -114,8 +114,8 @@ static void SubAtArray(void) { /* 2 */
|
|||||||
vAry2: 配列2
|
vAry2: 配列2
|
||||||
cnt : 個数
|
cnt : 個数
|
||||||
*/
|
*/
|
||||||
int *vAry1 = getCaliVariable();
|
vmvar_t *vAry1 = getCaliVariable();
|
||||||
int *vAry2 = getCaliVariable();
|
vmvar_t *vAry2 = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -140,8 +140,8 @@ static void MulAtArray(void) { /* 3 */
|
|||||||
vAry2: 配列2
|
vAry2: 配列2
|
||||||
cnt : 個数
|
cnt : 個数
|
||||||
*/
|
*/
|
||||||
int *vAry1 = getCaliVariable();
|
vmvar_t *vAry1 = getCaliVariable();
|
||||||
int *vAry2 = getCaliVariable();
|
vmvar_t *vAry2 = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -166,8 +166,8 @@ static void DivAtArray(void) { /* 4 */
|
|||||||
vAry2: 配列2
|
vAry2: 配列2
|
||||||
cnt : 個数
|
cnt : 個数
|
||||||
*/
|
*/
|
||||||
int *vAry1 = getCaliVariable();
|
vmvar_t *vAry1 = getCaliVariable();
|
||||||
int *vAry2 = getCaliVariable();
|
vmvar_t *vAry2 = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -196,8 +196,8 @@ static void MinAtArray(void) { /* 5 */
|
|||||||
vAry2: 配列2
|
vAry2: 配列2
|
||||||
cnt : 個数
|
cnt : 個数
|
||||||
*/
|
*/
|
||||||
int *vAry1 = getCaliVariable();
|
vmvar_t *vAry1 = getCaliVariable();
|
||||||
int *vAry2 = getCaliVariable();
|
vmvar_t *vAry2 = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -219,8 +219,8 @@ static void MaxAtArray(void) { /* 6 */
|
|||||||
vAry2: 配列2
|
vAry2: 配列2
|
||||||
cnt : 個数
|
cnt : 個数
|
||||||
*/
|
*/
|
||||||
int *vAry1 = getCaliVariable();
|
vmvar_t *vAry1 = getCaliVariable();
|
||||||
int *vAry2 = getCaliVariable();
|
vmvar_t *vAry2 = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ static void AndNumArray(void) { /* 7 */
|
|||||||
cnt : 個数
|
cnt : 個数
|
||||||
val : ANDをとる値
|
val : ANDをとる値
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
@@ -263,7 +263,7 @@ static void OrNumArray(void) { /* 8 */
|
|||||||
cnt : 個数
|
cnt : 個数
|
||||||
val : ORをとる値
|
val : ORをとる値
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
@@ -284,7 +284,7 @@ static void XorNumArray(void) { /* 9 */
|
|||||||
cnt : 個数
|
cnt : 個数
|
||||||
val : XORをとる値
|
val : XORをとる値
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
@@ -307,10 +307,10 @@ static void SetEquArray(void) { /* 10 */
|
|||||||
val : 比較する値
|
val : 比較する値
|
||||||
vResults : 結果を格納する配列
|
vResults : 結果を格納する配列
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.SetEquArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
TRACE("ShArray.SetEquArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
||||||
@@ -331,10 +331,10 @@ static void SetNotArray(void) { /* 11 */
|
|||||||
val : 比較する値
|
val : 比較する値
|
||||||
vResults : 結果を格納する配列
|
vResults : 結果を格納する配列
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.SetNotArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
TRACE("ShArray.SetNotArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
||||||
@@ -354,10 +354,10 @@ static void SetLowArray(void) { /* 12 */
|
|||||||
val : 閾値
|
val : 閾値
|
||||||
vResult: 結果を返す変数
|
vResult: 結果を返す変数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.SetLowArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
TRACE("ShArray.SetLowArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
||||||
@@ -377,10 +377,10 @@ static void SetHighArray(void) { /* 13 */
|
|||||||
val : 閾値
|
val : 閾値
|
||||||
vResults: 結果を返す変数
|
vResults: 結果を返す変数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.SetHighArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
TRACE("ShArray.SetHighArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
||||||
@@ -403,11 +403,11 @@ static void SetRangeArray(void) { /* 14 */
|
|||||||
min < vAry < max の時 vResults = 1;
|
min < vAry < max の時 vResults = 1;
|
||||||
それ以外 vResults = 0;
|
それ以外 vResults = 0;
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.SetRangeArray %p,%d,%d,%d,%p:", vAry, cnt, min, max, vResults);
|
TRACE("ShArray.SetRangeArray %p,%d,%d,%d,%p:", vAry, cnt, min, max, vResults);
|
||||||
@@ -430,11 +430,11 @@ static void SetAndEquArray(void) { /* 15 */
|
|||||||
vResults : 結果を代入する配列
|
vResults : 結果を代入する配列
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int mask = getCaliValue();
|
int mask = getCaliValue();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.SetAndEquArray: %p,%d,%d,%d,%p:", vAry, mask, cnt, val, vResults);
|
TRACE("ShArray.SetAndEquArray: %p,%d,%d,%d,%p:", vAry, mask, cnt, val, vResults);
|
||||||
@@ -455,10 +455,10 @@ static void AndEquArray(void) { /* 16 */
|
|||||||
val : 比較する値
|
val : 比較する値
|
||||||
vResults : 結果を代入する配列
|
vResults : 結果を代入する配列
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.AndEquArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
TRACE("ShArray.AndEquArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
||||||
@@ -479,10 +479,10 @@ static void AndNotArray(void) { /* 17 */
|
|||||||
val : 比較する値
|
val : 比較する値
|
||||||
vResults : 結果を代入する配列
|
vResults : 結果を代入する配列
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.AndNotArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
TRACE("ShArray.AndNotArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
||||||
@@ -503,10 +503,10 @@ static void AndLowArray(void) { /* 18 */
|
|||||||
min : 最小値
|
min : 最小値
|
||||||
vResults : 結果を代入する配列
|
vResults : 結果を代入する配列
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.AndLowArray: %d,%d,%d,%d:", vAry, cnt, min, vResults);
|
TRACE("ShArray.AndLowArray: %d,%d,%d,%d:", vAry, cnt, min, vResults);
|
||||||
@@ -527,10 +527,10 @@ static void AndHighArray(void) { /* 19 */
|
|||||||
max : 最小値
|
max : 最小値
|
||||||
vResults : 結果を代入する配列
|
vResults : 結果を代入する配列
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.AndHighArray: %p,%d,%d,%p:", vAry, cnt, max, vResults);
|
TRACE("ShArray.AndHighArray: %p,%d,%d,%p:", vAry, cnt, max, vResults);
|
||||||
@@ -552,11 +552,11 @@ static void AndRangeArray(void) { /* 20 */
|
|||||||
max: 最大値
|
max: 最大値
|
||||||
vResults: 結果を返す配列
|
vResults: 結果を返す配列
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.AndRangeArray %d,%d,%d,%d,%d:", vAry, cnt, min, max, vResults);
|
TRACE("ShArray.AndRangeArray %d,%d,%d,%d,%d:", vAry, cnt, min, max, vResults);
|
||||||
@@ -579,11 +579,11 @@ static void AndAndEquArray(void) { /* 21 */
|
|||||||
vResults : 結果を代入する配列
|
vResults : 結果を代入する配列
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int mask = getCaliValue();
|
int mask = getCaliValue();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.AndAndEquArray: %d,%d,%d,%d,%d:", vAry, mask, cnt, val, vResults);
|
TRACE("ShArray.AndAndEquArray: %d,%d,%d,%d,%d:", vAry, mask, cnt, val, vResults);
|
||||||
@@ -612,10 +612,10 @@ static void OrNotArray(void) { /* 23 */
|
|||||||
val : 比較する値
|
val : 比較する値
|
||||||
vResults: 結果を書き込む変数
|
vResults: 結果を書き込む変数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResults = getCaliVariable();
|
vmvar_t *vResults = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.OrNotArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
TRACE("ShArray.OrNotArray %p,%d,%d,%p:", vAry, cnt, val, vResults);
|
||||||
@@ -674,10 +674,10 @@ static void EnumEquArray(void) { /* 28 */
|
|||||||
val : 比較する値
|
val : 比較する値
|
||||||
vResult: 一致する個数を返す変数
|
vResult: 一致する個数を返す変数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.EnumEquArray %p,%d,%d,%p:", vAry, cnt, val, vResult);
|
TRACE("ShArray.EnumEquArray %p,%d,%d,%p:", vAry, cnt, val, vResult);
|
||||||
@@ -713,12 +713,12 @@ static void EnumEquNotArray2(void) { /* 30 */
|
|||||||
val2: 配列2と比較する値
|
val2: 配列2と比較する値
|
||||||
vResult: 条件に一致する数を返す変数
|
vResult: 条件に一致する数を返す変数
|
||||||
*/
|
*/
|
||||||
int *vAry1 = getCaliVariable();
|
vmvar_t *vAry1 = getCaliVariable();
|
||||||
int *vAry2 = getCaliVariable();
|
vmvar_t *vAry2 = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val1 = getCaliValue();
|
int val1 = getCaliValue();
|
||||||
int val2 = getCaliValue();
|
int val2 = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.EnumEquNotArray2 %p,%p,%d,%d,%d,%p:", vAry1, vAry2, cnt, val1, val2, vResult);
|
TRACE("ShArray.EnumEquNotArray2 %p,%p,%d,%d,%d,%p:", vAry1, vAry2, cnt, val1, val2, vResult);
|
||||||
@@ -742,10 +742,10 @@ static void EnumNotArray(void) { /* 31 */
|
|||||||
val: 比較する値
|
val: 比較する値
|
||||||
vResult: 等しくないものの数
|
vResult: 等しくないものの数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.EnumNotArray %p, %d, %d, %p:", vAry, cnt, val, vResult);
|
TRACE("ShArray.EnumNotArray %p, %d, %d, %p:", vAry, cnt, val, vResult);
|
||||||
@@ -799,11 +799,11 @@ static void EnumRangeArray(void) { /* 35 */
|
|||||||
max : 最大値
|
max : 最大値
|
||||||
vResult: 一致した数を返す変数
|
vResult: 一致した数を返す変数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.EnumRangeArray %d,%d,%d,%d,%d:", vAry, cnt, min, max, vResult);
|
TRACE("ShArray.EnumRangeArray %d,%d,%d,%d,%d:", vAry, cnt, min, max, vResult);
|
||||||
@@ -830,11 +830,11 @@ static void GrepEquArray(void) { /* 36 */
|
|||||||
vMatch: 一致したインデックス
|
vMatch: 一致したインデックス
|
||||||
vResult: 一つでも val と同じ値があれば 1
|
vResult: 一つでも val と同じ値があれば 1
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vMatch = getCaliVariable();
|
vmvar_t *vMatch = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.GrepEquArray %p,%d,%d,%p,%p:", vAry, cnt, val, vMatch, vResult);
|
TRACE("ShArray.GrepEquArray %p,%d,%d,%p,%p:", vAry, cnt, val, vMatch, vResult);
|
||||||
@@ -862,11 +862,11 @@ static void GrepNotArray(void) { /* 37 */
|
|||||||
vMatch: 一致するindex
|
vMatch: 一致するindex
|
||||||
vResult: 一つでも val と同じ値があれば 1
|
vResult: 一つでも val と同じ値があれば 1
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *vMatch = getCaliVariable();
|
vmvar_t *vMatch = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.GrepNotArray %p,%d,%d,%p,%p:", vAry, cnt, val, vMatch, vResult);
|
TRACE("ShArray.GrepNotArray %p,%d,%d,%p,%p:", vAry, cnt, val, vMatch, vResult);
|
||||||
@@ -930,11 +930,11 @@ static void GrepLowArray(void) { /* 41 */
|
|||||||
vMatch: 一致したインデックス
|
vMatch: 一致したインデックス
|
||||||
vResult: 一つでも val と同じ値があれば 1
|
vResult: 一つでも val と同じ値があれば 1
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int *vMatch = getCaliVariable();
|
vmvar_t *vMatch = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.GrepLowArray: %p,%d,%d,%p,%p:", vAry, cnt, min, vMatch, vResult);
|
TRACE("ShArray.GrepLowArray: %p,%d,%d,%p,%p:", vAry, cnt, min, vMatch, vResult);
|
||||||
@@ -962,11 +962,11 @@ static void GrepHighArray(void) { /* 42 */
|
|||||||
vMatch: 一致したインデックス
|
vMatch: 一致したインデックス
|
||||||
vResult: 一つでも val と同じ値があれば 1
|
vResult: 一つでも val と同じ値があれば 1
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *vMatch = getCaliVariable();
|
vmvar_t *vMatch = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.GrepHighArray: %p,%d,%d,%p,%p:", vAry, cnt, max, vMatch, vResult);
|
TRACE("ShArray.GrepHighArray: %p,%d,%d,%p,%p:", vAry, cnt, max, vMatch, vResult);
|
||||||
@@ -995,12 +995,12 @@ static void GrepRangeArray(void) { /* 43 */
|
|||||||
vMatch: 一致したインデックス
|
vMatch: 一致したインデックス
|
||||||
vResult: 一つでも val と同じ値があれば 1
|
vResult: 一つでも val と同じ値があれば 1
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *vMatch = getCaliVariable();
|
vmvar_t *vMatch = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShArray.GrepRangeArray %p,%d,%d,%d,%p,%p:", vAry, cnt, max, min, vMatch, vResult);
|
TRACE("ShArray.GrepRangeArray %p,%d,%d,%d,%p,%p:", vAry, cnt, max, min, vMatch, vResult);
|
||||||
@@ -1031,13 +1031,13 @@ static void GrepLowOrderArray(void) { /* 44 */
|
|||||||
vLastMatch: 最小値を示す配列のindex
|
vLastMatch: 最小値を示す配列のindex
|
||||||
vResult: 最小値が見つかれば 1, 見つからなければ 0
|
vResult: 最小値が見つかれば 1, 見つからなければ 0
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *v1 = getCaliVariable();
|
vmvar_t *v1 = getCaliVariable();
|
||||||
int *vLastMatch = getCaliVariable();
|
vmvar_t *vLastMatch = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i, j, k = 0;
|
int i, j, k = 0;
|
||||||
|
|
||||||
TRACE("ShArray.GrepLowOrderArray %p,%d,%d,%d,%p,%p,%p:", vAry, cnt, min, max, v1, vLastMatch, vResult);
|
TRACE("ShArray.GrepLowOrderArray %p,%d,%d,%d,%p,%p,%p:", vAry, cnt, min, max, v1, vLastMatch, vResult);
|
||||||
@@ -1082,13 +1082,13 @@ static void GrepHighOrderArray(void) { /* 45 */
|
|||||||
vLastMatch: 最大値を示す配列のindex
|
vLastMatch: 最大値を示す配列のindex
|
||||||
vResult: 最大値が見つかれば 1, 見つからなければ 0
|
vResult: 最大値が見つかれば 1, 見つからなければ 0
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
int *v1 = getCaliVariable();
|
vmvar_t *v1 = getCaliVariable();
|
||||||
int *vLastMatch = getCaliVariable();
|
vmvar_t *vLastMatch = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i, j, k = 0;
|
int i, j, k = 0;
|
||||||
|
|
||||||
TRACE("ShArray.GrepHighOrderArray %p,%d,%d,%d,%p,%p,%p:", vAry, cnt, min, max, v1, vLastMatch, vResult);
|
TRACE("ShArray.GrepHighOrderArray %p,%d,%d,%d,%p,%p,%p:", vAry, cnt, min, max, v1, vLastMatch, vResult);
|
||||||
@@ -1119,7 +1119,7 @@ static void GrepHighOrderArray(void) { /* 45 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ChangeEquArray(void) { /* 46 */
|
static void ChangeEquArray(void) { /* 46 */
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int src = getCaliValue();
|
int src = getCaliValue();
|
||||||
int dst = getCaliValue();
|
int dst = getCaliValue();
|
||||||
@@ -1172,7 +1172,7 @@ static void ChangeRangeArray(void) { /* 50 */
|
|||||||
max : 最大値
|
max : 最大値
|
||||||
val : 置き換える値
|
val : 置き換える値
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int min = getCaliValue();
|
int min = getCaliValue();
|
||||||
int max = getCaliValue();
|
int max = getCaliValue();
|
||||||
@@ -1202,12 +1202,12 @@ static void CopyArrayToRect(void) { /* 51 */
|
|||||||
dw : コピー先 width
|
dw : コピー先 width
|
||||||
dh : コピー先 height
|
dh : コピー先 height
|
||||||
*/
|
*/
|
||||||
int *vSrc = getCaliVariable();
|
vmvar_t *vSrc = getCaliVariable();
|
||||||
int sw = getCaliValue();
|
int sw = getCaliValue();
|
||||||
int sh = getCaliValue();
|
int sh = getCaliValue();
|
||||||
int sx = getCaliValue();
|
int sx = getCaliValue();
|
||||||
int sy = getCaliValue();
|
int sy = getCaliValue();
|
||||||
int *vDst = getCaliVariable();
|
vmvar_t *vDst = getCaliVariable();
|
||||||
int dw = getCaliValue();
|
int dw = getCaliValue();
|
||||||
int dh = getCaliValue();
|
int dh = getCaliValue();
|
||||||
int x, y;
|
int x, y;
|
||||||
@@ -1236,10 +1236,10 @@ static void CopyRectToArray(void) { /* 52 */
|
|||||||
dx : コピー先 x
|
dx : コピー先 x
|
||||||
dy : コピー先 y
|
dy : コピー先 y
|
||||||
*/
|
*/
|
||||||
int *vSrc = getCaliVariable();
|
vmvar_t *vSrc = getCaliVariable();
|
||||||
int sw = getCaliValue();
|
int sw = getCaliValue();
|
||||||
int sh = getCaliValue();
|
int sh = getCaliValue();
|
||||||
int *vDst = getCaliVariable();
|
vmvar_t *vDst = getCaliVariable();
|
||||||
int dw = getCaliValue();
|
int dw = getCaliValue();
|
||||||
int dh = getCaliValue();
|
int dh = getCaliValue();
|
||||||
int dx = getCaliValue();
|
int dx = getCaliValue();
|
||||||
@@ -1266,10 +1266,10 @@ static void ChangeSecretArray(void) { /* 53 */
|
|||||||
type: 機能番号
|
type: 機能番号
|
||||||
vResult: 結果を返す変数
|
vResult: 結果を返す変数
|
||||||
*/
|
*/
|
||||||
int *vAry = getCaliVariable();
|
vmvar_t *vAry = getCaliVariable();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int type = getCaliValue();
|
int type = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
static uint16_t key[4] = { 0x7A7A, 0xADAD, 0xBCBC, 0xCECE }; /* key */
|
static uint16_t key[4] = { 0x7A7A, 0xADAD, 0xBCBC, 0xCECE }; /* key */
|
||||||
|
|
||||||
TRACE("ShArray.ChangeSecretArray %p,%d,%d,%p:", vAry, cnt, type, vResult);
|
TRACE("ShArray.ChangeSecretArray %p,%d,%d,%p:", vAry, cnt, type, vResult);
|
||||||
|
|||||||
+19
-19
@@ -50,7 +50,7 @@ static int64_t div64(int64_t a1, int64_t a2) {
|
|||||||
return a1 / a2;
|
return a1 / a2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t get32(int *var) {
|
static int64_t get32(vmvar_t *var) {
|
||||||
return var[0] + mul64(var[1], 0x10000);
|
return var[0] + mul64(var[1], 0x10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ static void SetIntNum16(void) { /* 1 */
|
|||||||
|
|
||||||
var: 数値の入った変数
|
var: 数値の入った変数
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
accumulator = mul64(*var, numbase);
|
accumulator = mul64(*var, numbase);
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ static void SetIntNum16(void) { /* 1 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SetIntNum32(void) { /* 2 */
|
static void SetIntNum32(void) { /* 2 */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
accumulator = mul64(get32(var), numbase);
|
accumulator = mul64(get32(var), numbase);
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ static void GetIntNum16(void) { /* 3 */
|
|||||||
|
|
||||||
var: 数値をいれる変数
|
var: 数値をいれる変数
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int64_t i;
|
int64_t i;
|
||||||
|
|
||||||
i = div64(accumulator, numbase);
|
i = div64(accumulator, numbase);
|
||||||
@@ -110,7 +110,7 @@ static void GetIntNum16(void) { /* 3 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetIntNum32(void) { /* 4 */
|
static void GetIntNum32(void) { /* 4 */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int64_t i = div64(accumulator, numbase);
|
int64_t i = div64(accumulator, numbase);
|
||||||
|
|
||||||
var[0] = i & 0xFFFF;
|
var[0] = i & 0xFFFF;
|
||||||
@@ -126,7 +126,7 @@ static void AddIntNum16(void) { /* 5 */
|
|||||||
|
|
||||||
var: 足す数の入った変数
|
var: 足す数の入った変数
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
accumulator += mul64(*var, numbase);
|
accumulator += mul64(*var, numbase);
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ static void AddIntNum16(void) { /* 5 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void AddIntNum32(void) { /* 6 */
|
static void AddIntNum32(void) { /* 6 */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
accumulator += mul64(get32(var), numbase);
|
accumulator += mul64(get32(var), numbase);
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ static void SubIntNum16(void) { /* 7 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SubIntNum32(void) { /* 8 */
|
static void SubIntNum32(void) { /* 8 */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
accumulator -= mul64(get32(var), numbase);
|
accumulator -= mul64(get32(var), numbase);
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ static void MulIntNum16(void) { /* 9 */
|
|||||||
|
|
||||||
var: 掛ける数の入った変数
|
var: 掛ける数の入った変数
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
accumulator *= mul64(*var, numbase);
|
accumulator *= mul64(*var, numbase);
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ static void DivIntNum16(void) { /* 11 */
|
|||||||
|
|
||||||
var: 足す数の入った変数
|
var: 足す数の入った変数
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int64_t i;
|
int64_t i;
|
||||||
|
|
||||||
i = mul64(*var, numbase);
|
i = mul64(*var, numbase);
|
||||||
@@ -204,9 +204,9 @@ static void CmpIntNum16(void) { /* 13 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void CmpIntNum32(void) { /* 14 */
|
static void CmpIntNum32(void) { /* 14 */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int op = getCaliValue();
|
int op = getCaliValue();
|
||||||
int *result = getCaliVariable();
|
vmvar_t *result = getCaliVariable();
|
||||||
|
|
||||||
int64_t val = mul64(get32(var), numbase);
|
int64_t val = mul64(get32(var), numbase);
|
||||||
|
|
||||||
@@ -230,8 +230,8 @@ static void GetLengthNum16(void) { /* 15 */
|
|||||||
var: 数値
|
var: 数値
|
||||||
vResult: 数値の桁数を返す変数
|
vResult: 数値の桁数を返す変数
|
||||||
*/
|
*/
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
|
|
||||||
if (*var >= 10000) {
|
if (*var >= 10000) {
|
||||||
*vResult = 5;
|
*vResult = 5;
|
||||||
@@ -270,7 +270,7 @@ static void NumToRate(void) { /* 17 */
|
|||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int flag = getCaliValue();
|
int flag = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = (p1 * p3) / p2;
|
i = (p1 * p3) / p2;
|
||||||
@@ -302,7 +302,7 @@ static void NumToRateNum(void) { /* 18 */
|
|||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int flag = getCaliValue();
|
int flag = getCaliValue();
|
||||||
int *vResult = getCaliVariable();
|
vmvar_t *vResult = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = (p1 * p2) / p3;
|
i = (p1 * p2) / p3;
|
||||||
@@ -333,7 +333,7 @@ static void SetRandomSeed() {
|
|||||||
|
|
||||||
static void GetRandomNumA() {
|
static void GetRandomNumA() {
|
||||||
int num = getCaliValue();
|
int num = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
if (num == 0 || num == 1) {
|
if (num == 0 || num == 1) {
|
||||||
*var = num;
|
*var = num;
|
||||||
@@ -351,7 +351,7 @@ static void NumToBit() {
|
|||||||
var: 値を返す変数
|
var: 値を返す変数
|
||||||
*/
|
*/
|
||||||
int beki = getCaliValue();
|
int beki = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int i, j = 1;
|
int i, j = 1;
|
||||||
|
|
||||||
if (beki < 17) {
|
if (beki < 17) {
|
||||||
@@ -379,7 +379,7 @@ static void BitToNum() {
|
|||||||
var: 値を返す変数
|
var: 値を返す変数
|
||||||
*/
|
*/
|
||||||
int val = getCaliValue();
|
int val = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
TRACE("ShCalc.BitToNum %d,%p:", val, var);
|
TRACE("ShCalc.BitToNum %d,%p:", val, var);
|
||||||
|
|||||||
+12
-12
@@ -59,8 +59,8 @@ struct animsrc {
|
|||||||
static struct animsrc src[SLOT]; /* アニメーション各コマ転送元 */
|
static struct animsrc src[SLOT]; /* アニメーション各コマ転送元 */
|
||||||
|
|
||||||
struct _s0 {
|
struct _s0 {
|
||||||
int *dst_p1;
|
vmvar_t *dst_p1;
|
||||||
int *dst_p2;
|
vmvar_t *dst_p2;
|
||||||
int dw_1000A188;
|
int dw_1000A188;
|
||||||
};
|
};
|
||||||
static struct _s0 s0[SLOT];
|
static struct _s0 s0[SLOT];
|
||||||
@@ -84,7 +84,7 @@ struct _s2 {
|
|||||||
};
|
};
|
||||||
static struct _s2 s2[SLOT];
|
static struct _s2 s2[SLOT];
|
||||||
|
|
||||||
static int* add_p5[SLOT]; /* どこまでアニメーションのコマが進んだか */
|
static vmvar_t *add_p5[SLOT]; /* どこまでアニメーションのコマが進んだか */
|
||||||
|
|
||||||
static void copy_sprite(int sx, int sy, int width, int height, int dx, int dy, int r, int g, int b) {
|
static void copy_sprite(int sx, int sy, int width, int height, int dx, int dy, int r, int g, int b) {
|
||||||
SDL_Surface *sf = nact->ags.dib->sdl_surface;
|
SDL_Surface *sf = nact->ags.dib->sdl_surface;
|
||||||
@@ -115,8 +115,8 @@ static void ChangeEquColor() {
|
|||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int p4 = getCaliValue();
|
int p4 = getCaliValue();
|
||||||
int *p5 = getCaliVariable();
|
vmvar_t *p5 = getCaliVariable();
|
||||||
int *p6 = getCaliVariable();
|
vmvar_t *p6 = getCaliVariable();
|
||||||
int p7 = getCaliValue(); /* ISurface */
|
int p7 = getCaliValue(); /* ISurface */
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("ShGraph.ChangeEquColor %d,%d,%d,%d,%p,%p,%d:", p1, p2, p3, p4, p5, p6, p7);
|
TRACE_UNIMPLEMENTED("ShGraph.ChangeEquColor %d,%d,%d,%d,%p,%p,%d:", p1, p2, p3, p4, p5, p6, p7);
|
||||||
@@ -137,8 +137,8 @@ static void ChangeNotColor() {
|
|||||||
int y0 = getCaliValue();
|
int y0 = getCaliValue();
|
||||||
int width = getCaliValue();
|
int width = getCaliValue();
|
||||||
int height = getCaliValue();
|
int height = getCaliValue();
|
||||||
int *src = getCaliVariable(); /* r, g, b */
|
vmvar_t *src = getCaliVariable(); /* r, g, b */
|
||||||
int *dst = getCaliVariable(); /* r, g, b */
|
vmvar_t *dst = getCaliVariable(); /* r, g, b */
|
||||||
int p7 = getCaliValue(); /* ISurface */
|
int p7 = getCaliValue(); /* ISurface */
|
||||||
surface_t *dib;
|
surface_t *dib;
|
||||||
int x, y;
|
int x, y;
|
||||||
@@ -216,7 +216,7 @@ static void ResetAnimeData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(s1, 0, sizeof(struct _s1) * SLOT);
|
memset(s1, 0, sizeof(struct _s1) * SLOT);
|
||||||
memset(add_p5, 0, sizeof(int *) * SLOT);
|
memset(add_p5, 0, sizeof(vmvar_t *) * SLOT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ static void SetAnimeSrc() {
|
|||||||
int h = getCaliValue();
|
int h = getCaliValue();
|
||||||
int uw = getCaliValue();
|
int uw = getCaliValue();
|
||||||
int uh = getCaliValue();
|
int uh = getCaliValue();
|
||||||
int *pal = getCaliVariable();
|
vmvar_t *pal = getCaliVariable();
|
||||||
int r, g, b;
|
int r, g, b;
|
||||||
|
|
||||||
TRACE("ShGraph.SetAnimeSrc %d,%d,%d,%d,%d,%d,%d,%p:", no, x0, y0, w, h, uw, uh, pal);
|
TRACE("ShGraph.SetAnimeSrc %d,%d,%d,%d,%d,%d,%d,%p:", no, x0, y0, w, h, uw, uh, pal);
|
||||||
@@ -276,8 +276,8 @@ static void SetAnimeDst() {
|
|||||||
p6: 描画先オフセット追加分 (h) 10000が中央
|
p6: 描画先オフセット追加分 (h) 10000が中央
|
||||||
*/
|
*/
|
||||||
int no = getCaliValue();
|
int no = getCaliValue();
|
||||||
int *p1 = getCaliVariable();
|
vmvar_t *p1 = getCaliVariable();
|
||||||
int *p2 = getCaliVariable();
|
vmvar_t *p2 = getCaliVariable();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int p4 = getCaliValue();
|
int p4 = getCaliValue();
|
||||||
int p5 = getCaliValue();
|
int p5 = getCaliValue();
|
||||||
@@ -313,7 +313,7 @@ static void AddAnimeData() {
|
|||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int p4 = getCaliValue();
|
int p4 = getCaliValue();
|
||||||
int *p5 = getCaliVariable();
|
vmvar_t *p5 = getCaliVariable();
|
||||||
int p6 = getCaliValue();
|
int p6 = getCaliValue();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#include "xsystem35.h"
|
#include "xsystem35.h"
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "menu.h"
|
#include "input_modal.h"
|
||||||
|
|
||||||
// キー変換テーブル
|
// キー変換テーブル
|
||||||
#define KEYMAP_MAX 8
|
#define KEYMAP_MAX 8
|
||||||
@@ -47,7 +47,7 @@ static void OutputMessageBox(void) { /* 0 */
|
|||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int title = getCaliValue();
|
int title = getCaliValue();
|
||||||
int msg = getCaliValue();
|
int msg = getCaliValue();
|
||||||
int *res = getCaliVariable();
|
vmvar_t *res = getCaliVariable();
|
||||||
int ISys3xSystem = getCaliValue();
|
int ISys3xSystem = getCaliValue();
|
||||||
|
|
||||||
char *title_utf8 = toUTF8(svar_get(title));
|
char *title_utf8 = toUTF8(svar_get(title));
|
||||||
@@ -64,10 +64,10 @@ static void OutputMessageBox(void) { /* 0 */
|
|||||||
static void InputListNum(void) { /* 1 */
|
static void InputListNum(void) { /* 1 */
|
||||||
int flags = getCaliValue();
|
int flags = getCaliValue();
|
||||||
int title = getCaliValue();
|
int title = getCaliValue();
|
||||||
int *val = getCaliVariable();
|
vmvar_t *val = getCaliVariable();
|
||||||
int minval = getCaliValue();
|
int minval = getCaliValue();
|
||||||
int maxval = getCaliValue();
|
int maxval = getCaliValue();
|
||||||
int *res = getCaliVariable();
|
vmvar_t *res = getCaliVariable();
|
||||||
int ISys3xSystem = getCaliValue();
|
int ISys3xSystem = getCaliValue();
|
||||||
|
|
||||||
INPUTNUM_PARAM ni_param = {
|
INPUTNUM_PARAM ni_param = {
|
||||||
@@ -77,12 +77,11 @@ static void InputListNum(void) { /* 1 */
|
|||||||
.title = toUTF8(svar_get(title)),
|
.title = toUTF8(svar_get(title)),
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_inputnumber(&ni_param);
|
if (input_modal_number(&ni_param)) {
|
||||||
if (ni_param.value < 0) {
|
|
||||||
*res = 0;
|
|
||||||
} else {
|
|
||||||
*val = (uint16_t)ni_param.value;
|
*val = (uint16_t)ni_param.value;
|
||||||
*res = 1;
|
*res = 1;
|
||||||
|
} else {
|
||||||
|
*res = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ni_param.title);
|
free(ni_param.title);
|
||||||
@@ -152,7 +151,7 @@ static void SetKeyStatus(void) {
|
|||||||
*/
|
*/
|
||||||
static void GetKeyStatus(void) {
|
static void GetKeyStatus(void) {
|
||||||
int no = getCaliValue();
|
int no = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (no >= KEYMAP_MAX) {
|
if (no >= KEYMAP_MAX) {
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ static void wavPlayRing() {
|
|||||||
*/
|
*/
|
||||||
int start = getCaliValue();
|
int start = getCaliValue();
|
||||||
int cnt = getCaliValue();
|
int cnt = getCaliValue();
|
||||||
int *cur = getCaliVariable();
|
vmvar_t *cur = getCaliVariable();
|
||||||
|
|
||||||
mus_wav_play(start + (*cur % cnt), 1);
|
mus_wav_play(start + (*cur % cnt), 1);
|
||||||
*cur = (*cur + 1) % cnt;
|
*cur = (*cur + 1) % cnt;
|
||||||
@@ -321,7 +321,7 @@ static void wavIsPlay() {
|
|||||||
*result: 0なら停止中、!0なら再生中
|
*result: 0なら停止中、!0なら再生中
|
||||||
*/
|
*/
|
||||||
int slot = getCaliValue();
|
int slot = getCaliValue();
|
||||||
int *result = getCaliVariable();
|
vmvar_t *result = getCaliVariable();
|
||||||
|
|
||||||
*result = mus_wav_get_playposition(slot);
|
*result = mus_wav_get_playposition(slot);
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ static void wavIsPlayRange() {
|
|||||||
*/
|
*/
|
||||||
int slot = getCaliValue();
|
int slot = getCaliValue();
|
||||||
int range = getCaliValue();
|
int range = getCaliValue();
|
||||||
int *result = getCaliVariable();
|
vmvar_t *result = getCaliVariable();
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
for (i = slot; i < (slot + range); i++) {
|
for (i = slot; i < (slot + range); i++) {
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ static void SetStringNum16(void) {
|
|||||||
p2: 変換された数値を格納する変数
|
p2: 変換された数値を格納する変数
|
||||||
*/
|
*/
|
||||||
int st = getCaliValue();
|
int st = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
const char *str = svar_get(st);
|
const char *str = svar_get(st);
|
||||||
char _dst[100];
|
char _dst[100];
|
||||||
char *dst = _dst;
|
char *dst = _dst;
|
||||||
@@ -160,7 +160,7 @@ static void SetStringNum16(void) {
|
|||||||
|
|
||||||
static void SetStringNum32(void) {
|
static void SetStringNum32(void) {
|
||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int *p2 = getCaliVariable();
|
vmvar_t *p2 = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("ShString.SetStringNum32: %d,%p:", p1, p2);
|
TRACE_UNIMPLEMENTED("ShString.SetStringNum32: %d,%p:", p1, p2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
if (!nact->files.alk[0]) {
|
if (!nact->files.alk[0]) {
|
||||||
WARNING("dDEMO.alk not found");
|
WARNING("dDEMO.alk not found");
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,11 @@
|
|||||||
#include "ags.h"
|
#include "ags.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
static FontType ftype;
|
static FontSpec dt_spec = {
|
||||||
static int fsize; // フォントの大きさ
|
.type = FONT_GOTHIC,
|
||||||
|
.weight = FONT_WEIGHT_BOLD,
|
||||||
|
.size = 12
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 次に描く文字のフォントの種類と大きさを設定
|
* 次に描く文字のフォントの種類と大きさを設定
|
||||||
@@ -48,8 +51,8 @@ void dt_setfont(FontType type, int size) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ftype = type;
|
dt_spec.type = type;
|
||||||
fsize = size;
|
dt_spec.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +69,7 @@ void dt_setfont(FontType type, int size) {
|
|||||||
* @return: 実際に描画した幅
|
* @return: 実際に描画した幅
|
||||||
*/
|
*/
|
||||||
int dt_drawtext_col(SDL_Surface *sf, int x, int y, char *buf, int r, int g, int b) {
|
int dt_drawtext_col(SDL_Surface *sf, int x, int y, char *buf, int r, int g, int b) {
|
||||||
SDL_Surface *glyph = ags_drawStringToSurface(buf, r, g, b, (FontSpec){ .type = ftype, .size = fsize });
|
SDL_Surface *glyph = ags_drawStringToSurface(buf, r, g, b, dt_spec);
|
||||||
if (glyph == NULL) return 0;
|
if (glyph == NULL) return 0;
|
||||||
|
|
||||||
SDL_Rect rect = {x, y, glyph->w, glyph->h};
|
SDL_Rect rect = {x, y, glyph->w, glyph->h};
|
||||||
|
|||||||
+22
-16
@@ -35,6 +35,7 @@
|
|||||||
#include "ags.h"
|
#include "ags.h"
|
||||||
#include "variable.h"
|
#include "variable.h"
|
||||||
#include "sactcg.h"
|
#include "sactcg.h"
|
||||||
|
#include "ald_manager.h"
|
||||||
#include "cg.h"
|
#include "cg.h"
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
|
||||||
@@ -220,7 +221,8 @@ void scg_create_text(int wNumCG, int wSize, int wR, int wG, int wB, int wText) {
|
|||||||
// 勝手に出ていいのかな?
|
// 勝手に出ていいのかな?
|
||||||
if (svar_length(wText) == 0) return;
|
if (svar_length(wText) == 0) return;
|
||||||
|
|
||||||
SDL_Surface *glyph = ags_drawStringToSurface(svar_get(wText), wR, wG, wB, (FontSpec){ .size = wSize });
|
FontSpec spec = { .type = FONT_GOTHIC, .weight = FONT_WEIGHT_BOLD, .size = wSize };
|
||||||
|
SDL_Surface *glyph = ags_drawStringToSurface(svar_get(wText), wR, wG, wB, spec);
|
||||||
|
|
||||||
SDL_Surface *sf = SDL_CreateRGBSurfaceWithFormat(0, glyph->w, wSize, 32, SDL_PIXELFORMAT_ARGB8888);
|
SDL_Surface *sf = SDL_CreateRGBSurfaceWithFormat(0, glyph->w, wSize, 32, SDL_PIXELFORMAT_ARGB8888);
|
||||||
SDL_SetSurfaceBlendMode(glyph, SDL_BLENDMODE_NONE);
|
SDL_SetSurfaceBlendMode(glyph, SDL_BLENDMODE_NONE);
|
||||||
@@ -244,7 +246,8 @@ void scg_create_textnum(int wNumCG, int wSize, int wR, int wG, int wB, int wFigs
|
|||||||
}
|
}
|
||||||
sprintf(s, ss, wValue);
|
sprintf(s, ss, wValue);
|
||||||
|
|
||||||
SDL_Surface *glyph = ags_drawStringToSurface(s, wR, wG, wB, (FontSpec){ .size = wSize });
|
FontSpec spec = { .type = FONT_GOTHIC, .weight = FONT_WEIGHT_BOLD, .size = wSize };
|
||||||
|
SDL_Surface *glyph = ags_drawStringToSurface(s, wR, wG, wB, spec);
|
||||||
|
|
||||||
SDL_Surface *sf = SDL_CreateRGBSurfaceWithFormat(0, glyph->w, wSize, 32, SDL_PIXELFORMAT_ARGB8888);
|
SDL_Surface *sf = SDL_CreateRGBSurfaceWithFormat(0, glyph->w, wSize, 32, SDL_PIXELFORMAT_ARGB8888);
|
||||||
SDL_SetSurfaceBlendMode(glyph, SDL_BLENDMODE_NONE);
|
SDL_SetSurfaceBlendMode(glyph, SDL_BLENDMODE_NONE);
|
||||||
@@ -326,24 +329,27 @@ void scg_free(int no) {
|
|||||||
// CGの種類を取得
|
// CGの種類を取得
|
||||||
int scg_querytype(int wNumCG) {
|
int scg_querytype(int wNumCG) {
|
||||||
if (wNumCG >= (CGMAX -1)) return CG_NOTUSED;
|
if (wNumCG >= (CGMAX -1)) return CG_NOTUSED;
|
||||||
if (!cg_store || !cg_store[wNumCG]) return CG_NOTUSED;
|
if (cg_store && cg_store[wNumCG])
|
||||||
return cg_store[wNumCG]->type;
|
return cg_store[wNumCG]->type;
|
||||||
|
// Linked CGs are valid even before they are loaded into cg_store.
|
||||||
|
return ald_is_linked(DRIFILE_CG, wNumCG - 1) ? CG_LINKED : CG_NOTUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CGの大きさを取得
|
// CGの大きさを取得
|
||||||
bool scg_querysize(int wNumCG, int *w, int *h) {
|
bool scg_querysize(int wNumCG, vmvar_t *w, vmvar_t *h) {
|
||||||
if (wNumCG >= (CGMAX -1)) goto errexit;
|
|
||||||
if (!cg_store || !cg_store[wNumCG]) goto errexit;
|
|
||||||
if (cg_store[wNumCG]->sf == NULL) goto errexit;
|
|
||||||
|
|
||||||
*w = cg_store[wNumCG]->sf->w;
|
|
||||||
*h = cg_store[wNumCG]->sf->h;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
errexit:
|
|
||||||
*w = *h = 0;
|
*w = *h = 0;
|
||||||
return false;
|
|
||||||
|
if (wNumCG >= (CGMAX - 1))
|
||||||
|
return false;
|
||||||
|
cginfo_t *cg = cg_store ? cg_store[wNumCG] : NULL;
|
||||||
|
if (!cg && ald_is_linked(DRIFILE_CG, wNumCG - 1))
|
||||||
|
cg = scg_get(wNumCG);
|
||||||
|
if (!cg || !cg->sf)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*w = cg->sf->w;
|
||||||
|
*h = cg->sf->h;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CGのBPPを取得
|
// CGのBPPを取得
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ void scg_partcopy(int wNumDstCG, int wNumSrcCG, int wX, int wY, int wWidth, int
|
|||||||
void scg_freeall(void);
|
void scg_freeall(void);
|
||||||
void scg_free(int cg);
|
void scg_free(int cg);
|
||||||
int scg_querytype(int wNumCG);
|
int scg_querytype(int wNumCG);
|
||||||
bool scg_querysize(int wNumCG, int *w, int *h);
|
bool scg_querysize(int wNumCG, vmvar_t *w, vmvar_t *h);
|
||||||
int scg_querybpp(int wNumCG);
|
int scg_querybpp(int wNumCG);
|
||||||
bool scg_existalphamap(int wNumCG);
|
bool scg_existalphamap(int wNumCG);
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue(); /* ISys3x */
|
int p1 = getCaliValue(); /* ISys3x */
|
||||||
int p2 = getCaliValue(); /* IWinMsg */
|
int p2 = getCaliValue(); /* IWinMsg */
|
||||||
int p3 = getCaliValue(); /* ITimer */
|
int p3 = getCaliValue(); /* ITimer */
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 0;
|
*var = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
TRACE_UNIMPLEMENTED("nDEMOE.Init %p:", var);
|
TRACE_UNIMPLEMENTED("nDEMOE.Init %p:", var);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -83,9 +83,9 @@ static void MakeMapDraw() {
|
|||||||
int dstY = getCaliValue();
|
int dstY = getCaliValue();
|
||||||
int posX = getCaliValue();
|
int posX = getCaliValue();
|
||||||
int posY = getCaliValue();
|
int posY = getCaliValue();
|
||||||
int *a1 = getCaliVariable();
|
vmvar_t *a1 = getCaliVariable();
|
||||||
int *a2 = getCaliVariable();
|
vmvar_t *a2 = getCaliVariable();
|
||||||
int *a3 = getCaliVariable();
|
vmvar_t *a3 = getCaliVariable();
|
||||||
|
|
||||||
for (int y = 0; y < window_height; y++) {
|
for (int y = 0; y < window_height; y++) {
|
||||||
for (int x = 0; x < window_width; x++) {
|
for (int x = 0; x < window_width; x++) {
|
||||||
@@ -178,9 +178,9 @@ static void TempMapLoadToShadow() {
|
|||||||
WARNING("non-array destination variable");
|
WARNING("non-array destination variable");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int *a1 = v_resolveRef(&r1);
|
vmvar_t *a1 = v_resolveRef(&r1);
|
||||||
int *a2 = v_resolveRef(&r2);
|
vmvar_t *a2 = v_resolveRef(&r2);
|
||||||
int *a3 = v_resolveRef(&r3);
|
vmvar_t *a3 = v_resolveRef(&r3);
|
||||||
uint16_t *p = mapdata[map];
|
uint16_t *p = mapdata[map];
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
*a1++ = SDL_SwapLE16(*p++);
|
*a1++ = SDL_SwapLE16(*p++);
|
||||||
@@ -207,9 +207,9 @@ static void TempMapSaveToShadow() {
|
|||||||
WARNING("non-array source variable");
|
WARNING("non-array source variable");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int *a1 = v_resolveRef(&r1);
|
vmvar_t *a1 = v_resolveRef(&r1);
|
||||||
int *a2 = v_resolveRef(&r2);
|
vmvar_t *a2 = v_resolveRef(&r2);
|
||||||
int *a3 = v_resolveRef(&r3);
|
vmvar_t *a3 = v_resolveRef(&r3);
|
||||||
uint16_t *p = mapdata[map];
|
uint16_t *p = mapdata[map];
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
*p++ = SDL_SwapLE16(*a1++);
|
*p++ = SDL_SwapLE16(*a1++);
|
||||||
@@ -296,13 +296,13 @@ static void TempMapFileLoad() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void CalcMoveDiffer() {
|
static void CalcMoveDiffer() {
|
||||||
int *dx = getCaliVariable();
|
vmvar_t *dx = getCaliVariable();
|
||||||
int *dy = getCaliVariable();
|
vmvar_t *dy = getCaliVariable();
|
||||||
int moveL = getCaliValue();
|
int moveL = getCaliValue();
|
||||||
int moveU = getCaliValue();
|
int moveU = getCaliValue();
|
||||||
int moveR = getCaliValue();
|
int moveR = getCaliValue();
|
||||||
int moveD = getCaliValue();
|
int moveD = getCaliValue();
|
||||||
int *pt = getCaliVariable();
|
vmvar_t *pt = getCaliVariable();
|
||||||
int duration = getCaliValue();
|
int duration = getCaliValue();
|
||||||
|
|
||||||
int t = min(*pt, duration);
|
int t = min(*pt, duration);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ static void Init() {
|
|||||||
int p1 = getCaliValue();
|
int p1 = getCaliValue();
|
||||||
int p2 = getCaliValue();
|
int p2 = getCaliValue();
|
||||||
int p3 = getCaliValue();
|
int p3 = getCaliValue();
|
||||||
int *var = getCaliVariable();
|
vmvar_t *var = getCaliVariable();
|
||||||
|
|
||||||
*var = 1;
|
*var = 1;
|
||||||
|
|
||||||
|
|||||||
+41
-10
@@ -1,11 +1,42 @@
|
|||||||
# This creates a target "translations"
|
# Translation catalogs, built from the po/<lang>.po files listed in
|
||||||
gettext_create_translations(xsystem35.pot ALL ja.po)
|
# NLS_LANGUAGES. On platforms with libintl they are compiled to .mo files and
|
||||||
|
# loaded at runtime; otherwise they are compiled into the executable as a
|
||||||
|
# built-in catalog (see src/nls.c).
|
||||||
|
|
||||||
add_custom_target(pot
|
if (HAVE_LIBINTL)
|
||||||
xgettext --default-domain=${PACKAGE} --directory=${CMAKE_SOURCE_DIR}
|
# Compile the .po files into .mo catalogs for libintl.
|
||||||
--keyword=_ --keyword=N_
|
list(TRANSFORM NLS_LANGUAGES APPEND ".po" OUTPUT_VARIABLE po_files)
|
||||||
--files-from=${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in
|
gettext_create_translations(xsystem35.pot ALL ${po_files})
|
||||||
--copyright-holder='Masaki Chikama'
|
|
||||||
--output=${CMAKE_CURRENT_SOURCE_DIR}/xsystem35.pot
|
# The `pot` target re-extracts strings from POTFILES.in into xsystem35.pot.
|
||||||
)
|
# A normal build does not re-extract, so after adding/changing a _()/N_()
|
||||||
add_dependencies(translations pot)
|
# string build this target and translate the new entries. CI fails if
|
||||||
|
# xsystem35.pot is out of date.
|
||||||
|
add_custom_target(pot
|
||||||
|
xgettext --default-domain=${PACKAGE} --directory=${PROJECT_SOURCE_DIR}
|
||||||
|
--keyword=_ --keyword=N_
|
||||||
|
--files-from=${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in
|
||||||
|
--output=${CMAKE_CURRENT_SOURCE_DIR}/xsystem35.pot
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
# Generate a header with the built-in translation tables (nls_catalog.h),
|
||||||
|
# included by src/nls.c. xsystem35 is made to depend on it and to look in
|
||||||
|
# this build directory for the header.
|
||||||
|
set(po_files "")
|
||||||
|
foreach (lang IN LISTS NLS_LANGUAGES)
|
||||||
|
list(APPEND po_files ${CMAKE_CURRENT_SOURCE_DIR}/${lang}.po)
|
||||||
|
endforeach()
|
||||||
|
set(nls_header ${CMAKE_CURRENT_BINARY_DIR}/nls_catalog.h)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${nls_header}
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-DPO_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
"-DLANGUAGES=${NLS_LANGUAGES}"
|
||||||
|
-DOUTPUT=${nls_header}
|
||||||
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/generate_nls_catalog.cmake
|
||||||
|
DEPENDS ${po_files} ${CMAKE_CURRENT_SOURCE_DIR}/generate_nls_catalog.cmake
|
||||||
|
VERBATIM)
|
||||||
|
add_custom_target(generate_nls_catalog DEPENDS ${nls_header})
|
||||||
|
add_dependencies(xsystem35 generate_nls_catalog)
|
||||||
|
target_include_directories(xsystem35 PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
ja
|
|
||||||
@@ -1,317 +0,0 @@
|
|||||||
# Makefile for PO directory in any package using GNU gettext.
|
|
||||||
# Copyright (C) 1995-1997, 2000-2002 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
|
|
||||||
#
|
|
||||||
# This file can be copied and used freely without restrictions. It can
|
|
||||||
# be used in projects which are not available under the GNU General Public
|
|
||||||
# License but which still want to provide support for the GNU gettext
|
|
||||||
# functionality.
|
|
||||||
# Please note that the actual code of GNU gettext is covered by the GNU
|
|
||||||
# General Public License and is *not* in the public domain.
|
|
||||||
|
|
||||||
PACKAGE = @PACKAGE@
|
|
||||||
VERSION = @VERSION@
|
|
||||||
|
|
||||||
SHELL = /bin/sh
|
|
||||||
@SET_MAKE@
|
|
||||||
|
|
||||||
srcdir = @srcdir@
|
|
||||||
top_srcdir = @top_srcdir@
|
|
||||||
VPATH = @srcdir@
|
|
||||||
|
|
||||||
prefix = @prefix@
|
|
||||||
exec_prefix = @exec_prefix@
|
|
||||||
datadir = @datadir@
|
|
||||||
localedir = $(datadir)/locale
|
|
||||||
gettextsrcdir = $(datadir)/gettext/po
|
|
||||||
|
|
||||||
INSTALL = @INSTALL@
|
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
|
||||||
MKINSTALLDIRS = @MKINSTALLDIRS@
|
|
||||||
mkinstalldirs = $(SHELL) `case "$(MKINSTALLDIRS)" in /*) echo "$(MKINSTALLDIRS)" ;; *) echo "$(top_builddir)/$(MKINSTALLDIRS)" ;; esac`
|
|
||||||
|
|
||||||
GMSGFMT = @GMSGFMT@
|
|
||||||
MSGFMT = @MSGFMT@
|
|
||||||
XGETTEXT = @XGETTEXT@
|
|
||||||
MSGMERGE = msgmerge
|
|
||||||
MSGMERGE_UPDATE = @MSGMERGE@ --update
|
|
||||||
MSGINIT = msginit
|
|
||||||
MSGCONV = msgconv
|
|
||||||
MSGFILTER = msgfilter
|
|
||||||
|
|
||||||
POFILES = @POFILES@
|
|
||||||
GMOFILES = @GMOFILES@
|
|
||||||
UPDATEPOFILES = @UPDATEPOFILES@
|
|
||||||
DUMMYPOFILES = @DUMMYPOFILES@
|
|
||||||
DISTFILES.common = Makefile.in.in Makevars remove-potcdate.sin \
|
|
||||||
$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3)
|
|
||||||
DISTFILES = $(DISTFILES.common) POTFILES.in $(DOMAIN).pot \
|
|
||||||
$(POFILES) $(GMOFILES) \
|
|
||||||
$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3)
|
|
||||||
|
|
||||||
POTFILES = \
|
|
||||||
|
|
||||||
CATALOGS = @CATALOGS@
|
|
||||||
|
|
||||||
# Makevars gets inserted here. (Don't remove this line!)
|
|
||||||
|
|
||||||
.SUFFIXES:
|
|
||||||
.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-update
|
|
||||||
|
|
||||||
.po.mo:
|
|
||||||
@echo "$(MSGFMT) -c -o $@ $<"; \
|
|
||||||
$(MSGFMT) -c -o t-$@ $< && mv t-$@ $@
|
|
||||||
|
|
||||||
.po.gmo:
|
|
||||||
@lang=`echo $* | sed -e 's,.*/,,'`; \
|
|
||||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
|
|
||||||
echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \
|
|
||||||
cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
|
|
||||||
|
|
||||||
.sin.sed:
|
|
||||||
sed -e '/^#/d' $< > t-$@
|
|
||||||
mv t-$@ $@
|
|
||||||
|
|
||||||
|
|
||||||
all: all-@USE_NLS@
|
|
||||||
|
|
||||||
all-yes: $(CATALOGS)
|
|
||||||
all-no:
|
|
||||||
|
|
||||||
# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',
|
|
||||||
# otherwise packages like GCC can not be built if only parts of the source
|
|
||||||
# have been downloaded.
|
|
||||||
|
|
||||||
$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
|
|
||||||
$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
|
|
||||||
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \
|
|
||||||
--files-from=$(srcdir)/POTFILES.in \
|
|
||||||
--copyright-holder='$(COPYRIGHT_HOLDER)'
|
|
||||||
test ! -f $(DOMAIN).po || { \
|
|
||||||
if test -f $(srcdir)/$(DOMAIN).pot; then \
|
|
||||||
sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
|
|
||||||
sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \
|
|
||||||
if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \
|
|
||||||
rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \
|
|
||||||
else \
|
|
||||||
rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \
|
|
||||||
mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
|
|
||||||
fi; \
|
|
||||||
else \
|
|
||||||
mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
|
|
||||||
fi; \
|
|
||||||
}
|
|
||||||
|
|
||||||
$(srcdir)/$(DOMAIN).pot:
|
|
||||||
$(MAKE) $(DOMAIN).pot-update
|
|
||||||
|
|
||||||
$(POFILES): $(srcdir)/$(DOMAIN).pot
|
|
||||||
@lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
|
|
||||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
|
|
||||||
echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \
|
|
||||||
cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot
|
|
||||||
|
|
||||||
|
|
||||||
install: install-exec install-data
|
|
||||||
install-exec:
|
|
||||||
install-data: install-data-@USE_NLS@
|
|
||||||
if test "$(PACKAGE)" = "gettext"; then \
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
|
|
||||||
for file in $(DISTFILES.common); do \
|
|
||||||
$(INSTALL_DATA) $(srcdir)/$$file \
|
|
||||||
$(DESTDIR)$(gettextsrcdir)/$$file; \
|
|
||||||
done; \
|
|
||||||
else \
|
|
||||||
: ; \
|
|
||||||
fi
|
|
||||||
install-data-no: all
|
|
||||||
install-data-yes: all
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$(datadir)
|
|
||||||
@catalogs='$(CATALOGS)'; \
|
|
||||||
for cat in $$catalogs; do \
|
|
||||||
cat=`basename $$cat`; \
|
|
||||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
|
|
||||||
dir=$(localedir)/$$lang/LC_MESSAGES; \
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$$dir; \
|
|
||||||
if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
|
|
||||||
$(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \
|
|
||||||
echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \
|
|
||||||
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
|
|
||||||
if test -n "$$lc"; then \
|
|
||||||
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
|
|
||||||
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
|
|
||||||
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
|
||||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
|
||||||
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
|
|
||||||
for file in *; do \
|
|
||||||
if test -f $$file; then \
|
|
||||||
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
|
|
||||||
fi; \
|
|
||||||
done); \
|
|
||||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
|
||||||
else \
|
|
||||||
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
|
|
||||||
:; \
|
|
||||||
else \
|
|
||||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
|
||||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
|
||||||
fi; \
|
|
||||||
fi; \
|
|
||||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
|
|
||||||
ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
|
|
||||||
ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
|
|
||||||
cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
|
|
||||||
echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \
|
|
||||||
fi; \
|
|
||||||
done; \
|
|
||||||
done
|
|
||||||
|
|
||||||
install-strip: install
|
|
||||||
|
|
||||||
installdirs: installdirs-exec installdirs-data
|
|
||||||
installdirs-exec:
|
|
||||||
installdirs-data: installdirs-data-@USE_NLS@
|
|
||||||
if test "$(PACKAGE)" = "gettext"; then \
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
|
|
||||||
else \
|
|
||||||
: ; \
|
|
||||||
fi
|
|
||||||
installdirs-data-no:
|
|
||||||
installdirs-data-yes:
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$(datadir)
|
|
||||||
@catalogs='$(CATALOGS)'; \
|
|
||||||
for cat in $$catalogs; do \
|
|
||||||
cat=`basename $$cat`; \
|
|
||||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
|
|
||||||
dir=$(localedir)/$$lang/LC_MESSAGES; \
|
|
||||||
$(mkinstalldirs) $(DESTDIR)$$dir; \
|
|
||||||
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
|
|
||||||
if test -n "$$lc"; then \
|
|
||||||
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
|
|
||||||
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
|
|
||||||
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
|
||||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
|
||||||
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
|
|
||||||
for file in *; do \
|
|
||||||
if test -f $$file; then \
|
|
||||||
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
|
|
||||||
fi; \
|
|
||||||
done); \
|
|
||||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
|
||||||
else \
|
|
||||||
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
|
|
||||||
:; \
|
|
||||||
else \
|
|
||||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
|
||||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
|
||||||
fi; \
|
|
||||||
fi; \
|
|
||||||
fi; \
|
|
||||||
done; \
|
|
||||||
done
|
|
||||||
|
|
||||||
# Define this as empty until I found a useful application.
|
|
||||||
installcheck:
|
|
||||||
|
|
||||||
uninstall: uninstall-exec uninstall-data
|
|
||||||
uninstall-exec:
|
|
||||||
uninstall-data: uninstall-data-@USE_NLS@
|
|
||||||
if test "$(PACKAGE)" = "gettext"; then \
|
|
||||||
for file in $(DISTFILES.common); do \
|
|
||||||
rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
|
|
||||||
done; \
|
|
||||||
else \
|
|
||||||
: ; \
|
|
||||||
fi
|
|
||||||
uninstall-data-no:
|
|
||||||
uninstall-data-yes:
|
|
||||||
catalogs='$(CATALOGS)'; \
|
|
||||||
for cat in $$catalogs; do \
|
|
||||||
cat=`basename $$cat`; \
|
|
||||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
|
|
||||||
for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \
|
|
||||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
|
|
||||||
done; \
|
|
||||||
done
|
|
||||||
|
|
||||||
check: all
|
|
||||||
|
|
||||||
dvi info tags TAGS ID:
|
|
||||||
|
|
||||||
mostlyclean:
|
|
||||||
rm -f remove-potcdate.sed
|
|
||||||
rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po
|
|
||||||
rm -fr *.o
|
|
||||||
|
|
||||||
clean: mostlyclean
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
rm -f Makefile Makefile.in POTFILES *.mo
|
|
||||||
|
|
||||||
maintainer-clean: distclean
|
|
||||||
@echo "This command is intended for maintainers to use;"
|
|
||||||
@echo "it deletes files that may require special tools to rebuild."
|
|
||||||
rm -f $(GMOFILES)
|
|
||||||
|
|
||||||
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
|
|
||||||
dist distdir:
|
|
||||||
$(MAKE) update-po
|
|
||||||
@$(MAKE) dist2
|
|
||||||
# This is a separate target because 'update-po' must be executed before.
|
|
||||||
dist2: $(DISTFILES)
|
|
||||||
dists="$(DISTFILES)"; \
|
|
||||||
if test -f $(srcdir)/ChangeLog; then dists="$$dists ChangeLog"; fi; \
|
|
||||||
if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \
|
|
||||||
for file in $$dists; do \
|
|
||||||
if test -f $$file; then \
|
|
||||||
cp -p $$file $(distdir); \
|
|
||||||
else \
|
|
||||||
cp -p $(srcdir)/$$file $(distdir); \
|
|
||||||
fi; \
|
|
||||||
done
|
|
||||||
|
|
||||||
update-po: Makefile
|
|
||||||
$(MAKE) $(DOMAIN).pot-update
|
|
||||||
$(MAKE) $(UPDATEPOFILES)
|
|
||||||
$(MAKE) update-gmo
|
|
||||||
|
|
||||||
# General rule for updating PO files.
|
|
||||||
|
|
||||||
.nop.po-update:
|
|
||||||
@lang=`echo $@ | sed -e 's/\.po-update$$//'`; \
|
|
||||||
if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; fi; \
|
|
||||||
tmpdir=`pwd`; \
|
|
||||||
echo "$$lang:"; \
|
|
||||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
|
|
||||||
echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
|
|
||||||
cd $(srcdir); \
|
|
||||||
if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \
|
|
||||||
if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
|
|
||||||
rm -f $$tmpdir/$$lang.new.po; \
|
|
||||||
else \
|
|
||||||
if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
|
|
||||||
:; \
|
|
||||||
else \
|
|
||||||
echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
|
|
||||||
exit 1; \
|
|
||||||
fi; \
|
|
||||||
fi; \
|
|
||||||
else \
|
|
||||||
echo "msgmerge for $$lang.po failed!" 1>&2; \
|
|
||||||
rm -f $$tmpdir/$$lang.new.po; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
$(DUMMYPOFILES):
|
|
||||||
|
|
||||||
update-gmo: Makefile $(GMOFILES)
|
|
||||||
@:
|
|
||||||
|
|
||||||
Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in
|
|
||||||
cd $(top_builddir) \
|
|
||||||
&& CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
|
|
||||||
$(SHELL) ./config.status
|
|
||||||
|
|
||||||
force:
|
|
||||||
|
|
||||||
# Tell versions [3.59,3.63) of GNU make not to export all variables.
|
|
||||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
|
||||||
.NOEXPORT:
|
|
||||||
-41
@@ -1,41 +0,0 @@
|
|||||||
# Makefile variables for PO directory in any package using GNU gettext.
|
|
||||||
|
|
||||||
# Usually the message domain is the same as the package name.
|
|
||||||
DOMAIN = $(PACKAGE)
|
|
||||||
|
|
||||||
# These two variables depend on the location of this directory.
|
|
||||||
subdir = po
|
|
||||||
top_builddir = ..
|
|
||||||
|
|
||||||
# These options get passed to xgettext.
|
|
||||||
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
|
|
||||||
|
|
||||||
# This is the copyright holder that gets inserted into the header of the
|
|
||||||
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
|
|
||||||
# package. (Note that the msgstr strings, extracted from the package's
|
|
||||||
# sources, belong to the copyright holder of the package.) Translators are
|
|
||||||
# expected to transfer the copyright for their translations to this person
|
|
||||||
# or entity, or to disclaim their copyright. The empty string stands for
|
|
||||||
# the public domain; in this case the translators are expected to disclaim
|
|
||||||
# their copyright.
|
|
||||||
COPYRIGHT_HOLDER = Masaki Chikama
|
|
||||||
|
|
||||||
# This is the email address or URL to which the translators shall report
|
|
||||||
# bugs in the untranslated strings:
|
|
||||||
# - Strings which are not entire sentences, see the maintainer guidelines
|
|
||||||
# in the GNU gettext documentation, section 'Preparing Strings'.
|
|
||||||
# - Strings which use unclear terms or require additional context to be
|
|
||||||
# understood.
|
|
||||||
# - Strings which make invalid assumptions about notation of date, time or
|
|
||||||
# money.
|
|
||||||
# - Pluralisation problems.
|
|
||||||
# - Incorrect English spelling.
|
|
||||||
# - Incorrect formatting.
|
|
||||||
# It can be your email address, or a mailing list address where translators
|
|
||||||
# can write to without being subscribed, or the URL of a web page through
|
|
||||||
# which the translators can contact you.
|
|
||||||
MSGID_BUGS_ADDRESS = chikama@nabal.aist-nara.ac.jp
|
|
||||||
|
|
||||||
# This is the list of locale categories, beyond LC_MESSAGES, for which the
|
|
||||||
# message catalogs shall be used. It is usually empty.
|
|
||||||
EXTRA_LOCALE_CATEGORIES =
|
|
||||||
+2
-4
@@ -1,5 +1,3 @@
|
|||||||
./src/menu.c
|
./src/menu.c
|
||||||
./src/menu_gui.c
|
./src/input_modal.c
|
||||||
./src/menu_gui_volval.c
|
./src/volume.c
|
||||||
./src/s39init.c
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Generate a C header with the built-in translation catalogs, for the NLS used
|
||||||
|
# on platforms without libintl. It defines one table per language plus a
|
||||||
|
# registry (nls_catalogs) mapping language codes to tables, all as file-local
|
||||||
|
# statics, and is included by src/nls.c.
|
||||||
|
#
|
||||||
|
# .po and C share the same string-escape conventions (\n, \", \\, ...), so the
|
||||||
|
# quoted bodies are copied through verbatim and multi-line entries become
|
||||||
|
# adjacent C string literals, which the compiler concatenates.
|
||||||
|
#
|
||||||
|
# Expected variables: PO_DIR, LANGUAGES (list), OUTPUT
|
||||||
|
|
||||||
|
set(tables "")
|
||||||
|
set(registry "")
|
||||||
|
|
||||||
|
foreach(lang IN LISTS LANGUAGES)
|
||||||
|
file(STRINGS "${PO_DIR}/${lang}.po" lines ENCODING UTF-8)
|
||||||
|
|
||||||
|
set(entries "")
|
||||||
|
set(cur_id "")
|
||||||
|
set(cur_str "")
|
||||||
|
set(state none)
|
||||||
|
|
||||||
|
# Appends the current msgid/msgstr pair to `entries`, skipping the header
|
||||||
|
# entry (empty msgid).
|
||||||
|
macro(flush_entry)
|
||||||
|
if(NOT cur_id STREQUAL "" AND NOT cur_id STREQUAL "\"\"")
|
||||||
|
string(APPEND entries "\t{ ${cur_id}, ${cur_str} },\n")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
foreach(line IN LISTS lines)
|
||||||
|
if(line MATCHES "^msgid \"(.*)\"$")
|
||||||
|
flush_entry()
|
||||||
|
set(cur_id "\"${CMAKE_MATCH_1}\"")
|
||||||
|
set(cur_str "")
|
||||||
|
set(state id)
|
||||||
|
elseif(line MATCHES "^msgstr \"(.*)\"$")
|
||||||
|
set(cur_str "\"${CMAKE_MATCH_1}\"")
|
||||||
|
set(state str)
|
||||||
|
elseif(line MATCHES "^\"(.*)\"$")
|
||||||
|
if(state STREQUAL id)
|
||||||
|
set(cur_id "${cur_id} \"${CMAKE_MATCH_1}\"")
|
||||||
|
elseif(state STREQUAL str)
|
||||||
|
set(cur_str "${cur_str} \"${CMAKE_MATCH_1}\"")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(state none)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
flush_entry()
|
||||||
|
|
||||||
|
string(APPEND tables
|
||||||
|
"static const struct nls_entry nls_table_${lang}[] = {\n"
|
||||||
|
"${entries}"
|
||||||
|
"\t{ 0, 0 }, // terminator\n"
|
||||||
|
"};\n\n")
|
||||||
|
string(APPEND registry "\t{ \"${lang}\", nls_table_${lang} },\n")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
file(WRITE "${OUTPUT}"
|
||||||
|
"// Generated from the .po files. Do not edit.\n"
|
||||||
|
"#include \"nls.h\"\n"
|
||||||
|
"\n"
|
||||||
|
"${tables}"
|
||||||
|
"static const struct nls_catalog nls_catalogs[] = {\n"
|
||||||
|
"${registry}"
|
||||||
|
"\t{ 0, 0 }, // terminator\n"
|
||||||
|
"};\n")
|
||||||
@@ -8,8 +8,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: xsystem35 1.7.3pre3\n"
|
"Project-Id-Version: xsystem35 1.7.3pre3\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-07-14 18:38+0900\n"
|
"POT-Creation-Date: 2026-07-19 12:40+0900\n"
|
||||||
"PO-Revision-Date: 2004-08-24 14:40+0900\n"
|
"PO-Revision-Date: 2026-06-14 17:09+0900\n"
|
||||||
"Last-Translator: CHIKAMA Masaki <chika@8ne.sakura.ne.jp>\n"
|
"Last-Translator: CHIKAMA Masaki <chika@8ne.sakura.ne.jp>\n"
|
||||||
"Language-Team: Japanese <chika@8ne.sakura.ne.jp>\n"
|
"Language-Team: Japanese <chika@8ne.sakura.ne.jp>\n"
|
||||||
"Language: ja\n"
|
"Language: ja\n"
|
||||||
@@ -17,143 +17,74 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: src/menu_gui.c:127 src/menu_gui.c:137 src/menu_gui.c:147
|
#: src/menu.c:136 src/menu.c:139
|
||||||
msgid "0"
|
msgid "Message Skip"
|
||||||
msgstr ""
|
msgstr "文字送り"
|
||||||
|
|
||||||
#: src/menu_gui.c:374 src/menu_gui.c:658
|
#: src/menu.c:144
|
||||||
msgid "About"
|
msgid "Mouse Movement"
|
||||||
msgstr "情報"
|
msgstr "マウスカーソル移動"
|
||||||
|
|
||||||
#: src/menu_gui.c:593
|
#: src/menu.c:148 src/volume.c:198
|
||||||
msgid "CDROM-audio"
|
msgid "Sound Settings"
|
||||||
msgstr "CDROMオーディオ"
|
msgstr "サウンド設定"
|
||||||
|
|
||||||
#: src/menu_gui.c:171 src/menu_gui.c:266
|
#: src/menu.c:153 src/menu.c:221
|
||||||
|
msgid "Restart"
|
||||||
|
msgstr "再起動"
|
||||||
|
|
||||||
|
#: src/menu.c:158 src/menu.c:216
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "終了"
|
||||||
|
|
||||||
|
#: src/menu.c:197 src/input_modal.c:292 src/input_modal.c:485
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "キャンセル"
|
msgstr "キャンセル"
|
||||||
|
|
||||||
#: src/menu_gui.c:306 src/menu_gui.c:673
|
#: src/menu.c:203
|
||||||
msgid "Exit"
|
msgid "Any unsaved progress will be lost."
|
||||||
msgstr "終了"
|
msgstr "保存していない進行状況は失われます。"
|
||||||
|
|
||||||
#: src/menu_gui.c:317
|
#: src/menu.c:216
|
||||||
msgid "Exit System35 ?"
|
msgid "Quit game?"
|
||||||
msgstr "System35を終了しますか?"
|
msgstr "ゲームを終了しますか?"
|
||||||
|
|
||||||
#: src/menu_gui.c:400
|
#: src/menu.c:221
|
||||||
msgid "Information1"
|
msgid "Restart game?"
|
||||||
msgstr "情報1"
|
msgstr "ゲームを再起動しますか?"
|
||||||
|
|
||||||
#: src/menu_gui.c:410
|
#: src/input_modal.c:268
|
||||||
msgid "Information2"
|
msgid "Enter a string"
|
||||||
msgstr "情報2"
|
msgstr "文字を入力してください"
|
||||||
|
|
||||||
#: src/menu_gui.c:420
|
#: src/input_modal.c:280
|
||||||
msgid "Information3"
|
|
||||||
msgstr "情報3"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:60
|
|
||||||
msgid "InputNumber"
|
|
||||||
msgstr "数値入力"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:214
|
|
||||||
msgid "InputString"
|
|
||||||
msgstr "文字列入力"
|
|
||||||
|
|
||||||
#: src/menu.c:69
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "MAX %d charater"
|
msgid "Up to %d characters"
|
||||||
msgstr "最大 %d 文字"
|
msgstr "最大 %d 文字"
|
||||||
|
|
||||||
#: src/menu_gui.c:241
|
#: src/input_modal.c:288 src/input_modal.c:478 src/input_modal.c:483
|
||||||
msgid "MAX charater"
|
|
||||||
msgstr "最大文字数"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:621
|
|
||||||
msgid "MIDI-audio"
|
|
||||||
msgstr "MIDIオーディオ"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:764
|
|
||||||
#, fuzzy
|
|
||||||
msgid "MessageBox"
|
|
||||||
msgstr "メッセージスキップ"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:485
|
|
||||||
msgid "MessageSkip"
|
|
||||||
msgstr "メッセージスキップ"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:774
|
|
||||||
#, fuzzy
|
|
||||||
msgid "Messge"
|
|
||||||
msgstr "メッセージスキップ"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:521
|
|
||||||
msgid "MouseAutoMove"
|
|
||||||
msgstr "マウスカーソル移動"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:338
|
|
||||||
msgid "No"
|
|
||||||
msgstr "いいえ"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:250
|
|
||||||
msgid "Notice) HANKAKU is not available"
|
|
||||||
msgstr "註)全角文字のみ有効"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:505 src/menu_gui.c:541 src/menu_gui.c:585 src/menu_gui.c:613
|
|
||||||
#: src/menu_gui.c:641
|
|
||||||
msgid "OFF"
|
|
||||||
msgstr "無効"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:164 src/menu_gui.c:273 src/menu_gui.c:426 src/menu_gui.c:781
|
|
||||||
msgid "OK"
|
msgid "OK"
|
||||||
msgstr "OK"
|
msgstr "OK"
|
||||||
|
|
||||||
#: src/menu_gui.c:497 src/menu_gui.c:533 src/menu_gui.c:577 src/menu_gui.c:605
|
#: src/input_modal.c:434
|
||||||
#: src/menu_gui.c:633
|
msgid "Enter a number"
|
||||||
msgid "ON"
|
msgstr "数値を入力してください"
|
||||||
msgstr "有効"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:565
|
#: src/volume.c:106
|
||||||
msgid "PCM-audio"
|
msgid "BGM"
|
||||||
msgstr "PCMオーディオ"
|
msgstr "BGM"
|
||||||
|
|
||||||
#: src/menu_gui.c:557 src/menu_gui_volval.c:43
|
#: src/volume.c:107
|
||||||
msgid "VolumeValance"
|
msgid "Sound effects"
|
||||||
msgstr "ボリュームバランス"
|
msgstr "効果音"
|
||||||
|
|
||||||
#: src/menu_gui.c:331
|
#: src/volume.c:189
|
||||||
msgid "Yes"
|
|
||||||
msgstr "はい"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:97 src/menu_gui.c:745
|
|
||||||
msgid "default"
|
|
||||||
msgstr "既定値"
|
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:122
|
|
||||||
msgid "large"
|
|
||||||
msgstr "大"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:117
|
|
||||||
msgid "max"
|
|
||||||
msgstr "最大値"
|
|
||||||
|
|
||||||
#: src/menu_gui.c:107
|
|
||||||
msgid "min"
|
|
||||||
msgstr "最小値"
|
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:89
|
|
||||||
msgid "mute"
|
msgid "mute"
|
||||||
msgstr "ミュート"
|
msgstr "ミュート"
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:114
|
#: src/volume.c:223
|
||||||
msgid "small"
|
msgid "Close"
|
||||||
msgstr "小"
|
msgstr "閉じる"
|
||||||
|
|
||||||
#: src/menu_gui.c:225
|
#~ msgid "Volume"
|
||||||
msgid "title"
|
#~ msgstr "ボリューム"
|
||||||
msgstr "タイトル"
|
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:41
|
|
||||||
msgid "window1"
|
|
||||||
msgstr ""
|
|
||||||
|
|||||||
+35
-105
@@ -1,5 +1,5 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
# SOME DESCRIPTIVE TITLE.
|
||||||
# Copyright (C) YEAR Masaki Chikama
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-07-14 18:38+0900\n"
|
"POT-Creation-Date: 2026-07-19 12:40+0900\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -17,141 +17,71 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
"Content-Type: text/plain; charset=CHARSET\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: src/menu.c:69
|
#: src/menu.c:136 src/menu.c:139
|
||||||
#, c-format
|
msgid "Message Skip"
|
||||||
msgid "MAX %d charater"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:60
|
#: src/menu.c:144
|
||||||
msgid "InputNumber"
|
msgid "Mouse Movement"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:97 src/menu_gui.c:745
|
#: src/menu.c:148 src/volume.c:198
|
||||||
msgid "default"
|
msgid "Sound Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:107
|
#: src/menu.c:153 src/menu.c:221
|
||||||
msgid "min"
|
msgid "Restart"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:117
|
#: src/menu.c:158 src/menu.c:216
|
||||||
msgid "max"
|
msgid "Quit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:127 src/menu_gui.c:137 src/menu_gui.c:147
|
#: src/menu.c:197 src/input_modal.c:292 src/input_modal.c:485
|
||||||
msgid "0"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:164 src/menu_gui.c:273 src/menu_gui.c:426 src/menu_gui.c:781
|
|
||||||
msgid "OK"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:171 src/menu_gui.c:266
|
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:214
|
#: src/menu.c:203
|
||||||
msgid "InputString"
|
msgid "Any unsaved progress will be lost."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:225
|
#: src/menu.c:216
|
||||||
msgid "title"
|
msgid "Quit game?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:241
|
#: src/menu.c:221
|
||||||
msgid "MAX charater"
|
msgid "Restart game?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:250
|
#: src/input_modal.c:268
|
||||||
msgid "Notice) HANKAKU is not available"
|
msgid "Enter a string"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:306 src/menu_gui.c:673
|
#: src/input_modal.c:280
|
||||||
msgid "Exit"
|
#, c-format
|
||||||
|
msgid "Up to %d characters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:317
|
#: src/input_modal.c:288 src/input_modal.c:478 src/input_modal.c:483
|
||||||
msgid "Exit System35 ?"
|
msgid "OK"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:331
|
#: src/input_modal.c:434
|
||||||
msgid "Yes"
|
msgid "Enter a number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:338
|
#: src/volume.c:106
|
||||||
msgid "No"
|
msgid "BGM"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:374 src/menu_gui.c:658
|
#: src/volume.c:107
|
||||||
msgid "About"
|
msgid "Sound effects"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui.c:400
|
#: src/volume.c:189
|
||||||
msgid "Information1"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:410
|
|
||||||
msgid "Information2"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:420
|
|
||||||
msgid "Information3"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:485
|
|
||||||
msgid "MessageSkip"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:497 src/menu_gui.c:533 src/menu_gui.c:577 src/menu_gui.c:605
|
|
||||||
#: src/menu_gui.c:633
|
|
||||||
msgid "ON"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:505 src/menu_gui.c:541 src/menu_gui.c:585 src/menu_gui.c:613
|
|
||||||
#: src/menu_gui.c:641
|
|
||||||
msgid "OFF"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:521
|
|
||||||
msgid "MouseAutoMove"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:557 src/menu_gui_volval.c:43
|
|
||||||
msgid "VolumeValance"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:565
|
|
||||||
msgid "PCM-audio"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:593
|
|
||||||
msgid "CDROM-audio"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:621
|
|
||||||
msgid "MIDI-audio"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:764
|
|
||||||
msgid "MessageBox"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui.c:774
|
|
||||||
msgid "Messge"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:41
|
|
||||||
msgid "window1"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:89
|
|
||||||
msgid "mute"
|
msgid "mute"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:114
|
#: src/volume.c:223
|
||||||
msgid "small"
|
msgid "Close"
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/menu_gui_volval.c:122
|
|
||||||
msgid "large"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
+58
-43
@@ -1,8 +1,27 @@
|
|||||||
|
# src_lib contains sources that can be unit-tested without linking the
|
||||||
|
# rest of xsystem35. They may reference sys_* and other small hooks;
|
||||||
|
# tests provide stub definitions for those.
|
||||||
add_library(src_lib STATIC
|
add_library(src_lib STATIC
|
||||||
|
ald_manager.c
|
||||||
|
alpha_plane.c
|
||||||
|
audio_meta.c
|
||||||
|
bmp.c
|
||||||
|
cache.c
|
||||||
|
cali.c
|
||||||
|
dri.c
|
||||||
|
filecheck.c
|
||||||
|
font.c
|
||||||
gameresource.c
|
gameresource.c
|
||||||
hankaku.c
|
hankaku.c
|
||||||
|
mmap.c
|
||||||
msgqueue.c
|
msgqueue.c
|
||||||
|
pms.c
|
||||||
|
profile.c
|
||||||
|
qnt.c
|
||||||
|
scenario.c
|
||||||
utfsjis.c
|
utfsjis.c
|
||||||
|
variable.c
|
||||||
|
vsp.c
|
||||||
)
|
)
|
||||||
target_compile_options(src_lib PRIVATE -Wno-pointer-sign -Wall)
|
target_compile_options(src_lib PRIVATE -Wno-pointer-sign -Wall)
|
||||||
target_include_directories(src_lib PRIVATE .)
|
target_include_directories(src_lib PRIVATE .)
|
||||||
@@ -22,12 +41,6 @@ target_link_libraries(xsystem35 PRIVATE src_lib)
|
|||||||
|
|
||||||
target_sources(xsystem35 PRIVATE
|
target_sources(xsystem35 PRIVATE
|
||||||
ags.c
|
ags.c
|
||||||
ald_manager.c
|
|
||||||
alpha_plane.c
|
|
||||||
bgi.c
|
|
||||||
bmp.c
|
|
||||||
cache.c
|
|
||||||
cali.c
|
|
||||||
cdrom.bgm.c
|
cdrom.bgm.c
|
||||||
cg.c
|
cg.c
|
||||||
cmd2F.c
|
cmd2F.c
|
||||||
@@ -57,22 +70,22 @@ target_sources(xsystem35 PRIVATE
|
|||||||
cmdy.c
|
cmdy.c
|
||||||
cmdz.c
|
cmdz.c
|
||||||
cursor.c
|
cursor.c
|
||||||
dri.c
|
|
||||||
ecopy.c
|
ecopy.c
|
||||||
effect.c
|
effect.c
|
||||||
event.c
|
event.c
|
||||||
filecheck.c
|
|
||||||
font.c
|
|
||||||
hacks.c
|
hacks.c
|
||||||
gfx_draw.c
|
gfx_draw.c
|
||||||
gfx_image.c
|
gfx_image.c
|
||||||
gfx_video.c
|
gfx_video.c
|
||||||
image.c
|
image.c
|
||||||
input.c
|
input.c
|
||||||
|
input_modal.c
|
||||||
jpeg.c
|
jpeg.c
|
||||||
|
menu.c
|
||||||
message.c
|
message.c
|
||||||
|
microui/microui.c
|
||||||
midi.c
|
midi.c
|
||||||
mmap.c
|
modal.c
|
||||||
msgskip.c
|
msgskip.c
|
||||||
mt19937-1.c
|
mt19937-1.c
|
||||||
music.c
|
music.c
|
||||||
@@ -80,19 +93,13 @@ target_sources(xsystem35 PRIVATE
|
|||||||
music_midi.c
|
music_midi.c
|
||||||
nact.c
|
nact.c
|
||||||
network.c
|
network.c
|
||||||
pms.c
|
|
||||||
profile.c
|
|
||||||
qnt.c
|
|
||||||
s39ain.c
|
s39ain.c
|
||||||
savedata.c
|
savedata.c
|
||||||
scenario.c
|
|
||||||
scheduler.c
|
scheduler.c
|
||||||
selection.c
|
selection.c
|
||||||
system.c
|
system.c
|
||||||
texthook.c
|
texthook.c
|
||||||
variable.c
|
volume.c
|
||||||
virtual_pointer.c
|
|
||||||
vsp.c
|
|
||||||
xsystem35.c
|
xsystem35.c
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,16 +126,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (EMSCRIPTEN)
|
|
||||||
target_sources(xsystem35 PRIVATE menu_emscripten.c)
|
|
||||||
elseif (ANDROID)
|
|
||||||
target_sources(xsystem35 PRIVATE menu_android.c)
|
|
||||||
elseif (ENABLE_GTK)
|
|
||||||
target_sources(xsystem35 PRIVATE menu.c menu_callback.c menu_gui.c s39init.c)
|
|
||||||
else ()
|
|
||||||
target_sources(xsystem35 PRIVATE menu_sdl.c editor.c)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (HAVE_WEBP)
|
if (HAVE_WEBP)
|
||||||
target_sources(xsystem35 PRIVATE webp.c)
|
target_sources(xsystem35 PRIVATE webp.c)
|
||||||
target_link_libraries(xsystem35 PRIVATE WebP)
|
target_link_libraries(xsystem35 PRIVATE WebP)
|
||||||
@@ -140,12 +137,17 @@ if (ENABLE_DEBUGGER)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
target_sources(src_lib PRIVATE win/resources.c)
|
||||||
target_sources(xsystem35 PRIVATE
|
target_sources(xsystem35 PRIVATE
|
||||||
win/dialog.c win/resources.rc win/resources.c win/menubar.c win/console.c)
|
win/dialog.c win/resources.rc win/menubar.c win/console.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(src_lib PRIVATE sdl2 zlib)
|
if (NOT HAVE_LIBINTL)
|
||||||
target_link_libraries(xsystem35 PRIVATE m zlib sdl2 sdl2_ttf)
|
target_sources(xsystem35 PRIVATE nls.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(src_lib PRIVATE sdl2 freetype2 zlib)
|
||||||
|
target_link_libraries(xsystem35 PRIVATE m zlib sdl2)
|
||||||
if (TARGET sdl2_mixer)
|
if (TARGET sdl2_mixer)
|
||||||
target_link_libraries(xsystem35 PRIVATE sdl2_mixer)
|
target_link_libraries(xsystem35 PRIVATE sdl2_mixer)
|
||||||
endif()
|
endif()
|
||||||
@@ -156,18 +158,28 @@ if (EMSCRIPTEN)
|
|||||||
# Without optimizations, Asyncify generates very large code.
|
# Without optimizations, Asyncify generates very large code.
|
||||||
list(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG "-O1")
|
list(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG "-O1")
|
||||||
|
|
||||||
|
if (JSPI)
|
||||||
|
target_link_options(xsystem35 PRIVATE
|
||||||
|
-sJSPI
|
||||||
|
-sJSPI_IMPORTS=wait_vsync
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_link_options(xsystem35 PRIVATE
|
||||||
|
-sASYNCIFY=1
|
||||||
|
-sASYNCIFY_IGNORE_INDIRECT=1
|
||||||
|
-sASYNCIFY_REMOVE=SDL_Delay
|
||||||
|
-sASYNCIFY_IMPORTS=wait_vsync
|
||||||
|
# Functions that call an asynchronous function via a function pointer must
|
||||||
|
# be added to ASYNCIFY_ADD, even if it had a direct call to another
|
||||||
|
# asynchronous function, so that the indirect call itself is instrumented.
|
||||||
|
-sASYNCIFY_ADD=commands2F60,nact_main,send_agsevent,cb_waitkey_sprite,modal_run
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_options(xsystem35 PRIVATE
|
target_link_options(xsystem35 PRIVATE
|
||||||
-sENVIRONMENT=web
|
-sENVIRONMENT=web
|
||||||
-sMODULARIZE=1
|
-sMODULARIZE=1
|
||||||
-sEXPORT_ES6=1
|
-sEXPORT_ES6=1
|
||||||
-sASYNCIFY=1
|
|
||||||
-sASYNCIFY_IGNORE_INDIRECT=1
|
|
||||||
-sASYNCIFY_REMOVE=SDL_Delay
|
|
||||||
-sASYNCIFY_IMPORTS=wait_vsync
|
|
||||||
# Functions that call an asynchronous function via a function pointer must
|
|
||||||
# be added to ASYNCIFY_ADD, even if it had a direct call to another
|
|
||||||
# asynchronous function, so that the indirect call itself is instrumented.
|
|
||||||
-sASYNCIFY_ADD=commands2F60,nact_main,send_agsevent,cb_waitkey_sprite
|
|
||||||
-sALLOW_MEMORY_GROWTH=1
|
-sALLOW_MEMORY_GROWTH=1
|
||||||
-sNO_EXIT_RUNTIME=1
|
-sNO_EXIT_RUNTIME=1
|
||||||
-sEXPORTED_FUNCTIONS=_main,_malloc
|
-sEXPORTED_FUNCTIONS=_main,_malloc
|
||||||
@@ -182,9 +194,6 @@ else() # non-emscripten, non-android
|
|||||||
if (TARGET cJSON)
|
if (TARGET cJSON)
|
||||||
target_link_libraries(xsystem35 PRIVATE cJSON)
|
target_link_libraries(xsystem35 PRIVATE cJSON)
|
||||||
endif()
|
endif()
|
||||||
if (GTK3_FOUND)
|
|
||||||
target_link_libraries(xsystem35 PRIVATE PkgConfig::GTK3)
|
|
||||||
endif()
|
|
||||||
if (ENABLE_MIDI_PORTMIDI)
|
if (ENABLE_MIDI_PORTMIDI)
|
||||||
target_link_libraries(xsystem35 PRIVATE ${PORTMIDI})
|
target_link_libraries(xsystem35 PRIVATE ${PORTMIDI})
|
||||||
endif()
|
endif()
|
||||||
@@ -193,11 +202,17 @@ else() # non-emscripten, non-android
|
|||||||
|
|
||||||
add_executable(src_tests
|
add_executable(src_tests
|
||||||
src_tests.c
|
src_tests.c
|
||||||
|
cache_test.c
|
||||||
|
font_test.c
|
||||||
gameresource_test.c
|
gameresource_test.c
|
||||||
hankaku_test.c
|
hankaku_test.c
|
||||||
|
qnt_test.c
|
||||||
|
variable_test.c
|
||||||
)
|
)
|
||||||
target_compile_options(src_tests PRIVATE -Wno-pointer-sign -Wall)
|
target_compile_options(src_tests PRIVATE -Wno-pointer-sign -Wall)
|
||||||
target_link_libraries(src_tests PRIVATE src_lib)
|
target_compile_definitions(src_tests PRIVATE
|
||||||
|
TEST_FONT_DIR="${PROJECT_SOURCE_DIR}/fonts")
|
||||||
|
target_link_libraries(src_tests PRIVATE src_lib sdl2)
|
||||||
add_test(NAME src_tests COMMAND src_tests)
|
add_test(NAME src_tests COMMAND src_tests)
|
||||||
configure_file(testdata/test.gr ${CMAKE_CURRENT_BINARY_DIR}/testdata/test.gr COPYONLY)
|
file(COPY testdata DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ bool ags_check_param_xy(int *x, int *y) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ags_init(const char *render_driver, bool enable_zb) {
|
void ags_init(const char *render_driver) {
|
||||||
nact->ags.mouse_warp_enabled = true;
|
nact->ags.mouse_warp_enabled = true;
|
||||||
nact->ags.world_width = SYS35_DEFAULT_WIDTH;
|
nact->ags.world_width = SYS35_DEFAULT_WIDTH;
|
||||||
nact->ags.world_height = SYS35_DEFAULT_HEIGHT;
|
nact->ags.world_height = SYS35_DEFAULT_HEIGHT;
|
||||||
@@ -138,8 +138,7 @@ void ags_init(const char *render_driver, bool enable_zb) {
|
|||||||
nact->ags.font_type = FONT_GOTHIC;
|
nact->ags.font_type = FONT_GOTHIC;
|
||||||
nact->ags.text_decoration_type = 0;
|
nact->ags.text_decoration_type = 0;
|
||||||
nact->ags.text_decoration_color = 0;
|
nact->ags.text_decoration_color = 0;
|
||||||
nact->ags.enable_zb = enable_zb;
|
nact->ags.font_weight = FONT_WEIGHT_BOLD;
|
||||||
nact->ags.font_weight = enable_zb ? FONT_WEIGHT_BOLD : FONT_WEIGHT_NORMAL;
|
|
||||||
|
|
||||||
gfx_Initialize(render_driver);
|
gfx_Initialize(render_driver);
|
||||||
event_init();
|
event_init();
|
||||||
@@ -193,7 +192,7 @@ void ags_setViewArea(int x, int y, int width, int height) {
|
|||||||
nact->ags.view_area.y = y;
|
nact->ags.view_area.y = y;
|
||||||
nact->ags.view_area.w = width;
|
nact->ags.view_area.w = width;
|
||||||
nact->ags.view_area.h = height;
|
nact->ags.view_area.h = height;
|
||||||
gfx_setWindowSize(width, height);
|
gfx_setViewSize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ags_setWindowTitle(const char *title_utf8) {
|
void ags_setWindowTitle(const char *title_utf8) {
|
||||||
@@ -202,20 +201,33 @@ void ags_setWindowTitle(const char *title_utf8) {
|
|||||||
gfx_setWindowTitle(buf);
|
gfx_setWindowTitle(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ags_getDIBInfo(DispInfo *info) {
|
void ags_getDisplayInfo(enum ags_display display, int *width, int *height, int *depth) {
|
||||||
info->width = nact->ags.world_width;
|
SDL_DisplayMode dm;
|
||||||
info->height = nact->ags.world_height;
|
switch (display) {
|
||||||
info->depth = nact->ags.world_depth;
|
case AGS_DISPLAY_CURRENT:
|
||||||
}
|
SDL_GetCurrentDisplayMode(0, &dm);
|
||||||
|
*width = dm.w;
|
||||||
void ags_getViewAreaInfo(DispInfo *info) {
|
*height = dm.h;
|
||||||
gfx_getWindowInfo(NULL, NULL, &info->depth);
|
*depth = SDL_BITSPERPIXEL(dm.format);
|
||||||
info->width = nact->ags.view_area.w;
|
break;
|
||||||
info->height = nact->ags.view_area.h;
|
case AGS_DISPLAY_DIB:
|
||||||
}
|
*width = nact->ags.world_width;
|
||||||
|
*height = nact->ags.world_height;
|
||||||
void ags_getWindowInfo(DispInfo *info) {
|
*depth = nact->ags.world_depth;
|
||||||
gfx_getWindowInfo(&info->width, &info->height, &info->depth);
|
break;
|
||||||
|
case AGS_DISPLAY_VIEW_AREA:
|
||||||
|
SDL_GetCurrentDisplayMode(0, &dm);
|
||||||
|
*width = nact->ags.view_area.w;
|
||||||
|
*height = nact->ags.view_area.h;
|
||||||
|
*depth = SDL_BITSPERPIXEL(dm.format);
|
||||||
|
break;
|
||||||
|
case AGS_DISPLAY_DESKTOP:
|
||||||
|
SDL_GetDesktopDisplayMode(0, &dm);
|
||||||
|
*width = dm.w;
|
||||||
|
*height = dm.h;
|
||||||
|
*depth = SDL_BITSPERPIXEL(dm.format);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ags_setExposeSwitch(bool expose) {
|
void ags_setExposeSwitch(bool expose) {
|
||||||
@@ -466,7 +478,7 @@ int ags_drawString(int x, int y, const char *src, int col, int size, SDL_Rect *r
|
|||||||
SDL_Surface *ags_drawStringToSurface(const char *str, int r, int g, int b, FontSpec font) {
|
SDL_Surface *ags_drawStringToSurface(const char *str, int r, int g, int b, FontSpec font) {
|
||||||
char *utf8 = toUTF8(str);
|
char *utf8 = toUTF8(str);
|
||||||
SDL_Color color = {r, g, b, 255};
|
SDL_Color color = {r, g, b, 255};
|
||||||
SDL_Surface *sf = font_render_text(font, utf8, color);
|
SDL_Surface *sf = font_render_text(font, utf8, color, true);
|
||||||
free(utf8);
|
free(utf8);
|
||||||
return sf;
|
return sf;
|
||||||
}
|
}
|
||||||
@@ -579,7 +591,7 @@ void ags_alpha_copyArea(int sx, int sy, int w, int h, int dx, int dy) {
|
|||||||
alpha_copy_area(nact->ags.dib, sx, sy, w, h, dx, dy);
|
alpha_copy_area(nact->ags.dib, sx, sy, w, h, dx, dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ags_alpha_getPixel(int x, int y, int *pic) {
|
void ags_alpha_getPixel(int x, int y, vmvar_t *pic) {
|
||||||
if (nact->ags.world_depth == 8) return;
|
if (nact->ags.world_depth == 8) return;
|
||||||
|
|
||||||
if (!ags_check_param_xy(&x, &y)) {
|
if (!ags_check_param_xy(&x, &y)) {
|
||||||
@@ -716,10 +728,10 @@ void ags_setCursorLocation(int x, int y, bool is_dibgeo, bool for_selection) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
if (!for_selection) {
|
if (!sl_is_s380 && !for_selection) {
|
||||||
// We can't move the actual cursor in the browser, but can change the
|
// We can't move the actual cursor in the browser, but can change the
|
||||||
// internal mouse coordinates. This can help with keyboard/gamepad
|
// internal mouse coordinates. This can help with keyboard/gamepad
|
||||||
// navigation.
|
// navigation in Toushin Toshi 2.
|
||||||
event_set_mouse_internal_location(x, y);
|
event_set_mouse_internal_location(x, y);
|
||||||
EM_ASM({ xsystem35.shell.showMouseMoveEffect($0, $1); }, x, y);
|
EM_ASM({ xsystem35.shell.showMouseMoveEffect($0, $1); }, x, y);
|
||||||
sys_sleep(cursor_move_time);
|
sys_sleep(cursor_move_time);
|
||||||
@@ -733,11 +745,11 @@ void ags_setCursorLocation(int x, int y, bool is_dibgeo, bool for_selection) {
|
|||||||
for (int i = 1; i < 8; i++) {
|
for (int i = 1; i < 8; i++) {
|
||||||
int xi = ((dx*i*i*i) >> 9) - ((3*dx*i*i)>> 6) + ((3*dx*i) >> 3) + p.x;
|
int xi = ((dx*i*i*i) >> 9) - ((3*dx*i*i)>> 6) + ((3*dx*i) >> 3) + p.x;
|
||||||
int yi = ((dy*i*i*i) >> 9) - ((3*dy*i*i)>> 6) + ((3*dy*i) >> 3) + p.y;
|
int yi = ((dy*i*i*i) >> 9) - ((3*dy*i*i)>> 6) + ((3*dy*i) >> 3) + p.y;
|
||||||
event_set_mouse_location(xi, yi);
|
gfx_warpMouse(xi, yi);
|
||||||
sys_sleep(cursor_move_time / 7);
|
sys_sleep(cursor_move_time / 7);
|
||||||
}
|
}
|
||||||
event_set_mouse_location(x, y);
|
gfx_warpMouse(x, y);
|
||||||
} else if (!for_selection) {
|
} else if (!sl_is_s380 && !for_selection) {
|
||||||
event_set_mouse_internal_location(x, y);
|
event_set_mouse_internal_location(x, y);
|
||||||
sys_sleep(cursor_move_time);
|
sys_sleep(cursor_move_time);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,11 +102,12 @@ typedef struct {
|
|||||||
uint32_t index;
|
uint32_t index;
|
||||||
} PixelColor;
|
} PixelColor;
|
||||||
|
|
||||||
typedef struct {
|
enum ags_display {
|
||||||
int width;
|
AGS_DISPLAY_CURRENT,
|
||||||
int height;
|
AGS_DISPLAY_DIB,
|
||||||
int depth;
|
AGS_DISPLAY_VIEW_AREA,
|
||||||
} DispInfo;
|
AGS_DISPLAY_DESKTOP,
|
||||||
|
};
|
||||||
|
|
||||||
struct _ags {
|
struct _ags {
|
||||||
SDL_Color pal[256]; /* system palette */
|
SDL_Color pal[256]; /* system palette */
|
||||||
@@ -128,17 +129,15 @@ struct _ags {
|
|||||||
int text_decoration_color;
|
int text_decoration_color;
|
||||||
|
|
||||||
bool mouse_warp_enabled;
|
bool mouse_warp_enabled;
|
||||||
bool enable_zb;
|
|
||||||
bool noantialias; /* antialias を使用しない */
|
bool noantialias; /* antialias を使用しない */
|
||||||
bool noimagecursor; /* リソースファイルのカーソルを読みこまない */
|
bool noimagecursor; /* リソースファイルのカーソルを読みこまない */
|
||||||
bool virtualpointer; /* enable the virtual mouse pointer (trackpad-style touch) */
|
|
||||||
};
|
};
|
||||||
typedef struct _ags ags_t;
|
typedef struct _ags ags_t;
|
||||||
|
|
||||||
extern SDL_Surface *main_surface;
|
extern SDL_Surface *main_surface;
|
||||||
|
|
||||||
/* 初期化関係 */
|
/* 初期化関係 */
|
||||||
void ags_init(const char *render_driver, bool enable_zb);
|
void ags_init(const char *render_driver);
|
||||||
void ags_remove(void);
|
void ags_remove(void);
|
||||||
void ags_reset(void);
|
void ags_reset(void);
|
||||||
|
|
||||||
@@ -146,9 +145,7 @@ void ags_reset(void);
|
|||||||
extern void ags_setWorldSize(int width, int height, int depth);
|
extern void ags_setWorldSize(int width, int height, int depth);
|
||||||
extern void ags_setViewArea(int x, int y, int width, int height);
|
extern void ags_setViewArea(int x, int y, int width, int height);
|
||||||
extern void ags_setWindowTitle(const char *title_utf8);
|
extern void ags_setWindowTitle(const char *title_utf8);
|
||||||
extern void ags_getDIBInfo(DispInfo *info);
|
extern void ags_getDisplayInfo(enum ags_display display, int *width, int *height, int *depth);
|
||||||
extern void ags_getWindowInfo(DispInfo *info);
|
|
||||||
extern void ags_getViewAreaInfo(DispInfo *info);
|
|
||||||
extern bool ags_check_param(int *x, int *y, int *w, int *h);
|
extern bool ags_check_param(int *x, int *y, int *w, int *h);
|
||||||
extern bool ags_check_param_xy(int *x, int *y);
|
extern bool ags_check_param_xy(int *x, int *y);
|
||||||
extern surface_t *ags_getDIB();
|
extern surface_t *ags_getDIB();
|
||||||
@@ -200,7 +197,7 @@ extern void ags_alpha_uppercut(int sx, int sy, int w, int h, int s, int d);
|
|||||||
extern void ags_alpha_lowercut(int sx, int sy, int w, int h, int s, int d);
|
extern void ags_alpha_lowercut(int sx, int sy, int w, int h, int s, int d);
|
||||||
extern void ags_alpha_setLevel(int x, int y, int w, int h, int lv);
|
extern void ags_alpha_setLevel(int x, int y, int w, int h, int lv);
|
||||||
extern void ags_alpha_copyArea(int sx, int sy, int w, int h, int dx, int dy);
|
extern void ags_alpha_copyArea(int sx, int sy, int w, int h, int dx, int dy);
|
||||||
extern void ags_alpha_getPixel(int x, int y, int *pic);
|
extern void ags_alpha_getPixel(int x, int y, vmvar_t *pic);
|
||||||
extern void ags_alpha_setPixel(int x, int y, int w, int h, uint8_t *b);
|
extern void ags_alpha_setPixel(int x, int y, int w, int h, uint8_t *b);
|
||||||
|
|
||||||
/* fader */
|
/* fader */
|
||||||
|
|||||||
+37
-7
@@ -33,18 +33,34 @@
|
|||||||
/* drifiles object */
|
/* drifiles object */
|
||||||
static drifiles *dri[DRIFILETYPEMAX];
|
static drifiles *dri[DRIFILETYPEMAX];
|
||||||
|
|
||||||
/* cache handler for dri file */
|
static Cache *dri_cache;
|
||||||
static cacher *cacheid;
|
|
||||||
|
#ifndef ALD_CACHE_SIZE
|
||||||
|
#define ALD_CACHE_SIZE (10 << 20)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint32_t int_hash(const void *key) {
|
||||||
|
return (uint32_t)*(const int *)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool int_equal(const void *a, const void *b) {
|
||||||
|
return *(const int *)a == *(const int *)b;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free dridata
|
* free dridata
|
||||||
* dfile: dridata to be free
|
* dfile: dridata to be free
|
||||||
*/
|
*/
|
||||||
static void ald_free(dridata *dfile) {
|
static void ald_free(void *data) {
|
||||||
|
dridata *dfile = data;
|
||||||
free(dfile->data_raw);
|
free(dfile->data_raw);
|
||||||
free(dfile);
|
free(dfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ald_is_pinned(const void *data) {
|
||||||
|
return ((const dridata *)data)->refcnt != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool ald_is_linked(DRIFILETYPE type, int no) {
|
bool ald_is_linked(DRIFILETYPE type, int no) {
|
||||||
if (type >= DRIFILETYPEMAX || !dri[type])
|
if (type >= DRIFILETYPEMAX || !dri[type])
|
||||||
return false;
|
return false;
|
||||||
@@ -80,11 +96,12 @@ dridata *ald_getdata(DRIFILETYPE type, int no) {
|
|||||||
if (dri[type]->mmapped) return dri_getdata(dri[type], no);
|
if (dri[type]->mmapped) return dri_getdata(dri[type], no);
|
||||||
|
|
||||||
/* not mmapped */
|
/* not mmapped */
|
||||||
if (NULL == (ddata = (dridata *)cache_foreach(cacheid, (type << 16) + no))) {
|
int key = (type << 16) + no;
|
||||||
|
if (NULL == (ddata = cache_get(dri_cache, &key))) {
|
||||||
ddata = dri_getdata(dri[type], no);
|
ddata = dri_getdata(dri[type], no);
|
||||||
if (ddata != NULL) {
|
if (ddata != NULL) {
|
||||||
ddata->refcnt = 0;
|
ddata->refcnt = 0;
|
||||||
cache_insert(cacheid, (type << 16) + no, (void *)ddata, ddata->size, &(ddata->refcnt));
|
ddata->cached = cache_insert(dri_cache, &key, ddata, ddata->size) == CACHE_INSERT_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ddata != NULL)
|
if (ddata != NULL)
|
||||||
@@ -105,6 +122,8 @@ void ald_freedata(dridata *data) {
|
|||||||
free(data);
|
free(data);
|
||||||
} else {
|
} else {
|
||||||
data->refcnt--;
|
data->refcnt--;
|
||||||
|
if (!data->cached && data->refcnt == 0)
|
||||||
|
ald_free(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,8 +131,15 @@ void ald_init(int type, const char **file, int cnt, bool use_mmap) {
|
|||||||
if (type >= DRIFILETYPEMAX || cnt <= 0)
|
if (type >= DRIFILETYPEMAX || cnt <= 0)
|
||||||
return;
|
return;
|
||||||
dri[type] = dri_init(file, cnt, use_mmap);
|
dri[type] = dri_init(file, cnt, use_mmap);
|
||||||
if (!dri[type]->mmapped) {
|
if (!dri[type]->mmapped && !dri_cache) {
|
||||||
cacheid = cache_new(ald_free);
|
CacheOps ops = {
|
||||||
|
.key_size = sizeof(int),
|
||||||
|
.hash = int_hash,
|
||||||
|
.equal = int_equal,
|
||||||
|
.destroy = ald_free,
|
||||||
|
.is_pinned = ald_is_pinned,
|
||||||
|
};
|
||||||
|
dri_cache = cache_new((size_t)ALD_CACHE_SIZE, &ops);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,3 +148,7 @@ int ald_get_maxno(DRIFILETYPE type) {
|
|||||||
return 0;
|
return 0;
|
||||||
return dri[type]->maxno;
|
return dri[type]->maxno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CacheStats ald_get_cache_stats(void) {
|
||||||
|
return cache_get_stats(dri_cache);
|
||||||
|
}
|
||||||
|
|||||||
+2
-1
@@ -25,6 +25,7 @@
|
|||||||
#define __ALD_MANAGER__
|
#define __ALD_MANAGER__
|
||||||
|
|
||||||
#include "portab.h"
|
#include "portab.h"
|
||||||
|
#include "cache.h"
|
||||||
#include "dri.h"
|
#include "dri.h"
|
||||||
|
|
||||||
#define DRIFILETYPEMAX 7
|
#define DRIFILETYPEMAX 7
|
||||||
@@ -44,6 +45,6 @@ bool ald_exists(DRIFILETYPE type, int no);
|
|||||||
dridata *ald_getdata(DRIFILETYPE type, int no);
|
dridata *ald_getdata(DRIFILETYPE type, int no);
|
||||||
void ald_freedata(dridata *data);
|
void ald_freedata(dridata *data);
|
||||||
int ald_get_maxno(DRIFILETYPE type);
|
int ald_get_maxno(DRIFILETYPE type);
|
||||||
|
CacheStats ald_get_cache_stats(void);
|
||||||
|
|
||||||
#endif /* !__ALD_MANAGER__ */
|
#endif /* !__ALD_MANAGER__ */
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* bgi.c: BGI (BGM information) parser
|
* audio_meta.c: BGI (BGM information) / WAI (wave information) parser
|
||||||
*
|
*
|
||||||
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
||||||
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
||||||
@@ -23,10 +23,12 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "portab.h"
|
#include "portab.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "bgi.h"
|
#include "audio_meta.h"
|
||||||
|
#include "LittleEndian.h"
|
||||||
|
|
||||||
#define BGI_MAX 100
|
#define BGI_MAX 100
|
||||||
|
|
||||||
@@ -82,3 +84,77 @@ bgi_t *bgi_find(int no) {
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int *wai_channels;
|
||||||
|
static int wai_count;
|
||||||
|
|
||||||
|
static void wai_unload(void) {
|
||||||
|
free(wai_channels);
|
||||||
|
wai_channels = NULL;
|
||||||
|
wai_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wai_load(const char *path) {
|
||||||
|
wai_unload();
|
||||||
|
if (!path)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FILE *fp = fopen(path, "rb");
|
||||||
|
if (!fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8_t header[24];
|
||||||
|
if (fread(header, 1, sizeof(header), fp) != sizeof(header) ||
|
||||||
|
header[0] != 'X' || header[1] != 'I' || header[2] != '2' || header[3] != '\0')
|
||||||
|
{
|
||||||
|
WARNING("not WAI file");
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = LittleEndian_getDW(header, 8);
|
||||||
|
if (count <= 0) {
|
||||||
|
WARNING("invalid WAI record count: %d", count);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int version = LittleEndian_getDW(header, 12);
|
||||||
|
if (version != 3) {
|
||||||
|
WARNING("unsupported WAI version: %d", version);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *channels = calloc(count, sizeof(*channels));
|
||||||
|
if (!channels) {
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t record[12];
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (fread(record, 1, sizeof(record), fp) != sizeof(record)) {
|
||||||
|
WARNING("truncated WAI file");
|
||||||
|
free(channels);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
channels[i] = LittleEndian_getDW(record, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
wai_channels = channels;
|
||||||
|
wai_count = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wai_loaded(void) {
|
||||||
|
return wai_channels != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wai_mixch(int no) {
|
||||||
|
if (!wai_channels || no < 0 || no >= wai_count)
|
||||||
|
return -1;
|
||||||
|
return wai_channels[no];
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* bgi.c: BGI (BGM information) parser
|
* audio_meta.h: BGI (BGM information) / WAI (wave information) parser
|
||||||
*
|
*
|
||||||
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
||||||
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
||||||
@@ -35,4 +35,8 @@ typedef struct {
|
|||||||
extern bool bgi_read(const char *path);
|
extern bool bgi_read(const char *path);
|
||||||
extern bgi_t *bgi_find(int no);
|
extern bgi_t *bgi_find(int no);
|
||||||
|
|
||||||
|
bool wai_load(const char *path);
|
||||||
|
bool wai_loaded(void);
|
||||||
|
int wai_mixch(int no);
|
||||||
|
|
||||||
#endif /* _BGI_H__ */
|
#endif /* _BGI_H__ */
|
||||||
@@ -23,8 +23,9 @@
|
|||||||
#include "portab.h"
|
#include "portab.h"
|
||||||
#include "nact.h"
|
#include "nact.h"
|
||||||
#include "bgm.h"
|
#include "bgm.h"
|
||||||
#include "bgi.h"
|
#include "audio_meta.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include "music_private.h"
|
||||||
|
|
||||||
bool musbgm_init(DRIFILETYPE type, int base_no) {
|
bool musbgm_init(DRIFILETYPE type, int base_no) {
|
||||||
if (type == DRIFILE_BGM)
|
if (type == DRIFILE_BGM)
|
||||||
@@ -87,3 +88,7 @@ void musbgm_wait(int no, int timeout) {
|
|||||||
sys_wait_vsync();
|
sys_wait_vsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void musbgm_reapply_valance(void) {
|
||||||
|
EM_ASM({ xsystem35.cdPlayer.setValance($0); }, prv.volval[BGM_VOLVAL_CH]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,5 +33,6 @@ int musbgm_getlen(int no);
|
|||||||
bool musbgm_isplaying(int no);
|
bool musbgm_isplaying(int no);
|
||||||
void musbgm_stopall(int time);
|
void musbgm_stopall(int time);
|
||||||
void musbgm_wait(int no, int timeout);
|
void musbgm_wait(int no, int timeout);
|
||||||
|
void musbgm_reapply_valance(void);
|
||||||
|
|
||||||
#endif /* __BGM_H__ */
|
#endif /* __BGM_H__ */
|
||||||
|
|||||||
+19
-6
@@ -32,17 +32,27 @@
|
|||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "nact.h"
|
#include "nact.h"
|
||||||
#include "bgm.h"
|
#include "bgm.h"
|
||||||
#include "bgi.h"
|
#include "audio_meta.h"
|
||||||
#include "music_private.h"
|
#include "music_private.h"
|
||||||
#include "ald_manager.h"
|
#include "ald_manager.h"
|
||||||
|
|
||||||
static DRIFILETYPE dri_type;
|
static DRIFILETYPE dri_type;
|
||||||
static int base_no;
|
static int base_no;
|
||||||
static int current_no;
|
static int current_no;
|
||||||
|
static int current_vol = 100; // game-requested volume (0-100)
|
||||||
static Mix_Music *mix_music;
|
static Mix_Music *mix_music;
|
||||||
static dridata* dfile;
|
static dridata* dfile;
|
||||||
static Uint32 start_time;
|
static Uint32 start_time;
|
||||||
|
|
||||||
|
static void apply_music_volume(int vol) {
|
||||||
|
current_vol = vol;
|
||||||
|
Mix_VolumeMusic(current_vol * prv.volval[BGM_VOLVAL_CH] * MIX_MAX_VOLUME / (100 * 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
void musbgm_reapply_valance(void) {
|
||||||
|
apply_music_volume(current_vol);
|
||||||
|
}
|
||||||
|
|
||||||
static void free_music() {
|
static void free_music() {
|
||||||
current_no = 0;
|
current_no = 0;
|
||||||
if (mix_music) {
|
if (mix_music) {
|
||||||
@@ -101,11 +111,14 @@ bool musbgm_play(int no, int time, int vol, int loop_count) {
|
|||||||
if (!bgm_load(no))
|
if (!bgm_load(no))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// We don't use the loop information in the BGI file, but SDL_mixer
|
// We don't use the loop positions in the BGI file; SDL_mixer instead
|
||||||
// understands loop info in the WAVE's "smpl" chunk.
|
// understands loop positions in the WAVE's "smpl" chunk.
|
||||||
|
|
||||||
Mix_VolumeMusic(vol * MIX_MAX_VOLUME / 100);
|
apply_music_volume(vol);
|
||||||
if (Mix_FadeInMusic(mix_music, loop_count == 0 ? -1 : loop_count, time * 10) != 0) {
|
// SDL_mixer counts repeats after the first play, while System 3.x counts
|
||||||
|
// the total number of plays. In both APIs, an infinite loop is special.
|
||||||
|
int loops = loop_count == 0 ? -1 : loop_count - 1;
|
||||||
|
if (Mix_FadeInMusic(mix_music, loops, time * 10) != 0) {
|
||||||
free_music();
|
free_music();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -124,7 +137,7 @@ void musbgm_fade(int no, int time, int vol) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// SDL_mixer doesn't provide arbitrary fading, so just set the volume immediately.
|
// SDL_mixer doesn't provide arbitrary fading, so just set the volume immediately.
|
||||||
Mix_VolumeMusic(vol * MIX_MAX_VOLUME / 100);
|
apply_music_volume(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
int musbgm_getpos(int no) {
|
int musbgm_getpos(int no) {
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
/* XPM */
|
|
||||||
static const char *virtual_cursor[] = {
|
|
||||||
/* width height num_colors chars_per_pixel */
|
|
||||||
"16 19 3 1",
|
|
||||||
/* colors */
|
|
||||||
"X c #000000",
|
|
||||||
". c #ffffff",
|
|
||||||
" c None",
|
|
||||||
/* pixels */
|
|
||||||
"X ",
|
|
||||||
"XX ",
|
|
||||||
"X.X ",
|
|
||||||
"X..X ",
|
|
||||||
"X...X ",
|
|
||||||
"X....X ",
|
|
||||||
"X.....X ",
|
|
||||||
"X......X ",
|
|
||||||
"X.......X ",
|
|
||||||
"X........X ",
|
|
||||||
"X.....XXXXX ",
|
|
||||||
"X..X..X ",
|
|
||||||
"X.X X..X ",
|
|
||||||
"XX X..X ",
|
|
||||||
"X X..X ",
|
|
||||||
" X..X ",
|
|
||||||
" X..X ",
|
|
||||||
" X..X ",
|
|
||||||
" XX "
|
|
||||||
};
|
|
||||||
+162
-115
@@ -1,8 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* cache.c general cache manager
|
* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
*
|
|
||||||
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
|
||||||
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,130 +16,180 @@
|
|||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/* $Id: cache.c,v 1.5 2003/07/21 23:06:47 chikama Exp $ */
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "portab.h"
|
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
/* maximum cache size (in MB) */
|
#include <stdlib.h>
|
||||||
#ifndef CACHE_TOTALSIZE
|
#include <string.h>
|
||||||
#define CACHE_TOTALSIZE 20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int totalsize; /* total size in cache */
|
#define CACHE_BUCKETS 1024
|
||||||
static int dummyfalse = 0; /* dummy in_use flag */
|
|
||||||
static int dummytrue = 1; /* dummy in_use flag */
|
|
||||||
|
|
||||||
/*
|
typedef struct CacheEntry {
|
||||||
* static methods
|
struct CacheEntry *hash_next;
|
||||||
*/
|
struct CacheEntry *lru_prev;
|
||||||
static void remove_in_cache(cacher *id);
|
struct CacheEntry *lru_next;
|
||||||
|
uint32_t hash;
|
||||||
|
size_t cost;
|
||||||
|
void *data;
|
||||||
|
unsigned char key[];
|
||||||
|
} CacheEntry;
|
||||||
|
|
||||||
/*
|
struct Cache {
|
||||||
* Remove data in cache
|
CacheOps ops;
|
||||||
* id: cache handler
|
CacheEntry *buckets[CACHE_BUCKETS];
|
||||||
*/
|
CacheEntry *lru_head;
|
||||||
static void remove_in_cache(cacher *id) {
|
CacheEntry *lru_tail;
|
||||||
cacheinfo *ip = id->top;
|
size_t capacity;
|
||||||
cacheinfo *ic = ip->next;
|
size_t size;
|
||||||
if (!ic)
|
size_t count;
|
||||||
return;
|
size_t hits;
|
||||||
|
size_t misses;
|
||||||
while(ic->next != NULL) {
|
};
|
||||||
if (!*ic->in_use) {
|
|
||||||
totalsize -= ic->size;
|
static bool is_pinned(const Cache *cache, const CacheEntry *entry) {
|
||||||
ip->next = ic->next;
|
return cache->ops.is_pinned && cache->ops.is_pinned(entry->data);
|
||||||
id->free_(ic->data);
|
|
||||||
free(ic);
|
|
||||||
} else {
|
|
||||||
ip = ic;
|
|
||||||
}
|
|
||||||
ic = ip->next;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void lru_remove(Cache *cache, CacheEntry *entry) {
|
||||||
* Create new cache object
|
if (entry->lru_prev)
|
||||||
* delcallback: callback function for delete cache data object
|
entry->lru_prev->lru_next = entry->lru_next;
|
||||||
* return: new cache handler
|
else
|
||||||
*/
|
cache->lru_head = entry->lru_next;
|
||||||
cacher *cache_new(void *delcallback) {
|
if (entry->lru_next)
|
||||||
cacher *c = calloc(1, sizeof(cacher));
|
entry->lru_next->lru_prev = entry->lru_prev;
|
||||||
|
else
|
||||||
c->top = calloc(1, sizeof(cacheinfo));
|
cache->lru_tail = entry->lru_prev;
|
||||||
c->top->next = NULL;
|
|
||||||
c->top->in_use = &dummytrue;
|
|
||||||
c->free_ = delcallback;
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void lru_prepend(Cache *cache, CacheEntry *entry) {
|
||||||
* Insert data to cache
|
entry->lru_prev = NULL;
|
||||||
* id : cache handler
|
entry->lru_next = cache->lru_head;
|
||||||
* key : data key
|
if (cache->lru_head)
|
||||||
* data : data to be cached
|
cache->lru_head->lru_prev = entry;
|
||||||
* size : data size
|
else
|
||||||
* in_use: in_use mark pointer, if in_use is nonzero, dont remove from cache
|
cache->lru_tail = entry;
|
||||||
*/
|
cache->lru_head = entry;
|
||||||
void cache_insert(cacher *id, int key, void *data, int size, int *in_use) {
|
|
||||||
cacheinfo *i = id->top;
|
|
||||||
|
|
||||||
if (CACHE_TOTALSIZE <= (totalsize >> 20)) {
|
|
||||||
remove_in_cache(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
while(i->next != NULL) {
|
|
||||||
i = i->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
i->key = key;
|
|
||||||
i->data = data;
|
|
||||||
i->size = size;
|
|
||||||
i->next = calloc(1, sizeof(cacheinfo));
|
|
||||||
i->next->next = NULL;
|
|
||||||
if (in_use) {
|
|
||||||
i->in_use = in_use;
|
|
||||||
} else {
|
|
||||||
i->in_use = &dummyfalse;
|
|
||||||
}
|
|
||||||
totalsize += size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void remove_entry(Cache *cache, CacheEntry *entry) {
|
||||||
* Search data in cache
|
CacheEntry **link = &cache->buckets[entry->hash % CACHE_BUCKETS];
|
||||||
* id : cache handler
|
while (*link != entry)
|
||||||
* key: data search key
|
link = &(*link)->hash_next;
|
||||||
* return: pointer to cached data
|
*link = entry->hash_next;
|
||||||
*/
|
lru_remove(cache, entry);
|
||||||
void *cache_foreach(cacher *id, int key) {
|
cache->size -= entry->cost;
|
||||||
cacheinfo *i = id->top;
|
cache->count--;
|
||||||
|
cache->ops.destroy(entry->data);
|
||||||
while(i != NULL) {
|
free(entry);
|
||||||
if (i->key == key) {
|
}
|
||||||
return i->data;
|
|
||||||
}
|
static CacheEntry *find_entry(Cache *cache, const void *key, uint32_t hash) {
|
||||||
i = i->next;
|
for (CacheEntry *entry = cache->buckets[hash % CACHE_BUCKETS]; entry;
|
||||||
|
entry = entry->hash_next) {
|
||||||
|
if (entry->hash == hash && cache->ops.equal(entry->key, key))
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_clear(cacher *id) {
|
Cache *cache_new(size_t capacity, const CacheOps *ops) {
|
||||||
cacheinfo *ic = id->top->next;
|
if (!ops || !ops->key_size || !ops->hash || !ops->equal || !ops->destroy)
|
||||||
cacheinfo *next;
|
return NULL;
|
||||||
|
Cache *cache = calloc(1, sizeof(Cache));
|
||||||
while (ic != NULL) {
|
if (!cache)
|
||||||
next = ic->next;
|
return NULL;
|
||||||
if (ic->data) {
|
cache->ops = *ops;
|
||||||
totalsize -= ic->size;
|
cache->capacity = capacity;
|
||||||
id->free_(ic->data);
|
return cache;
|
||||||
}
|
}
|
||||||
free(ic);
|
|
||||||
ic = next;
|
void cache_destroy(Cache *cache) {
|
||||||
}
|
if (!cache)
|
||||||
id->top->next = NULL;
|
return;
|
||||||
|
while (cache->lru_tail)
|
||||||
|
remove_entry(cache, cache->lru_tail);
|
||||||
|
free(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *cache_get(Cache *cache, const void *key) {
|
||||||
|
if (!cache || !key)
|
||||||
|
return NULL;
|
||||||
|
CacheEntry *entry = find_entry(cache, key, cache->ops.hash(key));
|
||||||
|
if (!entry) {
|
||||||
|
cache->misses++;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
cache->hits++;
|
||||||
|
lru_remove(cache, entry);
|
||||||
|
lru_prepend(cache, entry);
|
||||||
|
return entry->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheInsertResult cache_insert(Cache *cache, const void *key, void *data, size_t cost) {
|
||||||
|
if (!cache || !key || !data)
|
||||||
|
return CACHE_INSERT_NOMEM;
|
||||||
|
uint32_t hash = cache->ops.hash(key);
|
||||||
|
if (find_entry(cache, key, hash))
|
||||||
|
return CACHE_INSERT_EXISTS;
|
||||||
|
if (cost > cache->capacity)
|
||||||
|
return CACHE_INSERT_FULL;
|
||||||
|
|
||||||
|
CacheEntry *entry = malloc(sizeof(CacheEntry) + cache->ops.key_size);
|
||||||
|
if (!entry)
|
||||||
|
return CACHE_INSERT_NOMEM;
|
||||||
|
|
||||||
|
for (CacheEntry *old = cache->lru_tail, *prev;
|
||||||
|
old && cache->size > cache->capacity - cost; old = prev) {
|
||||||
|
prev = old->lru_prev;
|
||||||
|
if (!is_pinned(cache, old))
|
||||||
|
remove_entry(cache, old);
|
||||||
|
}
|
||||||
|
if (cache->size > cache->capacity - cost) {
|
||||||
|
free(entry);
|
||||||
|
return CACHE_INSERT_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->hash = hash;
|
||||||
|
entry->cost = cost;
|
||||||
|
entry->data = data;
|
||||||
|
memcpy(entry->key, key, cache->ops.key_size);
|
||||||
|
unsigned bucket = hash % CACHE_BUCKETS;
|
||||||
|
entry->hash_next = cache->buckets[bucket];
|
||||||
|
cache->buckets[bucket] = entry;
|
||||||
|
lru_prepend(cache, entry);
|
||||||
|
cache->size += cost;
|
||||||
|
cache->count++;
|
||||||
|
return CACHE_INSERT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cache_remove(Cache *cache, const void *key) {
|
||||||
|
if (!cache || !key)
|
||||||
|
return false;
|
||||||
|
CacheEntry *entry = find_entry(cache, key, cache->ops.hash(key));
|
||||||
|
if (!entry || is_pinned(cache, entry))
|
||||||
|
return false;
|
||||||
|
remove_entry(cache, entry);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cache_clear(Cache *cache) {
|
||||||
|
if (!cache)
|
||||||
|
return 0;
|
||||||
|
for (CacheEntry *entry = cache->lru_tail, *prev; entry; entry = prev) {
|
||||||
|
prev = entry->lru_prev;
|
||||||
|
if (!is_pinned(cache, entry))
|
||||||
|
remove_entry(cache, entry);
|
||||||
|
}
|
||||||
|
return cache->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheStats cache_get_stats(const Cache *cache) {
|
||||||
|
if (!cache)
|
||||||
|
return (CacheStats){0};
|
||||||
|
return (CacheStats){
|
||||||
|
.count = cache->count,
|
||||||
|
.size = cache->size,
|
||||||
|
.capacity = cache->capacity,
|
||||||
|
.hits = cache->hits,
|
||||||
|
.misses = cache->misses,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-28
@@ -1,8 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* cache.h general cache manager
|
* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
*
|
|
||||||
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
|
||||||
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,33 +16,54 @@
|
|||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/* $Id: cache.h,v 1.2 2003/07/21 23:06:47 chikama Exp $ */
|
#ifndef XSYSTEM35_CACHE_H
|
||||||
|
#define XSYSTEM35_CACHE_H
|
||||||
|
|
||||||
#ifndef __CASHE__
|
#include <stdbool.h>
|
||||||
#define __CASHE__
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "portab.h"
|
typedef struct Cache Cache;
|
||||||
|
|
||||||
/* cache controlr infomartion */
|
typedef struct {
|
||||||
struct _cacheinfo {
|
size_t key_size;
|
||||||
int key; /* key of data */
|
uint32_t (*hash)(const void *key);
|
||||||
int size; /* data size */
|
bool (*equal)(const void *a, const void *b);
|
||||||
struct _cacheinfo *next; /* next data */
|
void (*destroy)(void *data);
|
||||||
int *in_use; /* if *in_use is nonzero, dont remove from cache */
|
bool (*is_pinned)(const void *data);
|
||||||
void *data; /* real data */
|
} CacheOps;
|
||||||
};
|
|
||||||
typedef struct _cacheinfo cacheinfo;
|
|
||||||
|
|
||||||
/* cache handler */
|
typedef enum {
|
||||||
struct _cacher {
|
CACHE_INSERT_OK,
|
||||||
void (*free_)(void *); /* free data callback */
|
CACHE_INSERT_EXISTS,
|
||||||
struct _cacheinfo *top; /* pointer to data */
|
CACHE_INSERT_FULL,
|
||||||
};
|
CACHE_INSERT_NOMEM,
|
||||||
typedef struct _cacher cacher;
|
} CacheInsertResult;
|
||||||
|
|
||||||
extern cacher *cache_new(void *delcallback);
|
typedef struct {
|
||||||
extern void cache_insert(cacher *id, int key, void *data, int size, int *in_use);
|
size_t count;
|
||||||
extern void *cache_foreach(cacher *id, int key);
|
size_t size;
|
||||||
extern void cache_clear(cacher *id);
|
size_t capacity;
|
||||||
|
size_t hits;
|
||||||
|
size_t misses;
|
||||||
|
} CacheStats;
|
||||||
|
|
||||||
#endif /* !__CASHE__ */
|
Cache *cache_new(size_t capacity, const CacheOps *ops);
|
||||||
|
void cache_destroy(Cache *cache);
|
||||||
|
|
||||||
|
/* The returned pointer is owned by the cache and is invalidated by removal. */
|
||||||
|
void *cache_get(Cache *cache, const void *key);
|
||||||
|
|
||||||
|
/* Ownership of data is transferred only when CACHE_INSERT_OK is returned. */
|
||||||
|
CacheInsertResult cache_insert(Cache *cache, const void *key, void *data, size_t cost);
|
||||||
|
|
||||||
|
/* Pinned entries cannot be removed. */
|
||||||
|
bool cache_remove(Cache *cache, const void *key);
|
||||||
|
|
||||||
|
/* Removes all unpinned entries and returns the number of entries left. */
|
||||||
|
size_t cache_clear(Cache *cache);
|
||||||
|
|
||||||
|
/* Returns zero-filled statistics when cache is NULL. */
|
||||||
|
CacheStats cache_get_stats(const Cache *cache);
|
||||||
|
|
||||||
|
#endif /* XSYSTEM35_CACHE_H */
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2026 <KichikuouChrome@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "cache.h"
|
||||||
|
#include "unittest.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int value;
|
||||||
|
bool pinned;
|
||||||
|
} TestValue;
|
||||||
|
|
||||||
|
static int destroyed;
|
||||||
|
|
||||||
|
static uint32_t int_hash(const void *key) {
|
||||||
|
return (uint32_t)*(const int *)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool int_equal(const void *a, const void *b) {
|
||||||
|
return *(const int *)a == *(const int *)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_value(void *data) {
|
||||||
|
destroyed++;
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool value_is_pinned(const void *data) {
|
||||||
|
return ((const TestValue *)data)->pinned;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestValue *new_value(int value) {
|
||||||
|
TestValue *data = malloc(sizeof(TestValue));
|
||||||
|
ASSERT_TRUE(data);
|
||||||
|
data->value = value;
|
||||||
|
data->pinned = false;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cache_test(void) {
|
||||||
|
CacheOps ops = {
|
||||||
|
.key_size = sizeof(int),
|
||||||
|
.hash = int_hash,
|
||||||
|
.equal = int_equal,
|
||||||
|
.destroy = destroy_value,
|
||||||
|
.is_pinned = value_is_pinned,
|
||||||
|
};
|
||||||
|
Cache *cache = cache_new(2, &ops);
|
||||||
|
ASSERT_TRUE(cache);
|
||||||
|
destroyed = 0;
|
||||||
|
CacheStats stats = cache_get_stats(cache);
|
||||||
|
ASSERT_EQUAL(stats.count, 0);
|
||||||
|
ASSERT_EQUAL(stats.size, 0);
|
||||||
|
ASSERT_EQUAL(stats.capacity, 2);
|
||||||
|
ASSERT_EQUAL(stats.hits, 0);
|
||||||
|
ASSERT_EQUAL(stats.misses, 0);
|
||||||
|
|
||||||
|
// A lookup makes k1 most-recently used, so inserting k3 evicts k2.
|
||||||
|
int k1 = 1, k2 = 2, k3 = 3, k4 = 4, k5 = 5;
|
||||||
|
ASSERT_EQUAL(cache_insert(cache, &k1, new_value(1), 1), CACHE_INSERT_OK);
|
||||||
|
ASSERT_EQUAL(cache_insert(cache, &k2, new_value(2), 1), CACHE_INSERT_OK);
|
||||||
|
stats = cache_get_stats(cache);
|
||||||
|
ASSERT_EQUAL(stats.count, 2);
|
||||||
|
ASSERT_EQUAL(stats.size, 2);
|
||||||
|
ASSERT_EQUAL(stats.capacity, 2);
|
||||||
|
ASSERT_EQUAL(((TestValue *)cache_get(cache, &k1))->value, 1);
|
||||||
|
ASSERT_EQUAL(cache_insert(cache, &k3, new_value(3), 1), CACHE_INSERT_OK);
|
||||||
|
ASSERT_NULL(cache_get(cache, &k2));
|
||||||
|
stats = cache_get_stats(cache);
|
||||||
|
ASSERT_EQUAL(stats.hits, 1);
|
||||||
|
ASSERT_EQUAL(stats.misses, 1);
|
||||||
|
|
||||||
|
// Pinned entries survive both capacity eviction and cache_clear().
|
||||||
|
((TestValue *)cache_get(cache, &k1))->pinned = true;
|
||||||
|
ASSERT_EQUAL(cache_insert(cache, &k4, new_value(4), 1), CACHE_INSERT_OK);
|
||||||
|
ASSERT_NULL(cache_get(cache, &k3));
|
||||||
|
((TestValue *)cache_get(cache, &k4))->pinned = true;
|
||||||
|
|
||||||
|
// Insertion fails when every remaining entry is pinned.
|
||||||
|
TestValue *rejected = new_value(5);
|
||||||
|
ASSERT_EQUAL(cache_insert(cache, &k5, rejected, 1), CACHE_INSERT_FULL);
|
||||||
|
ASSERT_EQUAL(((TestValue *)cache_get(cache, &k1))->value, 1);
|
||||||
|
ASSERT_EQUAL(((TestValue *)cache_get(cache, &k4))->value, 4);
|
||||||
|
ASSERT_EQUAL(cache_clear(cache), 2);
|
||||||
|
ASSERT_EQUAL(destroyed, 2);
|
||||||
|
free(rejected);
|
||||||
|
|
||||||
|
// Once unpinned, cache_clear() destroys the remaining entries.
|
||||||
|
((TestValue *)cache_get(cache, &k1))->pinned = false;
|
||||||
|
((TestValue *)cache_get(cache, &k4))->pinned = false;
|
||||||
|
ASSERT_EQUAL(cache_clear(cache), 0);
|
||||||
|
ASSERT_EQUAL(destroyed, 4);
|
||||||
|
cache_destroy(cache);
|
||||||
|
|
||||||
|
stats = cache_get_stats(NULL);
|
||||||
|
ASSERT_EQUAL(stats.count, 0);
|
||||||
|
ASSERT_EQUAL(stats.size, 0);
|
||||||
|
ASSERT_EQUAL(stats.capacity, 0);
|
||||||
|
ASSERT_EQUAL(stats.hits, 0);
|
||||||
|
ASSERT_EQUAL(stats.misses, 0);
|
||||||
|
}
|
||||||
+9
-9
@@ -24,10 +24,10 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "portab.h"
|
#include "portab.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "cali.h"
|
||||||
#include "variable.h"
|
#include "variable.h"
|
||||||
#include "scenario.h"
|
#include "scenario.h"
|
||||||
#include "nact.h"
|
|
||||||
#include "xsystem35.h"
|
|
||||||
|
|
||||||
#define OP_AND 0x74
|
#define OP_AND 0x74
|
||||||
#define OP_OR 0x75
|
#define OP_OR 0x75
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
#define CALI_DEPTH_MAX 256
|
#define CALI_DEPTH_MAX 256
|
||||||
|
|
||||||
static int *getVar(int c0, struct VarRef *ref) {
|
static vmvar_t *getVar(int c0, struct VarRef *ref) {
|
||||||
int addr = sl_getIndex();
|
int addr = sl_getIndex();
|
||||||
int var;
|
int var;
|
||||||
if ((c0 & 0x40) == 0) {
|
if ((c0 & 0x40) == 0) {
|
||||||
@@ -63,7 +63,7 @@ static int *getVar(int c0, struct VarRef *ref) {
|
|||||||
c1 = sl_getc();
|
c1 = sl_getc();
|
||||||
var = c0 << 8 | c1;
|
var = c0 << 8 | c1;
|
||||||
int index = getCaliValue();
|
int index = getCaliValue();
|
||||||
int *store = v_ref_indexed(var, index, ref);
|
vmvar_t *store = v_ref_indexed(var, index, ref);
|
||||||
if (!store)
|
if (!store)
|
||||||
WARNING("%03d:%05x: Out of bounds index access: %s[%d]", sl_getPage(), addr, v_name(var), index);
|
WARNING("%03d:%05x: Out of bounds index access: %s[%d]", sl_getPage(), addr, v_name(var), index);
|
||||||
return store;
|
return store;
|
||||||
@@ -74,15 +74,15 @@ static int *getVar(int c0, struct VarRef *ref) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int *store = v_ref(var, ref);
|
vmvar_t *store = v_ref(var, ref);
|
||||||
if (!store)
|
if (!store)
|
||||||
WARNING("%03d:%05x: Out of bounds array access: %s", sl_getPage(), addr, v_name(var));
|
WARNING("%03d:%05x: Out of bounds array access: %s", sl_getPage(), addr, v_name(var));
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a pointer to the variable
|
// Returns a pointer to the variable
|
||||||
int *getCaliVariable(void) {
|
vmvar_t *getCaliVariable(void) {
|
||||||
int *c0 = getVar(sl_getc(), NULL);
|
vmvar_t *c0 = getVar(sl_getc(), NULL);
|
||||||
if (sl_getc() != OP_END) {
|
if (sl_getc() != OP_END) {
|
||||||
SYSERROR("Invalid variable expression at %03d:%05x", sl_getPage(), sl_getIndex());
|
SYSERROR("Invalid variable expression at %03d:%05x", sl_getPage(), sl_getIndex());
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ bool getCaliArray(struct VarRef *ref) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For variable assignment commands
|
// For variable assignment commands
|
||||||
int *getVariable(void) {
|
vmvar_t *getVariable(void) {
|
||||||
return getVar(sl_getc(), NULL);
|
return getVar(sl_getc(), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ int getCaliValue(void) {
|
|||||||
while ((c0 = sl_getc()) != OP_END) {
|
while ((c0 = sl_getc()) != OP_END) {
|
||||||
if (c0 & 0x80) { // variable
|
if (c0 & 0x80) { // variable
|
||||||
int c1 = sl_getcAt(sl_getIndex());
|
int c1 = sl_getcAt(sl_getIndex());
|
||||||
int *t;
|
vmvar_t *t;
|
||||||
if (c0 == 0xc0) {
|
if (c0 == 0xc0) {
|
||||||
if (c1 == OP_C0_INDEX || c1 >= 0x34) goto l_var;
|
if (c1 == OP_C0_INDEX || c1 >= 0x34) goto l_var;
|
||||||
c1 = sl_getc();
|
c1 = sl_getc();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user