mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-09-22 22:48:08 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba52fbf5e9 | ||
|
|
85d40701c4 | ||
|
|
7b535b371a | ||
|
|
c0dbae8202 | ||
|
|
ca03450b87 | ||
|
|
f795a500cf | ||
|
|
3314f00bf8 | ||
|
|
a2d79f045c | ||
|
|
f247495578 | ||
|
|
f6583330de | ||
|
|
4b15f45897 | ||
|
|
7bc433731f | ||
|
|
4c21570eb1 | ||
|
|
a3e7feffc2 | ||
|
|
a4c1dd1acf | ||
|
|
09086ccc85 | ||
|
|
53e39b7c11 | ||
|
|
f0ccfee40f | ||
|
|
10cdec98e6 | ||
|
|
c61afb4308 | ||
|
|
f6cf881e61 | ||
|
|
a8277e71a7 | ||
|
|
3482fb6440 | ||
|
|
3c81c8fec2 | ||
|
|
e090485b37 | ||
|
|
d7deaec972 | ||
|
|
30467371f4 | ||
|
|
e9a30f7493 | ||
|
|
d9e42dd4bb | ||
|
|
0e06cc1e22 | ||
|
|
89423c94f1 | ||
|
|
c694d2282c | ||
|
|
39e94afc44 | ||
|
|
e37a491908 | ||
|
|
43dff9a9e4 | ||
|
|
e6b3d6094d | ||
|
|
61ad4282e6 | ||
|
|
e4628d8bbb | ||
|
|
21bd4279a1 | ||
|
|
b6c33fd761 | ||
|
|
1b9d8c48f1 | ||
|
|
55ef307e07 | ||
|
|
894cd51e01 | ||
|
|
880244020e | ||
|
|
9c2f423399 | ||
|
|
654a489f49 | ||
|
|
912af592ae | ||
|
|
6d70439dff | ||
|
|
aec06f775a | ||
|
|
446ffe9466 | ||
|
|
02cad74568 | ||
|
|
33e1ff3b4a | ||
|
|
11f8f00072 | ||
|
|
b59d683fef | ||
|
|
b9f4c7c03a | ||
|
|
2d2c6aa373 | ||
|
|
850af6d140 | ||
|
|
da4cf017bf | ||
|
|
e88dfcdaa1 | ||
|
|
70a940b216 | ||
|
|
db2bb03fdd | ||
|
|
5ef949ae14 | ||
|
|
043028cf7d | ||
|
|
eace5d1dbd | ||
|
|
878bea69d6 | ||
|
|
ae8becc4a3 | ||
|
|
1d863cfb2e | ||
|
|
7bb2bee693 | ||
|
|
47e7f5542e | ||
|
|
8087d11b2b | ||
|
|
4f1521ac90 | ||
|
|
99632397da | ||
|
|
59283815d8 | ||
|
|
a32c901eb8 | ||
|
|
03b84b8ba7 | ||
|
|
720da4e42c | ||
|
|
c4dc799c94 | ||
|
|
ce271ae5eb | ||
|
|
526e5f8709 | ||
|
|
c967e63be9 | ||
|
|
d4a32aee17 | ||
|
|
1191723612 | ||
|
|
addf2e3728 | ||
|
|
4785c8c77c | ||
|
|
b1ac106057 | ||
|
|
acdc40ec60 | ||
|
|
d9f635a6d0 | ||
|
|
e8357c4e6f | ||
|
|
8e44a87069 | ||
|
|
d1befbd355 | ||
|
|
ec0bae5490 | ||
|
|
f5b3b1a936 | ||
|
|
1b546e3bab | ||
|
|
d454899048 | ||
|
|
7aa704b3f4 | ||
|
|
50d7d7ee33 | ||
|
|
586a9c855e | ||
|
|
9600e34229 | ||
|
|
001c97ea00 | ||
|
|
b100dbe26c | ||
|
|
55e38f9db2 |
@@ -14,10 +14,15 @@ jobs:
|
||||
- name: Build
|
||||
run: |
|
||||
cd android
|
||||
ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk-bundle ./gradlew assembleRelease
|
||||
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > keystore.jks
|
||||
JAVA_HOME=$JAVA_HOME_17_X64 ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk-bundle ./gradlew assembleRelease
|
||||
env:
|
||||
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
||||
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
||||
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: xsystem35-release-unsigned-apk
|
||||
path: android/app/build/outputs/apk/release/app-release-unsigned.apk
|
||||
name: xsystem35-apk
|
||||
path: android/app/build/outputs/apk/release/app-release.apk
|
||||
|
||||
@@ -2,7 +2,7 @@ name: Emscripten Build
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
EM_VERSION: 3.1.15
|
||||
EM_VERSION: 3.1.50
|
||||
EM_CACHE_FOLDER: 'emsdk-cache'
|
||||
|
||||
jobs:
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
key: ${{env.EM_VERSION}}-${{ runner.os }}
|
||||
|
||||
- name: Setup Emscripten toolchain
|
||||
uses: mymindstorm/setup-emsdk@v11
|
||||
uses: mymindstorm/setup-emsdk@v13
|
||||
with:
|
||||
version: ${{ env.EM_VERSION }}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- { sys: MINGW32, installer: "xsystem35-32bit" }
|
||||
- { sys: MINGW64, installer: "xsystem35-64bit" }
|
||||
- { sys: UCRT64, installer: "xsystem35-64bit" }
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
@@ -19,7 +19,6 @@ jobs:
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.sys }}
|
||||
update: true
|
||||
pacboy: >-
|
||||
gcc:p
|
||||
cmake:p
|
||||
@@ -30,7 +29,7 @@ jobs:
|
||||
libwebp:p
|
||||
cjson:p
|
||||
nsis:p
|
||||
ntldd-git:p
|
||||
ntldd:p
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -2,7 +2,9 @@ out
|
||||
android/.gradle
|
||||
android/app/.externalNativeBuild
|
||||
android/app/build
|
||||
android/app/src/main/assets
|
||||
android/build
|
||||
android/keystore.jks
|
||||
.ccls-cache
|
||||
.dir-locals.el
|
||||
compile_commands.json
|
||||
|
||||
+2
-5
@@ -110,6 +110,7 @@ endif()
|
||||
|
||||
# CDROM
|
||||
|
||||
list(APPEND SRC_CDROM cdrom.bgm.c)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list(APPEND SRC_CDROM cdrom.Linux.c)
|
||||
list(APPEND SUMMARY_CDROM "Linux ioctl")
|
||||
@@ -122,14 +123,10 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
||||
list(APPEND SRC_CDROM cdrom.emscripten.c)
|
||||
list(APPEND SUMMARY_CDROM "Emscripten")
|
||||
set(ENABLE_CDROM_EMSCRIPTEN 1)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
list(APPEND SRC_CDROM cdrom.android.c)
|
||||
list(APPEND SUMMARY_CDROM "Android")
|
||||
set(ENABLE_CDROM_ANDROID 1)
|
||||
else()
|
||||
list(APPEND SRC_CDROM cdrom.empty.c)
|
||||
endif()
|
||||
if (SDL2MIXER_FOUND AND NOT ANDROID)
|
||||
if (SDL2MIXER_FOUND)
|
||||
list(APPEND SRC_CDROM cdrom.mp3.c)
|
||||
list(APPEND SUMMARY_CDROM "SDL_mixer (wav|mp3|ogg...)")
|
||||
set(ENABLE_CDROM_MP3 1)
|
||||
|
||||
@@ -3,17 +3,22 @@
|
||||
This is a multi-platform port of `xsystem35`, a free implementation of
|
||||
AliceSoft's System 3.x game engine.
|
||||
|
||||
## Compatibility
|
||||
|
||||
See the [game compatibility table](game_compatibility.md) for a list of games
|
||||
that can be played with xsystem35-sdl2.
|
||||
|
||||
## Unique Features
|
||||
|
||||
In addition to the original System 3.x's functionalities, xsystem35-sdl2 has
|
||||
the following features.
|
||||
In addition to the original System 3.x functionalities, xsystem35-sdl2 offers
|
||||
the following features:
|
||||
|
||||
### Playing audio files as fake CD music
|
||||
### Playing Audio Files as Virtual CD Music
|
||||
|
||||
Many System 3.x games had music as audio tracks on the CD-ROM. Xsystem35 can
|
||||
play music from audio files instead, to avoid the hassle of inserting CDs. To
|
||||
use ripped audio files, create a file named `playlist.txt` in the game
|
||||
directory, and enter the paths to your tracks, one per line. For example:
|
||||
Many System 3.x games feature music as audio tracks on the CD-ROM. xsystem35
|
||||
can play music from audio files, eliminating the need to insert CDs. To use
|
||||
ripped audio files, create a file named `playlist.txt` in the game directory
|
||||
and list the paths to your tracks, one per line. For example:
|
||||
|
||||
```
|
||||
# The first line is not used
|
||||
@@ -22,89 +27,109 @@ BGM/track03.mp3
|
||||
...
|
||||
```
|
||||
|
||||
The first line is not used, because track 1 of game CD is usually a data track.
|
||||
The first line is not used because the first track on a game CD is typically a
|
||||
data track.
|
||||
|
||||
### Unicode translation support
|
||||
Some games have integrated music as MIDI. In such cases, the music won't play
|
||||
using the virtual CD feature. If you encounter a `Cannot load MIDI` error
|
||||
message, you might need to set the `SDL_SOUNDFONTS` environment variable to
|
||||
point to an `.sf2` file. For example:
|
||||
|
||||
The original System 3.x only supported Shift_JIS (a Japanese character
|
||||
encoding), but xsystem35 supports Unicode and is able to run games translated
|
||||
into languages other than Japanese and English.
|
||||
```
|
||||
SDL_SOUNDFONTS=/usr/share/soundfonts/GeneralUser.sf2 xsystem35
|
||||
```
|
||||
|
||||
See [xsys35c](https://github.com/kichikuou/xsys35c)'s document for how to
|
||||
build a game with Unicode mode.
|
||||
### Unicode Translation Support
|
||||
|
||||
While the original System 3.x only supported Shift_JIS (a Japanese character
|
||||
encoding), xsystem35 supports Unicode and can run games translated into
|
||||
languages other than Japanese and English.
|
||||
|
||||
For instructions on how to build a game with Unicode support, see the
|
||||
[xsys35c](https://github.com/kichikuou/xsys35c) documentation.
|
||||
|
||||
### Debugging
|
||||
|
||||
Xsystem35 has a built-in debugger that allows you to step through the game and
|
||||
examine / modify variables in the game. There are two ways to use the debugger:
|
||||
xsystem35 features a built-in debugger that allows you to step through the game
|
||||
and examine or modify game variables. There are two ways to use the debugger:
|
||||
|
||||
- Through [Visual Studio Code](https://code.visualstudio.com/) (recommended):
|
||||
The [vscode-system3x](https://github.com/kichikuou/vscode-system3x) extension
|
||||
provides graphical debugging interface for System 3.x.
|
||||
- Using CUI debugger: Running xsystem35 with `-debug` option will start the
|
||||
debugger with console interface. Type `help` to see a list of available
|
||||
commands.
|
||||
provides a graphical debugging interface for System 3.x.
|
||||
- Using the CLI Debugger: Running xsystem35 with the `-debug` option will
|
||||
launch the debugger with a console interface. Type `help` to see a list of
|
||||
available commands.
|
||||
|
||||
## Installing
|
||||
## Installation
|
||||
|
||||
Prebuilt packages for Windows and Android can be downloaded from the
|
||||
[Releases](https://github.com/kichikuou/xsystem35-sdl2/releases) page. For
|
||||
other platforms, see the [Building](#building) section.
|
||||
other platforms, refer to the [Building](#building) section.
|
||||
|
||||
## Running
|
||||
### Windows
|
||||
|
||||
Execute `xsytem35`, and it will show a dialog to select a folder. Select the
|
||||
game folder (where the ALD files are located).
|
||||
Execute `xsystem35`, and a dialog will appear for you to select a folder.
|
||||
Choose the game folder (where the ALD files are located).
|
||||
|
||||
### Android
|
||||
|
||||
See [android/README.md](https://github.com/kichikuou/xsystem35-sdl2/blob/master/android/README.md#use).
|
||||
See [android/README.md](android/README.md#use).
|
||||
|
||||
### Other Platforms
|
||||
|
||||
Run xsystem35 from within the game directory.
|
||||
|
||||
cd /path/to/game_directory
|
||||
xsystem35
|
||||
```bash
|
||||
$ cd /path/to/game_directory
|
||||
$ xsystem35
|
||||
```
|
||||
|
||||
## Building
|
||||
### Linux (Debian / Ubuntu)
|
||||
|
||||
$ sudo apt install build-essential cmake libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libcjson-dev
|
||||
$ mkdir -p out/debug
|
||||
$ cd out/debug
|
||||
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
||||
$ make && make install
|
||||
```bash
|
||||
$ sudo apt install build-essential cmake libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libcjson-dev
|
||||
$ mkdir -p out/debug
|
||||
$ cd out/debug
|
||||
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
||||
$ make && make install
|
||||
```
|
||||
|
||||
### MacOS
|
||||
|
||||
[Homebrew](https://brew.sh/index_ja) is needed.
|
||||
[Homebrew](https://brew.sh/) is required.
|
||||
|
||||
$ brew install cmake pkg-config sdl2 sdl2_mixer sdl2_ttf webp cjson
|
||||
$ mkdir -p out/debug
|
||||
$ cd out/debug
|
||||
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
||||
$ make && make install
|
||||
```bash
|
||||
$ brew install cmake pkg-config sdl2 sdl2_mixer sdl2_ttf webp cjson
|
||||
$ mkdir -p out/debug
|
||||
$ cd out/debug
|
||||
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
|
||||
$ make && make install
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
[MSYS2](https://www.msys2.org) is needed.
|
||||
[MSYS2](https://www.msys2.org) is required.
|
||||
|
||||
$ pacman -S cmake mingw-w64-x86_64-cmake mingw-w64-x86_64-SDL2 mingw-w64-x86_64-SDL2_ttf mingw-w64-x86_64-SDL2_mixer mingw-w64-x86_64-libwebp mingw-w64-x86_64-cjson
|
||||
$ mkdir -p out/debug
|
||||
$ cd out/debug
|
||||
$ cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug ../../
|
||||
$ make
|
||||
```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-cjson
|
||||
$ mkdir -p out/debug
|
||||
$ cd out/debug
|
||||
$ cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug ../../
|
||||
$ make
|
||||
```
|
||||
|
||||
### Emscripten
|
||||
|
||||
$ mkdir -p out/wasm
|
||||
$ cd out/wasm
|
||||
$ emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../../
|
||||
$ make
|
||||
```bash
|
||||
$ mkdir -p out/wasm
|
||||
$ cd out/wasm
|
||||
$ emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../../
|
||||
$ make
|
||||
```
|
||||
|
||||
To use the generated binary, checkout
|
||||
To use the generated binary, check out
|
||||
[Kichikuou on Web](https://github.com/kichikuou/web) and copy `out/xsystem35.*`
|
||||
into its `docs` directory.
|
||||
|
||||
|
||||
+34
-20
@@ -1,7 +1,8 @@
|
||||
# xsystem35 for Android
|
||||
|
||||
## Download
|
||||
Prebuilt APKs are [here](https://github.com/kichikuou/xsystem35-sdl2/releases).
|
||||
You can download prebuilt APKs
|
||||
[here](https://github.com/kichikuou/xsystem35-sdl2/releases).
|
||||
|
||||
## Build
|
||||
Prerequisites:
|
||||
@@ -11,10 +12,10 @@ Prerequisites:
|
||||
### Using Android Studio
|
||||
Open this directory as an Android Studio project.
|
||||
|
||||
### Command line build
|
||||
Configure environment variables and run the `gradlew` script in this folder.
|
||||
### Command Line Build
|
||||
Set environment variables and run the `gradlew` script in this directory.
|
||||
|
||||
Example build instructions (for Debian bullseye):
|
||||
Example build instructions (for Debian bookworm):
|
||||
```sh
|
||||
# Install necessary packages
|
||||
sudo apt install git wget unzip default-jdk-headless ninja-build
|
||||
@@ -22,38 +23,51 @@ sudo apt install git wget unzip default-jdk-headless ninja-build
|
||||
# Install Android SDK / NDK
|
||||
export ANDROID_SDK_ROOT=$HOME/android-sdk
|
||||
mkdir -p $ANDROID_SDK_ROOT/cmdline-tools
|
||||
wget https://dl.google.com/android/repository/commandlinetools-linux-8512546_latest.zip
|
||||
unzip commandlinetools-linux-8512546_latest.zip -d $ANDROID_SDK_ROOT/cmdline-tools
|
||||
wget https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip
|
||||
unzip commandlinetools-linux-10406996_latest.zip -d $ANDROID_SDK_ROOT/cmdline-tools
|
||||
mv $ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools $ANDROID_SDK_ROOT/cmdline-tools/tools
|
||||
yes |$ANDROID_SDK_ROOT/cmdline-tools/tools/bin/sdkmanager --licenses
|
||||
yes | $ANDROID_SDK_ROOT/cmdline-tools/tools/bin/sdkmanager --licenses
|
||||
$ANDROID_SDK_ROOT/cmdline-tools/tools/bin/sdkmanager ndk-bundle 'cmake;3.22.1'
|
||||
export ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk-bundle
|
||||
|
||||
# Check out and build xsystem35
|
||||
# Clone and build xsystem35
|
||||
git clone https://github.com/kichikuou/xsystem35-sdl2.git
|
||||
cd xsystem35-sdl2/android
|
||||
./gradlew build # or ./gradlew installDebug if you have a connected device
|
||||
```
|
||||
|
||||
## Use
|
||||
## Usage
|
||||
### Basic Usage
|
||||
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.
|
||||
2. Open the app. A list of installed games is displayed. Since nothing has been installed yet, only the "Install from ZIP" button is displayed. Tap it.
|
||||
3. Select the ZIP file you created in 1.
|
||||
4. The game starts. To simulate right-click, tap the black bars on the left/right or top/bottom of the screen.
|
||||
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.
|
||||
2. Open the app. A list of installed games will be displayed. Since no games
|
||||
have been installed yet, only the "Install from ZIP" button will be visible.
|
||||
Tap it.
|
||||
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
|
||||
the left or right, or top or bottom of the screen.
|
||||
|
||||
### Preparing a ZIP
|
||||
- Include all files in the `GAMEDATA` folder (`.ALD` files and others). `.EXE` and `.DLL` are not really needed, but you can include them as well.
|
||||
- Music files (`.mp3`, `.ogg` or `.wav`) whose file names end with a number are recognized as BGM files. For example:
|
||||
- Include all files from the `GAMEDATA` folder (such as `.ALD` files and
|
||||
others). `.EXE` and `.DLL` files are not necessary, but you can include them
|
||||
if you want.
|
||||
- Music files (`.mp3`, `.ogg`, or `.wav`) whose filenames end with a number
|
||||
will be recognized as BGM files. For example:
|
||||
- `Track2.mp3`
|
||||
- `15.ogg`
|
||||
- `rance4_03.wav` (This shouldn't be `rance403.wav`, because it would be treated as the 403rd track)
|
||||
- `rance4_03.wav` (Note: The filename shouldn't be `rance403.wav`, as it
|
||||
would be treated as the 403rd track.)
|
||||
|
||||
Note: This form of ZIP can be used in [Kichikuou on Web](http://kichikuou.github.io/web/) as well.
|
||||
Note: This ZIP format is also compatible with
|
||||
[Kichikuou on Web](http://kichikuou.github.io/web/).
|
||||
|
||||
### Miscellaneous
|
||||
- You can export / import saved files using the option menu of the game list.
|
||||
- To uninstall a game, long-tap the title in the game list.
|
||||
- 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.
|
||||
|
||||
## Known Issues
|
||||
- Android versions older than 7.0 cannot handle ZIPs containing Shift-JIS file names. This is the case with some ZIPs distributed on [retroc.net](http://retropc.net/alice/). If you get the error "This type of ZIP is not supported.", unzip the ZIP file on your PC and re-archive it with a modern ZIP creation software.
|
||||
- Android versions older than 7.0 cannot handle ZIP files containing Shift-JIS
|
||||
filenames. This issue occurs with some ZIP files distributed on
|
||||
[retroc.net](http://retropc.net/alice/). If you encounter the error message
|
||||
"This type of ZIP is not supported," unzip the file on your PC and re-archive
|
||||
it using modern ZIP creation software.
|
||||
|
||||
+26
-11
@@ -9,27 +9,38 @@ else {
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
if (buildAsApplication) {
|
||||
namespace "io.github.kichikuou.xsystem35"
|
||||
}
|
||||
compileSdkVersion 34
|
||||
defaultConfig {
|
||||
if (buildAsApplication) {
|
||||
applicationId "io.github.kichikuou.xsystem35"
|
||||
}
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 31
|
||||
versionCode 11
|
||||
versionName "2.6.0"
|
||||
targetSdkVersion 34
|
||||
versionCode 17
|
||||
versionName "2.10.1" + gitRevision()
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static"
|
||||
arguments "-DANDROID_APP_PLATFORM=android-19", "-DANDROID_STL=c++_static"
|
||||
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile rootProject.file('keystore.jks')
|
||||
storePassword System.getenv('KEYSTORE_PASSWORD')
|
||||
keyAlias System.getenv('KEY_ALIAS')
|
||||
keyPassword System.getenv('KEY_PASSWORD')
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
if (rootProject.file('keystore.jks').exists()) {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
applicationVariants.all { variant ->
|
||||
@@ -39,7 +50,6 @@ android {
|
||||
if (!project.hasProperty('EXCLUDE_NATIVE_LIBS')) {
|
||||
sourceSets.main {
|
||||
jniLibs.srcDir 'libs'
|
||||
assets.srcDir '../../fonts'
|
||||
}
|
||||
aaptOptions {
|
||||
// Disable asset compression for fonts.
|
||||
@@ -54,10 +64,10 @@ android {
|
||||
}
|
||||
|
||||
}
|
||||
lintOptions {
|
||||
lint {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
|
||||
if (buildAsLibrary) {
|
||||
libraryVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
@@ -74,4 +84,9 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
|
||||
}
|
||||
|
||||
static String gitRevision() {
|
||||
' (git ' + "git rev-parse --short HEAD".execute().text.trim() + ')'
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(GAME)
|
||||
set(PROJECT_ROOT_DIR ../../..)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
SDL
|
||||
URL https://github.com/libsdl-org/SDL/releases/download/release-2.26.1/SDL2-2.26.1.tar.gz
|
||||
URL_HASH SHA1=08a8cec21ffcebf44e4633a786d594a7811100d2
|
||||
URL https://github.com/libsdl-org/SDL/releases/download/release-2.28.5/SDL2-2.28.5.tar.gz
|
||||
URL_HASH SHA1=50af6b564890d702e57e2a72d6429b43778ed29a
|
||||
)
|
||||
FetchContent_Declare(
|
||||
SDL_ttf
|
||||
@@ -46,4 +47,18 @@ if(NOT sdl_mixer_POPULATED)
|
||||
endif()
|
||||
|
||||
# The main CMakeLists.txt of xsystem35
|
||||
add_subdirectory(../../.. xsystem35)
|
||||
add_subdirectory(${PROJECT_ROOT_DIR} xsystem35)
|
||||
|
||||
# Copy asset files
|
||||
set(ASSETS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/assets)
|
||||
file(MAKE_DIRECTORY ${ASSETS_DIR}/licenses)
|
||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/MTLc3m.ttf ${ASSETS_DIR}/MTLc3m.ttf)
|
||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/mincho.otf ${ASSETS_DIR}/mincho.otf)
|
||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/COPYING ${ASSETS_DIR}/licenses/xsystem35)
|
||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/MTLc3m.ttf.license ${ASSETS_DIR}/licenses/MTLc3m)
|
||||
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/mincho.otf.license ${ASSETS_DIR}/licenses/mincho)
|
||||
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 ${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)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.github.kichikuou.xsystem35"
|
||||
android:installLocation="auto">
|
||||
|
||||
<!-- OpenGL ES 2.0 -->
|
||||
@@ -94,6 +93,17 @@
|
||||
</intent-filter>
|
||||
-->
|
||||
</activity>
|
||||
|
||||
<activity android:name=".LicensesMenuActivity"
|
||||
android:label="@string/action_licenses"
|
||||
android:parentActivityName=".LauncherActivity"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".LicensesActivity"
|
||||
android:parentActivityName=".LicensesMenuActivity"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -37,24 +37,20 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
|
||||
private lateinit var gameRoot: File
|
||||
private lateinit var cdda: CddaPlayer
|
||||
private val midi = MidiPlayer()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
gameRoot = File(intent.getStringExtra(EXTRA_GAME_ROOT)!!)
|
||||
cdda = CddaPlayer(File(gameRoot, Launcher.PLAYLIST_FILE))
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
cdda.onActivityStop()
|
||||
midi.onActivityStop()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
cdda.onActivityResume()
|
||||
midi.onActivityResume()
|
||||
}
|
||||
|
||||
@@ -63,7 +59,9 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
|
||||
override fun getArguments(): Array<String> {
|
||||
return arrayOf("-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!)
|
||||
return arrayOf(
|
||||
"-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!,
|
||||
"-devcd", Launcher.PLAYLIST_FILE)
|
||||
}
|
||||
|
||||
override fun setTitle(title: CharSequence?) {
|
||||
@@ -120,9 +118,6 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
|
||||
// The functions below are called in the SDL thread by JNI.
|
||||
@Suppress("unused") fun cddaStart(track: Int, loop: Boolean) = cdda.start(track, loop)
|
||||
@Suppress("unused") fun cddaStop() = cdda.stop()
|
||||
@Suppress("unused") fun cddaCurrentPosition() = cdda.currentPosition()
|
||||
@Suppress("unused") fun midiStart(path: String, loop: Boolean) = midi.start(path, loop)
|
||||
@Suppress("unused") fun midiStop() = midi.stop()
|
||||
@Suppress("unused") fun midiCurrentPosition() = midi.currentPosition()
|
||||
@@ -156,69 +151,6 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private class CddaPlayer(private val playlistPath: File) {
|
||||
private val playlist =
|
||||
try {
|
||||
playlistPath.readLines()
|
||||
} catch (e: IOException) {
|
||||
Log.e("loadPlaylist", "Cannot load $playlistPath", e)
|
||||
emptyList()
|
||||
}
|
||||
private var currentTrack = 0
|
||||
private val player = MediaPlayer()
|
||||
private var playerPaused = false
|
||||
|
||||
fun start(track: Int, loop: Boolean) {
|
||||
val f = playlist.elementAtOrNull(track - 1)
|
||||
if (f.isNullOrEmpty()) {
|
||||
Log.w("cddaStart", "No playlist entry for track $track")
|
||||
return
|
||||
}
|
||||
Log.v("cddaStart", "$f Loop:$loop")
|
||||
try {
|
||||
player.apply {
|
||||
reset()
|
||||
setDataSource(File(playlistPath.parent, f).path)
|
||||
isLooping = loop
|
||||
prepare()
|
||||
start()
|
||||
}
|
||||
currentTrack = track
|
||||
} catch (e: IOException) {
|
||||
Log.e("cddaStart", "Cannot play $f", e)
|
||||
player.reset()
|
||||
}
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
if (currentTrack > 0 && player.isPlaying) {
|
||||
player.stop()
|
||||
currentTrack = 0
|
||||
}
|
||||
}
|
||||
|
||||
fun currentPosition(): Int {
|
||||
if (currentTrack == 0)
|
||||
return 0
|
||||
val frames = player.currentPosition * 75 / 1000
|
||||
return currentTrack or (frames shl 8)
|
||||
}
|
||||
|
||||
fun onActivityStop() {
|
||||
if (currentTrack > 0 && player.isPlaying) {
|
||||
player.pause()
|
||||
playerPaused = true
|
||||
}
|
||||
}
|
||||
|
||||
fun onActivityResume() {
|
||||
if (playerPaused) {
|
||||
player.start()
|
||||
playerPaused = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MidiPlayer {
|
||||
private val player = MediaPlayer()
|
||||
private var playing = false
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
*/
|
||||
package io.github.kichikuou.xsystem35
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.*
|
||||
import java.lang.StringBuilder
|
||||
import java.nio.charset.Charset
|
||||
@@ -40,9 +42,6 @@ interface LauncherObserver {
|
||||
}
|
||||
|
||||
private const val SAVE_DIR = "save"
|
||||
private const val PROGRESS = 0
|
||||
private const val SUCCESS = 1
|
||||
private const val FAILURE = 2
|
||||
|
||||
class Launcher private constructor(private val rootDir: File) {
|
||||
companion object {
|
||||
@@ -74,31 +73,28 @@ class Launcher private constructor(private val rootDir: File) {
|
||||
updateGameList()
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun install(input: InputStream, archiveName: String?) {
|
||||
val dir = createDirForGame()
|
||||
@SuppressLint("HandlerLeak")
|
||||
val handler = object : Handler() {
|
||||
override fun handleMessage(msg: Message) {
|
||||
when (msg.what) {
|
||||
PROGRESS -> {
|
||||
observer?.onInstallProgress(msg.obj as String)
|
||||
}
|
||||
SUCCESS -> {
|
||||
isInstalling = false
|
||||
observer?.onInstallSuccess(msg.obj as File, archiveName)
|
||||
}
|
||||
FAILURE -> {
|
||||
isInstalling = false
|
||||
observer?.onInstallFailure(msg.obj as Int)
|
||||
isInstalling = true
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
extractFiles(input, dir) { msg ->
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
observer?.onInstallProgress(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
observer?.onInstallSuccess(dir, 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
|
||||
}
|
||||
val t = Thread {
|
||||
extractFiles(input, dir, handler)
|
||||
}
|
||||
t.start()
|
||||
isInstalling = true
|
||||
}
|
||||
|
||||
fun uninstall(id: Int) {
|
||||
@@ -183,32 +179,26 @@ class Launcher private constructor(private val rootDir: File) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractFiles(input: InputStream, outDir: File, handler: Handler) {
|
||||
try {
|
||||
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()
|
||||
handler.sendMessage(handler.obtainMessage(PROGRESS, zipEntry.name))
|
||||
FileOutputStream(path).buffered().use {
|
||||
zip.copyTo(it)
|
||||
}
|
||||
configWriter.maybeAdd(zipEntry.name)
|
||||
private fun extractFiles(input: InputStream, outDir: File, progressCallback: (String) -> Unit) {
|
||||
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)
|
||||
}
|
||||
if (!configWriter.readyToWrite()) {
|
||||
val msgId = if (hadDecodeError) R.string.unsupported_zip else R.string.cannot_find_ald
|
||||
handler.sendMessage(handler.obtainMessage(FAILURE, msgId))
|
||||
return
|
||||
}
|
||||
configWriter.write(outDir)
|
||||
handler.sendMessage(handler.obtainMessage(SUCCESS, outDir))
|
||||
} catch (e: IOException) {
|
||||
Log.e("launcher", "Failed to extract ZIP", e)
|
||||
handler.sendMessage(handler.obtainMessage(FAILURE, R.string.zip_extraction_error))
|
||||
configWriter.maybeAdd(zipEntry.name)
|
||||
}
|
||||
if (!configWriter.readyToWrite()) {
|
||||
if (hadDecodeError)
|
||||
throw InstallFailureException(R.string.unsupported_zip)
|
||||
throw InstallFailureException(R.string.cannot_find_ald)
|
||||
}
|
||||
configWriter.write(outDir)
|
||||
}
|
||||
|
||||
// Xsystem35-sdl2 <=2.2.0 had a bug where playlist had an extra empty line at
|
||||
@@ -219,12 +209,14 @@ class Launcher private constructor(private val rootDir: File) {
|
||||
if (!oldPlaylist.exists())
|
||||
return
|
||||
var tracks = oldPlaylist.readLines()
|
||||
if (!tracks.isEmpty())
|
||||
if (tracks.isNotEmpty())
|
||||
tracks = tracks.subList(1, tracks.size)
|
||||
File(dir, PLAYLIST_FILE).writeText(tracks.joinToString("\n"))
|
||||
oldPlaylist.delete()
|
||||
}
|
||||
|
||||
class InstallFailureException(val msgId: Int) : Exception()
|
||||
|
||||
// A helper class which generates xsystem35.gr and playlist.txt in the game root directory.
|
||||
private class GameConfigWriter {
|
||||
private val grb = StringBuilder()
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ListView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import java.io.*
|
||||
|
||||
@@ -34,10 +35,11 @@ private const val CONTENT_TYPE_ZIP = "application/zip"
|
||||
private const val INSTALL_REQUEST = 1
|
||||
private const val SAVEDATA_EXPORT_REQUEST = 2
|
||||
private const val SAVEDATA_IMPORT_REQUEST = 3
|
||||
private const val STATE_PROGRESS_TEXT = "progressText"
|
||||
|
||||
class LauncherActivity : Activity(), LauncherObserver {
|
||||
private lateinit var launcher: Launcher
|
||||
private var progressDialog: ProgressDialogFragment? = null
|
||||
private var progressDialog: Dialog? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -46,7 +48,7 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
launcher = Launcher.getInstance(filesDir)
|
||||
launcher.observer = this
|
||||
if (launcher.isInstalling) {
|
||||
showProgressDialog()
|
||||
showProgressDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
onGameListChange()
|
||||
@@ -61,9 +63,17 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
|
||||
override fun onDestroy() {
|
||||
launcher.observer = null
|
||||
dismissProgressDialog()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
progressDialog?.let {
|
||||
outState.putCharSequence(STATE_PROGRESS_TEXT, it.findViewById<TextView>(R.id.text).text)
|
||||
}
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
private fun onListItemClick(position: Int) {
|
||||
if (position < launcher.games.size) {
|
||||
startGame(launcher.games[position].path, null)
|
||||
@@ -106,6 +116,11 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
SAVEDATA_IMPORT_REQUEST)
|
||||
true
|
||||
}
|
||||
R.id.licenses -> {
|
||||
val intent = Intent(this, LicensesMenuActivity::class.java)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
@@ -148,7 +163,7 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
}
|
||||
|
||||
override fun onInstallProgress(path: String) {
|
||||
progressDialog?.setProgress(getString(R.string.install_progress, path))
|
||||
progressDialog?.findViewById<TextView>(R.id.text)?.text = getString(R.string.install_progress, path)
|
||||
}
|
||||
|
||||
override fun onInstallSuccess(path: File, archiveName: String?) {
|
||||
@@ -173,9 +188,17 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
launcher.uninstall(id)
|
||||
}
|
||||
|
||||
private fun showProgressDialog() {
|
||||
progressDialog = ProgressDialogFragment()
|
||||
progressDialog!!.show(fragmentManager, "progress_dialog")
|
||||
private fun showProgressDialog(savedInstanceState: Bundle? = null) {
|
||||
progressDialog = Dialog(this)
|
||||
progressDialog!!.apply {
|
||||
setTitle(R.string.install_dialog_title)
|
||||
setCancelable(false)
|
||||
setContentView(R.layout.progress_dialog)
|
||||
savedInstanceState?.let {
|
||||
findViewById<TextView>(R.id.text)?.text = it.getCharSequence(STATE_PROGRESS_TEXT)
|
||||
}
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissProgressDialog() {
|
||||
@@ -204,18 +227,3 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION") // for ProgressDialog
|
||||
class ProgressDialogFragment : DialogFragment() {
|
||||
private lateinit var dialog: ProgressDialog
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
dialog = ProgressDialog(activity)
|
||||
return dialog.apply {
|
||||
setTitle(R.string.install_dialog_title)
|
||||
setCancelable(true)
|
||||
}
|
||||
}
|
||||
fun setProgress(msg: String) {
|
||||
dialog.setMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.github.kichikuou.xsystem35
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.widget.TextView
|
||||
import java.io.BufferedReader
|
||||
|
||||
class LicensesActivity : Activity() {
|
||||
companion object {
|
||||
const val EXTRA_DISPLAY_NAME = "DISPLAY_NAME"
|
||||
const val EXTRA_FILE_NAME = "FILE_NAME"
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_licenses)
|
||||
|
||||
actionBar?.title = intent.getStringExtra(EXTRA_DISPLAY_NAME)
|
||||
val path = "licenses/" + intent.getStringExtra(EXTRA_FILE_NAME)
|
||||
val text = assets.open(path).bufferedReader().use(BufferedReader::readText)
|
||||
findViewById<TextView>(R.id.license_text).text = text
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package io.github.kichikuou.xsystem35
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.ListView
|
||||
import android.widget.SimpleAdapter
|
||||
|
||||
class LicensesMenuActivity : Activity() {
|
||||
class Entry(val displayName: String, val fileName: String, val url: String)
|
||||
private val entries: ArrayList<Entry> = arrayListOf(
|
||||
Entry("xsystem35-sdl2", "xsystem35", "https://github.com/kichikuou/xsystem35-sdl2"),
|
||||
Entry("SDL", "SDL", "https://www.libsdl.org/"),
|
||||
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("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("Source Han Serif", "mincho", "https://github.com/adobe-fonts/source-han-serif/"),
|
||||
)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_licenses_menu)
|
||||
|
||||
val items = entries.map { mapOf("name" to it.displayName, "url" to it.url)}
|
||||
val listView = findViewById<ListView>(R.id.list)
|
||||
listView.adapter = SimpleAdapter(this, items, android.R.layout.simple_list_item_2,
|
||||
arrayOf("name", "url"), intArrayOf(android.R.id.text1, android.R.id.text2))
|
||||
listView.setOnItemClickListener { _, _, pos, _ ->
|
||||
val intent = Intent(this, LicensesActivity::class.java).apply {
|
||||
putExtra(LicensesActivity.EXTRA_DISPLAY_NAME, entries[pos].displayName)
|
||||
putExtra(LicensesActivity.EXTRA_FILE_NAME, entries[pos].fileName)
|
||||
}
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||
// Because on Chromebooks we show up as a dual-mode device, it will attempt to connect TRANSPORT_AUTO, which will use TRANSPORT_BREDR instead
|
||||
// of TRANSPORT_LE. Let's force ourselves to connect low energy.
|
||||
private BluetoothGatt connectGatt(boolean managed) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (Build.VERSION.SDK_INT >= 23 /* Android 6.0 (M) */) {
|
||||
try {
|
||||
return mDevice.connectGatt(mManager.getContext(), managed, this, TRANSPORT_LE);
|
||||
} catch (Exception e) {
|
||||
@@ -429,7 +429,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (newState == 0) {
|
||||
mIsConnected = false;
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ public class HIDDeviceManager {
|
||||
Log.i(TAG," Interface protocol: " + mUsbInterface.getInterfaceProtocol());
|
||||
Log.i(TAG," Endpoint count: " + mUsbInterface.getEndpointCount());
|
||||
|
||||
// Get endpoint details
|
||||
// Get endpoint details
|
||||
for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
|
||||
{
|
||||
UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
|
||||
@@ -251,6 +251,8 @@ public class HIDDeviceManager {
|
||||
0x20d6, // PowerA
|
||||
0x24c6, // PowerA
|
||||
0x2c22, // Qanba
|
||||
0x2dc8, // 8BitDo
|
||||
0x9886, // ASTRO Gaming
|
||||
};
|
||||
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
|
||||
@@ -271,14 +273,17 @@ public class HIDDeviceManager {
|
||||
final int XB1_IFACE_SUBCLASS = 71;
|
||||
final int XB1_IFACE_PROTOCOL = 208;
|
||||
final int[] SUPPORTED_VENDORS = {
|
||||
0x03f0, // HP
|
||||
0x044f, // Thrustmaster
|
||||
0x045e, // Microsoft
|
||||
0x0738, // Mad Catz
|
||||
0x0e6f, // PDP
|
||||
0x0f0d, // Hori
|
||||
0x10f5, // Turtle Beach
|
||||
0x1532, // Razer Wildcat
|
||||
0x20d6, // PowerA
|
||||
0x24c6, // PowerA
|
||||
0x2dc8, /* 8BitDo */
|
||||
0x2dc8, // 8BitDo
|
||||
0x2e24, // Hyperkin
|
||||
};
|
||||
|
||||
@@ -353,13 +358,13 @@ public class HIDDeviceManager {
|
||||
private void initializeBluetooth() {
|
||||
Log.d(TAG, "Initializing Bluetooth");
|
||||
|
||||
if (Build.VERSION.SDK_INT <= 30 &&
|
||||
if (Build.VERSION.SDK_INT <= 30 /* Android 11.0 (R) */ &&
|
||||
mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || (Build.VERSION.SDK_INT < 18)) {
|
||||
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || (Build.VERSION.SDK_INT < 18 /* Android 4.3 (JELLY_BEAN_MR2) */)) {
|
||||
Log.d(TAG, "Couldn't initialize Bluetooth, this version of Android does not support Bluetooth LE");
|
||||
return;
|
||||
}
|
||||
@@ -524,7 +529,7 @@ public class HIDDeviceManager {
|
||||
for (HIDDevice device : mDevicesById.values()) {
|
||||
device.setFrozen(frozen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -573,7 +578,7 @@ public class HIDDeviceManager {
|
||||
try {
|
||||
final int FLAG_MUTABLE = 0x02000000; // PendingIntent.FLAG_MUTABLE, but don't require SDK 31
|
||||
int flags;
|
||||
if (Build.VERSION.SDK_INT >= 31) {
|
||||
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
|
||||
flags = FLAG_MUTABLE;
|
||||
} else {
|
||||
flags = 0;
|
||||
|
||||
@@ -52,7 +52,7 @@ class HIDDeviceUSB implements HIDDevice {
|
||||
@Override
|
||||
public String getSerialNumber() {
|
||||
String result = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
|
||||
try {
|
||||
result = mDevice.getSerialNumber();
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class HIDDeviceUSB implements HIDDevice {
|
||||
@Override
|
||||
public String getManufacturerName() {
|
||||
String result = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
|
||||
result = mDevice.getManufacturerName();
|
||||
}
|
||||
if (result == null) {
|
||||
@@ -86,7 +86,7 @@ class HIDDeviceUSB implements HIDDevice {
|
||||
@Override
|
||||
public String getProductName() {
|
||||
String result = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
|
||||
result = mDevice.getProductName();
|
||||
}
|
||||
if (result == null) {
|
||||
|
||||
@@ -29,6 +29,7 @@ public class SDL {
|
||||
|
||||
// This function stores the current activity (SDL or not)
|
||||
public static void setContext(Context context) {
|
||||
SDLAudioManager.setContext(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ import java.util.Locale;
|
||||
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
|
||||
private static final String TAG = "SDL";
|
||||
private static final int SDL_MAJOR_VERSION = 2;
|
||||
private static final int SDL_MINOR_VERSION = 26;
|
||||
private static final int SDL_MICRO_VERSION = 1;
|
||||
private static final int SDL_MINOR_VERSION = 28;
|
||||
private static final int SDL_MICRO_VERSION = 5;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
@@ -93,7 +93,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
|
||||
s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
tst = InputDevice.SOURCE_BLUETOOTH_STYLUS;
|
||||
if ((s & tst) == tst) src += " BLUETOOTH_STYLUS";
|
||||
s2 &= ~tst;
|
||||
@@ -107,7 +107,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
if ((s & tst) == tst) src += " GAMEPAD";
|
||||
s2 &= ~tst;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
tst = InputDevice.SOURCE_HDMI;
|
||||
if ((s & tst) == tst) src += " HDMI";
|
||||
s2 &= ~tst;
|
||||
@@ -146,7 +146,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
if ((s & tst) == tst) src += " TOUCHSCREEN";
|
||||
s2 &= ~tst;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
tst = InputDevice.SOURCE_TOUCH_NAVIGATION;
|
||||
if ((s & tst) == tst) src += " TOUCH_NAVIGATION";
|
||||
s2 &= ~tst;
|
||||
@@ -170,7 +170,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
*/
|
||||
|
||||
public static boolean mIsResumedCalled, mHasFocus;
|
||||
public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24);
|
||||
public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */);
|
||||
|
||||
// Cursor types
|
||||
// private static final int SDL_SYSTEM_CURSOR_NONE = -1;
|
||||
@@ -224,9 +224,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
|
||||
protected static SDLGenericMotionListener_API12 getMotionListener() {
|
||||
if (mMotionListener == null) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
|
||||
mMotionListener = new SDLGenericMotionListener_API26();
|
||||
} else if (Build.VERSION.SDK_INT >= 24) {
|
||||
} else if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
mMotionListener = new SDLGenericMotionListener_API24();
|
||||
} else {
|
||||
mMotionListener = new SDLGenericMotionListener_API12();
|
||||
@@ -393,7 +393,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
mHIDDeviceManager = HIDDeviceManager.acquire(this);
|
||||
|
||||
// Set up the surface
|
||||
mSurface = createSDLSurface(getApplication());
|
||||
mSurface = createSDLSurface(this);
|
||||
|
||||
mLayout = new RelativeLayout(this);
|
||||
mLayout.addView(mSurface);
|
||||
@@ -404,7 +404,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
SDLActivity.onNativeOrientationChanged(mCurrentOrientation);
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < 24) {
|
||||
if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) {
|
||||
mCurrentLocale = getContext().getResources().getConfiguration().locale;
|
||||
} else {
|
||||
mCurrentLocale = getContext().getResources().getConfiguration().getLocales().get(0);
|
||||
@@ -588,6 +588,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
mHIDDeviceManager = null;
|
||||
}
|
||||
|
||||
SDLAudioManager.release(this);
|
||||
|
||||
if (SDLActivity.mBrokenLibraries) {
|
||||
super.onDestroy();
|
||||
return;
|
||||
@@ -766,7 +768,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
}
|
||||
break;
|
||||
case COMMAND_CHANGE_WINDOW_STYLE:
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
|
||||
if (context instanceof Activity) {
|
||||
Window window = ((Activity) context).getWindow();
|
||||
if (window != null) {
|
||||
@@ -841,7 +843,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
msg.obj = data;
|
||||
boolean result = commandHandler.sendMessage(msg);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
|
||||
if (command == COMMAND_CHANGE_WINDOW_STYLE) {
|
||||
// Ensure we don't return until the resize has actually happened,
|
||||
// or 500ms have passed.
|
||||
@@ -969,15 +971,18 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
/* If set, hint "explicitly controls which UI orientations are allowed". */
|
||||
if (hint.contains("LandscapeRight") && hint.contains("LandscapeLeft")) {
|
||||
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
||||
} else if (hint.contains("LandscapeRight")) {
|
||||
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||
} else if (hint.contains("LandscapeLeft")) {
|
||||
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||
} else if (hint.contains("LandscapeRight")) {
|
||||
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
|
||||
}
|
||||
|
||||
if (hint.contains("Portrait") && hint.contains("PortraitUpsideDown")) {
|
||||
/* exact match to 'Portrait' to distinguish with PortraitUpsideDown */
|
||||
boolean contains_Portrait = hint.contains("Portrait ") || hint.endsWith("Portrait");
|
||||
|
||||
if (contains_Portrait && hint.contains("PortraitUpsideDown")) {
|
||||
orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
|
||||
} else if (hint.contains("Portrait")) {
|
||||
} else if (contains_Portrait) {
|
||||
orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
} else if (hint.contains("PortraitUpsideDown")) {
|
||||
orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
|
||||
@@ -1090,7 +1095,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
// thus SDK version 27. If we are in DeX mode and not API 27 or higher, as a result,
|
||||
// we should stick to relative mode.
|
||||
//
|
||||
if ((Build.VERSION.SDK_INT < 27) && isDeXMode()) {
|
||||
if (Build.VERSION.SDK_INT < 27 /* Android 8.1 (O_MR1) */ && isDeXMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1180,7 +1185,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static boolean isDeXMode() {
|
||||
if (Build.VERSION.SDK_INT < 24) {
|
||||
if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
@@ -1340,23 +1345,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
}
|
||||
}
|
||||
|
||||
if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (isTextInputEvent(event)) {
|
||||
if (ic != null) {
|
||||
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
} else {
|
||||
SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
}
|
||||
}
|
||||
onNativeKeyDown(keyCode);
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
onNativeKeyUp(keyCode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
||||
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
|
||||
// they are ignored here because sending them as mouse input to SDL is messy
|
||||
@@ -1371,6 +1359,21 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (isTextInputEvent(event)) {
|
||||
if (ic != null) {
|
||||
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
} else {
|
||||
SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
}
|
||||
}
|
||||
onNativeKeyDown(keyCode);
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
onNativeKeyUp(keyCode);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1617,7 +1620,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
private final Runnable rehideSystemUi = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
|
||||
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
|
||||
@@ -1670,7 +1673,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
|
||||
++mLastCursorID;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
try {
|
||||
mCursors.put(mLastCursorID, PointerIcon.create(bitmap, hotSpotX, hotSpotY));
|
||||
} catch (Exception e) {
|
||||
@@ -1686,7 +1689,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void destroyCustomCursor(int cursorID) {
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
try {
|
||||
mCursors.remove(cursorID);
|
||||
} catch (Exception e) {
|
||||
@@ -1700,7 +1703,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
*/
|
||||
public static boolean setCustomCursor(int cursorID) {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
try {
|
||||
mSurface.setPointerIcon(mCursors.get(cursorID));
|
||||
} catch (Exception e) {
|
||||
@@ -1755,7 +1758,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
cursor_type = 1002; //PointerIcon.TYPE_HAND;
|
||||
break;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
try {
|
||||
mSurface.setPointerIcon(PointerIcon.getSystemIcon(SDL.getContext(), cursor_type));
|
||||
} catch (Exception e) {
|
||||
@@ -1769,7 +1772,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void requestPermission(String permission, int requestCode) {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
|
||||
nativePermissionResult(requestCode, true);
|
||||
return;
|
||||
}
|
||||
@@ -1798,7 +1801,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
i.setData(Uri.parse(url));
|
||||
|
||||
int flags = Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
|
||||
flags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
|
||||
} else {
|
||||
flags |= Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
|
||||
@@ -2002,6 +2005,18 @@ class SDLInputConnection extends BaseInputConnection {
|
||||
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
if (Build.VERSION.SDK_INT <= 29 /* Android 10.0 (Q) */) {
|
||||
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection
|
||||
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
|
||||
if (beforeLength > 0 && afterLength == 0) {
|
||||
// backspace(s)
|
||||
while (beforeLength-- > 0) {
|
||||
nativeGenerateScancodeForUnichar('\b');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.libsdl.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioDeviceCallback;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioRecord;
|
||||
@@ -8,34 +11,67 @@ import android.media.MediaRecorder;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
public class SDLAudioManager
|
||||
{
|
||||
import java.util.Arrays;
|
||||
|
||||
public class SDLAudioManager {
|
||||
protected static final String TAG = "SDLAudio";
|
||||
|
||||
protected static AudioTrack mAudioTrack;
|
||||
protected static AudioRecord mAudioRecord;
|
||||
protected static Context mContext;
|
||||
|
||||
private static final int[] NO_DEVICES = {};
|
||||
|
||||
private static AudioDeviceCallback mAudioDeviceCallback;
|
||||
|
||||
public static void initialize() {
|
||||
mAudioTrack = null;
|
||||
mAudioRecord = null;
|
||||
mAudioDeviceCallback = null;
|
||||
|
||||
if(Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */)
|
||||
{
|
||||
mAudioDeviceCallback = new AudioDeviceCallback() {
|
||||
@Override
|
||||
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
|
||||
Arrays.stream(addedDevices).forEach(deviceInfo -> addAudioDevice(deviceInfo.isSink(), deviceInfo.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
|
||||
Arrays.stream(removedDevices).forEach(deviceInfo -> removeAudioDevice(deviceInfo.isSink(), deviceInfo.getId()));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static void setContext(Context context) {
|
||||
mContext = context;
|
||||
if (context != null) {
|
||||
registerAudioDeviceCallback();
|
||||
}
|
||||
}
|
||||
|
||||
public static void release(Context context) {
|
||||
unregisterAudioDeviceCallback(context);
|
||||
}
|
||||
|
||||
// Audio
|
||||
|
||||
protected static String getAudioFormatString(int audioFormat) {
|
||||
switch (audioFormat) {
|
||||
case AudioFormat.ENCODING_PCM_8BIT:
|
||||
return "8-bit";
|
||||
case AudioFormat.ENCODING_PCM_16BIT:
|
||||
return "16-bit";
|
||||
case AudioFormat.ENCODING_PCM_FLOAT:
|
||||
return "float";
|
||||
default:
|
||||
return Integer.toString(audioFormat);
|
||||
case AudioFormat.ENCODING_PCM_8BIT:
|
||||
return "8-bit";
|
||||
case AudioFormat.ENCODING_PCM_16BIT:
|
||||
return "16-bit";
|
||||
case AudioFormat.ENCODING_PCM_FLOAT:
|
||||
return "float";
|
||||
default:
|
||||
return Integer.toString(audioFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
|
||||
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
|
||||
int channelConfig;
|
||||
int sampleSize;
|
||||
int frameSize;
|
||||
@@ -43,14 +79,14 @@ public class SDLAudioManager
|
||||
Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", requested " + desiredFrames + " frames of " + desiredChannels + " channel " + getAudioFormatString(audioFormat) + " audio at " + sampleRate + " Hz");
|
||||
|
||||
/* On older devices let's use known good settings */
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
if (Build.VERSION.SDK_INT < 21 /* Android 5.0 (LOLLIPOP) */) {
|
||||
if (desiredChannels > 2) {
|
||||
desiredChannels = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* AudioTrack has sample rate limitation of 48000 (fixed in 5.0.2) */
|
||||
if (Build.VERSION.SDK_INT < 22) {
|
||||
if (Build.VERSION.SDK_INT < 22 /* Android 5.1 (LOLLIPOP_MR1) */) {
|
||||
if (sampleRate < 8000) {
|
||||
sampleRate = 8000;
|
||||
} else if (sampleRate > 48000) {
|
||||
@@ -59,7 +95,7 @@ public class SDLAudioManager
|
||||
}
|
||||
|
||||
if (audioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
|
||||
int minSDKVersion = (isCapture ? 23 : 21);
|
||||
int minSDKVersion = (isCapture ? 23 /* Android 6.0 (M) */ : 21 /* Android 5.0 (LOLLIPOP) */);
|
||||
if (Build.VERSION.SDK_INT < minSDKVersion) {
|
||||
audioFormat = AudioFormat.ENCODING_PCM_16BIT;
|
||||
}
|
||||
@@ -120,7 +156,7 @@ public class SDLAudioManager
|
||||
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER;
|
||||
break;
|
||||
case 8:
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (Build.VERSION.SDK_INT >= 23 /* Android 6.0 (M) */) {
|
||||
channelConfig = AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
|
||||
} else {
|
||||
Log.v(TAG, "Requested " + desiredChannels + " channels, getting 5.1 surround");
|
||||
@@ -201,6 +237,10 @@ public class SDLAudioManager
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */ && deviceId != 0) {
|
||||
mAudioRecord.setPreferredDevice(getOutputAudioDeviceInfo(deviceId));
|
||||
}
|
||||
|
||||
mAudioRecord.startRecording();
|
||||
}
|
||||
|
||||
@@ -224,6 +264,10 @@ public class SDLAudioManager
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */ && deviceId != 0) {
|
||||
mAudioTrack.setPreferredDevice(getInputAudioDeviceInfo(deviceId));
|
||||
}
|
||||
|
||||
mAudioTrack.play();
|
||||
}
|
||||
|
||||
@@ -238,11 +282,73 @@ public class SDLAudioManager
|
||||
return results;
|
||||
}
|
||||
|
||||
private static AudioDeviceInfo getInputAudioDeviceInfo(int deviceId) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
|
||||
.filter(deviceInfo -> deviceInfo.getId() == deviceId)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static AudioDeviceInfo getOutputAudioDeviceInfo(int deviceId) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS))
|
||||
.filter(deviceInfo -> deviceInfo.getId() == deviceId)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerAudioDeviceCallback() {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.registerAudioDeviceCallback(mAudioDeviceCallback, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void unregisterAudioDeviceCallback(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
|
||||
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames);
|
||||
public static int[] getAudioOutputDevices() {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)).mapToInt(AudioDeviceInfo::getId).toArray();
|
||||
} else {
|
||||
return NO_DEVICES;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static int[] getAudioInputDevices() {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).mapToInt(AudioDeviceInfo::getId).toArray();
|
||||
} else {
|
||||
return NO_DEVICES;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
|
||||
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames, deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,6 +360,11 @@ public class SDLAudioManager
|
||||
return;
|
||||
}
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT < 21 /* Android 5.0 (LOLLIPOP) */) {
|
||||
Log.e(TAG, "Attempted to make an incompatible audio call with uninitialized audio! (floating-point output is supported since Android 5.0 Lollipop)");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < buffer.length;) {
|
||||
int result = mAudioTrack.write(buffer, i, buffer.length - i, AudioTrack.WRITE_BLOCKING);
|
||||
if (result > 0) {
|
||||
@@ -326,18 +437,22 @@ public class SDLAudioManager
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
|
||||
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames);
|
||||
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
|
||||
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames, deviceId);
|
||||
}
|
||||
|
||||
/** This method is called by SDL using JNI. */
|
||||
public static int captureReadFloatBuffer(float[] buffer, boolean blocking) {
|
||||
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
|
||||
return 0;
|
||||
} else {
|
||||
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||
}
|
||||
}
|
||||
|
||||
/** This method is called by SDL using JNI. */
|
||||
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
|
||||
return mAudioRecord.read(buffer, 0, buffer.length);
|
||||
} else {
|
||||
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||
@@ -346,7 +461,7 @@ public class SDLAudioManager
|
||||
|
||||
/** This method is called by SDL using JNI. */
|
||||
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
|
||||
return mAudioRecord.read(buffer, 0, buffer.length);
|
||||
} else {
|
||||
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||
@@ -391,4 +506,9 @@ public class SDLAudioManager
|
||||
}
|
||||
|
||||
public static native int nativeSetupJNI();
|
||||
|
||||
public static native void removeAudioDevice(boolean isCapture, int deviceId);
|
||||
|
||||
public static native void addAudioDevice(boolean isCapture, int deviceId);
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class SDLControllerManager
|
||||
public static native int nativeAddJoystick(int device_id, String name, String desc,
|
||||
int vendor_id, int product_id,
|
||||
boolean is_accelerometer, int button_mask,
|
||||
int naxes, int nhats, int nballs);
|
||||
int naxes, int axis_mask, int nhats, int nballs);
|
||||
public static native int nativeRemoveJoystick(int device_id);
|
||||
public static native int nativeAddHaptic(int device_id, String name);
|
||||
public static native int nativeRemoveHaptic(int device_id);
|
||||
@@ -42,7 +42,7 @@ public class SDLControllerManager
|
||||
|
||||
public static void initialize() {
|
||||
if (mJoystickHandler == null) {
|
||||
if (Build.VERSION.SDK_INT >= 19) {
|
||||
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
|
||||
mJoystickHandler = new SDLJoystickHandler_API19();
|
||||
} else {
|
||||
mJoystickHandler = new SDLJoystickHandler_API16();
|
||||
@@ -50,7 +50,7 @@ public class SDLControllerManager
|
||||
}
|
||||
|
||||
if (mHapticHandler == null) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
|
||||
mHapticHandler = new SDLHapticHandler_API26();
|
||||
} else {
|
||||
mHapticHandler = new SDLHapticHandler();
|
||||
@@ -168,6 +168,32 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
|
||||
arg1Axis = MotionEvent.AXIS_GAS;
|
||||
}
|
||||
|
||||
// Make sure the AXIS_Z is sorted between AXIS_RY and AXIS_RZ.
|
||||
// This is because the usual pairing are:
|
||||
// - AXIS_X + AXIS_Y (left stick).
|
||||
// - AXIS_RX, AXIS_RY (sometimes the right stick, sometimes triggers).
|
||||
// - AXIS_Z, AXIS_RZ (sometimes the right stick, sometimes triggers).
|
||||
// This sorts the axes in the above order, which tends to be correct
|
||||
// for Xbox-ish game pads that have the right stick on RX/RY and the
|
||||
// triggers on Z/RZ.
|
||||
//
|
||||
// Gamepads that don't have AXIS_Z/AXIS_RZ but use
|
||||
// AXIS_LTRIGGER/AXIS_RTRIGGER are unaffected by this.
|
||||
//
|
||||
// References:
|
||||
// - https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input
|
||||
// - https://www.kernel.org/doc/html/latest/input/gamepad.html
|
||||
if (arg0Axis == MotionEvent.AXIS_Z) {
|
||||
arg0Axis = MotionEvent.AXIS_RZ - 1;
|
||||
} else if (arg0Axis > MotionEvent.AXIS_Z && arg0Axis < MotionEvent.AXIS_RZ) {
|
||||
--arg0Axis;
|
||||
}
|
||||
if (arg1Axis == MotionEvent.AXIS_Z) {
|
||||
arg1Axis = MotionEvent.AXIS_RZ - 1;
|
||||
} else if (arg1Axis > MotionEvent.AXIS_Z && arg1Axis < MotionEvent.AXIS_RZ) {
|
||||
--arg1Axis;
|
||||
}
|
||||
|
||||
return arg0Axis - arg1Axis;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +236,7 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
|
||||
mJoysticks.add(joystick);
|
||||
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
|
||||
getVendorId(joystickDevice), getProductId(joystickDevice), false,
|
||||
getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
|
||||
getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,6 +317,9 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
|
||||
public int getVendorId(InputDevice joystickDevice) {
|
||||
return 0;
|
||||
}
|
||||
public int getAxisMask(List<InputDevice.MotionRange> ranges) {
|
||||
return -1;
|
||||
}
|
||||
public int getButtonMask(InputDevice joystickDevice) {
|
||||
return -1;
|
||||
}
|
||||
@@ -308,6 +337,43 @@ class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
|
||||
return joystickDevice.getVendorId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAxisMask(List<InputDevice.MotionRange> ranges) {
|
||||
// For compatibility, keep computing the axis mask like before,
|
||||
// only really distinguishing 2, 4 and 6 axes.
|
||||
int axis_mask = 0;
|
||||
if (ranges.size() >= 2) {
|
||||
// ((1 << SDL_GAMEPAD_AXIS_LEFTX) | (1 << SDL_GAMEPAD_AXIS_LEFTY))
|
||||
axis_mask |= 0x0003;
|
||||
}
|
||||
if (ranges.size() >= 4) {
|
||||
// ((1 << SDL_GAMEPAD_AXIS_RIGHTX) | (1 << SDL_GAMEPAD_AXIS_RIGHTY))
|
||||
axis_mask |= 0x000c;
|
||||
}
|
||||
if (ranges.size() >= 6) {
|
||||
// ((1 << SDL_GAMEPAD_AXIS_LEFT_TRIGGER) | (1 << SDL_GAMEPAD_AXIS_RIGHT_TRIGGER))
|
||||
axis_mask |= 0x0030;
|
||||
}
|
||||
// Also add an indicator bit for whether the sorting order has changed.
|
||||
// This serves to disable outdated gamecontrollerdb.txt mappings.
|
||||
boolean have_z = false;
|
||||
boolean have_past_z_before_rz = false;
|
||||
for (InputDevice.MotionRange range : ranges) {
|
||||
int axis = range.getAxis();
|
||||
if (axis == MotionEvent.AXIS_Z) {
|
||||
have_z = true;
|
||||
} else if (axis > MotionEvent.AXIS_Z && axis < MotionEvent.AXIS_RZ) {
|
||||
have_past_z_before_rz = true;
|
||||
}
|
||||
}
|
||||
if (have_z && have_past_z_before_rz) {
|
||||
// If both these exist, the compare() function changed sorting order.
|
||||
// Set a bit to indicate this fact.
|
||||
axis_mask |= 0x8000;
|
||||
}
|
||||
return axis_mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonMask(InputDevice joystickDevice) {
|
||||
int button_mask = 0;
|
||||
@@ -743,7 +809,7 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
|
||||
|
||||
@Override
|
||||
public boolean supportsRelativeMouse() {
|
||||
return (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27));
|
||||
return (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -753,7 +819,7 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
|
||||
|
||||
@Override
|
||||
public boolean setRelativeMouseEnabled(boolean enabled) {
|
||||
if (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27)) {
|
||||
if (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */) {
|
||||
if (enabled) {
|
||||
SDLActivity.getContentView().requestPointerCapture();
|
||||
} else {
|
||||
|
||||
@@ -116,7 +116,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
int nDeviceHeight = height;
|
||||
try
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
if (Build.VERSION.SDK_INT >= 17 /* Android 4.2 (JELLY_BEAN_MR1) */) {
|
||||
DisplayMetrics realMetrics = new DisplayMetrics();
|
||||
mDisplay.getRealMetrics( realMetrics );
|
||||
nDeviceWidth = realMetrics.widthPixels;
|
||||
@@ -163,7 +163,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
|
||||
// Don't skip in MultiWindow.
|
||||
if (skip) {
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
|
||||
if (SDLActivity.mSingleton.isInMultiWindowMode()) {
|
||||
Log.v("SDL", "Don't skip in Multi-Window");
|
||||
skip = false;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<TextView android:id="@+id/license_text"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="20dp" />
|
||||
</ScrollView>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<ListView android:id="@+id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textSize="16sp"/>
|
||||
</LinearLayout>
|
||||
@@ -6,4 +6,7 @@
|
||||
<item
|
||||
android:id="@+id/import_savedata"
|
||||
android:title="@string/action_import_save_data" />
|
||||
<item
|
||||
android:id="@+id/licenses"
|
||||
android:title="@string/action_licenses" />
|
||||
</menu>
|
||||
@@ -3,6 +3,7 @@
|
||||
<string name="app_name">xsystem35</string>
|
||||
<string name="action_export_save_data">セーブデータをエクスポート</string>
|
||||
<string name="action_import_save_data">セーブデータをインポート</string>
|
||||
<string name="action_licenses">オープンソースライセンス</string>
|
||||
<string name="cancel">キャンセル</string>
|
||||
<string name="cannot_find_ald">System 3.x のファイル (*.ald) が見つかりません。</string>
|
||||
<string name="choose_a_file">ファイルを選択</string>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<string name="app_name">xsystem35</string>
|
||||
<string name="action_export_save_data">Export Save Files</string>
|
||||
<string name="action_import_save_data">Import Save Files</string>
|
||||
<string name="action_licenses">Open source licenses</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="cannot_find_ald">Cannot find System 3.x game files (*.ald).</string>
|
||||
<string name="choose_a_file">Choose a file</string>
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.20'
|
||||
ext.kotlin_version = '1.7.21'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
// AGP 7.1.x cannot be used due to https://issuetracker.google.com/issues/206099937
|
||||
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||
classpath 'com.android.tools.build:gradle:8.1.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Thu Nov 11 18:20:34 PST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
Vendored
+2
-2
@@ -126,8 +126,8 @@ if $cygwin ; then
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
CHECK=`echo "$arg"|grep -E -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|grep -E -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#cmakedefine PACKAGE "@PACKAGE@"
|
||||
#define VERSION "2.6.0"
|
||||
#define VERSION "2.10.1"
|
||||
|
||||
#cmakedefine CMAKE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@"
|
||||
|
||||
|
||||
-189
@@ -1,189 +0,0 @@
|
||||
それぞれのゲームに付いての注意書き
|
||||
|
||||
[鬼畜王ランス]
|
||||
|
||||
[ランス4(for Win95)]
|
||||
|
||||
[闘神都市2(for Win95)]
|
||||
|
||||
[いけないかつみ先生]
|
||||
= 外字データには対応していません
|
||||
|
||||
[かえるにょぱにょ〜ん]
|
||||
= フロアデータ(floor_1.map 〜 floor_16.map) はセーブデータと同じディレク
|
||||
トリに置いてください。
|
||||
= 一部のキャラの絵と説明が違う(金魚と????)
|
||||
|
||||
[戦巫女]
|
||||
= 戦巫女は2枚組のCDで、Windows版では一部のデータをCD-ROMに置いたままゲーム
|
||||
することになっていますが、xsystem35 では CD-Audio と CD-ROM上のデータを
|
||||
同時に使用することは出来ません。ハードディスク等に全てのデータをインス
|
||||
トールするか、あるいは CD-Audio 以外の演奏方法(MP3等)を使用してください。
|
||||
CD-Audio を使う場合は2枚目の CD に音楽データが入っています。
|
||||
|
||||
[零式(アリスの館456版)]
|
||||
= マップデータ(MAP_DATA.DAT, UR_DATA.DATA)はセーブデータと同じディレクトリに
|
||||
置いてください。
|
||||
|
||||
[ATLACH=NACHA(アリスの館456版)]
|
||||
|
||||
[人間狩り(アリスの館456版)]
|
||||
|
||||
[アリスの館456]
|
||||
- DALK
|
||||
|
||||
- 闘神都市
|
||||
|
||||
- DrStop!
|
||||
|
||||
- ランス1
|
||||
|
||||
- ランス2
|
||||
|
||||
- ランス3
|
||||
|
||||
[王道勇者]
|
||||
|
||||
[ディアボリカ]
|
||||
|
||||
[AmbivalenZ(for Win95)]
|
||||
|
||||
[夢幻泡影 (for Win95)]
|
||||
|
||||
[ぱすてるチャイム]
|
||||
= ぱすてるチャイムでは明らかにシナリオにおかしいところがあります。
|
||||
そこで、これに対するパッチを作成しました。
|
||||
|
||||
patch というディレクトリの下に pastel.diff というパッチ当てのスクリプト
|
||||
がありますので、ゲームのシナリオデータのあるディレクトリにコピーして
|
||||
そのディレクトリに移動した後、 ./pastel.diff (シナリオファイル名) と
|
||||
実行してください。
|
||||
(例)
|
||||
> ./pastel.diff pastel_sa.ald
|
||||
|
||||
古いデータは pastel_sa.ald.org として保存されます。
|
||||
シナリオデータは Ver 1.00 と Ver 1.01 に適用できます。
|
||||
|
||||
(廉価版では直っている?)
|
||||
|
||||
[ぷろすちゅーでんとGood]
|
||||
|
||||
[守り神様]
|
||||
|
||||
[ママトト]
|
||||
|
||||
[HushByBaby]
|
||||
|
||||
[Darcrows]
|
||||
|
||||
[PERSIOM]
|
||||
= DirectSound(3D Sound) には対応していません。
|
||||
|
||||
[隠れ月]
|
||||
|
||||
[SeeIn青]
|
||||
|
||||
[廉価版・デアボリカ]
|
||||
|
||||
[廉価版・アトラクナクア]
|
||||
|
||||
[廉価版・かえるにょ・ぱにょん]
|
||||
|
||||
[廉価版・零式]
|
||||
|
||||
[かえるにょ国にょありす(20世紀アリス)]
|
||||
= 外部MIDIプレイヤーモードでは音楽がリピートされません。
|
||||
|
||||
[これDPS?(20世紀アリス)]
|
||||
|
||||
[夜が来る!]
|
||||
= 動きません
|
||||
|
||||
[王子さま Lv1]
|
||||
|
||||
[Only You 〜リ・クルス〜]
|
||||
|
||||
[大悪司]
|
||||
= オープニングが動かない
|
||||
|
||||
[王子さま Lv1.5]
|
||||
|
||||
[妻みぐい]
|
||||
= オープニングが動かない
|
||||
|
||||
[エスカレイヤー]
|
||||
= オープニングが動かない
|
||||
|
||||
[Rance5D]
|
||||
|
||||
[妻みぐい2]
|
||||
= オープニングが動かない
|
||||
|
||||
[DALK外伝]
|
||||
[ままにょにょ]
|
||||
= System4につき動きません
|
||||
|
||||
|
||||
/*
|
||||
* その他
|
||||
*/
|
||||
|
||||
* センチメンタルシーズン (Aliceの館 CDをベースに UNITBASE が移植したもの)
|
||||
= http://www4.big.or.jp/~unitbase/sys35sdk/games.html
|
||||
|
||||
* Intruder (Aliceの館 CDをベースに UNITBASE が移植したもの)
|
||||
= まだ完了していません
|
||||
|
||||
* Crecent Moon がぁる (Aliceの館 CDをベースに UNITBASE が移植したもの)
|
||||
= http://www4.big.or.jp/~unitbase/sys35sdk/games.html
|
||||
|
||||
* あぶない天狗伝説 (Aliceの館 CD2をベースに UNITBASE が移植したもの)
|
||||
= 掲載許可が下りません
|
||||
|
||||
* OnlyYou (system3版をベースに TOTOさんが移植したもの)
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
|
||||
* ランス4.1 (system3版をベースに TOTOさんが移植したもの)
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
= スプライトの色がおかしい
|
||||
|
||||
* ランス4.2 (system3版をベースに TOTOさんが移植したもの
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
= スプライトの色がおかしい
|
||||
|
||||
* アリスの館3 (system3版をベースに TOTOさんが移植したもの)
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
|
||||
* 乙女戦記 (system3版をベースに TOTOさんが移植したもの)
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
|
||||
* 闘神都市2外伝 (system3版をベースに TOTOさんが移植したもの)
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
|
||||
* DPS全部 (system3版をベースに TOTOさんが移植したもの)
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
|
||||
* ProStudentG (system3版をベースに TOTOさんが移植したもの)
|
||||
= http://www1.interq.or.jp/t-takeda/index.html
|
||||
|
||||
* 学園KING (AliceCD Ver 1.??)
|
||||
= CDが鳴らない
|
||||
-> TOTOさんが、CD-DAに対応するためのシナリオパッチをつくっています。
|
||||
http://www1.interq.or.jp/t-takeda/midi.html
|
||||
|
||||
|
||||
* メイドのススメ (AliceCD Ver 1.02)
|
||||
|
||||
* ぶろぶろ (AliceCD Ver 1.02)
|
||||
|
||||
* 学園漂流戦記 (AliceCD Ver 1.02)
|
||||
|
||||
* 扉 (AliceCD Ver 2.02)
|
||||
|
||||
* 妖精 (AliceCD Ver 2.02)
|
||||
|
||||
/*
|
||||
* 3rd party 製作 ゲーム
|
||||
*/
|
||||
|
||||
#include "MISCGAME.TXT"
|
||||
@@ -1,58 +0,0 @@
|
||||
|
||||
その他の SYSTEM 3.5 のゲームについて
|
||||
|
||||
README にある動作確認ゲーム以外にも、ネット上で公開されているSYSTEM3.5対応
|
||||
のゲームのうち幾つかは動く事が確認されています。ここでは 1.4.0 preX での動作
|
||||
状況です。1.4.0 公開時点で手に入るゲームを順次追加していっています。
|
||||
また、XXXが動かないんだけど調べてください、XXXはちゃんと動きました、といった
|
||||
情報もおよせください。
|
||||
|
||||
OKは問題なく動く。GOODが多少の問題あるもののゲームをやるぶんで気にはなるけど
|
||||
耐えられる範囲のもの。BADは動かないものです。
|
||||
|
||||
|
||||
(作者の敬称略)
|
||||
【 ソフト名 】 【 ファイル名 】【 作者名 】【 動作 】
|
||||
国立ファーブル図
|
||||
書館司書〜
|
||||
ブックルちゃん〜 SSYO_100.LZH 大塚ヒロ OK
|
||||
バルーンぽっぷ BPOP_093.LZH 大塚ヒロ OK
|
||||
|
||||
Self self.lzh よこやまなおき OK
|
||||
おせろっと othellotto.exe よこやまなおき OK
|
||||
キャロル carol.lzh よこやまなおき GOOD(1)
|
||||
|
||||
積層四目並べ Te1.lzh 深叢 忍 OK
|
||||
16Piece Puzzle 16p1.lzh 深叢 忍 OK
|
||||
The Line Line0.lzh 深叢 忍 OK
|
||||
|
||||
Black Jack bj120.lzh かずき OK
|
||||
|
||||
マスカレイド (in AliceCD202) ちあぼう OK
|
||||
戦娘ver2.12 ikusa212.lzh ちあぼう OK
|
||||
|
||||
できるかなー! (in AliceCD202) KIMM SOFT OK(2)
|
||||
|
||||
恋は計算どおり♪ koi.lzh SS OK
|
||||
|
||||
動体視力を鍛えるにょ game_191.lzh LazyRichField BAD(3)
|
||||
集中力を鍛えるにょ game_22.lh LazyRichField GOOD(4)
|
||||
|
||||
|
||||
1) 雪が降らない (grDrawFillCircle が未実装)
|
||||
通信対戦が出来ない
|
||||
2) メッセージサイズ300ドットの表示は 100 ドットに制限しています
|
||||
3) DS 数字 となっている
|
||||
4) 色がおかしい
|
||||
|
||||
最後にこれらのデータを公開している作者の方々のURLです。
|
||||
|
||||
大塚ヒロさん http://www.studioHIRO.com/
|
||||
よこやまなおきさん http://www3.justnet.ne.jp/~naoki-yokoyama/
|
||||
深叢 忍さん http://www2s.biglobe.ne.jp/~nin/
|
||||
かずきさん http://www.din.or.jp/~kazuki/
|
||||
桐ヶ屋 inc.(ちあぼう)さん http://www.eucaly.net/~kiri
|
||||
KIMM SOFT/ネリワサヴィちーむ heavyd@syd.odn.ne.jp
|
||||
SSさん http://www.sspzgr.net/
|
||||
LazyRichFieldさん http://www2j.biglobe.ne.jp/~Lazy/staff/alice.htm
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
Game Compatibility
|
||||
==================
|
||||
|
||||
| Game | Status | Notes |
|
||||
| ------------------------------------------- | ----------- | ----- |
|
||||
| 鬼畜王ランス | Supported | |
|
||||
| Kichikuou Rance (EN) | Supported | |
|
||||
| RanceIV -教団の遺産- | Supported | Win95 edition, [Ver2.05](https://hannylaboratory.blogspot.com/2023/01/blog-post_26.html) |
|
||||
| Rance4 -Legacy of the Sect- (EN) | Supported | |
|
||||
| 兰斯IV -教团的遗产- (CN) | Supported | |
|
||||
| ランス4.1 | Supported | [Ver1.05](https://hannylaboratory.blogspot.com/2023/02/blog-post_9.html) |
|
||||
| ランス4.2 | Supported | [Ver1.05](https://hannylaboratory.blogspot.com/2023/02/blog-post_9.html) |
|
||||
| いけないかつみ先生 | Supported | Emojis are not supported |
|
||||
| 闘神都市II | Supported | Win95 edition |
|
||||
| かえるにょ・ぱにょ~ん | Supported | Normal / Low-priced edition |
|
||||
| 戦巫女 | Supported | Normal / Low-priced edition |
|
||||
| 零式 | Supported | From ALICEの館4・5・6 / Low-priced edition |
|
||||
| アトラク=ナクア | Supported | From ALICEの館4・5・6 / Low-priced edition |
|
||||
| Rance -光を求めて- | Supported | From ALICEの館4・5・6 |
|
||||
| Rance II -反逆の少女達- | Supported | From ALICEの館4・5・6 |
|
||||
| Rance III -リーザス陥落- | Supported | From ALICEの館4・5・6 |
|
||||
| DALK | Supported | From ALICEの館4・5・6 |
|
||||
| 闘神都市 | Supported | From ALICEの館4・5・6 |
|
||||
| Dr.STOP | Supported | From ALICEの館4・5・6 |
|
||||
| 人間狩り | Supported | From ALICEの館4・5・6 / アリスCD |
|
||||
| 女の子図鑑 | Unknown | From ALICEの館4・5・6 |
|
||||
| 恋のおわり | Unknown | |
|
||||
| 王道勇者 | Supported | |
|
||||
| AmbivalenZ | Supported | Win95 edition |
|
||||
| DiaboLiQuE | Supported | Normal / Low-priced edition |
|
||||
| 夢幻泡影 | Unknown | Win98 edition |
|
||||
| ぱすてるチャイム | Supported | See [patch/README.TXT](patch/README.TXT) |
|
||||
| ぷろすちゅーでんとGood | Supported | |
|
||||
| 守り神様 | Supported | |
|
||||
| ママトト | Supported | |
|
||||
| HUSHABY BABY | Supported | |
|
||||
| DARCROWS | Supported | |
|
||||
| 隠れ月 | Supported | |
|
||||
| PERSIOM | Supported | 3D sound is not supported |
|
||||
| SeeIn青 | Supported | |
|
||||
| かえるにょ国にょアリス | Supported | From 20世紀アリス |
|
||||
| これD・P・S? | Supported | From 20世紀アリス |
|
||||
| 夜が来る! | Unsupported | |
|
||||
| Only you ~リ・クルス~ | Supported | |
|
||||
| 大悪司 | Supported | Opening demo is not supported |
|
||||
| 王子さまLv1 | Supported | |
|
||||
| 王子さま1ヵ月後 | Supported | From 王子さまLV1.5 |
|
||||
| 白鳳の子分叩き | Supported | From 王子さまLV1.5 |
|
||||
| チェシャのお部屋1.5 | Supported | From 王子さまLV1.5 |
|
||||
| 王子さま1/16 | Supported | From 王子さまLV1.5 |
|
||||
| スパイ伊藤の「クイズ!俺にさぼらせろ」 | Supported | From 王子さまLV1.5 |
|
||||
| 妻みぐい | Supported | Opening demo is not supported |
|
||||
| 超昂天使エスカレイヤー | Supported | Opening demo is not supported |
|
||||
| ランス5D | Supported | |
|
||||
| Rance 5D - The Lonely Girl (MangaGamer) | Supported | |
|
||||
| 俺の下であがけ | Unknown | |
|
||||
| 楽園行 | Unknown | |
|
||||
| 妻みぐい2 | Supported | Opening demo is not supported |
|
||||
| シェル・クレイル | Supported | |
|
||||
| ナイトデーモン | Supported | |
|
||||
| 学園KING | Supported | From アリスCD |
|
||||
| 学園KING 番外編 | Supported | From アリスCD |
|
||||
| 蒼海に墜ちて | Supported | From アリスCD |
|
||||
| ぶろぶろ | Supported | From アリスCD |
|
||||
| 裸ぶろぶろ狂 | Supported | From アリスCD |
|
||||
| メイドのススメ | Supported | From アリスCD |
|
||||
| 学園漂流戦記 | Supported | From アリスCD |
|
||||
| 学園漂流戦記2 | Supported | From アリスCD |
|
||||
| 当たって!!KUDAKERO 予告編 | Supported | From アリスCD |
|
||||
| 妖精 | Supported | From アリスCD |
|
||||
| [扉] | Supported | From アリスCD |
|
||||
| 叩き殺し太郎 | Supported | From アリスCD |
|
||||
| バルーンぽっぷ | Supported | From アリスCD |
|
||||
| 高速ひよこ2 | Supported | From アリスCD |
|
||||
| おせろっと | Supported | From アリスCD |
|
||||
| マスカレイド | Supported | From アリスCD |
|
||||
| キャロル ~聖なる鐘が響く夜~ | Supported | From アリスCD, Online match is not supported |
|
||||
| できるかなー? | Supported | From アリスCD |
|
||||
| Child Assassin | Supported | From アリスCD |
|
||||
| Klavier | Supported | From アリスCD |
|
||||
| 弱肉狂食 | Supported | From アリスCD |
|
||||
| 眼鏡大戦2 | Supported | From アリスCD |
|
||||
| 妄想くん | Supported | From アリスCD |
|
||||
@@ -26,7 +26,6 @@ add_library(modules STATIC
|
||||
SACT/SACT.c
|
||||
SACT/sactcg.c
|
||||
SACT/sactsound.c
|
||||
SACT/sactbgm.c
|
||||
SACT/sacttimer.c
|
||||
SACT/sactstring.c
|
||||
SACT/sactcrypto.c
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "menu.h"
|
||||
#include "input.h"
|
||||
#include "nact.h"
|
||||
#include "key.h"
|
||||
#include "night.h"
|
||||
#include "sprite.h"
|
||||
|
||||
@@ -33,7 +32,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
switch (e->type) {
|
||||
case AGSEVENT_BUTTON_RELEASE:
|
||||
case AGSEVENT_KEY_RELEASE:
|
||||
night.waitkey = e->d3;
|
||||
night.waitkey = e->code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -59,15 +58,15 @@ void ntev_callback(agsevent_t *e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->d3 == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
||||
night.waitskiplv = 2;
|
||||
night.waitkey = e->d3;
|
||||
night.waitkey = e->code;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->d3 == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->code == KEY_CTRL) {
|
||||
night.waitskiplv = 0;
|
||||
night.waitkey = e->d3;
|
||||
night.waitkey = e->code;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -392,13 +392,11 @@ static void is_in_icon() {
|
||||
|
||||
|
||||
static void cb_keyrelease(agsevent_t *e) {
|
||||
int x = e->d1, y = e->d2;
|
||||
|
||||
switch (e->d3) {
|
||||
switch (e->code) {
|
||||
case AGSEVENT_BUTTON_LEFT:
|
||||
#if 0
|
||||
if (is_in_icon()) {
|
||||
do_icon(x, y);
|
||||
do_icon(e->mousex, e->mousey);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -408,19 +406,15 @@ static void cb_keyrelease(agsevent_t *e) {
|
||||
// unhide();
|
||||
break;
|
||||
}
|
||||
night.waitkey = e->d3;
|
||||
night.waitkey = e->code;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void cb_mousemove(agsevent_t *e) {
|
||||
int x = e->d1, y = e->d2;
|
||||
|
||||
// 音声mute/メッセージスキップ/メッセージ枠消去の領域に
|
||||
// マウスが移動したら、その部分のアイコンを変化させる
|
||||
|
||||
|
||||
}
|
||||
|
||||
// メッセージ表示時に、キー入力を促すアニメーションの設定
|
||||
|
||||
@@ -23,7 +23,7 @@ void nt_voice_set(int no) {
|
||||
}
|
||||
|
||||
void nt_cd_play(int no) {
|
||||
mus_cdrom_start(no +1, 0);
|
||||
muscd_start(no + 1, 0);
|
||||
}
|
||||
|
||||
void nt_cd_stop(int msec) {
|
||||
|
||||
@@ -51,7 +51,7 @@ static void ndd_run(int demonum) {
|
||||
|
||||
int mus = ndemo_mus[demonum];
|
||||
if (mus)
|
||||
mus_bgm_play(mus, 0, 100);
|
||||
musbgm_play(mus, 0, 100);
|
||||
|
||||
uint32_t start = sdl_getTicks();
|
||||
while (!nact->is_quit) {
|
||||
@@ -79,7 +79,7 @@ static void ndd_run(int demonum) {
|
||||
}
|
||||
|
||||
if (mus)
|
||||
mus_bgm_stop(ndemo_mus[demonum], 0);
|
||||
musbgm_stop(ndemo_mus[demonum], 0);
|
||||
|
||||
alk_free(alk);
|
||||
}
|
||||
|
||||
+16
-11
@@ -25,22 +25,25 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "portab.h"
|
||||
#include "system.h"
|
||||
#include "ald_manager.h"
|
||||
#include "input.h"
|
||||
#include "msgskip.h"
|
||||
#include "xsystem35.h"
|
||||
#include "gametitle.h"
|
||||
#include "message.h"
|
||||
#include "modules.h"
|
||||
#include "music.h"
|
||||
#include "nact.h"
|
||||
#include "sact.h"
|
||||
#include "sprite.h"
|
||||
#include "sactcg.h"
|
||||
#include "sactstring.h"
|
||||
#include "sactsound.h"
|
||||
#include "sactbgm.h"
|
||||
#include "sactcrypto.h"
|
||||
#include "sactchart.h"
|
||||
#include "ngraph.h"
|
||||
@@ -1790,7 +1793,9 @@ static void MusicCheck() {
|
||||
int wNum = getCaliValue();
|
||||
int *vRND = getCaliVariable();
|
||||
|
||||
*vRND = smus_check(wNum);
|
||||
dridata *dfile = ald_getdata(DRIFILE_BGM, wNum - 1);
|
||||
*vRND = dfile ? 1 : 0;
|
||||
ald_freedata(dfile);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicCheck %d,%p:", wNum, vRND);
|
||||
}
|
||||
@@ -1805,7 +1810,7 @@ static void MusicGetLength() {
|
||||
int wNum = getCaliValue();
|
||||
int *vRND = getCaliVariable();
|
||||
|
||||
*vRND = smus_getlength(wNum);
|
||||
*vRND = musbgm_getlen(wNum);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicGetLength %d,%d:", wNum, *vRND);
|
||||
}
|
||||
@@ -1820,7 +1825,7 @@ static void MusicGetPos() {
|
||||
int wNum = getCaliValue();
|
||||
int *vRND = getCaliVariable();
|
||||
|
||||
*vRND = smus_getpos(wNum);
|
||||
*vRND = musbgm_getpos(wNum);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicGetPos %d,%d:", wNum, *vRND);
|
||||
}
|
||||
@@ -1837,7 +1842,7 @@ static void MusicPlay() {
|
||||
int wFadeTime = getCaliValue();
|
||||
int wVolume = getCaliValue();
|
||||
|
||||
smus_play(wNum, wFadeTime, wVolume);
|
||||
musbgm_play(wNum, wFadeTime, wVolume);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicPlay %d,%d,%d:", wNum, wFadeTime, wVolume);
|
||||
}
|
||||
@@ -1852,7 +1857,7 @@ static void MusicStop() {
|
||||
int wNum = getCaliValue();
|
||||
int wFadeTime = getCaliValue();
|
||||
|
||||
smus_stop(wNum, wFadeTime);
|
||||
musbgm_stop(wNum, wFadeTime);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicStop %d,%d:", wNum, wFadeTime);
|
||||
}
|
||||
@@ -1865,7 +1870,7 @@ static void MusicStop() {
|
||||
static void MusicStopAll() {
|
||||
int wFadeTime = getCaliValue();
|
||||
|
||||
smus_stopall(wFadeTime);
|
||||
musbgm_stopall(wFadeTime);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicStopAll %d:", wFadeTime);
|
||||
}
|
||||
@@ -1882,7 +1887,7 @@ static void MusicFade() {
|
||||
int wFadeTime = getCaliValue();
|
||||
int wVolume = getCaliValue();
|
||||
|
||||
smus_fade(wNum, wFadeTime, wVolume);
|
||||
musbgm_fade(wNum, wFadeTime, wVolume);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicFade %d,%d,%d:", wNum, wFadeTime, wVolume);
|
||||
}
|
||||
@@ -1901,7 +1906,7 @@ static void MusicWait() {
|
||||
nTimeOut = getCaliValue();
|
||||
}
|
||||
|
||||
smus_wait(wNum, nTimeOut);
|
||||
musbgm_wait(wNum, nTimeOut);
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicWait %d,%d:", wNum, nTimeOut);
|
||||
}
|
||||
@@ -1917,7 +1922,7 @@ static void MusicWaitPos() {
|
||||
int wNum = getCaliValue();
|
||||
int wIndex = getCaliValue();
|
||||
|
||||
smus_waitpos(wNum, wIndex);
|
||||
WARNING("SACT.MusicWatiPos not implemented");
|
||||
|
||||
DEBUG_COMMAND_YET("SACT.MusicWaitPos %d,%d:", wNum, wIndex);
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* sactbgm.c: SACT Music 関連
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/* $Id: sactbgm.c,v 1.4 2003/08/30 21:29:16 chikama Exp $ */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "portab.h"
|
||||
#include "system.h"
|
||||
#include "ald_manager.h"
|
||||
#include "music.h"
|
||||
|
||||
// 指定の番号の音楽が存在するかチェック
|
||||
int smus_check(int no) {
|
||||
dridata *dfile = ald_getdata(DRIFILE_BGM, no -1);
|
||||
int st = 0;
|
||||
|
||||
if (dfile == NULL) {
|
||||
st = 0;
|
||||
} else {
|
||||
st = 1;
|
||||
ald_freedata(dfile);
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
// 指定の番号の音楽の長さを取得
|
||||
int smus_getlength(int no) {
|
||||
return mus_bgm_getlength(no);
|
||||
}
|
||||
|
||||
// 指定の番号の音楽の再生位置を取得
|
||||
int smus_getpos(int no) {
|
||||
return mus_bgm_getpos(no);
|
||||
}
|
||||
|
||||
// 指定の番号の音楽の再生開始
|
||||
int smus_play(int no, int time, int vol) {
|
||||
mus_bgm_play(no, time, vol);
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 指定の番号の音楽の再生停止
|
||||
int smus_stop(int no, int fadetime) {
|
||||
mus_bgm_stop(no, fadetime);
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 指定の番号の音楽のボリュームフェード
|
||||
int smus_fade(int no, int time, int vol) {
|
||||
mus_bgm_fade(no, time, vol);
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 指定の番号の音楽が終了するのを待つ
|
||||
int smus_wait(int no, int timeout) {
|
||||
mus_bgm_wait(no, timeout);
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 指定の番号の音楽が指定の位置まで再生されるのを待つ
|
||||
int smus_waitpos(int no, int index) {
|
||||
mus_bgm_waitpos(no, index);
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 全ての音楽の再生を停止
|
||||
int smus_stopall(int time) {
|
||||
mus_bgm_stopall(time);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "menu.h"
|
||||
#include "input.h"
|
||||
#include "nact.h"
|
||||
#include "key.h"
|
||||
#include "sact.h"
|
||||
#include "sprite.h"
|
||||
#include "ngraph.h"
|
||||
|
||||
+16
-14
@@ -24,6 +24,9 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "portab.h"
|
||||
#include "system.h"
|
||||
@@ -31,7 +34,6 @@
|
||||
#include "menu.h"
|
||||
#include "input.h"
|
||||
#include "nact.h"
|
||||
#include "key.h"
|
||||
#include "sact.h"
|
||||
#include "sprite.h"
|
||||
#include "sactsound.h"
|
||||
@@ -210,7 +212,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
|
||||
switch (e->type) {
|
||||
case AGSEVENT_KEY_PRESS:
|
||||
if (e->d3 == KEY_Z) {
|
||||
if (e->code == KEY_Z) {
|
||||
cur = sdl_getTicks();
|
||||
if (!sact.zhiding) {
|
||||
slist_foreach(sact.sp_zhide, cb_defocused_zkey, &update);
|
||||
@@ -239,7 +241,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
// fall through
|
||||
|
||||
case AGSEVENT_KEY_RELEASE:
|
||||
switch(e->d3) {
|
||||
switch(e->code) {
|
||||
case KEY_Z:
|
||||
cur = sdl_getTicks();
|
||||
if (500 < (cur - sact.zofftime) || !sact.zdooff) {
|
||||
@@ -255,7 +257,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
sact.waittype = KEYWAIT_BACKLOG;
|
||||
break;
|
||||
default:
|
||||
sact.waitkey = e->d3;
|
||||
sact.waitkey = e->code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -289,7 +291,7 @@ void cb_waitkey_sprite(agsevent_t *e) {
|
||||
// 右クリックキャンセル
|
||||
// drag中でない時のみ、キャンセルを受け付ける
|
||||
if (e->type == AGSEVENT_BUTTON_RELEASE &&
|
||||
e->d3 == AGSEVENT_BUTTON_RIGHT) {
|
||||
e->code == AGSEVENT_BUTTON_RIGHT) {
|
||||
sact.waitkey = 0;
|
||||
return;
|
||||
}
|
||||
@@ -308,7 +310,7 @@ void cb_waitkey_sprite(agsevent_t *e) {
|
||||
// dragg中の sprite は無視する
|
||||
if (sp == sact.draggedsp) continue;
|
||||
|
||||
if (focused_sp == NULL && sp_is_insprite(sp, e->d1, e->d2)) {
|
||||
if (focused_sp == NULL && sp_is_insprite(sp, e->mousex, e->mousey)) {
|
||||
/*
|
||||
focusを得ている sprite
|
||||
*/
|
||||
@@ -385,8 +387,8 @@ static void cb_waitkey_selection(agsevent_t *e) {
|
||||
static void cb_waitkey_backlog(agsevent_t *e) {
|
||||
switch (e->type) {
|
||||
case AGSEVENT_KEY_RELEASE:
|
||||
switch (e->d3) {
|
||||
case KEY_ESC:
|
||||
switch (e->code) {
|
||||
case KEY_ESCAPE:
|
||||
sblog_end();
|
||||
sact.waittype = KEYWAIT_MESSAGE;
|
||||
break;
|
||||
@@ -406,14 +408,14 @@ static void cb_waitkey_backlog(agsevent_t *e) {
|
||||
break;
|
||||
|
||||
case AGSEVENT_BUTTON_RELEASE:
|
||||
if (e->d3 == AGSEVENT_BUTTON_RIGHT) {
|
||||
if (e->code == AGSEVENT_BUTTON_RIGHT) {
|
||||
sblog_end();
|
||||
sact.waittype = KEYWAIT_MESSAGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case AGSEVENT_MOUSE_WHEEL:
|
||||
if (e->d3 > 0)
|
||||
if (e->code > 0)
|
||||
sblog_pagenext();
|
||||
else
|
||||
sblog_pagepre();
|
||||
@@ -431,15 +433,15 @@ void spev_callback(agsevent_t *e) {
|
||||
}
|
||||
|
||||
if (sact.waittype != KEYWAIT_BACKLOG) {
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->d3 == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
||||
sact.waitskiplv = 2;
|
||||
sact.waitkey = e->d3;
|
||||
sact.waitkey = e->code;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->d3 == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->code == KEY_CTRL) {
|
||||
sact.waitskiplv = 0;
|
||||
sact.waitkey = e->d3;
|
||||
sact.waitkey = e->code;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ static int eventCB_GET(sprite_t *sp, agsevent_t *e) {
|
||||
|
||||
switch(e->type) {
|
||||
case AGSEVENT_BUTTON_PRESS:
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) break;
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) break;
|
||||
|
||||
// drag開始時のマウスの位置記録
|
||||
sp->u.get.dragging = TRUE;
|
||||
sp->u.get.dragstart.x = e->d1;
|
||||
sp->u.get.dragstart.y = e->d2;
|
||||
sp->u.get.dragstart.x = e->mousex;
|
||||
sp->u.get.dragstart.y = e->mousey;
|
||||
|
||||
if (sp->cg3) {
|
||||
sp->curcg = sp->cg3;
|
||||
@@ -104,8 +104,8 @@ static int eventCB_GET(sprite_t *sp, agsevent_t *e) {
|
||||
// if (!sp->u.get.dragging) break;
|
||||
|
||||
// マウスの現在位置により新しい場所を計算
|
||||
newx = sp->loc.x + (e->d1 - sp->u.get.dragstart.x);
|
||||
newy = sp->loc.y + (e->d2 - sp->u.get.dragstart.y);
|
||||
newx = sp->loc.x + (e->mousex - sp->u.get.dragstart.x);
|
||||
newy = sp->loc.y + (e->mousey - sp->u.get.dragstart.y);
|
||||
if (newx != sp->cur.x || newy != sp->cur.y) {
|
||||
sp_updateme(sp);
|
||||
sp->cur.x = newx;
|
||||
|
||||
@@ -135,13 +135,13 @@ int sp_keywait(int *vOK, int *vRND, int *vD01, int *vD02, int *vD03, int timeout
|
||||
{
|
||||
// とりあえず、現在のマウス位置を送って、switch sprite の
|
||||
// 状態を更新しておく
|
||||
agsevent_t agse;
|
||||
MyPoint p;
|
||||
sys_getMouseInfo(&p, FALSE);
|
||||
agse.type = AGSEVENT_MOUSE_MOTION;
|
||||
agse.d1 = p.x;
|
||||
agse.d2 = p.y;
|
||||
agse.d3 = 0;
|
||||
agsevent_t agse = {
|
||||
.type = AGSEVENT_MOUSE_MOTION,
|
||||
.mousex = p.x,
|
||||
.mousey = p.y
|
||||
};
|
||||
spev_callback(&agse);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ static int eventCB_PUT(sprite_t *sp, agsevent_t *e) {
|
||||
|
||||
switch(e->type) {
|
||||
case AGSEVENT_BUTTON_PRESS:
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
|
||||
// ボタン押下時のスプライトがあれば、それを表示
|
||||
if (sp->cg3) {
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "nact.h"
|
||||
#include "ags.h"
|
||||
#include "input.h"
|
||||
#include "key.h"
|
||||
#include "sact.h"
|
||||
#include "sprite.h"
|
||||
#include "ngraph.h"
|
||||
@@ -77,7 +76,7 @@ static boolean sp_is_insprite2(sprite_t *sp, int x, int y, int margin) {
|
||||
|
||||
// マウスが移動したときの callback
|
||||
static void cb_select_move(agsevent_t *e) {
|
||||
int x = e->d1, y = e->d2;
|
||||
int x = e->mousex, y = e->mousey;
|
||||
sprite_t *sp = sact.sp[sact.sel.spno];
|
||||
boolean newstate;
|
||||
int newindex;
|
||||
@@ -115,12 +114,12 @@ static void cb_select_move(agsevent_t *e) {
|
||||
|
||||
// ボタンがリリースされたときの callback
|
||||
static void cb_select_release(agsevent_t *e) {
|
||||
int x = e->d1, y = e->d2;
|
||||
int x = e->mousex, y = e->mousey;
|
||||
sprite_t *sp = sact.sp[sact.sel.spno];
|
||||
boolean st;
|
||||
int iy;
|
||||
|
||||
switch (e->d3) {
|
||||
switch (e->code) {
|
||||
case AGSEVENT_BUTTON_LEFT:
|
||||
st = sp_is_insprite2(sp, x, y, sact.sel.frame_dot);
|
||||
iy = (y - (sp->cur.y + sact.sel.frame_dot)) / (sact.sel.font_size + sact.sel.linespace);
|
||||
@@ -198,8 +197,10 @@ static void setup_selwindow() {
|
||||
|
||||
// デフォルトで選択される選択肢がある場合、そこへカーソルを移動
|
||||
if (sact.sel.movecursor) {
|
||||
ags_setCursorLocation(sp->cur.x + sact.sel.frame_dot + 2,
|
||||
sp->cur.y + sact.sel.frame_dot + 2 + (sact.sel.font_size + sact.sel.linespace)*(sact.sel.movecursor -1), TRUE);
|
||||
int x = sp->cur.x + sact.sel.frame_dot + 2;
|
||||
int y = sp->cur.y + sact.sel.frame_dot + 2 +
|
||||
(sact.sel.font_size + sact.sel.linespace) * (sact.sel.movecursor - 1);
|
||||
ags_setCursorLocation(x, y, true, true);
|
||||
selected_item = (sact.sel.movecursor -1);
|
||||
oldstate = TRUE;
|
||||
oldindex = selected_item -1;
|
||||
|
||||
@@ -41,7 +41,7 @@ static int eventCB_switch(sprite_t *sp, agsevent_t *e) {
|
||||
|
||||
switch(e->type) {
|
||||
case AGSEVENT_BUTTON_PRESS:
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
|
||||
// ボタン押下時のスプライトがあれば、それを表示
|
||||
if (sp->cg3) {
|
||||
@@ -53,7 +53,7 @@ static int eventCB_switch(sprite_t *sp, agsevent_t *e) {
|
||||
break;
|
||||
|
||||
case AGSEVENT_BUTTON_RELEASE:
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
|
||||
// ここにくるときは forcusが当たっているときしかこないので、
|
||||
// curcg は cg2 に戻せばよい
|
||||
|
||||
@@ -1306,7 +1306,7 @@ static void ChangeSecretArray(void) { /* 53 */
|
||||
(*vAry) ^= ax; ax = (key[i&3] ^ *vAry);
|
||||
j ^= ax;
|
||||
if (i & 2) {
|
||||
ax = !ax ^ (i*3);
|
||||
ax = ~ax ^ (i*3);
|
||||
}
|
||||
if (i & 4) {
|
||||
ax = (ax >> 4) | (ax << 12);
|
||||
@@ -1328,13 +1328,12 @@ static void ChangeSecretArray(void) { /* 53 */
|
||||
*vAry ^= ax; ax = (key[i&3] ^ k);
|
||||
j ^= ax;
|
||||
if (i & 2) {
|
||||
ax = !ax ^ (i*3);
|
||||
ax = ~ax ^ (i*3);
|
||||
}
|
||||
if (i & 4) {
|
||||
ax = (ax >> 4) | (ax << 12);
|
||||
}
|
||||
vAry++;
|
||||
|
||||
}
|
||||
*vResult = j;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "ags.h"
|
||||
#include "music.h"
|
||||
#include "sdl_core.h"
|
||||
#include "hacks.h"
|
||||
|
||||
#define SLOT 40
|
||||
|
||||
@@ -166,14 +167,14 @@ static void ChangeNotColor() {
|
||||
case 24:
|
||||
case 32:
|
||||
{
|
||||
uint32_t pic24s = PIX24(*src, *(src+1), *(src+2)) & 0xf0f0f0;
|
||||
uint32_t pic24d = PIX24(*dst, *(dst+1), *(dst+2)) & 0xf0f0f0;
|
||||
uint32_t pic24s = PIX24(*src, *(src+1), *(src+2));
|
||||
uint32_t pic24d = PIX24(*dst, *(dst+1), *(dst+2));
|
||||
uint32_t *yl;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
yl = (uint32_t *)(dp + y * dib->bytes_per_line);
|
||||
for (x = 0; x < width; x++) {
|
||||
if ((*yl & 0xf0f0f0) != pic24s) {
|
||||
if (*yl != pic24s) {
|
||||
*yl = pic24d;
|
||||
}
|
||||
yl++;
|
||||
@@ -182,6 +183,9 @@ static void ChangeNotColor() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The CX command after ChangeNotColor (in FIGHT.ADV) must use a precise
|
||||
// calculation.
|
||||
daiakuji_cx_hack = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -585,14 +589,14 @@ static void copy_sprite(int sx, int sy, int width, int height, int dx, int dy, i
|
||||
case 24:
|
||||
case 32:
|
||||
{
|
||||
uint32_t pic24 = PIX24(r, g, b) & 0xf0f0f0;
|
||||
uint32_t pic24 = PIX24(r, g, b);
|
||||
uint32_t *yls, *yld;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
yls = (uint32_t *)(sp + y * dib->bytes_per_line);
|
||||
yld = (uint32_t *)(dp + y * dib->bytes_per_line);
|
||||
for (x = 0; x < width; x++) {
|
||||
if ((*yls & 0xf0f0f0) != pic24) {
|
||||
if (*yls != pic24) {
|
||||
*yld = *yls;
|
||||
}
|
||||
yls++; yld++;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "modules.h"
|
||||
#include "sdl_core.h"
|
||||
#include "sdl_private.h"
|
||||
#include "input.h"
|
||||
#include "menu.h"
|
||||
|
||||
// キー変換テーブル
|
||||
@@ -162,7 +163,7 @@ static void GetKeyStatus(void) {
|
||||
}
|
||||
|
||||
*var = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
for (i = 0; i < NUM_KEYCODES; i++) {
|
||||
*var |= (keymap[no -1][i] * RawKeyInfo[i]);
|
||||
}
|
||||
|
||||
|
||||
+89
-22
@@ -26,8 +26,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "portab.h"
|
||||
#include "LittleEndian.h"
|
||||
#include "xsystem35.h"
|
||||
#include "modules.h"
|
||||
#include "nact.h"
|
||||
@@ -35,12 +37,16 @@
|
||||
#include "ald_manager.h"
|
||||
#include "music.h"
|
||||
|
||||
#ifdef ENABLE_SDLMIXER
|
||||
#include "pcm.sdlmixer.h"
|
||||
#include "shpcmlib.c"
|
||||
static struct {
|
||||
SDL_AudioSpec spec; // must be 16-bit, stereo
|
||||
uint8_t *buf;
|
||||
uint32_t len;
|
||||
} memwav;
|
||||
|
||||
static Mix_Chunk *chunk;
|
||||
#endif
|
||||
static void free_memory_wav(void) {
|
||||
SDL_FreeWAV(memwav.buf);
|
||||
memwav.buf = NULL;
|
||||
}
|
||||
|
||||
static void Init() {
|
||||
/*
|
||||
@@ -117,10 +123,24 @@ static void wavLoadMemory() {
|
||||
no: 読み込むファイル番号
|
||||
*/
|
||||
int no = getCaliValue();
|
||||
|
||||
#ifdef ENABLE_SDLMIXER
|
||||
chunk = pcm_sdlmixer_load(no);
|
||||
#endif
|
||||
|
||||
if (memwav.buf)
|
||||
free_memory_wav();
|
||||
|
||||
dridata *dfile = ald_getdata(DRIFILE_WAVE, no - 1);
|
||||
if (!dfile) {
|
||||
WARNING("cannot open WAVE %d", no - 1);
|
||||
return;
|
||||
}
|
||||
if (!SDL_LoadWAV_RW(SDL_RWFromConstMem(dfile->data, dfile->size), 1, &memwav.spec, &memwav.buf, &memwav.len)) {
|
||||
WARNING("cannot load WAVE %d", no - 1);
|
||||
return;
|
||||
}
|
||||
if (memwav.spec.channels != 2 || memwav.spec.format != AUDIO_S16LSB) {
|
||||
WARNING("unexpected audio format");
|
||||
free_memory_wav();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_COMMAND("ShSound.wavLoadMemory %d:", no);
|
||||
}
|
||||
@@ -133,12 +153,38 @@ static void wavSendMemory() {
|
||||
*/
|
||||
int slot = getCaliValue();
|
||||
|
||||
#ifdef ENABLE_SDLMIXER
|
||||
if (chunk) {
|
||||
pcm_sdlmixer_load_chunk(slot, chunk);
|
||||
chunk = NULL;
|
||||
if (!memwav.buf) {
|
||||
WARNING("wave not loaded");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
const uint8_t wave_header[] = {
|
||||
'R', 'I', 'F', 'F',
|
||||
0, 0, 0, 0, // filesize - 8 (filled later)
|
||||
'W', 'A', 'V', 'E',
|
||||
'f', 'm', 't', ' ',
|
||||
16, 0, 0, 0, // size of fmt chunk
|
||||
1, 0, // PCM format
|
||||
2, 0, // stereo
|
||||
0, 0, 0, 0, // sampling rate (filled later)
|
||||
0, 0, 0, 0, // bytes / sec (filled later)
|
||||
4, 0, // block size
|
||||
16, 0, // bits / sample
|
||||
'd', 'a', 't', 'a',
|
||||
0, 0, 0, 0, // size of data chunk (filled later)
|
||||
};
|
||||
|
||||
uint32_t wav_size = sizeof(wave_header) + memwav.len;
|
||||
uint8_t *wav_buf = malloc(wav_size);
|
||||
memcpy(wav_buf, wave_header, sizeof(wave_header));
|
||||
LittleEndian_putDW(wav_size - 8, wav_buf, 4);
|
||||
LittleEndian_putDW(memwav.spec.freq, wav_buf, 24);
|
||||
LittleEndian_putDW(memwav.spec.freq * 4, wav_buf, 28);
|
||||
LittleEndian_putDW(memwav.len, wav_buf, 40);
|
||||
memcpy(wav_buf + sizeof(wave_header), memwav.buf, memwav.len);
|
||||
|
||||
mus_wav_load_data(slot, wav_buf, wav_size);
|
||||
free_memory_wav();
|
||||
free(wav_buf);
|
||||
|
||||
DEBUG_COMMAND("ShSound.wavSendMemory %d:", slot);
|
||||
}
|
||||
@@ -153,11 +199,26 @@ static void wavFadeVolumeMemory() {
|
||||
int start = getCaliValue();
|
||||
int range = getCaliValue();
|
||||
|
||||
#ifdef ENABLE_SDLMIXER
|
||||
if (chunk == NULL) return;
|
||||
if (!memwav.buf)
|
||||
return;
|
||||
|
||||
pcmlib_fade_volume_memory(chunk, start, range);
|
||||
#endif
|
||||
start *= memwav.spec.freq / 100; // 10ms -> sample
|
||||
range *= memwav.spec.freq / 100; // 10ms -> sample
|
||||
|
||||
if (memwav.len / 4 < start + range)
|
||||
return;
|
||||
|
||||
int16_t *buf = (int16_t*)memwav.buf + start * 2;
|
||||
|
||||
// 指定の場所から徐々に音量を下げる
|
||||
for (int i = range; i > 0; i--) {
|
||||
buf[0] = buf[0] * i / range;
|
||||
buf[1] = buf[1] * i / range;
|
||||
buf += 2;
|
||||
}
|
||||
|
||||
// 残りは無音
|
||||
memset(buf, 0, memwav.buf + memwav.len - (uint8_t*)buf);
|
||||
|
||||
DEBUG_COMMAND("ShSound.wavFadeVolumeMemory %d,%d:", start, range);
|
||||
}
|
||||
@@ -167,11 +228,17 @@ static void wavReversePanMemory() {
|
||||
wavLoadMemoryで読み込んだデータの左右のチャンネルを反転
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_SDLMIXER
|
||||
if (chunk == NULL) return;
|
||||
if (!memwav.buf)
|
||||
return;
|
||||
|
||||
pcmlib_reverse_pan_memory(chunk);
|
||||
#endif
|
||||
int16_t *buf = (int16_t*)memwav.buf;
|
||||
int len = memwav.len / 4;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int16_t tmp = buf[0];
|
||||
buf[0] = buf[1];
|
||||
buf[1] = tmp;
|
||||
buf += 2;
|
||||
}
|
||||
|
||||
DEBUG_COMMAND("ShSound.wavReversePanMemory:");
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* shpcmlib.c ShSound用 pcmlib
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/* $Id: shpcmlib.c,v 1.2 2003/08/02 13:10:32 chikama Exp $ */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <SDL_mixer.h>
|
||||
|
||||
#include "portab.h"
|
||||
|
||||
/*
|
||||
左右のチャンネルの入れ換え
|
||||
*/
|
||||
void pcmlib_reverse_pan_memory(Mix_Chunk *chunk) {
|
||||
if (chunk == NULL) return;
|
||||
|
||||
short *buf = (short*)chunk->abuf;
|
||||
int len = chunk->alen / 4;
|
||||
for (int i = 0; i < len; i++) {
|
||||
short tmp = buf[0];
|
||||
buf[0] = buf[1];
|
||||
buf[1] = tmp;
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
メモリ上の PCM データにフェード効果をかける
|
||||
*/
|
||||
void pcmlib_fade_volume_memory(Mix_Chunk *chunk, int start, int range) {
|
||||
if (chunk == NULL) return;
|
||||
|
||||
start *= 441; // 10ms -> sample
|
||||
range *= 441; // 10ms -> sample
|
||||
|
||||
if (chunk->alen / 4 < start + range)
|
||||
return;
|
||||
|
||||
short *buf = (short*)chunk->abuf;
|
||||
buf += start * 2;
|
||||
|
||||
// 指定の場所から徐々に音量を下げる
|
||||
for (int i = range; i > 0; i--) {
|
||||
buf[0] = buf[0] * i / range;
|
||||
buf[1] = buf[1] * i / range;
|
||||
buf += 2;
|
||||
}
|
||||
|
||||
// 残りは無音
|
||||
memset(buf, 0, chunk->abuf + chunk->alen - (Uint8*)buf);
|
||||
}
|
||||
@@ -89,7 +89,9 @@ static void SetWindowTitle(void) { /* 6 */
|
||||
int strno = getCaliValue();
|
||||
int p2 = getCaliValue(); /* ISys3xSystem */
|
||||
|
||||
ags_setWindowTitle(svar_get(strno));
|
||||
char *title_utf8 = toUTF8(svar_get(strno));
|
||||
ags_setWindowTitle(title_utf8);
|
||||
free(title_utf8);
|
||||
|
||||
DEBUG_COMMAND("ShString.SetWindowTitle: %d,%d:", strno, p2);
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ static void Run() {
|
||||
DEBUG_COMMAND_YET("dDemo.Run:");
|
||||
|
||||
#ifdef DDEMODEV
|
||||
mus_cdrom_start(13, 1);
|
||||
muscd_start(13, 1);
|
||||
// ddemo_scene();
|
||||
|
||||
while(0 == sys_getInputInfo()) {
|
||||
usleep(1000 * 100);
|
||||
}
|
||||
|
||||
mus_cdrom_stop();
|
||||
muscd_stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ void gr_drawimage16(surface_t *ds, cgdata *cg, int x, int y) {
|
||||
yl = (uint32_t *)(dp + y * ds->bytes_per_line);
|
||||
for (x = 0; x < dw; x++) {
|
||||
pic16 = *sp;
|
||||
*yl = PIX24(PIXR16(pic16), PIXG16(pic16), PIXB16(pic16));
|
||||
*yl = rgb565_to_rgb888(pic16);
|
||||
yl++; sp++;
|
||||
}
|
||||
sp += (cg->width - dw);
|
||||
|
||||
+4
-9
@@ -53,7 +53,7 @@ target_sources(xsystem35 PRIVATE
|
||||
|
||||
# Misc
|
||||
target_sources(xsystem35 PRIVATE
|
||||
LittleEndian.c input.c profile.c mt19937-1.c filecheck.c mmap.c)
|
||||
input.c profile.c mt19937-1.c filecheck.c mmap.c hacks.c)
|
||||
|
||||
# Scenario
|
||||
target_sources(xsystem35 PRIVATE
|
||||
@@ -84,6 +84,7 @@ if (EMSCRIPTEN)
|
||||
"SHELL:-s USE_ZLIB=1"
|
||||
"SHELL:-s USE_SDL=2"
|
||||
"SHELL:-s USE_SDL_TTF=2")
|
||||
target_compile_options(src_lib PRIVATE ${LIBS})
|
||||
target_compile_options(xsystem35 PRIVATE ${LIBS})
|
||||
target_link_options(xsystem35 PRIVATE ${LIBS})
|
||||
target_link_libraries(xsystem35 PRIVATE idbfs.js)
|
||||
@@ -95,10 +96,11 @@ if (EMSCRIPTEN)
|
||||
"SHELL:-s ENVIRONMENT=web"
|
||||
"SHELL:-s ASYNCIFY=1 -s ASYNCIFY_IGNORE_INDIRECT=1"
|
||||
"SHELL:-s ASYNCIFY_REMOVE=SDL_Delay"
|
||||
"SHELL:-s ASYNCIFY_IMPORTS=muspcm_load_no,muspcm_load_mixlr,muspcm_waitend,wait_vsync,load_mincho_font"
|
||||
"SHELL:-s ASYNCIFY_IMPORTS=muspcm_load_no,muspcm_load_data,muspcm_load_mixlr,muspcm_waitend,wait_vsync,load_mincho_font"
|
||||
"SHELL:-s ASYNCIFY_ADD=commands2F60,nact_main,send_agsevent,cb_waitkey_sprite"
|
||||
"SHELL:-s ALLOW_MEMORY_GROWTH=1"
|
||||
"SHELL:-s NO_EXIT_RUNTIME=1"
|
||||
"SHELL:-s EXPORTED_FUNCTIONS=_main,_malloc"
|
||||
"SHELL:-s EXPORTED_RUNTIME_METHODS=getValue,addRunDependency,removeRunDependency")
|
||||
|
||||
elseif (ANDROID)
|
||||
@@ -140,10 +142,3 @@ else() # non-emscripten, non-android
|
||||
add_test(NAME src_tests COMMAND src_tests)
|
||||
configure_file(testdata/test.gr ${CMAKE_CURRENT_BINARY_DIR}/testdata/test.gr COPYONLY)
|
||||
endif()
|
||||
|
||||
# FIXME: set up dependency for xsystem35 on this
|
||||
if (NOT EMSCRIPTEN AND NOT ANDROID)
|
||||
add_custom_target(sdl_keytable.h
|
||||
COMMAND perl ../tools/xsyskey.pl ${SDL2_INCLUDE_DIRS} > sdl_keytable.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* LittleEndian.c get little endian value
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* @version 0.00 97/11/06 初版
|
||||
*/
|
||||
/* $Id: LittleEndian.c,v 1.5 2000/11/25 13:08:56 chikama Exp $ */
|
||||
|
||||
#include "portab.h"
|
||||
|
||||
int LittleEndian_getDW(const uint8_t *b,int index) {
|
||||
int c0, c1, c2, c3;
|
||||
int d0, d1;
|
||||
c0 = *(b + index + 0);
|
||||
c1 = *(b + index + 1);
|
||||
c2 = *(b + index + 2);
|
||||
c3 = *(b + index + 3);
|
||||
d0 = c0 + (c1 << 8);
|
||||
d1 = c2 + (c3 << 8);
|
||||
return (uint32_t)(d0 + (d1 << 16));
|
||||
}
|
||||
|
||||
int LittleEndian_get3B(const uint8_t *b,int index) {
|
||||
int c0, c1, c2;
|
||||
c0 = *(b + index + 0);
|
||||
c1 = *(b + index + 1);
|
||||
c2 = *(b + index + 2);
|
||||
return c0 + (c1 << 8) + (c2 << 16);
|
||||
}
|
||||
|
||||
int LittleEndian_getW(const uint8_t *b,int index) {
|
||||
int c0, c1;
|
||||
c0 = *(b + index + 0);
|
||||
c1 = *(b + index + 1);
|
||||
return c0 + (c1 << 8);
|
||||
}
|
||||
|
||||
void LittleEndian_putW(int num, uint8_t *b, int index) {
|
||||
int c0, c1;
|
||||
num %= 65536;
|
||||
c0 = num % 256;
|
||||
c1 = num / 256;
|
||||
b[index] = c0; b[index+1] = c1;
|
||||
}
|
||||
|
||||
+29
-5
@@ -26,11 +26,35 @@
|
||||
#ifndef __LITTLEENDIAN__
|
||||
#define __LITTLEENDIAN__
|
||||
|
||||
#include "portab.h"
|
||||
#include <string.h>
|
||||
#include <SDL_endian.h>
|
||||
|
||||
extern int LittleEndian_getDW(const uint8_t *b,int index);
|
||||
extern int LittleEndian_get3B(const uint8_t *b,int index);
|
||||
extern int LittleEndian_getW(const uint8_t *b,int index);
|
||||
extern void LittleEndian_putW(int num, uint8_t *b, int index);
|
||||
static inline int LittleEndian_getDW(const uint8_t *b, int index) {
|
||||
uint32_t t;
|
||||
memcpy(&t, b + index, sizeof t);
|
||||
return SDL_SwapLE32(t);
|
||||
}
|
||||
|
||||
static inline int LittleEndian_get3B(const uint8_t *b, int index) {
|
||||
uint32_t t = 0;
|
||||
memcpy(&t, b + index, 3);
|
||||
return SDL_SwapLE32(t);
|
||||
}
|
||||
|
||||
static inline int LittleEndian_getW(const uint8_t *b, int index) {
|
||||
uint16_t t;
|
||||
memcpy(&t, b + index, sizeof t);
|
||||
return SDL_SwapLE16(t);
|
||||
}
|
||||
|
||||
static inline void LittleEndian_putW(uint16_t num, uint8_t *b, int index) {
|
||||
num = SDL_SwapLE16(num);
|
||||
memcpy(b + index, &num, sizeof(num));
|
||||
}
|
||||
|
||||
static inline void LittleEndian_putDW(uint32_t num, uint8_t *b, int index) {
|
||||
num = SDL_SwapLE32(num);
|
||||
memcpy(b + index, &num, sizeof(num));
|
||||
}
|
||||
|
||||
#endif /* !__LITTLEENDIAN__ */
|
||||
|
||||
@@ -42,23 +42,44 @@
|
||||
#include "font.h"
|
||||
#include "cursor.h"
|
||||
#include "image.h"
|
||||
#include "debugger.h"
|
||||
|
||||
static Palette256 pal_256;
|
||||
static boolean need_update = TRUE;
|
||||
static boolean fade_outed = FALSE;
|
||||
static int cursor_move_time = 50; /* カーソル移動にかかる時間(ms) */
|
||||
|
||||
static void initPal(Palette256 *pal) {
|
||||
int i;
|
||||
for (i = 0; i < 256; i++) {
|
||||
pal->red[i] = 0; pal->green[i] = 0; pal->blue[i] = 0;
|
||||
}
|
||||
pal->red[0] = 0; pal->green[0] = 0; pal->blue[0] = 0;
|
||||
pal->red[7] = 255; pal->green[7] = 255; pal->blue[7] = 255;
|
||||
pal->red[15] = 255; pal->green[15] = 255; pal->blue[15] = 255;
|
||||
pal->red[255] = 255; pal->green[255] = 255; pal->blue[255] = 255;
|
||||
sdl_setPalette(pal, 0, 256);
|
||||
static void palette_changed(void) {
|
||||
nact->ags.pal_changed = TRUE;
|
||||
dbg_on_palette_change();
|
||||
}
|
||||
|
||||
static void initPal(void) {
|
||||
static const Color initial_palette[256] = {
|
||||
[ 0] = { 0, 0, 0},
|
||||
[ 1] = {128, 0, 0},
|
||||
[ 2] = { 0, 128, 0},
|
||||
[ 3] = {128, 128, 0},
|
||||
[ 4] = { 0, 0, 128},
|
||||
[ 5] = {128, 0, 128},
|
||||
[ 6] = { 0, 128, 128},
|
||||
[ 7] = {192, 192, 192},
|
||||
[ 8] = {192, 220, 192},
|
||||
[ 9] = {166, 202, 240},
|
||||
[ 15] = {255, 255, 255},
|
||||
[246] = {255, 251, 240},
|
||||
[247] = {160, 160, 164},
|
||||
[248] = {128, 128, 128},
|
||||
[249] = {255, 0, 0},
|
||||
[250] = { 0, 255, 0},
|
||||
[251] = {255, 255, 0},
|
||||
[252] = { 0, 0, 255},
|
||||
[253] = {255, 0, 255},
|
||||
[254] = { 0, 255, 255},
|
||||
[255] = {255, 255, 255},
|
||||
};
|
||||
memcpy(nact->ags.pal, initial_palette, sizeof(initial_palette));
|
||||
sdl_setPalette(nact->ags.pal, 0, 256);
|
||||
palette_changed();
|
||||
}
|
||||
|
||||
boolean ags_check_param(int *x, int *y, int *w, int *h) {
|
||||
@@ -100,8 +121,7 @@ boolean ags_check_param_xy(int *x, int *y) {
|
||||
}
|
||||
|
||||
void ags_init(const char *render_driver) {
|
||||
nact->ags.mouse_movesw = MOUSE_WARP_SMOOTH;
|
||||
nact->ags.pal = &pal_256;
|
||||
nact->ags.mouse_warp_enabled = true;
|
||||
nact->ags.world_size.width = SYS35_DEFAULT_WIDTH;
|
||||
nact->ags.world_size.height = SYS35_DEFAULT_HEIGHT;
|
||||
nact->ags.world_depth = SYS35_DEFAULT_DEPTH;
|
||||
@@ -113,7 +133,7 @@ void ags_init(const char *render_driver) {
|
||||
sdl_Initialize(render_driver);
|
||||
font_init();
|
||||
|
||||
initPal(&pal_256);
|
||||
initPal();
|
||||
cg_init();
|
||||
}
|
||||
|
||||
@@ -123,9 +143,9 @@ void ags_remove(void) {
|
||||
}
|
||||
|
||||
void ags_reset(void) {
|
||||
nact->ags.mouse_movesw = MOUSE_WARP_SMOOTH;
|
||||
nact->ags.mouse_warp_enabled = true;
|
||||
nact->ags.eventcb = NULL;
|
||||
initPal(&pal_256);
|
||||
initPal();
|
||||
cg_reset();
|
||||
}
|
||||
|
||||
@@ -151,7 +171,7 @@ void ags_setWorldSize(int width, int height, int depth) {
|
||||
|
||||
fade_outed = FALSE; /* thanx tajiri@wizard */
|
||||
|
||||
nact->ags.pal_changed = TRUE;
|
||||
palette_changed();
|
||||
}
|
||||
|
||||
void ags_setViewArea(int x, int y, int width, int height) {
|
||||
@@ -162,19 +182,10 @@ void ags_setViewArea(int x, int y, int width, int height) {
|
||||
sdl_setWindowSize(width, height);
|
||||
}
|
||||
|
||||
void ags_setWindowTitle(const char *src) {
|
||||
#define TITLEHEAD "XSystem35 Version "VERSION":"
|
||||
uint8_t *utf, *d;
|
||||
|
||||
utf = toUTF8(src);
|
||||
if (NULL == (d = malloc(strlen(utf) + strlen(TITLEHEAD) + 1))) {
|
||||
NOMEMERR();
|
||||
}
|
||||
strcpy(d, TITLEHEAD);
|
||||
strcat(d, utf);
|
||||
sdl_setWindowTitle(d);
|
||||
free(utf);
|
||||
free(d);
|
||||
void ags_setWindowTitle(const char *title_utf8) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "XSystem35 Version %s: %s", VERSION, title_utf8);
|
||||
sdl_setWindowTitle(buf);
|
||||
}
|
||||
|
||||
void ags_getDIBInfo(DispInfo *info) {
|
||||
@@ -225,21 +236,18 @@ void ags_updateFull() {
|
||||
sdl_updateArea(&r, &p);
|
||||
}
|
||||
|
||||
void ags_setPalettes(Palette256 *src_pal, int src, int dst, int cnt) {
|
||||
int i;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
nact->ags.pal->red [dst + i] = src_pal->red [src + i];
|
||||
nact->ags.pal->green[dst + i] = src_pal->green[src + i];
|
||||
nact->ags.pal->blue [dst + i] = src_pal->blue [src + i];
|
||||
void ags_setPalettes(Color *src, int dst, int cnt) {
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
nact->ags.pal[dst + i] = src[i];
|
||||
}
|
||||
nact->ags.pal_changed = TRUE;
|
||||
palette_changed();
|
||||
}
|
||||
|
||||
void ags_setPalette(int no, int red, int green, int blue) {
|
||||
nact->ags.pal->red[no] = red;
|
||||
nact->ags.pal->green[no] = green;
|
||||
nact->ags.pal->blue[no] = blue;
|
||||
nact->ags.pal_changed = TRUE;
|
||||
nact->ags.pal[no].r = red;
|
||||
nact->ags.pal[no].g = green;
|
||||
nact->ags.pal[no].b = blue;
|
||||
palette_changed();
|
||||
}
|
||||
|
||||
void ags_setPaletteToSystem(int src, int cnt) {
|
||||
@@ -586,9 +594,9 @@ void ags_fadeOut(int rate, boolean flag) {
|
||||
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_FADEOUT : EFFECT_DITHERING_FADEOUT);
|
||||
|
||||
if (nact->ags.world_depth == 8) {
|
||||
Palette256 pal;
|
||||
Color pal[256];
|
||||
memset(&pal, 0, sizeof(pal));
|
||||
sdl_setPalette(&pal, 0, 256);
|
||||
sdl_setPalette(pal, 0, 256);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,9 +623,9 @@ void ags_whiteOut(int rate, boolean flag) {
|
||||
fade(duration, flag, nact->ags.world_depth == 8 ? EFFECT_WHITEIN : EFFECT_DITHERING_WHITEOUT);
|
||||
|
||||
if (nact->ags.world_depth == 8) {
|
||||
Palette256 pal;
|
||||
Color pal[256];
|
||||
memset(&pal, 255, sizeof(pal));
|
||||
sdl_setPalette(&pal, 0, 256);
|
||||
sdl_setPalette(pal, 0, 256);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,42 +644,42 @@ void ags_loadCursor(int p1,int p2) {
|
||||
}
|
||||
}
|
||||
|
||||
void ags_setCursorLocation(int x, int y, boolean is_dibgeo) {
|
||||
int dx[8], dy[8];
|
||||
int i, delx, dely;
|
||||
MyPoint p;
|
||||
void ags_setCursorLocation(int x, int y, bool is_dibgeo, bool for_selection) {
|
||||
if (!ags_check_param_xy(&x, &y)) return;
|
||||
|
||||
/* DIB 座表系か Window 座表系か */
|
||||
if (is_dibgeo) {
|
||||
// DIB coordinates -> Window coordinates
|
||||
x -= nact->ags.view_area.x;
|
||||
y -= nact->ags.view_area.y;
|
||||
}
|
||||
|
||||
switch(nact->ags.mouse_movesw) {
|
||||
case MOUSE_WARP_DISABLED:
|
||||
return;
|
||||
case MOUSE_WARP_DIRECT:
|
||||
sdl_setCursorLocation(x, y); break;
|
||||
case MOUSE_WARP_SMOOTH:
|
||||
sys_getMouseInfo(&p, is_dibgeo);
|
||||
delx = x - p.x;
|
||||
dely = y - p.y;
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
dx[i-1] = ((delx*i*i*i) >> 9) - ((3*delx*i*i)>> 6) + ((3*delx*i) >> 3) + p.x;
|
||||
dy[i-1] = ((dely*i*i*i) >> 9) - ((3*dely*i*i)>> 6) + ((3*dely*i) >> 3) + p.y;
|
||||
}
|
||||
dx[7] = x; dy[7] = y;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
sdl_setCursorLocation(dx[i], dy[i]);
|
||||
usleep(cursor_move_time * 1000 / 8);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (!for_selection) {
|
||||
// We can't move the actual cursor in the browser, but can change the
|
||||
// internal mouse coordinates. This can help with keyboard/gamepad
|
||||
// navigation.
|
||||
sdl_setCursorInternalLocation(x, y);
|
||||
EM_ASM({ xsystem35.shell.showMouseMoveEffect($0, $1); }, x, y);
|
||||
sdl_sleep(cursor_move_time);
|
||||
}
|
||||
#else
|
||||
if (nact->ags.mouse_warp_enabled) {
|
||||
MyPoint p;
|
||||
sys_getMouseInfo(&p, is_dibgeo);
|
||||
int dx = x - p.x;
|
||||
int dy = y - p.y;
|
||||
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 yi = ((dy*i*i*i) >> 9) - ((3*dy*i*i)>> 6) + ((3*dy*i) >> 3) + p.y;
|
||||
sdl_setCursorLocation(xi, yi);
|
||||
sdl_sleep(cursor_move_time / 7);
|
||||
}
|
||||
sdl_setCursorLocation(x, y);
|
||||
} else if (!for_selection) {
|
||||
sdl_setCursorInternalLocation(x, y);
|
||||
sdl_sleep(cursor_move_time);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
|
||||
@@ -78,33 +78,30 @@ typedef struct agsurface agsurface_t;
|
||||
// for SDL_surface
|
||||
#define PIXEL_AT(suf, x, y) ((suf)->pixels + (y) * (suf)->pitch + (x) * (suf)->format->BytesPerPixel)
|
||||
|
||||
struct _agsevent {
|
||||
typedef struct {
|
||||
int type;
|
||||
int d1, d2, d3;
|
||||
int code;
|
||||
int mousex, mousey;
|
||||
} agsevent_t;
|
||||
|
||||
enum agsevent_type {
|
||||
AGSEVENT_MOUSE_MOTION,
|
||||
AGSEVENT_BUTTON_PRESS,
|
||||
AGSEVENT_BUTTON_RELEASE,
|
||||
AGSEVENT_KEY_PRESS,
|
||||
AGSEVENT_KEY_RELEASE,
|
||||
AGSEVENT_TIMER,
|
||||
AGSEVENT_MOUSE_WHEEL,
|
||||
};
|
||||
typedef struct _agsevent agsevent_t;
|
||||
|
||||
|
||||
#define AGSEVENT_MOUSE_MOTION 1
|
||||
#define AGSEVENT_BUTTON_PRESS 2
|
||||
#define AGSEVENT_BUTTON_RELEASE 3
|
||||
#define AGSEVENT_KEY_PRESS 4
|
||||
#define AGSEVENT_KEY_RELEASE 5
|
||||
#define AGSEVENT_TIMER 6
|
||||
#define AGSEVENT_MOUSE_WHEEL 7
|
||||
|
||||
#define AGSEVENT_BUTTON_LEFT 1
|
||||
#define AGSEVENT_BUTTON_MID 2
|
||||
#define AGSEVENT_BUTTON_RIGHT 3
|
||||
|
||||
enum mouse_warp_mode {
|
||||
MOUSE_WARP_DISABLED,
|
||||
MOUSE_WARP_DIRECT,
|
||||
MOUSE_WARP_SMOOTH,
|
||||
enum agsevent_button {
|
||||
AGSEVENT_BUTTON_LEFT,
|
||||
AGSEVENT_BUTTON_MID,
|
||||
AGSEVENT_BUTTON_RIGHT,
|
||||
};
|
||||
|
||||
struct _ags {
|
||||
Palette256 *pal; /* system palette */
|
||||
Color pal[256]; /* system palette */
|
||||
boolean pal_changed; /* system palette has changed */
|
||||
|
||||
MyDimension world_size; /* size of off-screen */
|
||||
@@ -113,11 +110,10 @@ struct _ags {
|
||||
|
||||
int world_depth; /* depth of off-screen (bits per pixel) */
|
||||
|
||||
enum mouse_warp_mode mouse_movesw;
|
||||
|
||||
agsurface_t *dib; /* main surface */
|
||||
void (*eventcb)(agsevent_t *e); /* deliver event */
|
||||
|
||||
bool mouse_warp_enabled;
|
||||
boolean noantialias; /* antialias を使用しない */
|
||||
boolean noimagecursor; /* リソースファイルのカーソルを読みこまない */
|
||||
};
|
||||
@@ -133,7 +129,7 @@ void ags_reset(void);
|
||||
/* ウィンド関係 */
|
||||
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_setWindowTitle(const char *str);
|
||||
extern void ags_setWindowTitle(const char *title_utf8);
|
||||
extern void ags_getDIBInfo(DispInfo *info);
|
||||
extern void ags_getWindowInfo(DispInfo *info);
|
||||
extern void ags_getViewAreaInfo(DispInfo *info);
|
||||
@@ -147,7 +143,7 @@ extern void ags_updateFull(void);
|
||||
extern void ags_updateArea(int x, int y, int width, int height);
|
||||
|
||||
/* パレット関係 */
|
||||
extern void ags_setPalettes(Palette256 *src_pal, int src, int dst, int cnt);
|
||||
extern void ags_setPalettes(Color *src, int dst, int cnt);
|
||||
extern void ags_setPalette(int no, int red, int green, int blue);
|
||||
extern void ags_setPaletteToSystem(int src, int cnt);
|
||||
|
||||
@@ -208,7 +204,7 @@ extern agsurface_t *ags_drawStringToSurface(const char *str);
|
||||
/* カーソル関係 */
|
||||
extern void ags_setCursorType(int type);
|
||||
extern void ags_loadCursor(int ,int);
|
||||
extern void ags_setCursorLocation(int x, int y, boolean dibgeo);
|
||||
extern void ags_setCursorLocation(int x, int y, bool is_dibgeo, bool for_selection);
|
||||
extern void ags_setCursorMoveTime(int msec);
|
||||
extern int ags_getCursorMoveTime();
|
||||
|
||||
|
||||
+6
-5
@@ -36,11 +36,6 @@ static drifiles *dri[DRIFILETYPEMAX];
|
||||
/* cache handler for dri file */
|
||||
static cacher *cacheid;
|
||||
|
||||
/*
|
||||
* static maethods
|
||||
*/
|
||||
static void ald_free(dridata *dfile);
|
||||
|
||||
/*
|
||||
* free dridata
|
||||
* dfile: dridata to be free
|
||||
@@ -109,3 +104,9 @@ void ald_init(int type, const char **file, int cnt, boolean use_mmap) {
|
||||
cacheid = cache_new(ald_free);
|
||||
}
|
||||
}
|
||||
|
||||
int ald_get_maxno(DRIFILETYPE type) {
|
||||
if (type >= DRIFILETYPEMAX || !dri[type])
|
||||
return 0;
|
||||
return dri[type]->maxno;
|
||||
}
|
||||
|
||||
+4
-3
@@ -38,9 +38,10 @@ typedef enum {
|
||||
DRIFILE_BGM =6 /* stream music data */
|
||||
} DRIFILETYPE;
|
||||
|
||||
extern void ald_init(int type, const char **file, int cnt, boolean use_mmap);
|
||||
extern dridata *ald_getdata(DRIFILETYPE type, int no);
|
||||
extern void ald_freedata(dridata *data);
|
||||
void ald_init(int type, const char **file, int cnt, boolean use_mmap);
|
||||
dridata *ald_getdata(DRIFILETYPE type, int no);
|
||||
void ald_freedata(dridata *data);
|
||||
int ald_get_maxno(DRIFILETYPE type);
|
||||
|
||||
#endif /* !__ALD_MANAGER__ */
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "portab.h"
|
||||
#include "bgm.h"
|
||||
|
||||
int musbgm_init(void) {
|
||||
int musbgm_init(DRIFILETYPE type, int base_no) {
|
||||
return NG;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,12 @@
|
||||
#include "bgi.h"
|
||||
#include "sdl_core.h"
|
||||
|
||||
int musbgm_init(void) {
|
||||
return bgi_read(nact->files.bgi);
|
||||
int musbgm_init(DRIFILETYPE type, int base_no) {
|
||||
if (type == DRIFILE_BGM)
|
||||
return bgi_read(nact->files.bgi);
|
||||
else
|
||||
EM_ASM({ xsystem35.cdPlayer.setBGMLoader($0, $1); }, type, base_no);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int musbgm_exit(void) {
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#ifndef __BGM_H__
|
||||
#define __BGM_H__
|
||||
|
||||
int musbgm_init(void);
|
||||
#include "ald_manager.h"
|
||||
|
||||
int musbgm_init(DRIFILETYPE type, int base_no);
|
||||
int musbgm_exit(void);
|
||||
int musbgm_reset(void);
|
||||
int musbgm_play(int no, int time, int vol);
|
||||
|
||||
+12
-5
@@ -36,6 +36,8 @@
|
||||
#include "music_private.h"
|
||||
#include "ald_manager.h"
|
||||
|
||||
static DRIFILETYPE dri_type;
|
||||
static int base_no;
|
||||
static int current_no;
|
||||
static Mix_Music *mix_music;
|
||||
static dridata* dfile;
|
||||
@@ -56,9 +58,10 @@ static void free_music() {
|
||||
static Mix_Music *bgm_load(int no) {
|
||||
free_music();
|
||||
|
||||
dfile = ald_getdata(DRIFILE_BGM, no -1);
|
||||
int ald_no = no + base_no - 1;
|
||||
dfile = ald_getdata(dri_type, ald_no);
|
||||
if (dfile == NULL) {
|
||||
WARNING("DRIFILE_BGM fail to open %d", no -1);
|
||||
WARNING("Failed to open BGM %d", ald_no);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -66,7 +69,7 @@ static Mix_Music *bgm_load(int no) {
|
||||
|
||||
mix_music = Mix_LoadMUS_RW(rwops, SDL_TRUE /* freesrc */);
|
||||
if (mix_music == NULL) {
|
||||
WARNING("Failed to load BGM %d: %s", no, SDL_GetError());
|
||||
WARNING("Failed to load BGM %d: %s", ald_no, SDL_GetError());
|
||||
free_music();
|
||||
return NULL;
|
||||
}
|
||||
@@ -75,8 +78,12 @@ static Mix_Music *bgm_load(int no) {
|
||||
return mix_music;
|
||||
}
|
||||
|
||||
int musbgm_init(void) {
|
||||
return bgi_read(nact->files.bgi);
|
||||
int musbgm_init(DRIFILETYPE type, int base) {
|
||||
dri_type = type;
|
||||
base_no = base;
|
||||
if (type == DRIFILE_BGM)
|
||||
return bgi_read(nact->files.bgi);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int musbgm_exit(void) {
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
* static methods
|
||||
*/
|
||||
static bmp_header *extract_header(uint8_t *b);
|
||||
static void getpal(Palette256 *pal, uint8_t *b);
|
||||
static void extract_8bit(bmp_header *bmp, uint8_t *pic, uint8_t *b);
|
||||
static void extract_24bit(bmp_header *bmp, uint16_t *pic, uint8_t *b);
|
||||
|
||||
@@ -65,17 +64,16 @@ static bmp_header *extract_header(uint8_t *b) {
|
||||
|
||||
/*
|
||||
* Get palette from raw data
|
||||
* pal: palette to be stored
|
||||
* b : raw data (pointer to palette)
|
||||
*/
|
||||
static void getpal(Palette256 *pal, uint8_t *b) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
pal->blue[i] = *b++;
|
||||
pal->red[i] = *b++;
|
||||
pal->green[i] = *b++;
|
||||
static Color *getpal(uint8_t *b) {
|
||||
Color *pal = malloc(sizeof(Color) * 256);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
pal[i].b = *b++;
|
||||
pal[i].r = *b++;
|
||||
pal[i].g = *b++;
|
||||
}
|
||||
return pal;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -168,8 +166,7 @@ cgdata *bmp256_extract(uint8_t *data) {
|
||||
bmp_header *bmp = extract_header(data);
|
||||
cgdata *cg = calloc(1, sizeof(cgdata));
|
||||
|
||||
cg->pal = malloc(sizeof(Palette256));
|
||||
getpal(cg->pal, data + bmp->bmpPp);
|
||||
cg->pal = getpal(data + bmp->bmpPp);
|
||||
|
||||
/* +10: margin for broken cg */
|
||||
cg->pic = malloc(sizeof(uint8_t) * ((bmp->bmpXW + 10) * (bmp->bmpYW + 10)));
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 <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 <SDL.h>
|
||||
#include <jni.h>
|
||||
#include "system.h"
|
||||
#include "portab.h"
|
||||
#include "cdrom.h"
|
||||
|
||||
static int cdrom_init(char *);
|
||||
static int cdrom_exit(void);
|
||||
static int cdrom_reset(void);
|
||||
static int cdrom_start(int, int);
|
||||
static int cdrom_stop();
|
||||
static int cdrom_getPlayingInfo(cd_time *);
|
||||
|
||||
#define cdrom cdrom_android
|
||||
cdromdevice_t cdrom = {
|
||||
cdrom_init,
|
||||
cdrom_exit,
|
||||
cdrom_reset,
|
||||
cdrom_start,
|
||||
cdrom_stop,
|
||||
cdrom_getPlayingInfo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
int cdrom_init(char *name) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_reset(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_exit(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_start(int trk, int loop) {
|
||||
JNIEnv *env = SDL_AndroidGetJNIEnv();
|
||||
if ((*env)->PushLocalFrame(env, 16) < 0) {
|
||||
WARNING("Failed to allocate JVM local references");
|
||||
return NG;
|
||||
}
|
||||
jobject context = SDL_AndroidGetActivity();
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
|
||||
"cddaStart", "(IZ)V");
|
||||
(*env)->CallVoidMethod(env, context, mid, trk, loop == 0);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_stop() {
|
||||
JNIEnv *env = SDL_AndroidGetJNIEnv();
|
||||
if ((*env)->PushLocalFrame(env, 16) < 0) {
|
||||
WARNING("Failed to allocate JVM local references");
|
||||
return NG;
|
||||
}
|
||||
jobject context = SDL_AndroidGetActivity();
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
|
||||
"cddaStop", "()V");
|
||||
(*env)->CallVoidMethod(env, context, mid);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_getPlayingInfo (cd_time *info) {
|
||||
JNIEnv *env = SDL_AndroidGetJNIEnv();
|
||||
if ((*env)->PushLocalFrame(env, 16) < 0) {
|
||||
WARNING("Failed to allocate JVM local references");
|
||||
return NG;
|
||||
}
|
||||
jobject context = SDL_AndroidGetActivity();
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
|
||||
"cddaCurrentPosition", "()I");
|
||||
int t = (*env)->CallIntMethod(env, context, mid);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
|
||||
info->t = t & 0xff;
|
||||
FRAMES_TO_MSF(t >> 8, &info->m, &info->s, &info->f);
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* cdrom.bgm.c CD->bgm bridge
|
||||
*
|
||||
* Copyright (C) 2023 <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 <stdio.h>
|
||||
|
||||
#include "cdrom.h"
|
||||
#include "ald_manager.h"
|
||||
#include "music.h"
|
||||
#include "music_private.h"
|
||||
|
||||
static int current_track;
|
||||
|
||||
static int cdrom_bgm_init(char *dev) {
|
||||
prv.cd_maxtrk = ald_get_maxno(DRIFILE_BGM) + 1;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int cdrom_bgm_exit(void) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int cdrom_bgm_reset(void) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int cdrom_bgm_start(int trk, int loop) {
|
||||
if (musbgm_play(trk, 0, 100) != OK)
|
||||
return NG;
|
||||
current_track = trk;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int cdrom_bgm_stop(void) {
|
||||
return musbgm_stop(current_track, 0);
|
||||
}
|
||||
|
||||
static int cdrom_bgm_getPlayingInfo(cd_time *info) {
|
||||
int t = musbgm_getpos(current_track); // in 10ms
|
||||
if (!t)
|
||||
return NG;
|
||||
info->t = current_track;
|
||||
info->m = t / (60*100); t %= (60*100);
|
||||
info->s = t / 100; t %= 100;
|
||||
info->f = t * CD_FPS / 100;
|
||||
return OK;
|
||||
}
|
||||
|
||||
cdromdevice_t cdrom_bgm = {
|
||||
cdrom_bgm_init,
|
||||
cdrom_bgm_exit,
|
||||
cdrom_bgm_reset,
|
||||
cdrom_bgm_start,
|
||||
cdrom_bgm_stop,
|
||||
cdrom_bgm_getPlayingInfo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
+16
-58
@@ -26,7 +26,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "portab.h"
|
||||
#include "cdrom.h"
|
||||
@@ -34,80 +33,39 @@
|
||||
|
||||
#if defined(ENABLE_CDROM_LINUX)
|
||||
extern cdromdevice_t cdrom_linux;
|
||||
#define DEV_PLAY_MODE &cdrom_linux
|
||||
#define NATIVE_CD_DEVICE &cdrom_linux
|
||||
|
||||
#elif defined(ENABLE_CDROM_BSD)
|
||||
extern cdromdevice_t cdrom_bsd;
|
||||
#define DEV_PLAY_MODE &cdrom_bsd
|
||||
#define NATIVE_CD_DEVICE &cdrom_bsd
|
||||
|
||||
#elif defined(ENABLE_CDROM_EMSCRIPTEN)
|
||||
extern cdromdevice_t cdrom_emscripten;
|
||||
#define DEV_PLAY_MODE &cdrom_emscripten
|
||||
|
||||
#elif defined(ENABLE_CDROM_ANDROID)
|
||||
extern cdromdevice_t cdrom_android;
|
||||
#define DEV_PLAY_MODE &cdrom_android
|
||||
#define NATIVE_CD_DEVICE &cdrom_emscripten
|
||||
|
||||
#else
|
||||
|
||||
extern cdromdevice_t cdrom_empty;
|
||||
#define DEV_PLAY_MODE &cdrom_empty
|
||||
#define NATIVE_CD_DEVICE &cdrom_empty
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CDROM_MP3
|
||||
extern cdromdevice_t cdrom_mp3;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
temporary cdrom device name
|
||||
|
||||
default ... /dev/cdrom
|
||||
|
||||
FreeBSD ... /dev/acd0a
|
||||
etc...
|
||||
*/
|
||||
static char *dev = CDROM_DEVICE;
|
||||
|
||||
|
||||
/*
|
||||
初期化
|
||||
dev: cdromdevice に関する情報を格納する場所
|
||||
RET: 成功 0
|
||||
失敗 -1
|
||||
*/
|
||||
int cd_init(cdromdevice_t *cd) {
|
||||
#if defined(ENABLE_CDROM_EMSCRIPTEN) || defined(ENABLE_CDROM_ANDROID)
|
||||
memcpy(cd, DEV_PLAY_MODE, sizeof(cdromdevice_t));
|
||||
return cd->init(dev);
|
||||
cdromdevice_t *cd_init(const char *dev) {
|
||||
#if defined(ENABLE_CDROM_EMSCRIPTEN)
|
||||
return NATIVE_CD_DEVICE;
|
||||
#else
|
||||
struct stat st;
|
||||
int ret = NG;
|
||||
|
||||
if (dev == NULL) return -1;
|
||||
|
||||
stat(dev, &st);
|
||||
if (S_ISBLK(st.st_mode) | S_ISCHR(st.st_mode)) {
|
||||
/* CDROM MODE */
|
||||
memcpy(cd, DEV_PLAY_MODE, sizeof(cdromdevice_t));
|
||||
ret = cd->init(dev);
|
||||
}
|
||||
else {
|
||||
#ifdef ENABLE_CDROM_MP3
|
||||
/* MP3 MODE */
|
||||
memcpy(cd, &cdrom_mp3, sizeof(cdromdevice_t));
|
||||
ret = cd->init(dev);
|
||||
#else
|
||||
/* error */
|
||||
WARNING("no cdrom device available");
|
||||
ret = NG;
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
#endif // ENABLE_CDROM_EMSCRIPTEN || ENABLE_CDROM_ANDROID
|
||||
}
|
||||
if (dev && stat(dev, &st) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
|
||||
return NATIVE_CD_DEVICE;
|
||||
|
||||
void cd_set_devicename(char *name) {
|
||||
if (0 == strcmp("none", name)) dev = NULL;
|
||||
else dev = strdup(name);
|
||||
#ifdef ENABLE_CDROM_MP3
|
||||
return &cdrom_mp3;
|
||||
#else
|
||||
WARNING("no cdrom device available");
|
||||
return NULL;
|
||||
#endif
|
||||
#endif // ENABLE_CDROM_EMSCRIPTEN
|
||||
}
|
||||
|
||||
+21
-29
@@ -27,39 +27,10 @@
|
||||
|
||||
static int frame_of_getpos = -1;
|
||||
|
||||
static int cdrom_init(char *);
|
||||
static int cdrom_exit(void);
|
||||
static int cdrom_reset(void);
|
||||
extern int cdrom_start(int, int);
|
||||
extern int cdrom_stop();
|
||||
static int cdrom_getPlayingInfo(cd_time *);
|
||||
|
||||
#define cdrom cdrom_emscripten
|
||||
cdromdevice_t cdrom = {
|
||||
cdrom_init,
|
||||
cdrom_exit,
|
||||
cdrom_reset,
|
||||
cdrom_start,
|
||||
cdrom_stop,
|
||||
cdrom_getPlayingInfo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
int cdrom_init(char *name) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_exit(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_reset(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
EM_JS(int, cdrom_start, (int trk, int loop), {
|
||||
xsystem35.cdPlayer.play(trk, loop == 0 ? 1 : 0);
|
||||
return xsystem35.Status.OK;
|
||||
@@ -70,6 +41,16 @@ EM_JS(int, cdrom_stop, (), {
|
||||
return xsystem35.Status.OK;
|
||||
});
|
||||
|
||||
int cdrom_exit(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_reset(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_getPlayingInfo(cd_time *info) {
|
||||
if (nact->frame_count == frame_of_getpos)
|
||||
nact->wait_vsync = TRUE;
|
||||
@@ -82,3 +63,14 @@ int cdrom_getPlayingInfo(cd_time *info) {
|
||||
FRAMES_TO_MSF(t >> 8, &info->m, &info->s, &info->f);
|
||||
return OK;
|
||||
}
|
||||
|
||||
cdromdevice_t cdrom_emscripten = {
|
||||
cdrom_init,
|
||||
cdrom_exit,
|
||||
cdrom_reset,
|
||||
cdrom_start,
|
||||
cdrom_stop,
|
||||
cdrom_getPlayingInfo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
+3
-2
@@ -49,8 +49,9 @@ struct _cdromdevice {
|
||||
};
|
||||
typedef struct _cdromdevice cdromdevice_t;
|
||||
|
||||
extern int cd_init(cdromdevice_t *);
|
||||
extern void cd_set_devicename(char *);
|
||||
extern cdromdevice_t cdrom_bgm;
|
||||
|
||||
extern cdromdevice_t *cd_init(const char *dev);
|
||||
|
||||
#define CD_FPS 75
|
||||
#define FRAMES_TO_MSF(f, M,S,F) { \
|
||||
|
||||
+3
-1
@@ -72,7 +72,9 @@ static int cdrom_init(char *playlist_path) {
|
||||
fp = fopen("_inmm.ini", "r");
|
||||
}
|
||||
if (!fp) {
|
||||
NOTICE("cdrom: Cannot open playlist %s", playlist_path);
|
||||
// If the game has MIDI music, lack of the playlist is not a problem.
|
||||
if (ald_get_maxno(DRIFILE_MIDI) == 0)
|
||||
NOTICE("cdrom: Cannot open playlist %s", playlist_path);
|
||||
return NG;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "qnt.h"
|
||||
#include "jpeg.h"
|
||||
#include "ald_manager.h"
|
||||
#include "savedata.h"
|
||||
#include "filecheck.h"
|
||||
#include "cache.h"
|
||||
|
||||
/* VSPのパレット展開バンク */
|
||||
@@ -293,13 +293,8 @@ void cg_load(int no, int flg) {
|
||||
bank = cg_vspPB == -1 ? cg->vsp_bank : cg_vspPB;
|
||||
set_vspbank(cg->pic, bank << 4, cg->width, cg->height);
|
||||
/* copy palettes 0 -> bank */
|
||||
{
|
||||
int i, i_dst = bank << 4;
|
||||
for (i = 0; i < 16; i++) {
|
||||
cg->pal->red[i + i_dst] = cg->pal->red[i];
|
||||
cg->pal->green[i + i_dst] = cg->pal->green[i];
|
||||
cg->pal->blue[i + i_dst] = cg->pal->blue[i];
|
||||
}
|
||||
if (bank != 0) {
|
||||
memcpy(cg->pal + bank * 16, cg->pal, 16 * sizeof(cg->pal[0]));
|
||||
}
|
||||
if (flg != -1) {
|
||||
flg |= (bank << 4);
|
||||
@@ -310,22 +305,22 @@ void cg_load(int no, int flg) {
|
||||
if (GCMD_LOAD_PALETTE(cg_fflg)) {
|
||||
switch(cg->type) {
|
||||
case ALCG_VSP:
|
||||
ags_setPalettes(cg->pal, 0, bank << 4, 16);
|
||||
ags_setPalettes(cg->pal, bank << 4, 16);
|
||||
break;
|
||||
case ALCG_PMS8:
|
||||
// Avoid changing the Windows' reserved palette area (0-9, 246-255)
|
||||
if (cg->pms_bank & 1)
|
||||
ags_setPalettes(cg->pal, 10, 10, 6);
|
||||
ags_setPalettes(cg->pal + 10, 10, 6);
|
||||
if (cg->pms_bank & (1 << 15))
|
||||
//ags_setPalettes(cg->pal, 240, 240, 15);
|
||||
ags_setPalettes(cg->pal, 240, 240, 10);
|
||||
ags_setPalettes(cg->pal + 240, 240, 6);
|
||||
for (i = 1; i < 15; i++) {
|
||||
if (cg->pms_bank & (1 << i)) {
|
||||
ags_setPalettes(cg->pal, i * 16, i * 16, 16);
|
||||
ags_setPalettes(cg->pal + i * 16, i * 16, 16);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ALCG_BMP8:
|
||||
ags_setPalettes(cg->pal, 10, 10, 236);
|
||||
ags_setPalettes(cg->pal + 10, 10, 236);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -346,9 +341,9 @@ void cg_load(int no, int flg) {
|
||||
}
|
||||
/* draw cg pixel */
|
||||
display_cg(cg, p.x, p.y, flg, flg != -1);
|
||||
/* clear display offset */
|
||||
clear_display_loc();
|
||||
}
|
||||
/* clear display offset */
|
||||
clear_display_loc();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -391,6 +386,41 @@ void cg_load_with_alpha(int cgno, int shadowno) {
|
||||
clear_display_loc();
|
||||
}
|
||||
|
||||
static uint8_t* load_cg_from_file(char *fname_utf8, int *status, long *filesize) {
|
||||
int size;
|
||||
FILE *fp;
|
||||
static uint8_t *tmp;
|
||||
|
||||
*status = 0;
|
||||
|
||||
if (NULL == (fp = fc_open(fname_utf8, 'r'))) {
|
||||
*status = SAVE_LOADERR; return NULL;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
*filesize = ftell(fp);
|
||||
if (*filesize == 0) {
|
||||
*status = SAVE_LOADERR; return NULL;
|
||||
}
|
||||
|
||||
tmp = (char *)malloc(*filesize);
|
||||
if (tmp == NULL) {
|
||||
WARNING("Out of memory");
|
||||
*status = SAVE_LOADERR; return NULL;
|
||||
}
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
size = fread(tmp, 1, *filesize,fp);
|
||||
|
||||
if (size != *filesize) {
|
||||
*status = SAVE_LOADSHORTAGE;
|
||||
} else {
|
||||
*status = SAVE_LOADOK;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load and display cg from file 'name' (not cached right now)
|
||||
* name: file name to be read
|
||||
@@ -405,7 +435,7 @@ int cg_load_with_filename(char *fname_utf8, int x, int y) {
|
||||
cgdata *cg = NULL;
|
||||
MyPoint p;
|
||||
|
||||
data = load_cg_with_file(fname_utf8, &status, &filesize);
|
||||
data = load_cg_from_file(fname_utf8, &status, &filesize);
|
||||
if (data == NULL) return status;
|
||||
|
||||
cg_set_display_location(x, y, OFFSET_ABSOLUTE_GC);
|
||||
@@ -428,7 +458,7 @@ int cg_load_with_filename(char *fname_utf8, int x, int y) {
|
||||
/* load palette if not extracted */
|
||||
if (cg->depth == 8) {
|
||||
if (GCMD_LOAD_PALETTE(cg_fflg))
|
||||
ags_setPalettes(cg->pal, 10, 10, 236);
|
||||
ags_setPalettes(cg->pal + 10, 10, 236);
|
||||
if (GCMD_SET_PALETTE(cg_fflg))
|
||||
ags_setPaletteToSystem(0, 256);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ typedef struct {
|
||||
|
||||
uint8_t *pic; // extracted pixel data
|
||||
uint8_t *alpha; // extracted alpha data if exists
|
||||
Palette256 *pal; // extracted palette data if exists
|
||||
Color *pal; // 256-color palette if exists
|
||||
|
||||
int vsp_bank; // palette bank for vsp
|
||||
int pms_bank; // palette bank for pms
|
||||
@@ -87,4 +87,11 @@ extern int cg_fflg;
|
||||
extern int *cg_loadCountVar;
|
||||
extern int cg_brightness;
|
||||
|
||||
static inline uint32_t rgb565_to_rgb888(uint16_t rgb) {
|
||||
uint32_t r = rgb >> 11;
|
||||
uint32_t g = (rgb >> 5) & 0x3f;
|
||||
uint32_t b = rgb & 0x1f;
|
||||
return (r << 19) | (r >> 2 << 16) | (g << 10) | (g >> 4 << 8) | (b << 3) | (b >> 2);
|
||||
}
|
||||
|
||||
#endif /* !__CG__ */
|
||||
|
||||
+23
-62
@@ -41,14 +41,11 @@
|
||||
#include "sdl_core.h"
|
||||
#include "ald_manager.h"
|
||||
#include "LittleEndian.h"
|
||||
#include "gametitle.h"
|
||||
#include "hacks.h"
|
||||
#if HAVE_UNAME
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
/* defined by cmdm.c */
|
||||
extern boolean have_eng_mp_patch;
|
||||
|
||||
/* 選択 Window OPEN 時 callback */
|
||||
static int cb_sel_init_page = 0;
|
||||
static int cb_sel_init_address = 0;
|
||||
@@ -68,82 +65,49 @@ static fncall_table fnctbl[FCTBL_MAX];
|
||||
|
||||
void commands2F00() {
|
||||
/* テキストカラーをスタックからポップして設定する */
|
||||
int data[3];
|
||||
|
||||
sl_popData(data, 3);
|
||||
if (data[0] == TxxTEXTCOLOR) {
|
||||
if (data[1] == 0) {
|
||||
nact->msg.MsgFontColor = data[2];
|
||||
} else {
|
||||
nact->sel.MsgFontColor = data[2];
|
||||
}
|
||||
}
|
||||
|
||||
sl_popState(STACK_TEXTCOLOR);
|
||||
DEBUG_COMMAND("TOC:");
|
||||
}
|
||||
|
||||
void commands2F01() {
|
||||
/* テキストフォントサイズをスタックからポップして設定する */
|
||||
int data[3];
|
||||
|
||||
sl_popData(data, 3);
|
||||
if (data[0] == TxxTEXTSIZE) {
|
||||
if (data[1] == 0) {
|
||||
nact->msg.MsgFontSize = data[2];
|
||||
} else {
|
||||
nact->sel.MsgFontSize = data[2];
|
||||
}
|
||||
}
|
||||
|
||||
sl_popState(STACK_TEXTSIZE);
|
||||
DEBUG_COMMAND("TOS:");
|
||||
}
|
||||
|
||||
void commands2F02() {
|
||||
/* 現在のテキストカラーをスタックにプッシュする */
|
||||
int exp = getCaliValue();
|
||||
int data[] = {TxxTEXTCOLOR,0,0};
|
||||
|
||||
data[1] = exp;
|
||||
data[2] = (exp == 0 ? nact->msg.MsgFontColor : nact->sel.MsgFontColor);
|
||||
sl_pushData(data, 3);
|
||||
|
||||
int type = getCaliValue();
|
||||
switch (type) {
|
||||
case 0: sl_pushTextColor(type, nact->msg.MsgFontColor); break;
|
||||
case 1: sl_pushTextColor(type, nact->sel.MsgFontColor); break;
|
||||
default: WARNING("TPC: unknown type %d", type); break;
|
||||
}
|
||||
DEBUG_COMMAND("TPC %d", exp);
|
||||
}
|
||||
|
||||
void commands2F03() {
|
||||
/* 現在のテキストフォントサイズをスタックにプッシュする */
|
||||
int exp = getCaliValue();
|
||||
int data[] = {TxxTEXTSIZE, 0, 0};
|
||||
|
||||
data[1] = exp;
|
||||
data[2] = (exp == 0 ? nact->msg.MsgFontSize : nact->sel.MsgFontSize);
|
||||
sl_pushData(data, 3);
|
||||
|
||||
DEBUG_COMMAND("TPS %d:%s", exp, "");
|
||||
int type = getCaliValue();
|
||||
switch (type) {
|
||||
case 0: sl_pushTextSize(type, nact->msg.MsgFontSize); break;
|
||||
case 1: sl_pushTextSize(type, nact->sel.MsgFontSize); break;
|
||||
default: WARNING("TPS: unknown type %d", type); break;
|
||||
}
|
||||
DEBUG_COMMAND("TPS %d", exp);
|
||||
}
|
||||
|
||||
void commands2F04() {
|
||||
/* テキスト表示位置をスタックからポップして設定する */
|
||||
int data[3];
|
||||
|
||||
sl_popData(data, 3);
|
||||
if (data[0] == TxxTEXTLOC) {
|
||||
msg_setMessageLocation(data[1], data[2]);
|
||||
}
|
||||
|
||||
sl_popState(STACK_TEXTLOC);
|
||||
DEBUG_COMMAND("TOP:");
|
||||
}
|
||||
|
||||
void commands2F05() {
|
||||
/* 現在のテキスト表示位置をスタックにプッシュする */
|
||||
int data[] = {TxxTEXTLOC, 0, 0};
|
||||
MyPoint loc;
|
||||
|
||||
msg_getMessageLocation(&loc);
|
||||
data[1] = loc.x;
|
||||
data[2] = loc.y;
|
||||
sl_pushData(data, 3);
|
||||
|
||||
sl_pushTextLoc(loc.x, loc.y);
|
||||
DEBUG_COMMAND("TPP:");
|
||||
}
|
||||
|
||||
@@ -394,7 +358,7 @@ void commands2F24() {
|
||||
case 1:
|
||||
var = getCaliValue();
|
||||
cnt = getCaliValue();
|
||||
sysVar[0] = save_load_str_with_file(fname_utf8, var, cnt);
|
||||
sysVar[0] = load_strs_from_file(fname_utf8, var, cnt);
|
||||
break;
|
||||
default:
|
||||
var = getCaliValue();
|
||||
@@ -461,12 +425,9 @@ void commands2F28() {
|
||||
free(nact->game_title_utf8);
|
||||
nact->game_title_utf8 = toUTF8(title);
|
||||
|
||||
ags_setWindowTitle(title);
|
||||
ags_setWindowTitle(nact->game_title_utf8);
|
||||
|
||||
if (0 == strcmp(nact->game_title_utf8, GT_RANCE3_ENG) ||
|
||||
0 == strcmp(nact->game_title_utf8, GT_RANCE4_ENG)) {
|
||||
have_eng_mp_patch = TRUE;
|
||||
}
|
||||
enable_hack_by_title(nact->game_title_utf8);
|
||||
|
||||
DEBUG_COMMAND("MT(new) %s:",title);
|
||||
}
|
||||
@@ -503,7 +464,7 @@ void commands2F2A() {
|
||||
case 1:
|
||||
var = getCaliValue();
|
||||
cnt = getCaliValue();
|
||||
sysVar[0] = save_save_str_with_file(fname_utf8, var, cnt);
|
||||
sysVar[0] = save_strs_to_file(fname_utf8, var, cnt);
|
||||
break;
|
||||
default:
|
||||
var = getCaliValue();
|
||||
@@ -1290,7 +1251,7 @@ void commands2F72() {
|
||||
void commands2F73() {
|
||||
int *vTrack = getCaliVariable();
|
||||
|
||||
*vTrack = mus_cdrom_get_maxtrack();
|
||||
*vTrack = muscd_get_maxtrack();
|
||||
|
||||
DEBUG_COMMAND("cdGetMaxTrack %d:", *vTrack);
|
||||
}
|
||||
|
||||
@@ -773,6 +773,8 @@ void exec_command(void) {
|
||||
commandLXR(); break;
|
||||
case 'W':
|
||||
commandLXW(); break;
|
||||
case 'X':
|
||||
commandLXX(); break;
|
||||
default:
|
||||
undeferr();
|
||||
}
|
||||
@@ -974,6 +976,8 @@ void exec_command(void) {
|
||||
commandST(); break;
|
||||
case 'U':
|
||||
commandSU(); break;
|
||||
case 'V':
|
||||
commandSV(); break;
|
||||
case 'W':
|
||||
commandSW(); break;
|
||||
case 'X':
|
||||
|
||||
+2
-1
@@ -135,7 +135,7 @@ extern void commandLXS();
|
||||
extern void commandLXP();
|
||||
extern void commandLXR();
|
||||
extern void commandLXW();
|
||||
|
||||
extern void commandLXX();
|
||||
|
||||
/* defined by cmdm.c */
|
||||
extern void commandMA();
|
||||
@@ -220,6 +220,7 @@ extern void commandSR();
|
||||
extern void commandSS();
|
||||
extern void commandST();
|
||||
extern void commandSU();
|
||||
extern void commandSV();
|
||||
extern void commandSW();
|
||||
extern void commandSX();
|
||||
extern void commandSI();
|
||||
|
||||
+17
-17
@@ -47,7 +47,7 @@ void commandB0() {
|
||||
}
|
||||
|
||||
void commandB1() {
|
||||
int num = getCaliValue() - 1;
|
||||
int num = getCaliValue();
|
||||
int X1 = getCaliValue();
|
||||
int Y1 = getCaliValue();
|
||||
int X2 = getCaliValue();
|
||||
@@ -64,7 +64,7 @@ void commandB1() {
|
||||
nact->sel.wininfo[num].height = Y2;
|
||||
nact->sel.wininfo[num].save = (V == 0) ? false : true;
|
||||
|
||||
DEBUG_COMMAND("B1 %d,%d,%d,%d,%d,%d:", num + 1, X1, Y1, X2, Y2, V);
|
||||
DEBUG_COMMAND("B1 %d,%d,%d,%d,%d,%d:", num, X1, Y1, X2, Y2, V);
|
||||
}
|
||||
|
||||
void commandB2() {
|
||||
@@ -75,13 +75,13 @@ void commandB2() {
|
||||
int C3 = getCaliValue();
|
||||
int dot = getCaliValue();
|
||||
|
||||
if (num < 1 || num - 1 >= SELWINMAX) {
|
||||
if (num < 0 || num >= SELWINMAX) {
|
||||
WARNING("commandB2(): Window number is out of range %d", num);
|
||||
return;
|
||||
}
|
||||
|
||||
nact->sel.winno = num;
|
||||
nact->sel.win = &nact->sel.wininfo[num - 1];
|
||||
nact->sel.win = &nact->sel.wininfo[num];
|
||||
|
||||
nact->sel.WindowFrameType = W;
|
||||
nact->sel.FrameCgNoTop = C1;
|
||||
@@ -93,7 +93,7 @@ void commandB2() {
|
||||
}
|
||||
|
||||
void commandB3() {
|
||||
int num = getCaliValue() - 1;
|
||||
int num = getCaliValue();
|
||||
int X1 = getCaliValue();
|
||||
int Y1 = getCaliValue();
|
||||
int X2 = getCaliValue();
|
||||
@@ -110,7 +110,7 @@ void commandB3() {
|
||||
nact->msg.wininfo[num].height = Y2;
|
||||
nact->msg.wininfo[num].save = (V == 0) ? FALSE : TRUE;
|
||||
|
||||
DEBUG_COMMAND("B3 %d,%d,%d,%d,%d,%d:", num + 1, X1, Y1, X2, Y2, V);
|
||||
DEBUG_COMMAND("B3 %d,%d,%d,%d,%d,%d:", num, X1, Y1, X2, Y2, V);
|
||||
}
|
||||
|
||||
void commandB4() {
|
||||
@@ -121,13 +121,13 @@ void commandB4() {
|
||||
int N = getCaliValue();
|
||||
int M = getCaliValue();
|
||||
|
||||
if (num < 1 || num - 1 >= MSGWINMAX) {
|
||||
if (num < 0 || num >= MSGWINMAX) {
|
||||
WARNING("commandB4(): Window number is out of range %d", num);
|
||||
num = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
nact->msg.winno = num;
|
||||
nact->msg.win = &nact->msg.wininfo[num - 1];
|
||||
nact->msg.win = &nact->msg.wininfo[num];
|
||||
msg_openWindow(W, C1, C2, N, M);
|
||||
|
||||
DEBUG_COMMAND("B4 %d,%d,%d,%d,%d,%d:", num, W, C1, C2, N, M);
|
||||
@@ -225,8 +225,8 @@ void commandB31() {
|
||||
int *x_var = getCaliVariable();
|
||||
int *y_var = getCaliVariable();
|
||||
|
||||
*x_var = nact->sel.wininfo[no - 1].x;
|
||||
*y_var = nact->sel.wininfo[no - 1].y;
|
||||
*x_var = nact->sel.wininfo[no].x;
|
||||
*y_var = nact->sel.wininfo[no].y;
|
||||
|
||||
DEBUG_COMMAND("B31 %d,%d,%d:", no, *x_var, *y_var);
|
||||
}
|
||||
@@ -236,8 +236,8 @@ void commandB32() {
|
||||
int *x_var_size = getCaliVariable();
|
||||
int *y_var_size = getCaliVariable();
|
||||
|
||||
*x_var_size = nact->sel.wininfo[no - 1].width;
|
||||
*y_var_size = nact->sel.wininfo[no - 1].height;
|
||||
*x_var_size = nact->sel.wininfo[no].width;
|
||||
*y_var_size = nact->sel.wininfo[no].height;
|
||||
|
||||
DEBUG_COMMAND("B32 %d,%d,%d:", no, *x_var_size, *y_var_size);
|
||||
}
|
||||
@@ -247,8 +247,8 @@ void commandB33() {
|
||||
int *x_var = getCaliVariable();
|
||||
int *y_var = getCaliVariable();
|
||||
|
||||
*x_var = nact->msg.wininfo[no - 1].x;
|
||||
*y_var = nact->msg.wininfo[no - 1].y;
|
||||
*x_var = nact->msg.wininfo[no].x;
|
||||
*y_var = nact->msg.wininfo[no].y;
|
||||
DEBUG_COMMAND("B33 %d,%d,%d:", no, *x_var, *y_var);
|
||||
}
|
||||
|
||||
@@ -257,8 +257,8 @@ void commandB34() {
|
||||
int *x_var_size = getCaliVariable();
|
||||
int *y_var_size = getCaliVariable();
|
||||
|
||||
*x_var_size = nact->msg.wininfo[no - 1].width;
|
||||
*y_var_size = nact->msg.wininfo[no - 1].height;
|
||||
*x_var_size = nact->msg.wininfo[no].width;
|
||||
*y_var_size = nact->msg.wininfo[no].height;
|
||||
DEBUG_COMMAND("B34 %d,%d,%d:", no, *x_var_size, *y_var_size);
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -27,6 +27,7 @@
|
||||
#include "xsystem35.h"
|
||||
#include "scenario.h"
|
||||
#include "ags.h"
|
||||
#include "hacks.h"
|
||||
|
||||
void commandCC() {
|
||||
int src_x = getCaliValue();
|
||||
@@ -69,7 +70,16 @@ void commandCX() {
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ags_copyArea_shadow(src_x, src_y, width, height, dst_x, dst_y);
|
||||
// In Daiakuji, the image after the blending is used as a source image
|
||||
// for sprite copy (CX 1). SDL's SIMD blending implementation has some
|
||||
// error (blending #ff00ff and #ff00ff results in #fd00fd), so the
|
||||
// resulting color may not match the colorkey of CX 1. To workaround
|
||||
// this, specify a small alpha mod so that SDL will use a "slow path"
|
||||
// that does accurate calculation.
|
||||
if (daiakuji_cx_hack)
|
||||
ags_copyArea_shadow_withrate(src_x, src_y, width, height, dst_x, dst_y, 254);
|
||||
else
|
||||
ags_copyArea_shadow(src_x, src_y, width, height, dst_x, dst_y);
|
||||
ags_updateArea(dst_x, dst_y, width, height);
|
||||
break;
|
||||
case 1:
|
||||
@@ -94,6 +104,7 @@ void commandCX() {
|
||||
DEBUG_COMMAND_YET("CX %d,%d,%d,%d,%d,%d,%d,%d:", mode, src_x, src_y, width, height, dst_x, dst_y, col);
|
||||
break;
|
||||
}
|
||||
daiakuji_cx_hack = false;
|
||||
|
||||
DEBUG_COMMAND("CX %d,%d,%d,%d,%d,%d,%d,%d:", mode, src_x, src_y, width, height, dst_x, dst_y, col);
|
||||
}
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ void commandIZ() {
|
||||
int x = getCaliValue();
|
||||
int y = getCaliValue();
|
||||
|
||||
ags_setCursorLocation(x, y, TRUE);
|
||||
ags_setCursorLocation(x, y, true, false);
|
||||
DEBUG_COMMAND("IZ %d,%d:", x, y);
|
||||
}
|
||||
|
||||
|
||||
+62
-22
@@ -72,13 +72,13 @@ void commandLT() {
|
||||
struct stat buf;
|
||||
struct tm *lc;
|
||||
|
||||
if (num <= 0) {
|
||||
*var = 0;
|
||||
*(var + 1) = 0;
|
||||
*(var + 2) = 0;
|
||||
*(var + 3) = 0;
|
||||
*(var + 4) = 0;
|
||||
*(var + 5) = 0;
|
||||
if (num <= 0 || num > SAVE_MAXNUMBER) {
|
||||
var[0] = 0;
|
||||
var[1] = 0;
|
||||
var[2] = 0;
|
||||
var[3] = 0;
|
||||
var[4] = 0;
|
||||
var[5] = 0;
|
||||
sysVar[0] = 255;
|
||||
return;
|
||||
}
|
||||
@@ -86,21 +86,21 @@ void commandLT() {
|
||||
status = stat(save_get_file(num - 1), &buf);
|
||||
if (status) {
|
||||
/* んなんどこにもかいてないやん! */
|
||||
*var = 0;
|
||||
*(var + 1) = 0;
|
||||
*(var + 2) = 0;
|
||||
*(var + 3) = 0;
|
||||
*(var + 4) = 0;
|
||||
*(var + 5) = 0;
|
||||
var[0] = 0;
|
||||
var[1] = 0;
|
||||
var[2] = 0;
|
||||
var[3] = 0;
|
||||
var[4] = 0;
|
||||
var[5] = 0;
|
||||
sysVar[0] = 255;
|
||||
} else {
|
||||
lc = localtime(&buf.st_mtime);
|
||||
*var = 1900 + lc->tm_year;
|
||||
*(var + 1) = 1 + lc->tm_mon;
|
||||
*(var + 2) = lc->tm_mday;
|
||||
*(var + 3) = lc->tm_hour;
|
||||
*(var + 4) = lc->tm_min;
|
||||
*(var + 5) = lc->tm_sec;
|
||||
var[0] = lc->tm_year + 1900;
|
||||
var[1] = lc->tm_mon + 1;
|
||||
var[2] = lc->tm_mday;
|
||||
var[3] = lc->tm_hour;
|
||||
var[4] = lc->tm_min;
|
||||
var[5] = lc->tm_sec;
|
||||
sysVar[0] = 0;
|
||||
}
|
||||
DEBUG_COMMAND("LT %d,%p",num, var);
|
||||
@@ -114,16 +114,16 @@ void commandLE() {
|
||||
|
||||
char *fname_utf8 = toUTF8(filename);
|
||||
switch (type) {
|
||||
case 0: /* T2 */
|
||||
case 0:
|
||||
getCaliArray(&vref);
|
||||
var = vref.var;
|
||||
cnt = getCaliValue();
|
||||
sysVar[0] = load_vars_from_file(fname_utf8, &vref, cnt);
|
||||
break;
|
||||
case 1: /* 456 */
|
||||
case 1:
|
||||
var = getCaliValue();
|
||||
cnt = getCaliValue();
|
||||
sysVar[0] = save_load_str_with_file(fname_utf8, var, cnt);
|
||||
sysVar[0] = load_strs_from_file(fname_utf8, var, cnt);
|
||||
break;
|
||||
default:
|
||||
var = getCaliValue();
|
||||
@@ -336,3 +336,43 @@ void commandLXW() {
|
||||
|
||||
DEBUG_COMMAND_YET("LXW %d,%d,%d:",num,*var,size);
|
||||
}
|
||||
|
||||
void commandLXX() {
|
||||
/* Gets file timestamp to [var, var+6] */
|
||||
int type = getCaliValue();
|
||||
int num = getCaliValue();
|
||||
int *var = getCaliVariable();
|
||||
|
||||
struct stat buf;
|
||||
struct tm *lc;
|
||||
|
||||
switch (type) {
|
||||
case 5: // save data
|
||||
if (num <= 0 || num > SAVE_MAXNUMBER || stat(save_get_file(num - 1), &buf)) {
|
||||
sysVar[0] = 255;
|
||||
break;
|
||||
}
|
||||
lc = localtime(&buf.st_mtime);
|
||||
var[0] = lc->tm_year + 1900;
|
||||
var[1] = lc->tm_mon + 1;
|
||||
var[2] = lc->tm_mday;
|
||||
var[3] = lc->tm_hour;
|
||||
var[4] = lc->tm_min;
|
||||
var[5] = lc->tm_sec;
|
||||
var[6] = lc->tm_wday;
|
||||
sysVar[0] = 0;
|
||||
break;
|
||||
|
||||
case 0: // scenario
|
||||
case 1: // CG
|
||||
case 2: // wave
|
||||
case 3: // MIDI
|
||||
case 4: // data
|
||||
case 6: // resource
|
||||
default:
|
||||
DEBUG_COMMAND_YET("LXX %d,%d,%d:", type, num, *var);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_COMMAND("LXX %d,%d,%d:", type, num, *var);
|
||||
}
|
||||
|
||||
+6
-26
@@ -31,22 +31,13 @@
|
||||
#include "utfsjis.h"
|
||||
#include "menu.h"
|
||||
#include "ags.h"
|
||||
#include "input.h"
|
||||
#include "message.h"
|
||||
#include "gametitle.h"
|
||||
#include "hankaku.h"
|
||||
|
||||
/* defined by cmds.c */
|
||||
extern boolean dummy_pcm_su_flag;
|
||||
/* defined by cmdy.c */
|
||||
extern boolean Y3waitFlags;
|
||||
|
||||
|
||||
/* MI 用パラメータ */
|
||||
INPUTSTRING_PARAM mi_param;
|
||||
|
||||
boolean have_eng_mp_patch = FALSE;
|
||||
|
||||
void commandMS() {
|
||||
/* Xコマンドで表示される文字列領域に文字列を入れる */
|
||||
int num = getCaliValue();
|
||||
@@ -69,7 +60,7 @@ void commandMP() {
|
||||
char *str;
|
||||
|
||||
/* Patched English executable appends num2 spaces instead of truncating */
|
||||
if (have_eng_mp_patch) {
|
||||
if (nact->game == GAME_RANCE3_ENG || nact->game == GAME_RANCE4_ENG) {
|
||||
str = calloc(strlen(src) + num2 * strlen(fullwidth_blank[nact->encoding]) + 1, 1);
|
||||
if (NULL == str) {
|
||||
NOMEMERR();
|
||||
@@ -163,17 +154,9 @@ void commandMT() {
|
||||
if (nact->game_title_utf8)
|
||||
free(nact->game_title_utf8);
|
||||
nact->game_title_utf8 = toUTF8(str);
|
||||
ags_setWindowTitle(str);
|
||||
ags_setWindowTitle(nact->game_title_utf8);
|
||||
|
||||
/* 闘神都市II 対策 */
|
||||
if (0 == strcmp(nact->game_title_utf8, GT_TOSHIN2)) {
|
||||
dummy_pcm_su_flag = TRUE;
|
||||
}
|
||||
|
||||
/* Rance4 対策? */
|
||||
if (0 == strcmp(nact->game_title_utf8, GT_RANCE4)) {
|
||||
Y3waitFlags = KEYWAIT_NONCANCELABLE;
|
||||
}
|
||||
enable_hack_by_title(nact->game_title_utf8);
|
||||
|
||||
DEBUG_COMMAND("MT %s:",str);
|
||||
}
|
||||
@@ -266,16 +249,13 @@ void commandMF() {
|
||||
|
||||
void commandMZ0() {
|
||||
/* 文字列変数の文字数・個数の設定の変更 */
|
||||
int max_len = getCaliValue();
|
||||
int max_len = getCaliValue(); // deprecated in System3.9
|
||||
int max_num = getCaliValue();
|
||||
int rsv = getCaliValue();
|
||||
|
||||
DEBUG_COMMAND("MZ0 %d,%d,%d:",max_len, max_num, rsv);
|
||||
|
||||
/* いつからか、文字列変数の最大長さは∞になったようだ */
|
||||
if (max_len == 0) max_len = STRVAR_LEN * 2;
|
||||
|
||||
svar_init(max_num, max_len * 2 + 1);
|
||||
svar_init(max_num);
|
||||
}
|
||||
|
||||
void commandMG() {
|
||||
@@ -346,7 +326,7 @@ void commandMJ() {
|
||||
mj_param.h = h;
|
||||
mj_param.oldstring = t1;
|
||||
|
||||
ags_setCursorLocation(x, y, FALSE); /* XXX */
|
||||
ags_setCursorLocation(x, y, false, false);
|
||||
menu_inputstring2(&mj_param);
|
||||
if (mj_param.newstring == NULL) return;
|
||||
|
||||
|
||||
+3
-3
@@ -112,9 +112,9 @@ void commandPG() { /* T2 */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num2; i++) {
|
||||
*var = nact->ags.pal->red[num1 + i]; var++;
|
||||
*var = nact->ags.pal->green[num1 + i]; var++;
|
||||
*var = nact->ags.pal->blue[num1 + i]; var++;
|
||||
*var++ = nact->ags.pal[num1 + i].r;
|
||||
*var++ = nact->ags.pal[num1 + i].g;
|
||||
*var++ = nact->ags.pal[num1 + i].b;
|
||||
}
|
||||
DEBUG_COMMAND("PG %p,%d,%d:", var, num1, num2);
|
||||
}
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ void commandQE() {
|
||||
case 1:
|
||||
var = getCaliValue();
|
||||
cnt = getCaliValue();
|
||||
sysVar[0] = save_save_str_with_file(fname_utf8, var, cnt);
|
||||
sysVar[0] = save_strs_to_file(fname_utf8, var, cnt);
|
||||
break;
|
||||
default:
|
||||
var = getCaliValue();
|
||||
|
||||
+16
-8
@@ -29,8 +29,6 @@
|
||||
|
||||
/* ぱにょ〜ん 異常シナリオ対策 */
|
||||
static boolean dummy_pcm_in_play = FALSE;
|
||||
/* 闘神都市II 異常シナリオ対策 */
|
||||
boolean dummy_pcm_su_flag = FALSE;
|
||||
/* 次の cdrom の loop 回数 */
|
||||
static int next_cdrom_loopcnt = 0;
|
||||
|
||||
@@ -41,9 +39,9 @@ void commandSS() {
|
||||
DEBUG_COMMAND("SS %d:",num);
|
||||
|
||||
if (num == 0) {
|
||||
mus_cdrom_stop();
|
||||
muscd_stop();
|
||||
} else {
|
||||
mus_cdrom_start(num + 1, next_cdrom_loopcnt);
|
||||
muscd_start(num + 1, next_cdrom_loopcnt);
|
||||
}
|
||||
|
||||
next_cdrom_loopcnt = 0;
|
||||
@@ -54,7 +52,7 @@ void commandSC() {
|
||||
int *var = getCaliVariable();
|
||||
int t, m, s, f;
|
||||
|
||||
if (mus_cdrom_get_playposition(&t, &m, &s, &f) == OK) {
|
||||
if (muscd_getpos(&t, &m, &s, &f) == OK) {
|
||||
*var++ = t - 1;
|
||||
*var++ = m;
|
||||
*var++ = s;
|
||||
@@ -97,7 +95,7 @@ void commandSR() {
|
||||
|
||||
if (num == 0) {
|
||||
int t, m, s, f;
|
||||
if (mus_cdrom_get_playposition(&t, &m, &s, &f) == OK) {
|
||||
if (muscd_getpos(&t, &m, &s, &f) == OK) {
|
||||
// System3.5 returns the music number (track_no - 1),
|
||||
// while System3.6 and later return the track number.
|
||||
if (!memcmp(sl_sco, "S350", 4))
|
||||
@@ -135,7 +133,7 @@ void commandSI() {
|
||||
} else if (type == 1) { /* PCM */
|
||||
*var = mus_pcm_get_state() == TRUE ? 1 : 0;
|
||||
} else if (type == 2) { /* CD */
|
||||
*var = mus_cdrom_get_state() == TRUE ? 1 : 0;
|
||||
*var = muscd_is_available() ? 1 : 0;
|
||||
}
|
||||
|
||||
DEBUG_COMMAND("SI %d,%d:",type,*var);
|
||||
@@ -273,13 +271,23 @@ void commandSU() {
|
||||
dummy_pcm_in_play = dummy_pcm_in_play ? FALSE : TRUE;
|
||||
}
|
||||
}
|
||||
if (dummy_pcm_su_flag) {
|
||||
/* 闘神都市II 異常シナリオ対策 */
|
||||
if (nact->game == GAME_TT2) {
|
||||
*var1 = *var2 = 0;
|
||||
}
|
||||
|
||||
DEBUG_COMMAND("SU %d,%d:",*var1, *var2);
|
||||
}
|
||||
|
||||
void commandSV() {
|
||||
// Set volume (Rance4 v2)
|
||||
int device = getCaliValue();
|
||||
int volume = getCaliValue();
|
||||
mus_mixer_set_level(device, volume);
|
||||
|
||||
DEBUG_COMMAND("SV %d,%d", device, volume);
|
||||
}
|
||||
|
||||
void commandSQ() {
|
||||
/* 左右別々のPCMデータを合成して演奏する */
|
||||
int noL = getCaliValue();
|
||||
|
||||
+19
-6
@@ -33,12 +33,16 @@ void commandUC() { /* 王道勇者 */
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
sl_stackClear_allCall(); break;
|
||||
sl_clearStack(true);
|
||||
break;
|
||||
case 1:
|
||||
sl_stackClear_labelCall(num); break;
|
||||
sl_dropLabelCalls(num);
|
||||
break;
|
||||
case 2:
|
||||
sl_stackClear_pageCall(num); break;
|
||||
default:
|
||||
sl_dropPageCalls(num);
|
||||
break;
|
||||
case 3:
|
||||
sl_clearStack(false);
|
||||
break;
|
||||
}
|
||||
DEBUG_COMMAND("UC %d,%d:",mode,num);
|
||||
@@ -51,7 +55,7 @@ void commandUD() {
|
||||
case 0:
|
||||
sl_reinit(); break;
|
||||
case 1:
|
||||
sl_retFar2(); break;
|
||||
sl_retFar(); break;
|
||||
default:
|
||||
WARNING("UnKnown UD command %d", mode);
|
||||
}
|
||||
@@ -62,8 +66,17 @@ void commandUD() {
|
||||
void commandUR() {
|
||||
/* 最後に積まれたスタックの属性をリード */
|
||||
int *var = getCaliVariable();
|
||||
|
||||
struct stack_info info;
|
||||
sl_getStackInfo(&info);
|
||||
var[0] = info.top_attr;
|
||||
var[1] = info.page_calls;
|
||||
var[2] = info.label_calls;
|
||||
var[3] = info.var_pushes;
|
||||
var[4] = info.label_calls_after_page_call;
|
||||
var[5] = info.var_pushes_after_call;
|
||||
|
||||
DEBUG_COMMAND_YET("UR %p:",var);
|
||||
DEBUG_COMMAND("UR %p:",var);
|
||||
}
|
||||
|
||||
void commandUS() {
|
||||
|
||||
+37
-10
@@ -32,6 +32,7 @@
|
||||
#include "scenario.h"
|
||||
#include "cmd_check.h"
|
||||
#include "sdl_core.h"
|
||||
#include "music_cdrom.h"
|
||||
|
||||
unsigned Y3waitFlags = KEYWAIT_CANCELABLE;
|
||||
|
||||
@@ -63,6 +64,9 @@ unsigned Y3waitFlags = KEYWAIT_CANCELABLE;
|
||||
*
|
||||
* To fix this, this hack processes `Y 3, 1:` followed by the IM command without
|
||||
* delay, when a button is pressed.
|
||||
*
|
||||
* For Rance4 v2, this does not work because the UI loop also checks keyboard
|
||||
* status, so we use a different hack. See rance4v2_hack() in sdl_event.c.
|
||||
*/
|
||||
static void rance4_Y3_IM_hack() {
|
||||
static int count;
|
||||
@@ -82,7 +86,8 @@ void commandY() {
|
||||
unsigned int p1 = getCaliValue();
|
||||
unsigned int p2 = getCaliValue();
|
||||
|
||||
if (p1 == 1) {
|
||||
switch (p1) {
|
||||
case 1:
|
||||
if (p2 == 0) {
|
||||
/* メッセージ領域の初期化と、文字の表示位置を左上端にセットする */
|
||||
msg_nextPage(TRUE);
|
||||
@@ -90,18 +95,23 @@ void commandY() {
|
||||
/* メッセージ領域の文字の表示位置を左上端にセットする */
|
||||
msg_nextPage(FALSE);
|
||||
}
|
||||
} else if (p1 == 2) {
|
||||
break;
|
||||
case 2:
|
||||
/*システム変数 D01〜D20 までを初期化する */
|
||||
for (i = 0; i < 20; i++) {
|
||||
sysVar[i + 1] = 0;
|
||||
}
|
||||
} else if (p1 == 3) {
|
||||
int orig_pc = sl_getIndex();
|
||||
if (p2 == 1 && sl_getc() == 'I' && sl_getc() == 'M') {
|
||||
rance4_Y3_IM_hack();
|
||||
return;
|
||||
break;
|
||||
case 3:
|
||||
case 1003: // Rance4 ver2.05
|
||||
{
|
||||
int orig_pc = sl_getIndex();
|
||||
if (p2 == 1 && sl_getc() == 'I' && sl_getc() == 'M') {
|
||||
rance4_Y3_IM_hack();
|
||||
return;
|
||||
}
|
||||
sl_jmpNear(orig_pc);
|
||||
}
|
||||
sl_jmpNear(orig_pc);
|
||||
|
||||
switch (p2) {
|
||||
case 10000:
|
||||
@@ -114,18 +124,35 @@ void commandY() {
|
||||
sysVar[0] = sys_getInputInfo();
|
||||
break;
|
||||
default:
|
||||
if (p1 == 1003) {
|
||||
sys_key_releasewait(SYS35KEY_RET, FALSE);
|
||||
} else if (nact->game == GAME_RANCE4_V2 && p2 == 1) {
|
||||
// Return immediately if any key is pressed.
|
||||
sysVar[0] = sys_getInputInfo();
|
||||
if (sysVar[0])
|
||||
break;
|
||||
}
|
||||
sysVar[0] = sys_keywait(16 * p2, Y3waitFlags | KEYWAIT_SKIPPABLE);
|
||||
break;
|
||||
}
|
||||
} else if (p1 == 4) {
|
||||
break;
|
||||
case 4:
|
||||
/* 1 〜 n までの乱数を RND に返す。*/
|
||||
if (p2 == 0 || p2 == 1) {
|
||||
sysVar[0] = p2;
|
||||
} else {
|
||||
sysVar[0] = (int)(genrand() * p2) +1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
case 1900:
|
||||
nact->patch_ec = p2;
|
||||
// We're sure this game was built for System3.9 v5.50, which by default
|
||||
// routes CD-DA commands to DRIFILE_WAVE.
|
||||
muscd_init_bgm(DRIFILE_WAVE, 999);
|
||||
break;
|
||||
default:
|
||||
WARNING("Y undefined command %d", p1);
|
||||
break;
|
||||
}
|
||||
DEBUG_COMMAND("Y %d,%d:",p1,p2);
|
||||
}
|
||||
|
||||
+2
-4
@@ -345,10 +345,8 @@ void commandZZ0() {
|
||||
sys_exit(sysVar[0]);
|
||||
#endif
|
||||
} else if (sw == 1) {
|
||||
while (TRUE) {
|
||||
usleep(1000*1000);
|
||||
sys_getInputInfo();
|
||||
}
|
||||
while (!nact->is_quit)
|
||||
sys_keywait(1000, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-43
@@ -360,21 +360,23 @@ void dbg_delete_breakpoints_in_page(int page) {
|
||||
}
|
||||
|
||||
uint8_t dbg_handle_breakpoint(int page, int addr) {
|
||||
uint8_t restore_op = BREAKPOINT;
|
||||
for (Breakpoint *bp = breakpoints; bp; bp = bp->next) {
|
||||
if (bp->phys->page != page || bp->phys->addr != addr)
|
||||
continue;
|
||||
restore_op = bp->phys->restore_op;
|
||||
if (bp->condition && !eval_condition(bp->condition))
|
||||
continue;
|
||||
|
||||
dbg_state = bp->no == INTERNAL_BREAKPOINT_NO ?
|
||||
DBG_STOPPED_NEXT : DBG_STOPPED_BREAKPOINT;
|
||||
|
||||
uint8_t restore_op = bp->phys->restore_op;
|
||||
dbg_main(bp->no); // this may destroy bp
|
||||
return restore_op;
|
||||
}
|
||||
SYSERROR("Illegal BREAKPOINT instruction");
|
||||
return BREAKPOINT;
|
||||
if (restore_op == BREAKPOINT)
|
||||
SYSERROR("Illegal BREAKPOINT instruction");
|
||||
return restore_op;
|
||||
}
|
||||
|
||||
static void set_stack_frame(StackFrame *frame, int page, int addr, boolean is_return_addr) {
|
||||
@@ -389,9 +391,6 @@ static void set_stack_frame(StackFrame *frame, int page, int addr, boolean is_re
|
||||
}
|
||||
|
||||
StackTrace *dbg_stack_trace(void) {
|
||||
int stack_size;
|
||||
const int *stack_base = sl_getStackInfo(&stack_size);
|
||||
|
||||
int page = nact->current_page;
|
||||
|
||||
int cap = 16;
|
||||
@@ -399,26 +398,17 @@ StackTrace *dbg_stack_trace(void) {
|
||||
set_stack_frame(&trace->frames[0], page, nact->current_addr, false);
|
||||
trace->nr_frame = 1;
|
||||
|
||||
const int *p = stack_base + stack_size - 1;
|
||||
while (p >= stack_base) {
|
||||
int addr = -1;
|
||||
switch (*p) {
|
||||
case STACK_NEARJMP:
|
||||
addr = p[-2];
|
||||
break;
|
||||
case STACK_FARJMP:
|
||||
page = p[-2];
|
||||
addr = p[-3];
|
||||
break;
|
||||
struct stack_frame_info *sfi = NULL;
|
||||
while ((sfi = sl_next_stack_frame(sfi)) != NULL) {
|
||||
if (sfi->tag != STACK_NEARCALL && sfi->tag != STACK_FARCALL)
|
||||
continue;
|
||||
if (trace->nr_frame >= cap) {
|
||||
cap *= 2;
|
||||
trace = realloc(trace, sizeof(StackTrace) + cap * sizeof(StackFrame));
|
||||
}
|
||||
if (addr >= 0) {
|
||||
if (trace->nr_frame >= cap) {
|
||||
cap *= 2;
|
||||
trace = realloc(trace, sizeof(StackTrace) + cap * sizeof(StackFrame));
|
||||
}
|
||||
set_stack_frame(&trace->frames[trace->nr_frame++], page, addr, true);
|
||||
}
|
||||
p -= p[-1] + 2;
|
||||
if (sfi->tag == STACK_FARCALL)
|
||||
page = sfi->page;
|
||||
set_stack_frame(&trace->frames[trace->nr_frame++], page, sfi->addr, true);
|
||||
}
|
||||
|
||||
return trace;
|
||||
@@ -439,26 +429,16 @@ static boolean should_continue_step(void) {
|
||||
|
||||
void dbg_stepout(void) {
|
||||
// Set an internal breakpoint at the return address of current frame.
|
||||
int stack_size;
|
||||
const int *stack_base = sl_getStackInfo(&stack_size);
|
||||
const int *p = stack_base + stack_size - 1;
|
||||
while (p >= stack_base) {
|
||||
int page, addr = -1;
|
||||
switch (*p) {
|
||||
case STACK_NEARJMP:
|
||||
page = nact->current_page;
|
||||
addr = p[-2];
|
||||
break;
|
||||
case STACK_FARJMP:
|
||||
page = p[-2];
|
||||
addr = p[-3];
|
||||
break;
|
||||
}
|
||||
if (addr >= 0) {
|
||||
internal_breakpoint = dbg_set_breakpoint(page, addr, true);
|
||||
struct stack_frame_info *sfi = NULL;
|
||||
while ((sfi = sl_next_stack_frame(sfi)) != NULL) {
|
||||
switch (sfi->tag) {
|
||||
case STACK_NEARCALL:
|
||||
internal_breakpoint = dbg_set_breakpoint(nact->current_page, sfi->addr, true);
|
||||
return;
|
||||
case STACK_FARCALL:
|
||||
internal_breakpoint = dbg_set_breakpoint(sfi->page, sfi->addr, true);
|
||||
return;
|
||||
}
|
||||
p -= p[-1] + 2;
|
||||
}
|
||||
// No parent frame found, continue execution.
|
||||
}
|
||||
@@ -550,6 +530,11 @@ void dbg_onsleep(void) {
|
||||
dbg_impl->onsleep();
|
||||
}
|
||||
|
||||
void dbg_on_palette_change(void) {
|
||||
if (dbg_impl)
|
||||
dbg_impl->on_palette_change();
|
||||
}
|
||||
|
||||
boolean dbg_console_vprintf(int lv, const char *format, va_list ap) {
|
||||
if (!dbg_impl || !dbg_impl->console_output)
|
||||
return false;
|
||||
|
||||
@@ -45,8 +45,10 @@ void dbg_init(const char *symbols_path, boolean use_dap);
|
||||
void dbg_quit(void);
|
||||
void dbg_main(int bp_no);
|
||||
void dbg_onsleep(void);
|
||||
void dbg_on_palette_change(void);
|
||||
uint8_t dbg_handle_breakpoint(int page, int addr);
|
||||
boolean dbg_console_vprintf(int lv, const char *format, va_list ap);
|
||||
void dbg_post_command(void *data);
|
||||
|
||||
#else // ENABLE_DEBUGGER
|
||||
|
||||
@@ -55,8 +57,10 @@ boolean dbg_console_vprintf(int lv, const char *format, va_list ap);
|
||||
#define dbg_quit()
|
||||
#define dbg_main(bp_no)
|
||||
#define dbg_onsleep()
|
||||
#define dbg_on_palette_change()
|
||||
#define dbg_handle_breakpoint(page, addr) BREAKPOINT
|
||||
#define dbg_console_vprintf(lv, format, ap) false
|
||||
#define dbg_post_command(data)
|
||||
|
||||
#endif // ENABLE_DEBUGGER
|
||||
|
||||
|
||||
+63
-17
@@ -51,6 +51,7 @@ static char *symbols_path;
|
||||
static char *src_dir;
|
||||
static struct msgq *queue;
|
||||
static bool break_on_warnings;
|
||||
static uint32_t palette_version;
|
||||
|
||||
cJSON *create_source(const char *name) {
|
||||
cJSON *source = cJSON_CreateObject();
|
||||
@@ -67,12 +68,12 @@ cJSON *create_source(const char *name) {
|
||||
static void send_json(cJSON *json) {
|
||||
static int seq = 0;
|
||||
|
||||
cJSON_AddNumberToObject(json, "seq", seq);
|
||||
cJSON_AddNumberToObject(json, "seq", ++seq);
|
||||
char *str = cJSON_PrintUnformatted(json);
|
||||
printf("Content-Length: %zu\r\n\r\n%s", strlen(str), str);
|
||||
fflush(stdout);
|
||||
free(str);
|
||||
cJSON_free(json);
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
|
||||
static void emit_initialized_event(void) {
|
||||
@@ -480,6 +481,20 @@ static void cmd_disconnect(cJSON *args, cJSON *resp) {
|
||||
sys_exit(0);
|
||||
}
|
||||
|
||||
static void cmd_palette(cJSON *args, cJSON *resp) {
|
||||
cJSON *body, *palette;
|
||||
cJSON_AddBoolToObject(resp, "success", true);
|
||||
cJSON_AddItemToObjectCS(resp, "body", body = cJSON_CreateObject());
|
||||
cJSON_AddNumberToObject(body, "version", palette_version);
|
||||
cJSON_AddItemToObjectCS(body, "palette", palette = cJSON_CreateArray());
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int val = nact->ags.pal[i].r << 16 |
|
||||
nact->ags.pal[i].g << 8 |
|
||||
nact->ags.pal[i].b;
|
||||
cJSON_AddItemToArray(palette, cJSON_CreateNumber(val));
|
||||
}
|
||||
}
|
||||
|
||||
static boolean handle_request(cJSON *request) {
|
||||
boolean continue_repl = true;
|
||||
|
||||
@@ -494,7 +509,7 @@ static boolean handle_request(cJSON *request) {
|
||||
if (!cJSON_IsString(command)) {
|
||||
fprintf(stderr, "protocol error: command is not a string\n");
|
||||
// FIXME: return an error response
|
||||
cJSON_free(resp);
|
||||
cJSON_Delete(resp);
|
||||
return continue_repl;
|
||||
}
|
||||
|
||||
@@ -536,8 +551,15 @@ static boolean handle_request(cJSON *request) {
|
||||
cmd_setVariable(args, resp);
|
||||
} else if (!strcmp(command->valuestring, "disconnect")) {
|
||||
cmd_disconnect(args, resp);
|
||||
} else if (!strcmp(command->valuestring, "xsystem35.palette")) {
|
||||
cmd_palette(args, resp);
|
||||
} else {
|
||||
fprintf(stderr, "unknown command \"%s\"\n", command->valuestring);
|
||||
cJSON_AddBoolToObject(resp, "success", false);
|
||||
char *buf = malloc(strlen(command->valuestring) + 30);
|
||||
sprintf(buf, "unknown request \"%s\"", command->valuestring);
|
||||
cJSON_AddStringToObject(resp, "message", buf);
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
free(buf);
|
||||
}
|
||||
send_json(resp);
|
||||
return continue_repl;
|
||||
@@ -549,7 +571,7 @@ static boolean handle_message(char *msg) {
|
||||
boolean continue_repl = true;
|
||||
if (cJSON_IsString(type) && !strcmp(type->valuestring, "request"))
|
||||
continue_repl = handle_request(json);
|
||||
cJSON_free(json);
|
||||
cJSON_Delete(json);
|
||||
free(msg);
|
||||
return continue_repl;
|
||||
}
|
||||
@@ -567,13 +589,13 @@ static int read_command_thread(void *data) {
|
||||
}
|
||||
char *buf = malloc(content_length);
|
||||
fread(buf, content_length, 1, stdin);
|
||||
msgq_enqueue(queue, buf);
|
||||
sdl_post_debugger_command(buf);
|
||||
content_length = -1;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown Debug Adapter Protocol header: %s", header);
|
||||
}
|
||||
}
|
||||
msgq_enqueue(queue, NULL); // EOF
|
||||
sdl_post_debugger_command(NULL); // end of messages
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -588,11 +610,16 @@ static void dbg_dap_init(const char *path) {
|
||||
|
||||
SDL_CreateThread(read_command_thread, "Debugger", NULL);
|
||||
|
||||
while (!initialized) {
|
||||
char *msg = msgq_dequeue(queue);
|
||||
if (!msg)
|
||||
break;
|
||||
handle_message(msg);
|
||||
while (!initialized && !nact->is_quit) {
|
||||
SDL_Event e;
|
||||
SDL_WaitEvent(&e);
|
||||
sdl_handle_event(&e);
|
||||
while (!msgq_isempty(queue)) {
|
||||
char *msg = msgq_dequeue(queue);
|
||||
if (!msg)
|
||||
return;
|
||||
handle_message(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,11 +632,16 @@ static void dbg_dap_repl(int bp_no) {
|
||||
dbg_state = DBG_RUNNING;
|
||||
|
||||
boolean continue_repl = true;
|
||||
while (continue_repl) {
|
||||
char *msg = msgq_dequeue(queue);
|
||||
if (!msg)
|
||||
break;
|
||||
continue_repl = handle_message(msg);
|
||||
while (continue_repl && !nact->is_quit) {
|
||||
SDL_Event e;
|
||||
SDL_WaitEvent(&e);
|
||||
sdl_handle_event(&e);
|
||||
while (!msgq_isempty(queue)) {
|
||||
char *msg = msgq_dequeue(queue);
|
||||
if (!msg)
|
||||
return;
|
||||
continue_repl = handle_message(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,10 +656,24 @@ static void dbg_dap_onsleep(void) {
|
||||
dbg_main(0);
|
||||
}
|
||||
|
||||
static void dbg_dap_on_palette_change(void) {
|
||||
cJSON *event = cJSON_CreateObject(), *body;
|
||||
cJSON_AddStringToObject(event, "type", "event");
|
||||
cJSON_AddStringToObject(event, "event", "xsystem35.paletteChanged");
|
||||
cJSON_AddItemToObjectCS(event, "body", body = cJSON_CreateObject());
|
||||
cJSON_AddNumberToObject(body, "version", ++palette_version);
|
||||
send_json(event);
|
||||
}
|
||||
|
||||
void dbg_post_command(void *data) {
|
||||
msgq_enqueue(queue, data);
|
||||
}
|
||||
|
||||
DebuggerImpl dbg_dap_impl = {
|
||||
.init = dbg_dap_init,
|
||||
.quit = dbg_dap_quit,
|
||||
.repl = dbg_dap_repl,
|
||||
.onsleep = dbg_dap_onsleep,
|
||||
.on_palette_change = dbg_dap_on_palette_change,
|
||||
.console_output = emit_output_event,
|
||||
};
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef struct {
|
||||
void (*quit)(void);
|
||||
void (*repl)(int bp_no);
|
||||
void (*onsleep)(void);
|
||||
void (*on_palette_change)(void);
|
||||
void (*console_output)(int lv, const char *output);
|
||||
} DebuggerImpl;
|
||||
|
||||
|
||||
@@ -30,169 +30,78 @@
|
||||
#include "LittleEndian.h"
|
||||
#include "dri.h"
|
||||
|
||||
/*
|
||||
* static maethods
|
||||
*/
|
||||
static long getfilesize(FILE *fp);
|
||||
static boolean filecheck (FILE *fp);
|
||||
static void get_filemap(drifiles *d, FILE *fp);
|
||||
static void get_fileptr(drifiles *d, FILE *fp, int disk);
|
||||
|
||||
/*
|
||||
* Get file size of FILE
|
||||
* fp: FILE pointer
|
||||
* return: filesize in byte
|
||||
*/
|
||||
static long getfilesize(FILE *fp) {
|
||||
static bool read_index(int disk, drifiles *d, FILE *fp) {
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
return ftell(fp);
|
||||
}
|
||||
int filesize = ftell(fp);
|
||||
|
||||
/*
|
||||
* Check whether dri file type or not
|
||||
* fp: FILE pointer
|
||||
* return: TRUE if it's dri file
|
||||
*/
|
||||
static boolean filecheck (FILE *fp) {
|
||||
uint8_t b[6];
|
||||
int mapsize, ptrsize;
|
||||
long filesize;
|
||||
|
||||
/* get filesize / 256 */
|
||||
filesize = (getfilesize(fp) + 255) >> 8;
|
||||
|
||||
/* read top 6bytes */
|
||||
// Get ptrsize and mapsize
|
||||
uint8_t hdr[6];
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
fread(b, 1, 6, fp);
|
||||
|
||||
/* get ptrsize and mapsize */
|
||||
ptrsize = LittleEndian_get3B(b, 0);
|
||||
mapsize = LittleEndian_get3B(b, 3) - ptrsize;
|
||||
|
||||
/* must lager than 0 */
|
||||
if (ptrsize < 0 || mapsize < 0) return FALSE;
|
||||
|
||||
/* must smaller than filesize */
|
||||
if (ptrsize > (int)filesize || mapsize > (int)filesize ) {
|
||||
return FALSE;
|
||||
if (fread(hdr, 6, 1, fp) != 1)
|
||||
return false;
|
||||
int ptrsize = LittleEndian_get3B(hdr, 0) << 8;
|
||||
int mapsize = (LittleEndian_get3B(hdr, 3) << 8) - ptrsize;
|
||||
if (ptrsize <= 0 || mapsize <= 0 || ptrsize + mapsize > filesize)
|
||||
return false;
|
||||
|
||||
// Read the pointer table and the link table
|
||||
uint8_t *ptbl = malloc(ptrsize + mapsize);
|
||||
memcpy(ptbl, hdr, 6);
|
||||
if (fread(ptbl + 6, ptrsize + mapsize - 6, 1, fp) != 1) {
|
||||
free(ptbl);
|
||||
return false;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
uint8_t *ltbl = ptbl + ptrsize;
|
||||
|
||||
/*
|
||||
* Get file map
|
||||
* d : drifile object
|
||||
* fp: FILE object
|
||||
*/
|
||||
static void get_filemap(drifiles *d, FILE *fp) {
|
||||
uint8_t b[6], *_b;
|
||||
int mapsize, ptrsize, i;
|
||||
|
||||
/* read top 6bytes */
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
fread(b, 1, 6, fp);
|
||||
|
||||
/* get ptrsize and mapsize */
|
||||
ptrsize = LittleEndian_get3B(b, 0);
|
||||
mapsize = LittleEndian_get3B(b, 3) - ptrsize;
|
||||
|
||||
/* allocate read buffer */
|
||||
_b = malloc(sizeof(char) * (mapsize << 8));
|
||||
|
||||
/* read filemap */
|
||||
fseek(fp, ptrsize << 8L , SEEK_SET);
|
||||
fread(_b, 256, mapsize, fp);
|
||||
|
||||
/* get max file number from mapdata */
|
||||
d->maxfile = (mapsize << 8) / 3;
|
||||
|
||||
/* map of disk */
|
||||
d->map_disk = malloc(sizeof(char ) * d->maxfile);
|
||||
/* map of data in disk */
|
||||
d->map_ptr = malloc(sizeof(short) * d->maxfile);
|
||||
|
||||
for (i = 0; i < d->maxfile; i++) {
|
||||
/* map_disk[?] and map_ptr[?] are from 0 */
|
||||
*(d->map_disk + i) = _b[i * 3] - 1;
|
||||
*(d->map_ptr + i) = LittleEndian_getW(_b, i * 3 + 1) - 1;
|
||||
// (Re)allocate the index buffers
|
||||
int nr_files = mapsize / 3;
|
||||
if (d->nr_files < nr_files) {
|
||||
d->disk = realloc(d->disk, nr_files);
|
||||
d->offset = realloc(d->offset, sizeof(uint32_t) * nr_files);
|
||||
memset(d->disk + d->nr_files, 0, nr_files - d->nr_files);
|
||||
memset(d->offset + d->nr_files, 0, sizeof(uint32_t) * (nr_files - d->nr_files));
|
||||
d->nr_files = nr_files;
|
||||
}
|
||||
|
||||
free(_b);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get data pointer in file
|
||||
* d : drifile object
|
||||
* fp : FILE object
|
||||
* disk: no in drifile object
|
||||
*/
|
||||
static void get_fileptr(drifiles *d, FILE *fp, int disk) {
|
||||
char b[6], *_b;
|
||||
int ptrsize, filecnt, i;
|
||||
|
||||
/* read top 6bytes */
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
fread(b, 1, 6, fp);
|
||||
|
||||
/* get pinter size */
|
||||
ptrsize = LittleEndian_get3B(b,0);
|
||||
|
||||
/* estimate file number in file */
|
||||
filecnt = (ptrsize << 8) / 3;
|
||||
|
||||
/* allocate read buffer */
|
||||
_b = malloc(sizeof(char) * (ptrsize << 8));
|
||||
|
||||
/* read pointers */
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
fread(_b, 256, ptrsize, fp);
|
||||
|
||||
/* allocate pointers buffer */
|
||||
d->fileptr[disk] = calloc(filecnt, sizeof(int));
|
||||
|
||||
/* store pointers */
|
||||
for (i = 0; i < filecnt - 1; i++) {
|
||||
*(d->fileptr[disk] + i) = (LittleEndian_get3B(_b, i * 3 + 3) << 8);
|
||||
// Parse the index
|
||||
for (int i = 0; i < nr_files; i++) {
|
||||
if (disk != ltbl[i * 3] - 1)
|
||||
continue;
|
||||
if (d->maxno < i)
|
||||
d->maxno = i;
|
||||
d->disk[i] = ltbl[i * 3];
|
||||
int ptr = LittleEndian_getW(ltbl, i * 3 + 1);
|
||||
d->offset[i] = LittleEndian_get3B(ptbl, ptr * 3) << 8;
|
||||
}
|
||||
|
||||
free(_b);
|
||||
return;
|
||||
free(ptbl);
|
||||
return true;
|
||||
}
|
||||
|
||||
drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
|
||||
drifiles *d = calloc(1, sizeof(drifiles));
|
||||
FILE *fp;
|
||||
int i;
|
||||
boolean gotmap = FALSE;
|
||||
#ifndef HAVE_MEMORY_MAPPED_FILE
|
||||
use_mmap = FALSE;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (file[i] == NULL) continue;
|
||||
/* open check */
|
||||
if (NULL == (fp = fopen(file[i], "rb"))) {
|
||||
SYSERROR("File %s is not found", file[i]);
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (!file[i])
|
||||
continue;
|
||||
|
||||
FILE *fp = fopen(file[i], "rb");
|
||||
if (!fp)
|
||||
SYSERROR("%s: %s", file[i], strerror(errno));
|
||||
if (!read_index(i, d, fp)) {
|
||||
// Only errors in *A.ALD are fatal, because some games have
|
||||
// dummy (invalid) *[B-Z].ALD files.
|
||||
if (i == 0)
|
||||
SYSERROR("%s: not an ALD file", file[i]);
|
||||
WARNING("%s: not an ALD file", file[i]);
|
||||
fclose(fp);
|
||||
continue;
|
||||
}
|
||||
/* check is drifile or noe */
|
||||
if (!filecheck(fp)) {
|
||||
SYSERROR("File %s is not dri file", file[i]);
|
||||
}
|
||||
/* get file map */
|
||||
if (!gotmap) {
|
||||
get_filemap(d, fp);
|
||||
gotmap = TRUE;
|
||||
}
|
||||
/* get pointer */
|
||||
get_fileptr(d, fp, i);
|
||||
/* copy filenme */
|
||||
d->fnames[i] = strdup(file[i]);
|
||||
/* close */
|
||||
fclose(fp);
|
||||
|
||||
/* mmap */
|
||||
if (use_mmap) {
|
||||
mmap_t *m = map_file(file[i]);
|
||||
if (!m) {
|
||||
@@ -207,54 +116,44 @@ drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get data
|
||||
* d : drifile object
|
||||
* no: drifile no ( >= 0 )
|
||||
* return: dridata obhect
|
||||
*/
|
||||
dridata *dri_getdata(drifiles *d, int no) {
|
||||
if (no < 0 || no >= d->nr_files || !d->disk[no] || !d->offset[no])
|
||||
return NULL;
|
||||
int disk = d->disk[no] - 1;
|
||||
|
||||
uint8_t *data;
|
||||
dridata *dfile;
|
||||
int disk, ptr, dataptr, dataptr2, size;
|
||||
|
||||
/* check no is lager than files which contains */
|
||||
if (no > d->maxfile) return NULL;
|
||||
|
||||
/* check disk & ptr are negative, if negative, file does not exist */
|
||||
disk = d->map_disk[no];
|
||||
ptr = d->map_ptr[no];
|
||||
if (disk < 0 || ptr < 0) return NULL;
|
||||
|
||||
/* no file registered */
|
||||
if (d->fileptr[disk] == NULL) return NULL;
|
||||
|
||||
/* get pointer in file and size */
|
||||
dataptr = *(d->fileptr[disk] + ptr);
|
||||
dataptr2 = *(d->fileptr[disk] + ptr + 1);
|
||||
if (dataptr == 0 || dataptr2 == 0) return NULL;
|
||||
|
||||
/* get data top */
|
||||
int ptr, size;
|
||||
if (d->mmapped) {
|
||||
data = d->mmap[disk]->addr + dataptr;
|
||||
data = d->mmap[disk]->addr + d->offset[no];
|
||||
ptr = LittleEndian_getDW(data, 0);
|
||||
size = LittleEndian_getDW(data, 4);
|
||||
} else {
|
||||
int readsize = dataptr2 - dataptr;
|
||||
FILE *fp;
|
||||
data = malloc(sizeof(char) * readsize);
|
||||
fp = fopen(d->fnames[disk], "rb");
|
||||
fseek(fp, dataptr, SEEK_SET);
|
||||
fread(data, 1, readsize, fp);
|
||||
FILE *fp = fopen(d->fnames[disk], "rb");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
uint8_t entry_header[8];
|
||||
fseek(fp, d->offset[no], SEEK_SET);
|
||||
if (fread(entry_header, sizeof(entry_header), 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
ptr = LittleEndian_getDW(entry_header, 0);
|
||||
size = LittleEndian_getDW(entry_header, 4);
|
||||
data = malloc(ptr + size);
|
||||
memcpy(data, entry_header, sizeof(entry_header));
|
||||
if (fread(data + sizeof(entry_header), ptr + size - sizeof(entry_header), 1, fp) != 1) {
|
||||
free(data);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/* get real data and size */
|
||||
ptr = LittleEndian_getDW(data, 0);
|
||||
size = LittleEndian_getDW(data, 4);
|
||||
|
||||
dfile = calloc(1, sizeof(dridata));
|
||||
dridata *dfile = calloc(1, sizeof(dridata));
|
||||
dfile->data_raw = data; /* dri data header */
|
||||
dfile->data = data + ptr; /* real data */
|
||||
dfile->size = size;
|
||||
dfile->name = data + 16;
|
||||
dfile->a = d; /* archive file */
|
||||
return dfile;
|
||||
}
|
||||
|
||||
@@ -28,21 +28,15 @@
|
||||
#include "mmap.h"
|
||||
|
||||
#define DRIFILEMAX 255 /* maximum file number for one data type */
|
||||
#define DRIDATAMAX 65535 /* maximum file number in one file */
|
||||
|
||||
struct _drifiles {
|
||||
/* for mmap */
|
||||
boolean mmapped;
|
||||
mmap_t *mmap[DRIFILEMAX];
|
||||
/* for file access */
|
||||
char *fnames[DRIFILEMAX];
|
||||
/* max file number in files */
|
||||
int maxfile;
|
||||
/* file mapping */
|
||||
char *map_disk;
|
||||
short *map_ptr;
|
||||
/* pointers in file */
|
||||
int *fileptr[DRIFILEMAX];
|
||||
boolean mmapped;
|
||||
mmap_t *mmap[DRIFILEMAX];
|
||||
char *fnames[DRIFILEMAX];
|
||||
int nr_files; // upper limit on how many files could be referenced by this archive
|
||||
int maxno;
|
||||
uint8_t *disk; // file numbers
|
||||
uint32_t *offset; // offsets in file
|
||||
};
|
||||
typedef struct _drifiles drifiles;
|
||||
|
||||
|
||||
+23
-4
@@ -66,6 +66,8 @@ static void storeSaveName(GameResource *gr, int no, char *src) {
|
||||
boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_readdir)(DIR *)) {
|
||||
memset(gr, 0, sizeof(GameResource));
|
||||
|
||||
char *basename = NULL;
|
||||
bool found_xsleep = false;
|
||||
struct dirent* d;
|
||||
while ((d = p_readdir(dir))) {
|
||||
char *filename = d->d_name;
|
||||
@@ -91,6 +93,10 @@ boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_r
|
||||
switch (toupper(filename[len - 6])) {
|
||||
case 'S':
|
||||
storeDataName(gr, DRIFILE_SCO, dno, filename);
|
||||
if (!basename) {
|
||||
basename = strdup(filename);
|
||||
basename[len - 5] = '\0';
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
storeDataName(gr, DRIFILE_CG, dno, filename);
|
||||
@@ -111,13 +117,26 @@ boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_r
|
||||
storeDataName(gr, DRIFILE_BGM, dno, filename);
|
||||
break;
|
||||
}
|
||||
} else if (strcasecmp(filename + 1, "sleep.asd") == 0) {
|
||||
found_xsleep = true;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < SAVE_MAXNUMBER; i++) {
|
||||
char buf[] = "asleep.asd";
|
||||
buf[0] = 'a' + i;
|
||||
storeSaveName(gr, i, buf);
|
||||
if (basename && !found_xsleep) {
|
||||
char *buf = malloc(strlen(basename) + 6);
|
||||
int a = basename[strlen(basename) - 1] == 'S' ? 'A' : 'a';
|
||||
for (int i = 0; i < SAVE_MAXNUMBER; i++) {
|
||||
sprintf(buf, "%s%c.asd", basename, a + i);
|
||||
storeSaveName(gr, i, buf);
|
||||
}
|
||||
free(buf);
|
||||
} else {
|
||||
for (int i = 0; i < SAVE_MAXNUMBER; i++) {
|
||||
char buf[] = "asleep.asd";
|
||||
buf[0] = 'a' + i;
|
||||
storeSaveName(gr, i, buf);
|
||||
}
|
||||
}
|
||||
free(basename);
|
||||
|
||||
return (gr->cnt[DRIFILE_SCO] > 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
+62
-43
@@ -74,50 +74,69 @@ static struct dirent *mockReaddir(DIR *dir) {
|
||||
}
|
||||
|
||||
static void initGameResourceFromDir_test(void) {
|
||||
const char *files[] = {
|
||||
"ADISK.ALD",
|
||||
"FOOSB.ALD",
|
||||
"foogz.ald",
|
||||
"WA.ALD",
|
||||
"unknownXA.ald",
|
||||
"a.ald",
|
||||
".ald",
|
||||
"a",
|
||||
"SYSTEM39.AIN",
|
||||
"foo_WA.WAI",
|
||||
"foo_BA.BGI",
|
||||
"SACTEFAM.KLD",
|
||||
"System39.ini",
|
||||
"foo1.alk",
|
||||
"0.alk",
|
||||
".alk",
|
||||
NULL
|
||||
};
|
||||
const char **dir = files;
|
||||
GameResource gr;
|
||||
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, mockReaddir));
|
||||
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 2);
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "ADISK.ALD");
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][1], "FOOSB.ALD");
|
||||
ASSERT_EQUAL(gr.cnt[DRIFILE_CG], 26);
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_CG][25], "foogz.ald");
|
||||
ASSERT_EQUAL(gr.cnt[DRIFILE_WAVE], 1);
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_WAVE][0], "WA.ALD");
|
||||
for (int i = 0; i < 26; i++) {
|
||||
char buf[16];
|
||||
sprintf(buf, "%csleep.asd", 'a' + i);
|
||||
ASSERT_STRCMP(gr.save_fname[i], buf);
|
||||
{
|
||||
const char *files[] = {
|
||||
"FOOSA.ALD",
|
||||
"FOOSB.ALD",
|
||||
"foogz.ald",
|
||||
"WA.ALD",
|
||||
"unknownXA.ald",
|
||||
"a.ald",
|
||||
".ald",
|
||||
"a",
|
||||
"SYSTEM39.AIN",
|
||||
"foo_WA.WAI",
|
||||
"foo_BA.BGI",
|
||||
"SACTEFAM.KLD",
|
||||
"System39.ini",
|
||||
"foo1.alk",
|
||||
"0.alk",
|
||||
".alk",
|
||||
NULL
|
||||
};
|
||||
const char **dir = files;
|
||||
GameResource gr;
|
||||
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, mockReaddir));
|
||||
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 2);
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "FOOSA.ALD");
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][1], "FOOSB.ALD");
|
||||
ASSERT_EQUAL(gr.cnt[DRIFILE_CG], 26);
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_CG][25], "foogz.ald");
|
||||
ASSERT_EQUAL(gr.cnt[DRIFILE_WAVE], 1);
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_WAVE][0], "WA.ALD");
|
||||
for (int i = 0; i < 26; i++) {
|
||||
char buf[16];
|
||||
sprintf(buf, "FOOS%c.asd", 'A' + i);
|
||||
ASSERT_STRCMP(gr.save_fname[i], buf);
|
||||
}
|
||||
ASSERT_STRCMP(gr.save_path, ".");
|
||||
ASSERT_STRCMP(gr.ain, "SYSTEM39.AIN");
|
||||
ASSERT_STRCMP(gr.wai, "foo_WA.WAI");
|
||||
ASSERT_STRCMP(gr.bgi, "foo_BA.BGI");
|
||||
ASSERT_STRCMP(gr.sact01, "SACTEFAM.KLD");
|
||||
ASSERT_STRCMP(gr.init, "System39.ini");
|
||||
ASSERT_STRCMP(gr.alk[0], "0.alk");
|
||||
ASSERT_STRCMP(gr.alk[1], "foo1.alk");
|
||||
for (int i = 2; i < 10; i++)
|
||||
ASSERT_NULL(gr.alk[i]);
|
||||
}
|
||||
{
|
||||
const char *files[] = {
|
||||
"ADISK.ALD",
|
||||
"asleep.asd",
|
||||
NULL
|
||||
};
|
||||
const char **dir = files;
|
||||
GameResource gr;
|
||||
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, mockReaddir));
|
||||
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 1);
|
||||
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "ADISK.ALD");
|
||||
for (int i = 0; i < 26; i++) {
|
||||
char buf[16];
|
||||
sprintf(buf, "%csleep.asd", 'a' + i);
|
||||
ASSERT_STRCMP(gr.save_fname[i], buf);
|
||||
}
|
||||
}
|
||||
ASSERT_STRCMP(gr.save_path, ".");
|
||||
ASSERT_STRCMP(gr.ain, "SYSTEM39.AIN");
|
||||
ASSERT_STRCMP(gr.wai, "foo_WA.WAI");
|
||||
ASSERT_STRCMP(gr.bgi, "foo_BA.BGI");
|
||||
ASSERT_STRCMP(gr.sact01, "SACTEFAM.KLD");
|
||||
ASSERT_STRCMP(gr.init, "System39.ini");
|
||||
ASSERT_STRCMP(gr.alk[0], "0.alk");
|
||||
ASSERT_STRCMP(gr.alk[1], "foo1.alk");
|
||||
for (int i = 2; i < 10; i++)
|
||||
ASSERT_NULL(gr.alk[i]);
|
||||
}
|
||||
|
||||
void gameresource_test(void) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user