Compare commits

..
114 Commits
Author SHA1 Message Date
kichikuou bcaed3a687 Version 2.11.5 2024-06-10 13:56:51 +09:00
kichikuou 894e8e26a6 Add CHANGELOG.md 2024-06-10 10:24:46 +09:00
kichikuou 7206b0a4f7 emscripten: Build with libwebp 2024-06-10 09:46:41 +09:00
kichikuou 343f3bb7c5 Fix fileCheckExist
This fixes https://github.com/kichikuou/xsystem35-sdl2/issues/55.
2024-06-10 08:59:58 +09:00
kichikuou d3650ce293 Update game_compatibility.md 2024-05-24 21:32:39 +09:00
kichikuou 386cfeb60c Update .gitignore 2024-05-24 21:31:49 +09:00
kichikuou 9cd66c83ef Android: Build with libwebp
Fixes https://github.com/kichikuou/xsystem35-sdl2/issues/46.
2024-05-23 10:57:38 +09:00
kichikuou 065e16a082 Version 2.11.4 2024-05-22 13:38:33 +09:00
kichikuou 3699aa5c2d Windows: Hide menu bar in fullscreen mode
The menu bar is displayed when the mouse is moved to the top of the
screen, like System39.exe's full-screen mode.

This fixes https://github.com/kichikuou/xsystem35-sdl2/issues/53.
2024-05-22 13:37:12 +09:00
kichikuou 20914970c9 Fix text rendering issue in Rance 3 OP
This fixes https://github.com/kichikuou/xsystem35-sdl2/issues/54.
2024-05-22 09:13:09 +09:00
kichikuou 3f2f555aa6 Add a link to SDL issue 2024-05-16 20:55:35 +09:00
kichikuou 095da0bb86 Version 2.11.3 2024-04-11 09:12:55 +09:00
kichikuou 7b8acd6e05 Use lowercase s[a-z].asd in Android and Emscripten
To make sure that save files created in older versions can be loaded.
2024-04-11 09:10:39 +09:00
kichikuou 1b13e331e4 emscripten: Enable msgskip in initGameResourceFromDir()
This is in preparation to stop using xsystem35.gr in Kichikuou on Web,
without changing the current behavior.
2024-04-11 09:00:42 +09:00
kichikuou 5621ab4d86 Version 2.11.2 2024-04-10 17:21:55 +09:00
kichikuou 79805d9ea2 Android: Update SDL, SDL_ttf and SDL_mixer 2024-04-10 15:32:40 +09:00
kichikuou f427d50fa3 Android: Remove playlist migration code
And stop using -playlist option, so that it can be overridden by
.xsys35rc.
2024-04-10 15:07:07 +09:00
kichikuou 7c7768fba4 Android: Improve installation when game is in non-root directory of ZIP
Launcher.kt extracts given ZIP file to the internal storage, preserving
its directory structure.

Before this change, if the game files were in a subdirectory, an
xsystem35.gr file was generated containing the path to the game files.
However, with this method, .xsys35rc and some data files (such as map
files of Kaeru Nyo) could not be loaded.

After this change, Launcher.kt will no longer generate the xsystem35.gr
file. Instead, it records the directory where the game is located in
game_directory.txt, and specify that directory in -gamedir to launch
xsystem35.

Fixes #51.
2024-04-10 15:06:51 +09:00
kichikuou 2b6267aeb9 Create save directory if it doesn't exist 2024-04-10 14:37:21 +09:00
kichikuou 16e7d3baf1 Add -savedir option
It allows specifying a save directory without writing a game resource
file.
2024-04-10 14:37:21 +09:00
kichikuou 2d8d95ac6f emscripten: Simplify link options 2024-03-12 17:03:57 +09:00
kichikuou d5899ff55a emscripten: Add return in wait_vsync
To make it work with ASYNCIFY=2.
2024-03-12 13:04:30 +09:00
kichikuou 04037682ee Version 2.11.1 2024-02-18 10:36:16 +09:00
kichikuou cdb16f73a3 Read link table only from first ALD volume
This fixes https://github.com/kichikuou/xsystem35-sdl2/issues/45.

The behavior when the contents of link table differ between ALD volumes
is different between System 3.8 and System 3.9, and System 3.9 uses the
link table of the first volume. The MangaGamer version of Rance 5D
depends on this behavior.

As far as I know, the only game that depends on the System 3.8 behavior
is Child Assassin (in Alice CD 2.50). Considering the additional
complexity, we do not implement switching to the old behavior.
2024-02-18 10:28:13 +09:00
kichikuou 2895e338c0 Fix a crash in command-line debugger 2024-02-18 08:36:15 +09:00
kichikuou 1a2268e94b Update emscripten to 3.1.54 2024-02-16 12:44:00 +09:00
kichikuou 07643c82a4 emscripten: Don't let SDL change document.title 2024-02-16 12:44:00 +09:00
kichikuou a16156f8e4 CMake: Generate compile_commands.json 2024-01-28 11:26:05 +09:00
kichikuou ea5cef91fd Rename cdrom_device profile to playlist
Also renames `-devcd` command line flag to `-playlist`.

The old names can still be used for backwards compatibility.
2024-01-28 10:28:15 +09:00
kichikuou 48a41b9f82 Require SDL2_mixer on non-Emscripten platforms 2024-01-28 10:20:42 +09:00
kichikuou c11c80d95d Remove CD-ROM device support
This removes (old, unmaintained) real CD-ROM support for Linux and
FreeBSD. It may be possible to implement cross-platform CD support using
libcdio (https://www.gnu.org/software/libcdio/), but it would not be
worth the effort given the low avilability of hardware that can play
CD-DA these days.
2024-01-28 10:20:32 +09:00
kichikuou d7082a9d80 CI: Update GitHub actions 2024-01-27 10:40:17 +09:00
kichikuou 083cf885de CI: Enable COMPILE_WARNING_AS_ERROR on Windows and Emscripten 2024-01-27 10:25:15 +09:00
kichikuou 7b1fef4ad7 Fix a deprecated-non-prototype warning 2024-01-27 09:08:31 +09:00
kichikuou f039baf061 Refactor CMakeLists.txt 2024-01-21 08:49:30 +09:00
kichikuou 22c6b8e963 Version 2.11.0 2024-01-20 13:57:18 +09:00
kichikuou 576afecbfc Update xsys35rc.sample and include it in the package 2024-01-20 13:13:02 +09:00
kichikuou 4e28d92a2d Windows: Load %USERPROFILE%/.xys35rc if %HOME% is not set 2024-01-20 12:42:17 +09:00
kichikuou 22192c245f Windows: Remove game selection dialog 2024-01-20 11:55:29 +09:00
kichikuou 409fa83406 Windows CI: Add packaging step 2024-01-20 11:35:04 +09:00
kichikuou 894b0592f4 Windows: Remove installer 2024-01-20 11:04:43 +09:00
kichikuou 370100a6f2 Windows: Fix static library options 2024-01-20 09:59:10 +09:00
kichikuou 18cfbc90f2 Windows: Do not read profile from registry
This was only used for the default font path, so it should be safe to
remove it.
2024-01-20 09:38:44 +09:00
kichikuou cd51dc7f02 Windows: Embed fonts as PE resources 2024-01-20 09:30:10 +09:00
kichikuou e2638ed840 Refactor CMakeLists.txt using alias targets 2024-01-19 14:56:50 +09:00
kichikuou 6607815df3 MSYS build: Use static linking 2024-01-19 14:55:53 +09:00
kichikuou 77ed85aff7 Display error when debugger is requested but not available 2024-01-18 10:49:31 +09:00
kichikuou 3b1a311f32 CI: Disable debugger on MinGW32 build
The 32-bit cJSON package was removed from MSYS2.
2024-01-18 10:16:54 +09:00
kichikuou 1b3c2190b8 profile: get_profile() returns const char* 2024-01-18 10:16:54 +09:00
kichikuou 52e2d6095a profile: Allow various boolean expressions
In .xsys35rc, now "yes", "true", "on", "1" (case insensitive) mean true
and "no", "false", "off", "0" mean false.
2024-01-18 10:16:48 +09:00
kichikuou 47e2fcaec0 Add enable_zb option for enabling ZB command
By default it is disabled and normal weight is always used.

Issue: https://github.com/kichikuou/xsystem35-sdl2/issues/44
2024-01-18 08:27:46 +09:00
kichikuou 183ceb614a Implement ZB command
Although undocumented, it also affects the font weight of selection
window.

Issue: https://github.com/kichikuou/xsystem35-sdl2/issues/44
2024-01-17 14:32:32 +09:00
kichikuou 185e62010b Fix argument range check in commands2F60() 2024-01-14 11:35:35 +09:00
kichikuou 6f647701dd Android CMake: Use FetchContent_MakeAvailable 2024-01-13 16:18:38 +09:00
kichikuou a9c79b2e31 sysGetOSName: Use SDL_GetPlatform() 2024-01-11 14:08:31 +09:00
kichikuou ba52fbf5e9 Version 2.10.1 2024-01-01 13:17:44 +09:00
kichikuou 85d40701c4 Palette 246-249 should be preserved when loading PMS8 2024-01-01 12:46:13 +09:00
kichikuou 7b535b371a Fix initial palette values
These match the System3.9 default colors that came from the default
system colors in Windows 256-color mode [1].

[1] https://en.wikipedia.org/wiki/List_of_software_palettes#Microsoft_Windows_default_20-color_palette
2024-01-01 12:25:43 +09:00
kichikuou c0dbae8202 Refactor palette data structure 2024-01-01 11:47:11 +09:00
kichikuou ca03450b87 Windows: Add menu command for integer scaling 2023-12-15 10:46:06 +09:00
kichikuou f795a500cf Update emscripten to 3.1.50 2023-12-10 13:24:49 +09:00
kichikuou 3314f00bf8 Fix cdGetMaxTrack for download edition of Daiakuji
It should return the maximum index of the BGM archive.

Fixes #43.
2023-12-09 14:57:01 +09:00
kichikuou a2d79f045c Version 2.10.0 2023-12-09 13:08:30 +09:00
kichikuou f247495578 Breaking change: Fix ShArray.ChangeSecretArray
This breaks save file compatibility for Daiakuji and Kaeru nyo Kuni nyo
Alice.

Due to an incorrect encryption code in ShArray.ChangeSecretArray, save
files were not interoperable with system3.9. (Even worse, this bug did
not affect the checksum calculation and did not cause a "corrupt save
file" error when a file saved with system3.9 was loaded with xsystem35
or vice versa.)

Fixes #41.
2023-12-09 11:35:40 +09:00
kichikuou f6583330de debugger_dap: Fix a bug that seq of outgoing messages was not increasing 2023-12-08 08:57:56 +09:00
kichikuou 4b15f45897 debugger: Add custom DAP messages for communicating palette changes
This implements "xsystem35.palette" custom request and
"xsystem35.paletteChanged" custom event.

The "xsystem35.palette" request retrieves the color values of the AGS
palette.

  interface PaletteRequest extends Request {
    command: 'xsystem35.palette';
  }

  interface PaletteResponse extends Response {
    body: {
      /**
       * A number that increases each time the palette changes.
       */
      version: number;

      /**
       * 256 element array containing color values in 0xRRGGBB format.
       */
      palette: number[];
    };
  }

The "xsystem35.paletteChanged" event indicates that the AGS palette has
changed.

  interface PaletteChangedEvent extends Event {
    event: 'xsystem35.paletteChanged';

    body: {
      /**
       * A number that increases each time the palette changes.
       */
      version: number;
    };
  }

DAP clients can know if the received value is up to date by comparing
the `version` values of paletteChanged and PaletteResponse.
2023-12-08 08:35:45 +09:00
kichikuou 7bc433731f CI: Fix Android build
AGP 8.0 requires JDK 17.
2023-11-17 13:00:56 +09:00
kichikuou 4c21570eb1 Android: Upgrade SDL to 2.28.5 2023-11-17 12:15:17 +09:00
kichikuou a3e7feffc2 Switch Windows 64-bit build from mingw64 to ucrt64 2023-11-17 09:08:24 +09:00
kichikuou a4c1dd1acf Remove unused MOUSE_WARP_DIRECT mode 2023-09-04 17:14:17 +09:00
kichikuou 09086ccc85 IZ command: add delay even if mouse movement is disabled
Without it, it's hard to exit camp mode in TT2.
2023-09-04 17:03:06 +09:00
kichikuou 53e39b7c11 emscripten: Call xsystem35.shell.showMouseMoveEffect()
See kichikuou/web@07a6118 for details.
2023-09-04 13:32:04 +09:00
kichikuou f0ccfee40f Update internal mouse coordinates even if cursor movement is disabled
In TT2, keyboard/gamepad navigation is implemented by moving the mouse
cursor using IZ command. It did not work in browsers where mouse cursor
could not be moved or when mouse movement was disabled from the menu.

Now IZ command updates the internal mouse coordinates even when the
cursor cannot be moved.
2023-09-04 13:32:00 +09:00
kichikuou 10cdec98e6 emscripten: Improve gamepads support
In the W3C gamepad API, many gamepads are mapped to the "standard
layout", where D-pad keys are mapped to buttons 12-15.
2023-09-03 22:41:12 +09:00
kichikuou c61afb4308 Improve README.md
With the help of ChatGPT.
2023-08-29 12:09:30 +09:00
kichikuou f6cf881e61 Android: Sign apk only when keystore file exists 2023-08-28 11:01:33 +09:00
kichikuou a8277e71a7 Android: Update command line build instructions 2023-08-28 10:26:17 +09:00
kichikuou 3482fb6440 Android: Upgrade SDL to 2.28.2 2023-08-13 12:42:54 +09:00
kichikuou 3c81c8fec2 Improve error messages for when MIDI cannot be played
* Show warnings on failure of Mix_LoadMUS / Mix_PlayMusic
* Display "Cannot open playlist" warning only when the game does not
  have MIDI
2023-07-29 07:50:55 +09:00
fcolecumberri e090485b37 Update README.md
https://github.com/kichikuou/xsystem35-sdl2/issues/39
2023-07-28 21:42:59 +09:00
kichikuou d7deaec972 Version 2.9.1 2023-06-22 08:52:49 +09:00
kichikuou 30467371f4 debugger_dap: Handle SDL messages while paused in the debugger
So that you can move around the window while the game is paused.

Now DAP messages read from stdin are once posted to the SDL message
queue, and then inserted into the debugger command queue in the main
thread.
2023-06-20 11:07:28 +09:00
kichikuou e9a30f7493 Debugger: Fix crash when breakpoint condition was not met 2023-06-19 21:33:51 +09:00
kichikuou d9e42dd4bb Add a hack to fix Daiakuji's magenta battle background issue 2023-06-19 17:23:03 +09:00
kichikuou 0e06cc1e22 Simplify sdl_copyAreaSP16_shadow 2023-06-19 17:18:31 +09:00
kichikuou 89423c94f1 ShGraph: Use exact color match in PlayAnimeData and ChangeNotColor 2023-06-19 17:18:31 +09:00
kichikuou c694d2282c Fix CX (sprite copy) in 24-bit color games with 16-bit CGs
System3.x uses the following bit expansion when converting RGB565 to
RGB888:

  RRRRR GGGGGG BBBBB => RRRRRRRR GGGGGGGG BBBBBBBB
  12345 123456 12345    12345123 12345612 12345123

However, SDL's blit functions use a slightly different mapping, so
sometimes expanded color did not match the color key specified in the CX
command.

To avoid this, convert to RGB888 by ourselves when drawing 16-bit CGs.
2023-06-19 17:18:17 +09:00
kichikuou 39e94afc44 Specify pixel format explicitly when creating SDL surfaces 2023-06-18 14:47:50 +09:00
kichikuou e37a491908 Refactor keycode definitions 2023-05-21 10:46:22 +09:00
kichikuou 43dff9a9e4 Version 2.9.0 2023-05-04 14:19:52 +09:00
kichikuou e6b3d6094d Use System3.9 compatible save format by default, except emscripten 2023-05-04 13:40:35 +09:00
kichikuou 61ad4282e6 Refactor agsevent_t struct 2023-05-04 11:51:21 +09:00
kichikuou e4628d8bbb emscripten: Add simulate_right_button() 2023-05-04 11:27:45 +09:00
kichikuou 21bd4279a1 Send AGS mouse events on touch events
This fixes a bug where SACT games were not responding to touch.
2023-05-04 09:01:16 +09:00
kichikuou b6c33fd761 Update emscripten to 3.1.34 2023-05-03 17:43:35 +09:00
kichikuou 1b9d8c48f1 Android: Use Kotlin coroutine for background installation 2023-04-15 15:59:54 +09:00
kichikuou 55ef307e07 Android: Stop using deprecated ProgressDialog 2023-04-15 11:43:41 +09:00
kichikuou 894cd51e01 Improve ZZ0,1 behavior
- Check nact->is_quit
- Avoid busy loop in emscripten
2023-03-28 22:03:12 +09:00
kichikuou 880244020e Android: Use SDL_mixer for CD audio 2023-03-18 11:21:06 +09:00
kichikuou 9c2f423399 Fix use-of-uninitialized-value in save_savePartial 2023-03-18 10:41:12 +09:00
kichikuou 654a489f49 Fix memory leaks in debugger_dap.c 2023-03-18 10:32:49 +09:00
kichikuou 912af592ae Clean up savedata.c 2023-03-18 09:51:57 +09:00
kichikuou 6d70439dff Change how save file names are determined when no .gr file is specified
If `?sleep.asd` already exist, use them. Otherwise use `*s?.asd` as in
System3x.exe.
2023-03-18 09:51:51 +09:00
kichikuou aec06f775a Support the save format of original System3.x (except System3.5 v1)
Now xsystem35 can load ASD files created by System3.5 (v2+) - System3.9.
The format for saving can be configured with the -saveformat option.
2023-02-23 19:03:23 +09:00
kichikuou 446ffe9466 UG command: Fix order of popping variables 2023-02-22 17:35:45 +09:00
kichikuou 02cad74568 Allow resizing system page by DC command 2023-02-20 17:39:21 +09:00
kichikuou 33e1ff3b4a Increase system variable page size to 65537
To match System3.x.
2023-02-20 17:05:54 +09:00
kichikuou 11f8f00072 Match default message/selection window locations to System3.x 2023-02-20 16:32:32 +09:00
kichikuou b59d683fef Change the stack layout
Now we use the same stack structure as System3.9. In order to maintain
the compatibility of save files, it is converted to/from the old layout
when saving/loading.
2023-02-20 14:24:37 +09:00
kichikuou b9f4c7c03a Compatibility fix for Bx commands
These commands accept 0-127 as valid window numbers, which were 1-128
before this change.

To maintain savedata compatibility, window positions are saved in the
order 1,...,127,0.
2023-02-18 21:45:39 +09:00
kichikuou 2d2c6aa373 Remove strvar_len
The length limit of string variables was removed a long time ago, but it
was recorded in save files.

Now the first argument of MZ0 is completely ignored (as in System3.9).
The maxlen field in the save file is set to a constant so that older
versions of xsystem35 can load it.
2023-02-18 14:55:02 +09:00
kichikuou 850af6d140 Refactor implementation of LE and QE commands 2023-02-18 14:47:28 +09:00
kichikuou da4cf017bf Clean up savedata.h 2023-02-18 14:47:25 +09:00
kichikuou e88dfcdaa1 Move load_cg_with_file to cg.c 2023-02-18 09:27:21 +09:00
140 changed files with 3700 additions and 3821 deletions
+3 -3
View File
@@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install Deps
run: sudo apt install ninja-build
@@ -15,14 +15,14 @@ jobs:
run: |
cd android
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > keystore.jks
ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk-bundle ./gradlew assembleRelease
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
uses: actions/upload-artifact@v4
with:
name: xsystem35-apk
path: android/app/build/outputs/apk/release/app-release.apk
+7 -7
View File
@@ -2,7 +2,7 @@ name: Emscripten Build
on: [push, pull_request]
env:
EM_VERSION: 3.1.27
EM_VERSION: 3.1.54
EM_CACHE_FOLDER: 'emsdk-cache'
jobs:
@@ -10,17 +10,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup cache
id: cache-system-libraries
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{env.EM_CACHE_FOLDER}}
key: ${{env.EM_VERSION}}-${{ runner.os }}
- name: Setup Emscripten toolchain
uses: mymindstorm/setup-emsdk@v12
uses: mymindstorm/setup-emsdk@v14
with:
version: ${{ env.EM_VERSION }}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
@@ -29,13 +29,13 @@ jobs:
run: |
mkdir -p out/wasm
cd out/wasm
emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../../
make
emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_COMPILE_WARNING_AS_ERROR=YES ../../
make -j4
mkdir xsystem35
mv src/xsystem35.* xsystem35/
- name: Upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: xsystem35-wasm
path: out/wasm/xsystem35
+2 -2
View File
@@ -10,7 +10,7 @@ jobs:
name: Linux ${{ matrix.build-type }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install Deps
run: |
@@ -22,7 +22,7 @@ jobs:
mkdir -p out/${{ matrix.build-type }}
cd out/${{ matrix.build-type }}
cmake -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} ../../
make
make -j4
- name: Test
run: ctest --output-on-failure
+28 -16
View File
@@ -5,10 +5,17 @@ jobs:
build:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- { sys: MINGW32, installer: "xsystem35-32bit" }
- { sys: MINGW64, installer: "xsystem35-64bit" }
- sys: mingw32
package: "xsystem35-32bit"
cmake_args: "-DENABLE_DEBUGGER=no"
deps: ""
- sys: ucrt64
package: "xsystem35-64bit"
cmake_args: ""
deps: "cjson:p"
defaults:
run:
shell: msys2 {0}
@@ -19,27 +26,31 @@ jobs:
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.sys }}
update: true
pacboy: >-
gcc:p
cmake:p
ninja:p
SDL2:p
SDL2_ttf:p
SDL2_mixer:p
libwebp:p
cjson:p
nsis:p
ntldd-git:p
${{ matrix.deps }}
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Copy licenses
run: |
ls /${{ matrix.sys }}/share/licenses
mkdir dist
cp -r /${{ matrix.sys }}/share/licenses dist/
cp fonts/*.license dist/licenses/
- name: Install dev dependencies
run: pacboy --noconfirm -S --needed gcc:p cmake:p ninja:p
- name: Build
run: |
mkdir -p out/release
cd out/release
cmake -G"Ninja" -DCMAKE_BUILD_TYPE=Release ../../
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=YES ${{ matrix.cmake_args }} ../../
ninja
- name: Test
@@ -47,11 +58,12 @@ jobs:
working-directory: out/release
- name: Package
working-directory: tools/installer
run: ./make-installer.sh ../../out/release ${{ matrix.installer }}.nsi
run: |
cp out/release/src/xsystem35.exe *.md COPYING xsys35rc.sample dist/
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.installer }}
path: tools/installer/${{ matrix.installer }}.exe
name: ${{ matrix.package }}
path: dist
compression-level: 9 # because we use it for releases
+3
View File
@@ -1,10 +1,13 @@
out
android/.gradle
android/.idea
android/app/.cxx
android/app/.externalNativeBuild
android/app/build
android/app/src/main/assets
android/build
android/keystore.jks
android/local.properties
.ccls-cache
.dir-locals.el
compile_commands.json
+107
View File
@@ -0,0 +1,107 @@
# Changelog
## 2.11.5 - 2024-06-10
- Android: Fixed a black screen issue in the MangaGamer version of Rance 5D.
- Fixed `fileCheckExist` command. (#55)
## 2.11.4 - 2024-05-22
- Windows: In full-screen mode, the menu bar now appears only when the mouse pointer is at the top of the screen. (#53)
- Fixed text rendering issue in Rance 3 intro. (#54)
## 2.11.3 - 2024-04-11
- Android: Fixed a bug where save files from older versions could not be loaded in version 2.11.2.
## 2.11.2 - 2024-04-10
- Added `-savedir` option to specify save directory.
- Android: Fixed a bug where .xsys35rc in a subdirectory of ZIP was not loaded. (#51)
## 2.11.1 - 2024-02-18
- Windows: Fixed a black screen issue in the MangaGamer version of Rance 5D (#45).
- Fixed a crash bug in command-line debugger.
## 2.11.0 - 2024-01-20
- Windows: Now `xsystem35.exe` is a standalone executable. You can just copy it to the game folder and run it.
- Windows: The installer is no longer provided. If you have an earlier version installed, please uninstall it.
- Windows: The debugger is no longer available in the 32-bit version. Please use the 64-bit version if you need it.
- Added experimental `enable_zb` option (#44). See `xsys35rc.sample` for details.
## 2.10.1 - 2024-01-01
- Windows: Added "Integer Scaling" menu option
- Fixed initial palette colors (to match System3.9)
- Fixed a bug where palette 246 to 249 were unintentionally changed after loading 256-color CGs
## 2.10.0 - 2023-12-09
- Breaking change: A [bug](https://github.com/kichikuou/xsystem35-sdl2/issues/41) has been fixed in which save format for 大悪司 and かえるにょ国にょアリス was not compatible with System3.9. As a result, save files for these games created with older versions of xsystem35 are no longer usable. (Loading will not fail, but wrong values will be loaded.)
- Now the 64-bit executable supports Windows 10 or later. For older Windows, please use the 32-bit version.
- Fixed a problem with the download edition of Daiakuji requiring insertion of Disk 2. (#43)
- Debugger: Added debug commands for monitoring the color palette.
- Minor bug fixes.
## 2.9.1 - 2023-06-22
- Fixed a bug where the `CX 1` command (copy with transparent color) did not work in some games (e.g. Daiakuji)
- Debugger: Now breakpoints do not make the window completely unresponsive
- Debugger: Fixed a conditional breakpoint crash bug
## 2.9.0 - 2023-05-04
- Now xsystem35 uses the System3.9 save file format (unless `-saveformat` command line flag is specified). Old save files can still be loaded.
- Changed the default naming convention for save files from `[a-z]sleep.asd` to `<gamename>s[a-z].asd`.
- Fixed a bug where SACT games (e.g. Rance 5D) were not responding to touch.
- Fixed memory leaks in debugger.
## 2.8.0 - 2023-02-12
- Added support for Rance 4.1/4.2 ver1.05
- Fixed movement animation in rooms in Rance 4 v2.05 (#35)
- Added `-game` option which can be used to enable game-specific hacks in translated games
## 2.7.0 - 2023-01-28
- Added support for Rance4 ver.2.05
- Now supports BGM playback for the download edition of Daiakuji
- Bug fixes
## 2.6.0 - 2023-01-01
- Android: Introduced a new way to simulate right-click; tapping on the black bars at the left/right or top/bottom of the screen is treated as a right click. (Two-finger touch, the old way to simulate a right click, still works.)
- Windows: Added a menu command to enable/disable automatic mouse movements.
## 2.5.1 - 2022-07-31
- Implemented "palette shift" graphic effect (used in 闘神都市II).
- Implemented `grDrawFillCircle` command (used in グレイメルカ).
- Fixed color update bug in 256-color games.
- Fixed crash by out-of-bounds variable access in debugger.
## 2.5.0 - 2022-07-17
- Supported JPEG image format on Android.
## 2.4.0 - 2022-07-02
- Windows: Added "Restart" menu command.
- Fixed a bug where wrong music is played in Kichikuou Rance (System3.9 version). #32
- Supported mouse wheel input.
- Fixed a bug in `MF` command.
- Implemented `grEffectMoveView` command.
## 2.3.0 - 2022-04-08
- Code for screen transition effects have been substantially rewritten (but you probably wouldn't notice any difference).
- Fixed bugs in System3.9 games.
- Android: Enabled joystick input.
- Debugger improvements.
## 2.2.0 - 2021-12-03
From now on, the Android and Windows versions will use a common version number.
- Android: Use custom fonts specified in `.xsys35c`. (#20)
- Supported "王子さまLv1".
- Debugger improvements.
- Fixed some bugs and compatibility issues.
## 2.1.0 - 2021-11-07
- Fixed issues with MangaGamer version of Rance 5D.
- Fixed garbled text in some System3.9 games with Unicode mode.
- Display a message box on fatal errors.
- Various debugger improvements.
## 2.0.1 - 2021-10-24
- Fixed crash during shutdown.
## 2.0.0 - 2021-10-23
- Added window menubar from which you can save screenshots, change fullscreen mode, and enable message skipping.
- Added debugger support that can be used from Visual Studio Code. See [vscode-system3x](https://github.com/kichikuou/vscode-system3x) for details.
- Many bug fixes and compatibility fixes.
+98 -69
View File
@@ -3,16 +3,10 @@ cmake_minimum_required(VERSION 3.13)
project(xsystem35 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
enable_testing()
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
include(CheckIncludeFile)
include(CheckLibraryExists)
include(CheckSymbolExists)
# In msys, `pkg-config --libs` returns `-lmingw32` but find_library() cannot
# find it in default search paths.
if (MSYS)
list(APPEND CMAKE_LIBRARY_PATH $ENV{MINGW_PREFIX}/$ENV{MINGW_CHOST}/lib)
endif ()
include(FetchContent)
# A wrapper around pkg_check_modules() that skips the check if ENABLE_<prefix> is false
macro (optional_pkg_check_modules prefix)
@@ -22,19 +16,73 @@ macro (optional_pkg_check_modules prefix)
endif()
endmacro()
# Generates a static library from pkg_check_modules() result
function(add_static_library name pkg)
add_library(${name} INTERFACE)
set_target_properties(${name}
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${${pkg}_STATIC_INCLUDE_DIRS}"
INTERFACE_COMPILE_OPTIONS "${${pkg}_STATIC_CFLAGS_OTHER}"
INTERFACE_LINK_LIBRARIES "${${pkg}_STATIC_LIBRARIES}"
INTERFACE_LINK_OPTIONS "${${pkg}_STATIC_LDFLAGS_OTHER}")
endfunction()
function(fetch_webp)
FetchContent_Declare(
libwebp
URL https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.4.0.tar.gz
URL_HASH SHA1=0b1c8bea200caaa010182609dbaaa91aec69b64d
)
set(WEBP_BUILD_ANIM_UTILS OFF CACHE BOOL "Build animation utilities." FORCE)
set(WEBP_BUILD_CWEBP OFF CACHE BOOL "Build the cwebp command line tool." FORCE)
set(WEBP_BUILD_DWEBP OFF CACHE BOOL "Build the dwebp command line tool." FORCE)
set(WEBP_BUILD_GIF2WEBP OFF CACHE BOOL "Build the gif2webp conversion tool." FORCE)
set(WEBP_BUILD_IMG2WEBP OFF CACHE BOOL "Build the img2webp animation tool." FORCE)
set(WEBP_BUILD_VWEBP OFF CACHE BOOL "Build the vwebp viewer tool." FORCE)
set(WEBP_BUILD_WEBPINFO OFF CACHE BOOL "Build the webpinfo command line tool." FORCE)
set(WEBP_BUILD_LIBWEBPMUX OFF CACHE BOOL "Build the libwebpmux library." FORCE)
set(WEBP_BUILD_WEBPMUX OFF CACHE BOOL "Build the webpmux command line tool." FORCE)
set(WEBP_BUILD_EXTRAS OFF CACHE BOOL "Build extras." FORCE)
set(WEBP_BUILD_WEBP_JS OFF CACHE BOOL "Emscripten build of webp.js." FORCE)
FetchContent_MakeAvailable(libwebp)
add_library(WebP ALIAS webp)
endfunction()
check_symbol_exists(getlogin "unistd.h" HAVE_GETLOGIN)
check_symbol_exists(mmap "sys/mman.h" HAVE_MMAP)
check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION)
check_symbol_exists(uname "sys/utsname.h" HAVE_UNAME)
if (EMSCRIPTEN)
function(add_emscripten_library name option)
add_library(${name} INTERFACE)
set_target_properties(${name} PROPERTIES
INTERFACE_COMPILE_OPTIONS ${option}
INTERFACE_LINK_OPTIONS ${option})
endfunction()
add_emscripten_library(zlib -sUSE_ZLIB=1)
add_emscripten_library(sdl2 -sUSE_SDL=2)
add_emscripten_library(sdl2_ttf -sUSE_SDL_TTF=2)
set(DEFAULT_FONT_PATH /fonts/)
fetch_webp()
set(HAVE_WEBP 1)
elseif (ANDROID)
set(SDL2MIXER_FOUND 1)
find_library(ndk_zlib z)
add_library(sdl2 ALIAS SDL2)
add_library(sdl2_ttf ALIAS SDL2_ttf)
add_library(sdl2_mixer ALIAS SDL2_mixer)
find_library(ndk_log log)
else()
find_library(ndk_zlib z)
add_library(zlib INTERFACE)
set_target_properties(zlib PROPERTIES INTERFACE_LINK_LIBRARIES ${ndk_zlib})
fetch_webp()
set(HAVE_WEBP 1)
else() # non-emscripten, non-android
if (WIN32)
set(ZLIB_USE_STATIC_LIBS ON)
endif()
find_package(ZLIB REQUIRED)
add_library(zlib ALIAS ZLIB::ZLIB)
include(FindPkgConfig)
optional_pkg_check_modules(GTK3 IMPORTED_TARGET gtk+-3.0)
@@ -42,45 +90,61 @@ else()
set(ENABLE_GTK 1)
endif()
pkg_check_modules(SDL2 IMPORTED_TARGET sdl2)
pkg_check_modules(SDL2TTF IMPORTED_TARGET SDL2_ttf)
optional_pkg_check_modules(SDL2MIXER IMPORTED_TARGET SDL2_mixer)
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
pkg_check_modules(SDL2TTF REQUIRED IMPORTED_TARGET SDL2_ttf)
pkg_check_modules(SDL2MIXER REQUIRED IMPORTED_TARGET SDL2_mixer)
if (WIN32)
add_static_library(sdl2 SDL2)
add_static_library(sdl2_ttf SDL2TTF)
# Workaround for linking error
set_property(TARGET sdl2_ttf PROPERTY INTERFACE_LINK_LIBRARIES
$<LINK_GROUP:RESCAN,${SDL2TTF_STATIC_LIBRARIES} -lstdc++>)
add_static_library(sdl2_mixer SDL2MIXER)
else()
add_library(sdl2 ALIAS PkgConfig::SDL2)
add_library(sdl2_ttf ALIAS PkgConfig::SDL2TTF)
add_library(sdl2_mixer ALIAS PkgConfig::SDL2MIXER)
set(DEFAULT_FONT_PATH ${CMAKE_INSTALL_PREFIX}/share/xsystem35/fonts/)
endif()
option(ENABLE_DEBUGGER "Enable built-in debugger" ON)
if (ENABLE_DEBUGGER)
pkg_check_modules(cJSON IMPORTED_TARGET libcjson)
if (NOT cJSON_FOUND)
if (cJSON_FOUND)
if (WIN32)
add_static_library(cJSON cJSON)
else ()
add_library(cJSON ALIAS PkgConfig::cJSON)
endif()
else ()
# libcjson-dev of Debian buster / Ubuntu 20.04 does not install pkgconfig files.
find_library(cJSON cjson)
if (NOT cJSON)
message(FATAL_ERROR "libcjson is required but not found.")
endif()
add_library(cJSON ALIAS ${cJSON})
endif()
endif()
optional_pkg_check_modules(WEBP IMPORTED_TARGET libwebp)
if (WEBP_FOUND)
set(HAVE_WEBP 1)
if (WIN32)
add_static_library(WebP WEBP)
else()
add_library(WebP ALIAS PkgConfig::WEBP)
endif()
endif()
find_library(PORTMIDI portmidi)
if (PORTMIDI)
set(HAVE_PORTMIDI 1)
set(ENABLE_MIDI_PORTMIDI 1)
endif()
set(DEFAULT_FONT_PATH ${CMAKE_INSTALL_PREFIX}/share/xsystem35/fonts/)
endif()
# Menu
if (EMSCRIPTEN)
set(SRC_MENU menu_emscripten.c)
elseif (ANDROID)
set(SRC_MENU menu_android.c)
elseif (ENABLE_GTK)
set(SRC_MENU menu.c menu_callback.c menu_gui.c s39init.c)
if (ENABLE_GTK)
# i18n support (currently only menus are translated)
include(FindIntl)
include(FindGettext)
@@ -90,64 +154,36 @@ elseif (ENABLE_GTK)
include_directories(${Intl_INCLUDE_DIRS})
link_libraries(${Intl_LIBRARIES})
endif()
else ()
set(SRC_MENU menu_sdl.c sdl_input.c)
endif()
# PCM audio
if (EMSCRIPTEN)
list(APPEND SRC_AUDIO)
list(APPEND SRC_AUDIO pcm.emscripten.c bgm.emscripten.c bgi.c)
list(APPEND SUMMARY_AUDIO "Emscripten")
elseif (SDL2MIXER_FOUND)
list(APPEND SRC_AUDIO pcm.sdlmixer.c bgm.sdlmixer.c bgi.c)
list(APPEND SUMMARY_AUDIO "SDL_mixer")
set(ENABLE_SDLMIXER 1)
else()
list(APPEND SRC_AUDIO pcm.dummy.c bgm.dummy.c)
list(APPEND SUMMARY_AUDIO "SDL_mixer")
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")
set(ENABLE_CDROM_LINUX 1)
elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
list(APPEND SRC_CDROM cdrom.FreeBSD.c)
list(APPEND SUMMARY_CDROM "*BSD ioctl")
set(ENABLE_CDROM_BSD 1)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
list(APPEND SRC_CDROM cdrom.emscripten.c)
if (EMSCRIPTEN)
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)
list(APPEND SRC_CDROM cdrom.mp3.c)
list(APPEND SUMMARY_CDROM "SDL_mixer (wav|mp3|ogg...)")
set(ENABLE_CDROM_MP3 1)
endif()
set(CDROM_DEVICE "playlist.txt" CACHE STRING "CDROM Device Name")
set(DEFAULT_PLAYLIST_PATH "playlist.txt" CACHE STRING "Default playlist path")
# MIDI
if (EMSCRIPTEN)
list(APPEND SRC_MIDI midi.emscripten.c)
list(APPEND SUMMARY_MIDI "Emscripten")
elseif (ANDROID)
list(APPEND SRC_MIDI midi.android.c)
list(APPEND SUMMARY_MIDI "Android")
else()
list(APPEND SUMMARY_MIDI "SDL_mixer")
set(ENABLE_MIDI_SDLMIXER 1)
if (HAVE_SIGACTION)
list(APPEND SRC_MIDI midi.rawmidi.c midifile.c)
list(APPEND SUMMARY_MIDI "raw")
set(MIDI_DEVICE "/dev/midi" CACHE STRING "midi device")
set(ENABLE_MIDI_RAWMIDI 1)
@@ -166,15 +202,9 @@ else()
set(SEQ_DEVICE "/dev/sequencer" CACHE STRING "sequencer device")
endif()
if (SDL2MIXER_FOUND)
list(APPEND SRC_MIDI midi.sdlmixer.c)
list(APPEND SUMMARY_MIDI "SDL_mixer")
set(ENABLE_MIDI_SDLMIXER 1)
endif()
if (HAVE_PORTMIDI AND ENABLE_MIDI_PORTMIDI)
list(APPEND SRC_MIDI midi.portmidi.c)
if (HAVE_PORTMIDI)
list(APPEND SUMMARY_MIDI "PortMidi")
set(ENABLE_MIDI_PORTMIDI 1)
endif()
endif()
@@ -197,7 +227,6 @@ message("------------------")
set(PACKAGE ${PROJECT_NAME})
configure_file(config.h.in config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_compile_definitions(HAVE_CONFIG_H)
add_compile_definitions($<$<CONFIG:Debug>:DEBUG>)
add_subdirectory(src)
+70 -51
View File
@@ -3,22 +3,22 @@
This is a multi-platform port of `xsystem35`, a free implementation of
AliceSoft's System 3.x game engine.
## Compatiblity
## Compatibility
See the [game compatibility table](game_compatibility.md) for a list of games
that can be played on xsystem35-sdl2.
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
@@ -27,89 +27,108 @@ 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).
Copy `xsystem35.exe` to the game folder and run it.
### 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
View File
@@ -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.
+14 -11
View File
@@ -9,18 +9,18 @@ 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 13
versionName "2.8.0" + gitRevision()
targetSdkVersion 34
versionCode 23
versionName "2.11.5" + 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'
}
@@ -38,7 +38,9 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
if (rootProject.file('keystore.jks').exists()) {
signingConfig signingConfigs.release
}
}
}
applicationVariants.all { variant ->
@@ -62,10 +64,10 @@ android {
}
}
lintOptions {
lint {
abortOnError false
}
if (buildAsLibrary) {
libraryVariants.all { variant ->
variant.outputs.each { output ->
@@ -82,6 +84,7 @@ 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() {
+21 -32
View File
@@ -1,50 +1,39 @@
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.14)
project(GAME)
set(PROJECT_ROOT_DIR ../../..)
# Compilation of SDL and companion libraries
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.30.2/SDL2-2.30.2.tar.gz
URL_HASH SHA1=37a0557fc39460dc2a4fbbf162d95f115d2c9be2
)
FetchContent_Declare(
SDL_ttf
URL https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.20.1/SDL2_ttf-2.20.1.tar.gz
URL_HASH SHA1=f774ff407915ae4afa3d03e5a9395283d9090f28
URL https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.22.0/SDL2_ttf-2.22.0.tar.gz
URL_HASH SHA1=da5e86b601ad299a697878fab1af6f3be47b529d
)
FetchContent_Declare(
SDL_mixer
URL https://github.com/libsdl-org/SDL_mixer/releases/download/release-2.6.2/SDL2_mixer-2.6.2.tar.gz
URL_HASH SHA1=036fc7839a6b8dc1af3dbfed4e2531224bbacdd7
URL https://github.com/libsdl-org/SDL_mixer/releases/download/release-2.8.0/SDL2_mixer-2.8.0.tar.gz
URL_HASH SHA1=a58c69f9d00e44833b9e00e1adb58d85759ca499
)
# Compilation of SDL and companion libraries
FetchContent_GetProperties(SDL)
if(NOT sdl_POPULATED)
FetchContent_Populate(SDL)
add_subdirectory(${sdl_SOURCE_DIR} ${sdl_BINARY_DIR})
endif()
FetchContent_GetProperties(SDL_ttf)
if(NOT sdl_ttf_POPULATED)
FetchContent_Populate(SDL_ttf)
set(SDL2TTF_SAMPLES OFF CACHE BOOL "Build the SDL2_ttf sample program(s)" FORCE)
set(SDL2TTF_INSTALL OFF CACHE BOOL "Enable SDL2_ttf install target" FORCE)
set(SDL2TTF_VENDORED ON CACHE BOOL "Use vendored third-party libraries" FORCE)
add_subdirectory(${sdl_ttf_SOURCE_DIR} ${sdl_ttf_BINARY_DIR})
endif()
FetchContent_GetProperties(SDL_mixer)
if(NOT sdl_mixer_POPULATED)
FetchContent_Populate(SDL_mixer)
set(SDL2MIXER_OPUS OFF CACHE BOOL "Enable Opus music" FORCE)
set(SDL2MIXER_FLAC OFF CACHE BOOL "Enable FLAC music" FORCE)
set(SDL2MIXER_MOD OFF CACHE BOOL "Support loading MOD music" FORCE)
set(SDL2MIXER_MIDI OFF CACHE BOOL "Enable MIDI music" FORCE)
set(SDL2MIXER_SAMPLES OFF CACHE BOOL "Build the SDL2_mixer sample program(s)" FORCE)
set(SDL2MIXER_INSTALL OFF CACHE BOOL "Enable SDL2_mixer install target" FORCE)
add_subdirectory(${sdl_mixer_SOURCE_DIR} ${sdl_mixer_BINARY_DIR})
endif()
set(SDL2TTF_SAMPLES OFF CACHE BOOL "Build the SDL2_ttf sample program(s)" FORCE)
set(SDL2TTF_INSTALL OFF CACHE BOOL "Enable SDL2_ttf install target" FORCE)
set(SDL2TTF_VENDORED ON CACHE BOOL "Use vendored third-party libraries" FORCE)
set(SDL2MIXER_OPUS OFF CACHE BOOL "Enable Opus music" FORCE)
set(SDL2MIXER_FLAC OFF CACHE BOOL "Enable FLAC music" FORCE)
set(SDL2MIXER_MOD OFF CACHE BOOL "Support loading MOD music" FORCE)
set(SDL2MIXER_MIDI OFF CACHE BOOL "Enable MIDI music" FORCE)
set(SDL2MIXER_WAVPACK OFF CACHE BOOL "Enable WavPack music" FORCE)
set(SDL2MIXER_SAMPLES OFF CACHE BOOL "Build the SDL2_mixer sample program(s)" FORCE)
set(SDL2MIXER_INSTALL OFF CACHE BOOL "Enable SDL2_mixer install target" FORCE)
FetchContent_MakeAvailable(SDL SDL_ttf SDL_mixer)
# The main CMakeLists.txt of xsystem35
add_subdirectory(${PROJECT_ROOT_DIR} xsystem35)
-1
View File
@@ -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 -->
@@ -30,31 +30,29 @@ import java.io.IOException
// Intent for this activity must have the following extra:
// - EXTRA_GAME_ROOT (string): A path to the game installation.
// - EXTRA_SAVE_DIRECTORY (string): A path to the save data directory.
class GameActivity : SDLActivity() {
companion object {
const val EXTRA_GAME_ROOT = "GAME_ROOT"
const val EXTRA_SAVE_DIRECTORY = "SAVE_DIRECTORY"
const val EXTRA_ARCHIVE_NAME = "ARCHIVE_NAME"
}
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 +61,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)!!,
"-savedir", intent.getStringExtra(EXTRA_SAVE_DIRECTORY)!!)
}
override fun setTitle(title: CharSequence?) {
@@ -120,9 +120,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 +153,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,15 +17,15 @@
*/
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
import java.util.*
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
@@ -39,16 +39,13 @@ interface LauncherObserver {
fun onInstallFailure(msgId: Int)
}
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 {
const val SAVE_DIR = "save"
const val TITLE_FILE = "title.txt"
const val PLAYLIST_FILE = "playlist2.txt"
const val OLD_PLAYLIST_FILE = "playlist.txt"
const val GAMEDIR_FILE = "game_directory.txt"
const val PLAYLIST_FILE = "playlist.txt"
const val OLD_PLAYLIST_FILE = "playlist2.txt"
fun getInstance(rootDir: File): Launcher {
if (gLauncher == null) {
@@ -74,31 +71,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 {
val gameDir = withContext(Dispatchers.IO) {
extractFiles(input, dir) { msg ->
GlobalScope.launch(Dispatchers.Main) {
observer?.onInstallProgress(msg)
}
}
}
observer?.onInstallSuccess(gameDir, archiveName)
} catch (e: InstallFailureException) {
observer?.onInstallFailure(e.msgId)
} catch (e: Exception) {
Log.e("launcher", "Failed to extract ZIP", e)
observer?.onInstallFailure(R.string.zip_extraction_error)
}
isInstalling = false
}
val t = Thread {
extractFiles(input, dir, handler)
}
t.start()
isInstalling = true
}
fun uninstall(id: Int) {
@@ -118,9 +112,11 @@ class Launcher private constructor(private val rootDir: File) {
continue
}
try {
val titleFile = File(path, TITLE_FILE)
val gameDirFile = File(path, GAMEDIR_FILE)
val gamePath = if (gameDirFile.exists()) File(path, gameDirFile.readText()) else path
val titleFile = File(gamePath, TITLE_FILE)
val title = titleFile.readText()
games.add(Entry(path, title, titleFile.lastModified()))
games.add(Entry(gamePath, title, titleFile.lastModified()))
migratePlaylist(path)
} catch (e: IOException) {
// Incomplete game installation. Delete it.
@@ -183,108 +179,76 @@ 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): File {
val configWriter = GameConfigWriter()
val hadDecodeError = forEachZipEntry(input) { zipEntry, zip ->
Log.i("extractFiles", zipEntry.name)
val path = File(outDir, zipEntry.name)
if (zipEntry.isDirectory)
return@forEachZipEntry
path.parentFile?.mkdirs()
progressCallback(zipEntry.name)
FileOutputStream(path).buffered().use {
zip.copyTo(it)
}
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.ready) {
if (hadDecodeError)
throw InstallFailureException(R.string.unsupported_zip)
throw InstallFailureException(R.string.cannot_find_ald)
}
configWriter.write(outDir)
return configWriter.gameDir?.let { File(outDir, it) } ?: outDir
}
// Xsystem35-sdl2 2.3.0 - 2.11.1 used playlist2.txt. Rename it to playlist.txt.
private fun migratePlaylist(dir: File) {
val oldPlaylist = File(dir, OLD_PLAYLIST_FILE)
if (oldPlaylist.exists()) {
oldPlaylist.renameTo(File(dir, PLAYLIST_FILE))
}
}
// Xsystem35-sdl2 <=2.2.0 had a bug where playlist had an extra empty line at
// the beginning of the file. This migrates playlist.txt created by an old
// version of xsystem35-sdl2 to playlist2.txt.
private fun migratePlaylist(dir: File) {
val oldPlaylist = File(dir, OLD_PLAYLIST_FILE)
if (!oldPlaylist.exists())
return
var tracks = oldPlaylist.readLines()
if (!tracks.isEmpty())
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.
// A helper class which generates GAMEDIR_FILE and PLAYLIST_FILE.
private class GameConfigWriter {
private val grb = StringBuilder()
private var basename: String? = null
private val aldRegex = """(.*?)([a-z])([a-z])\.(ald|wai|bgi)""".toRegex(RegexOption.IGNORE_CASE)
private val aldType = mapOf(
"b" to "BGM",
"d" to "Data",
"g" to "Graphics",
"m" to "Midi",
"r" to "Resource",
"s" to "Scenario",
"w" to "Wave")
private val specialResources = mapOf(
"system39.ain" to "Ain",
"system39.ini" to "Init",
"sactefam.kld" to "SACT01"
)
var ready = false
private set
var gameDir: String? = null
private set
private val aldRegex = """.*?s[a-z]\.ald""".toRegex(RegexOption.IGNORE_CASE)
private val audioRegex = """.*?(\d+)\.(wav|mp3|ogg)""".toRegex(RegexOption.IGNORE_CASE)
private val audioFiles: Array<String?> = arrayOfNulls(100)
fun maybeAdd(path: String) {
val name = File(path).name
specialResources[name.lowercase(Locale.US)]?.let {
grb.appendLine("$it $path")
return
aldRegex.matchEntire(path)?.let {
gameDir = File(path).parent
ready = true
}
aldRegex.matchEntire(name)?.let {
val ext = it.groupValues[4].uppercase(Locale.US)
val type = if (ext == "ALD") {
aldType[it.groupValues[2].lowercase(Locale.US)]
} else {
ext
}
val id = it.groupValues[3].uppercase(Locale.US)
if (type != null) {
grb.appendLine("$type$id $path")
basename = it.groupValues[1]
}
}
audioRegex.matchEntire(name)?.let {
audioRegex.matchEntire(path)?.let {
val track = it.groupValues[1].toInt()
if (0 < track && track <= audioFiles.size)
audioFiles[track - 1] = path
}
}
fun readyToWrite() = basename != null
fun write(outDir: File) {
for (id in 'A' .. 'Z') {
grb.appendLine("Save$id ../save/${basename}s${id.lowercase(Locale.US)}.asd")
// Generate GAMEDIR_FILE
gameDir?.let {
File(outDir, GAMEDIR_FILE).writeText(it)
}
// Generate PLAYLIST_FILE
val absGameDir = gameDir?.let { File(outDir, it) } ?: outDir
val playlistFile = File(absGameDir, PLAYLIST_FILE)
if (!playlistFile.exists()) {
val prefixToRemove = gameDir?.let { "$it/" } ?: ""
val playlist = audioFiles.joinToString("\n") {
it?.removePrefix(prefixToRemove) ?: ""
}.trimEnd('\n')
playlistFile.writeText(playlist)
}
val gr = grb.toString()
Log.i("xsystem35.gr", gr)
File(outDir, "xsystem35.gr").writeText(gr)
val playlist = audioFiles.joinToString("\n") { it ?: "" }.trimEnd('\n')
File(outDir, PLAYLIST_FILE).writeText(playlist)
}
}
}
@@ -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)
@@ -153,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?) {
@@ -170,6 +180,7 @@ class LauncherActivity : Activity(), LauncherObserver {
val i = Intent()
i.setClass(applicationContext, GameActivity::class.java)
i.putExtra(GameActivity.EXTRA_GAME_ROOT, path.path)
i.putExtra(GameActivity.EXTRA_SAVE_DIRECTORY, File(filesDir, Launcher.SAVE_DIR).path)
i.putExtra(GameActivity.EXTRA_ARCHIVE_NAME, archiveName)
startActivity(i)
}
@@ -178,9 +189,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() {
@@ -209,18 +228,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)
}
}
@@ -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,15 +273,19 @@ 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
0x3537, // GameSir
};
if (usbInterface.getId() == 0 &&
@@ -353,13 +359,19 @@ public class HIDDeviceManager {
private void initializeBluetooth() {
Log.d(TAG, "Initializing Bluetooth");
if (Build.VERSION.SDK_INT <= 30 &&
if (Build.VERSION.SDK_INT >= 31 /* Android 12 */ &&
mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH_CONNECT, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH_CONNECT");
return;
}
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 +536,7 @@ public class HIDDeviceManager {
for (HIDDevice device : mDevicesById.values()) {
device.setFrozen(frozen);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -573,7 +585,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 = 30;
private static final int SDL_MICRO_VERSION = 2;
/*
// 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;
@@ -480,13 +546,15 @@ class SDLHapticHandler {
if (haptic == null) {
InputDevice device = InputDevice.getDevice(deviceIds[i]);
Vibrator vib = device.getVibrator();
if (vib.hasVibrator()) {
haptic = new SDLHaptic();
haptic.device_id = deviceIds[i];
haptic.name = device.getName();
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
if (vib != null) {
if (vib.hasVibrator()) {
haptic = new SDLHaptic();
haptic.device_id = deviceIds[i];
haptic.name = device.getName();
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
}
@@ -743,7 +811,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 +821,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,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>
+2 -2
View File
@@ -1,13 +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 {
classpath 'com.android.tools.build:gradle:7.3.1'
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
View File
@@ -1,6 +1,6 @@
#Thu Nov 11 18:20:34 PST 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
+2 -2
View File
@@ -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"`
+2 -11
View File
@@ -1,15 +1,8 @@
#cmakedefine PACKAGE "@PACKAGE@"
#define VERSION "2.8.0"
#cmakedefine CMAKE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@"
#define VERSION "2.11.5"
#cmakedefine CACHE_TOTALSIZE @CACHE_TOTALSIZE@
#cmakedefine ENABLE_CDROM_ANDROID @ENABLE_CDROM_ANDROID@
#cmakedefine ENABLE_CDROM_BSD @ENABLE_CDROM_BSD@
#cmakedefine ENABLE_CDROM_EMSCRIPTEN @ENABLE_CDROM_EMSCRIPTEN@
#cmakedefine ENABLE_CDROM_LINUX @ENABLE_CDROM_LINUX@
#cmakedefine ENABLE_CDROM_MP3 @ENABLE_CDROM_MP3@
#cmakedefine ENABLE_DEBUGGER @ENABLE_DEBUGGER@
#cmakedefine ENABLE_GTK @ENABLE_GTK@
#cmakedefine ENABLE_MIDI_RAWMIDI @ENABLE_MIDI_RAWMIDI@
@@ -17,9 +10,8 @@
#cmakedefine ENABLE_MIDI_SEQMIDI @ENABLE_MIDI_SEQMIDI@
#cmakedefine ENABLE_MIDI_PORTMIDI @ENABLE_MIDI_PORTMIDI@
#cmakedefine ENABLE_NLS @ENABLE_NLS@
#cmakedefine ENABLE_SDLMIXER @ENABLE_SDLMIXER@
#cmakedefine CDROM_DEVICE "@CDROM_DEVICE@"
#cmakedefine DEFAULT_PLAYLIST_PATH "@DEFAULT_PLAYLIST_PATH@"
#cmakedefine JOY_DEVICE "@JOY_DEVICE@"
#cmakedefine MIDI_DEVICE "@MIDI_DEVICE@"
#cmakedefine SEQ_DEVICE "@SEQ_DEVICE@"
@@ -27,7 +19,6 @@
#cmakedefine HAVE_GETLOGIN @HAVE_GETLOGIN@
#cmakedefine HAVE_MMAP @HAVE_MMAP@
#cmakedefine HAVE_SIGACTION @HAVE_SIGACTION@
#cmakedefine HAVE_UNAME @HAVE_UNAME@
#cmakedefine HAVE_WEBP @HAVE_WEBP@
#define DEFAULT_GOTHIC_TTF "@DEFAULT_FONT_PATH@MTLc3m.ttf"
+7 -7
View File
@@ -5,11 +5,11 @@ Game Compatibility
| ------------------------------------------- | ----------- | ----- |
| 鬼畜王ランス | Supported | |
| Kichikuou Rance (EN) | Supported | |
| RanceIV -教団の遺産- | Supported | Win95 edition, [Ver2.05](https://hannylaboratory.blogspot.com/2023/01/blog-post_26.html) |
| RanceIV -教団の遺産- | Supported | Win95 edition and [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) |
| ランス4.1 | Supported | [Ver1.05](https://hannylaboratory.blogspot.com/2023/02/blog-post_9.html). Use system3-sdl2 for older versions |
| ランス4.2 | Supported | [Ver1.05](https://hannylaboratory.blogspot.com/2023/02/blog-post_9.html). Use system3-sdl2 for older versions |
| いけないかつみ先生 | Supported | Emojis are not supported |
| 闘神都市II | Supported | Win95 edition |
| かえるにょ・ぱにょ~ん | Supported | Normal / Low-priced edition |
@@ -22,7 +22,7 @@ Game Compatibility
| DALK | Supported | From ALICEの館4・5・6 |
| 闘神都市 | Supported | From ALICEの館4・5・6 |
| Dr.STOP | Supported | From ALICEの館4・5・6 |
| 人間狩り | Unsupported | From ALICEの館4・5・6 / アリスCD |
| 人間狩り | Supported | From ALICEの館4・5・6 / アリスCD |
| 女の子図鑑 | Unknown | From ALICEの館4・5・6 |
| 恋のおわり | Unknown | |
| 王道勇者 | Supported | |
@@ -71,13 +71,13 @@ Game Compatibility
| [扉] | Supported | From アリスCD |
| 叩き殺し太郎 | Supported | From アリスCD |
| バルーンぽっぷ | Supported | From アリスCD |
| 高速ひよこ2 | Unsupported | 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 |
| Child Assassin | Unsupported | From アリスCD |
| Klavier | Supported | From アリスCD |
| 弱肉狂食 | Unsupported | From アリスCD |
| 弱肉狂食 | Supported | From アリスCD |
| 眼鏡大戦2 | Supported | From アリスCD |
| 妄想くん | Supported | From アリスCD |
+3 -16
View File
@@ -98,20 +98,7 @@ endif()
target_compile_options(modules PRIVATE -Wno-pointer-sign)
if (EMSCRIPTEN)
set(LIBS
"SHELL:-s USE_ZLIB=1"
"SHELL:-s USE_SDL=2")
target_compile_options(modules PRIVATE ${LIBS})
target_link_options(modules PRIVATE ${LIBS})
elseif (ANDROID)
target_link_libraries(modules PRIVATE ${ndk_zlib})
if (SDL2MIXER_FOUND)
target_link_libraries(modules PRIVATE SDL2 SDL2_mixer)
endif()
else()
target_link_libraries(modules PRIVATE ZLIB::ZLIB)
if (SDL2MIXER_FOUND)
target_link_libraries(modules PRIVATE PkgConfig::SDL2MIXER)
endif()
target_link_libraries(modules PRIVATE sdl2 zlib)
if (TARGET sdl2_mixer)
target_link_libraries(modules PRIVATE sdl2_mixer)
endif()
+5 -6
View File
@@ -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;
}
+3 -9
View File
@@ -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/メッセージスキップ/メッセージ枠消去の領域に
// マウスが移動したら、その部分のアイコンを変化させる
}
// メッセージ表示時に、キー入力を促すアニメーションの設定
+3
View File
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <string.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include "portab.h"
#include "system.h"
-1
View File
@@ -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
View File
@@ -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;
}
}
+5 -5
View File
@@ -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;
+5 -5
View File
@@ -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);
}
+1 -1
View File
@@ -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) {
+7 -6
View File
@@ -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;
+2 -2
View File
@@ -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 に戻せばよい
+2 -3
View File
@@ -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;
}
+9 -5
View File
@@ -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++;
+2 -1
View File
@@ -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]);
}
+1 -1
View File
@@ -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);
+130 -82
View File
@@ -11,6 +11,9 @@ if (ANDROID)
add_library(xsystem35 SHARED)
else()
add_executable(xsystem35)
if (WIN32)
target_link_options(xsystem35 PRIVATE -static)
endif()
endif()
target_compile_options(xsystem35 PRIVATE -Wno-pointer-sign $<$<CONFIG:Debug>:-Wall>)
@@ -18,112 +21,164 @@ target_include_directories(xsystem35 PRIVATE .)
target_link_libraries(xsystem35 PRIVATE src_lib)
target_sources(xsystem35 PRIVATE
xsystem35.c
dri.c
ags.c
ald_manager.c
alpha_plane.c
bgi.c
bmp.c
cache.c
${SRC_AUDIO}
${SRC_CDROM}
${SRC_MIDI}
${SRC_MENU})
cali.c
cdrom.bgm.c
cg.c
cmd2F.c
cmd2F60.c
cmd_check.c
cmdb.c
cmdc.c
cmdd.c
cmde.c
cmdf.c
cmdg.c
cmdh.c
cmdi.c
cmdj.c
cmdk.c
cmdl.c
cmdm.c
cmdn.c
cmdo.c
cmdp.c
cmdq.c
cmds.c
cmdt.c
cmdu.c
cmdv.c
cmdw.c
cmdy.c
cmdz.c
cursor.c
dri.c
ecopy.c
filecheck.c
font.c
hacks.c
image.c
input.c
jpeg.c
message.c
midi.c
mmap.c
msgskip.c
mt19937-1.c
music.c
music_cdrom.c
music_midi.c
nact.c
network.c
pms.c
profile.c
qnt.c
s39ain.c
savedata.c
scenario.c
sdl_cursor.c
sdl_draw.c
sdl_effect.c
sdl_event.c
sdl_image.c
sdl_video.c
selection.c
texthook.c
variable.c
vsp.c
xsystem35.c
)
# System3.x commands
target_sources(xsystem35 PRIVATE
cmdb.c cmdc.c cmdd.c cmde.c cmdf.c cmdg.c cmdh.c cmdi.c cmdj.c
cmdk.c cmdl.c cmdm.c cmdn.c cmdo.c cmdp.c cmdq.c cmds.c cmdt.c
cmdu.c cmdv.c cmdw.c cmdy.c cmdz.c cmd2F.c cmd2F60.c)
# Graphics
target_sources(xsystem35 PRIVATE
sdl_video.c sdl_draw.c sdl_event.c sdl_image.c sdl_cursor.c sdl_effect.c
image.c font.c)
# CG
target_sources(xsystem35 PRIVATE
pms.c vsp.c bmp.c qnt.c jpeg.c)
if (HAVE_WEBP)
target_sources(xsystem35 PRIVATE webp.c)
target_link_libraries(xsystem35 PRIVATE PkgConfig::WEBP)
if (EMSCRIPTEN)
target_sources(xsystem35 PRIVATE pcm.emscripten.c bgm.emscripten.c)
else()
target_sources(xsystem35 PRIVATE pcm.sdlmixer.c bgm.sdlmixer.c)
endif()
# Music
target_sources(xsystem35 PRIVATE
music.c music_cdrom.c music_midi.c midi.c cdrom.c)
if (EMSCRIPTEN)
target_sources(xsystem35 PRIVATE cdrom.emscripten.c)
else()
target_sources(xsystem35 PRIVATE cdrom.mp3.c)
endif()
# Misc
target_sources(xsystem35 PRIVATE
input.c profile.c mt19937-1.c filecheck.c mmap.c hacks.c)
if (EMSCRIPTEN)
target_sources(xsystem35 PRIVATE midi.emscripten.c)
elseif (ANDROID)
target_sources(xsystem35 PRIVATE midi.android.c)
else()
target_sources(xsystem35 PRIVATE midi.sdlmixer.c)
if (ENABLE_MIDI_RAWMIDI)
target_sources(xsystem35 PRIVATE midi.rawmidi.c midifile.c)
endif()
if (ENABLE_MIDI_PORTMIDI)
target_sources(xsystem35 PRIVATE midi.portmidi.c)
endif()
endif()
# Scenario
target_sources(xsystem35 PRIVATE
cali.c scenario.c variable.c cmd_check.c nact.c
selection.c message.c savedata.c s39ain.c texthook.c msgskip.c)
if (EMSCRIPTEN)
target_sources(xsystem35 PRIVATE menu_emscripten.c)
elseif (ANDROID)
target_sources(xsystem35 PRIVATE menu_android.c)
elseif (ENABLE_GTK)
target_sources(xsystem35 PRIVATE menu.c menu_callback.c menu_gui.c s39init.c)
else ()
target_sources(xsystem35 PRIVATE menu_sdl.c sdl_input.c)
endif()
# Graphics
target_sources(xsystem35 PRIVATE
ags.c cg.c ecopy.c alpha_plane.c cursor.c)
if (HAVE_WEBP)
target_sources(xsystem35 PRIVATE webp.c)
target_link_libraries(xsystem35 PRIVATE WebP)
endif()
# Network
target_sources(xsystem35 PRIVATE
network.c)
# Debugger
if (ENABLE_DEBUGGER)
target_sources(xsystem35 PRIVATE
debug_symbol.c debugger.c debugger_cui.c debugger_dap.c)
endif()
if (WIN32)
target_sources(xsystem35 PRIVATE win/dialog.c win/resources.rc win/menubar.c win/console.c)
target_sources(xsystem35 PRIVATE
win/dialog.c win/resources.rc win/resources.c win/menubar.c win/console.c)
endif()
target_link_libraries(src_lib PRIVATE sdl2 zlib)
target_link_libraries(xsystem35 PRIVATE m zlib sdl2 sdl2_ttf)
if (TARGET sdl2_mixer)
target_link_libraries(xsystem35 PRIVATE sdl2_mixer)
endif()
if (EMSCRIPTEN)
set(LIBS
"SHELL:-s USE_ZLIB=1"
"SHELL:-s USE_SDL=2"
"SHELL:-s USE_SDL_TTF=2")
target_compile_options(xsystem35 PRIVATE ${LIBS})
target_link_options(xsystem35 PRIVATE ${LIBS})
target_link_libraries(xsystem35 PRIVATE idbfs.js)
# Without optimizations, Asyncify generates very large code.
list(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG "-O1")
target_link_options(xsystem35 PRIVATE
"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_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_RUNTIME_METHODS=getValue,addRunDependency,removeRunDependency")
-sENVIRONMENT=web
-sASYNCIFY=1
-sASYNCIFY_IGNORE_INDIRECT=1
-sASYNCIFY_REMOVE=SDL_Delay
-sASYNCIFY_IMPORTS=muspcm_load_no,muspcm_load_data,muspcm_load_mixlr,muspcm_waitend,wait_vsync,load_mincho_font
-sASYNCIFY_ADD=commands2F60,nact_main,send_agsevent,cb_waitkey_sprite
-sALLOW_MEMORY_GROWTH=1
-sNO_EXIT_RUNTIME=1
-sEXPORTED_FUNCTIONS=_main,_malloc
-sEXPORTED_RUNTIME_METHODS=getValue,addRunDependency,removeRunDependency)
elseif (ANDROID)
target_link_libraries(src_lib PRIVATE SDL2)
target_link_libraries(xsystem35 PRIVATE SDL2 SDL2_ttf SDL2_mixer ${ndk_zlib} ${ndk_log})
target_link_libraries(xsystem35 PRIVATE ${ndk_log})
else() # non-emscripten, non-android
target_link_libraries(src_lib PRIVATE PkgConfig::SDL2)
target_link_libraries(xsystem35 PRIVATE m ZLIB::ZLIB)
target_link_libraries(xsystem35 PRIVATE PkgConfig::SDL2)
target_link_libraries(xsystem35 PRIVATE PkgConfig::SDL2TTF)
if (TARGET cJSON)
target_link_libraries(xsystem35 PRIVATE cJSON)
endif()
if (GTK3_FOUND)
target_link_libraries(xsystem35 PRIVATE PkgConfig::GTK3)
endif()
if (SDL2MIXER_FOUND)
target_link_libraries(xsystem35 PRIVATE PkgConfig::SDL2MIXER)
endif()
if (ENABLE_DEBUGGER)
if (cJSON_FOUND)
target_link_libraries(xsystem35 PRIVATE PkgConfig::cJSON)
else()
target_link_libraries(xsystem35 PRIVATE ${cJSON})
endif()
endif()
if (ENABLE_MIDI_PORTMIDI)
target_link_libraries(xsystem35 PRIVATE ${PORTMIDI})
endif()
@@ -140,10 +195,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()
+87 -63
View File
@@ -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) {
@@ -99,9 +120,8 @@ boolean ags_check_param_xy(int *x, int *y) {
return TRUE;
}
void ags_init(const char *render_driver) {
nact->ags.mouse_movesw = MOUSE_WARP_SMOOTH;
nact->ags.pal = &pal_256;
void ags_init(const char *render_driver, bool enable_zb) {
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;
@@ -109,11 +129,14 @@ void ags_init(const char *render_driver) {
nact->ags.view_area.y = 0;
nact->ags.view_area.w = SYS35_DEFAULT_WIDTH;
nact->ags.view_area.h = SYS35_DEFAULT_HEIGHT;
nact->ags.enable_zb = enable_zb;
nact->ags.font_weight = enable_zb ? FONT_WEIGHT_BOLD : FONT_WEIGHT_NORMAL;
sdl_Initialize(render_driver);
font_init();
initPal(&pal_256);
initPal();
cg_init();
}
@@ -123,9 +146,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 +174,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) {
@@ -216,21 +239,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) {
@@ -577,9 +597,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);
}
}
@@ -606,14 +626,18 @@ 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);
}
}
void ags_setFont(int type, int size) {
font_select(type, size);
font_select(type, size, FONT_WEIGHT_NORMAL);
}
void ags_setFontWithWeight(int type, int size, int weight) {
font_select(type, size, weight);
}
void ags_setCursorType(int type) {
@@ -627,42 +651,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
+26 -26
View File
@@ -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,13 @@ 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 */
int font_weight;
bool mouse_warp_enabled;
bool enable_zb;
boolean noantialias; /* antialias を使用しない */
boolean noimagecursor; /* リソースファイルのカーソルを読みこまない */
};
@@ -126,7 +125,7 @@ typedef struct _ags ags_t;
/* 初期化関係 */
void ags_init(const char *render_driver);
void ags_init(const char *render_driver, bool enable_zb);
void ags_remove(void);
void ags_reset(void);
@@ -147,7 +146,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);
@@ -203,12 +202,13 @@ enum FontType {
FONT_MINCHO,
};
extern void ags_setFont(int type, int size);
extern void ags_setFontWithWeight(int type, int size, int weight);
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();
+1 -1
View File
@@ -108,5 +108,5 @@ void ald_init(int type, const char **file, int cnt, boolean use_mmap) {
int ald_get_maxno(DRIFILETYPE type) {
if (type >= DRIFILETYPEMAX || !dri[type])
return 0;
return dri[type]->nr_files;
return dri[type]->maxno;
}
-75
View File
@@ -1,75 +0,0 @@
/*
* bgm.dummy.c BGM (*BA.ALD) dummy implementation
*
* Copyright (C) 2019 <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 "portab.h"
#include "bgm.h"
int musbgm_init(DRIFILETYPE type, int base_no) {
return NG;
}
int musbgm_exit(void) {
return NG;
}
int musbgm_reset(void) {
return NG;
}
int musbgm_play(int no, int time, int vol) {
WARNING("not implemented");
return NG;
}
int musbgm_stop(int no, int time) {
WARNING("not implemented");
return NG;
}
int musbgm_fade(int no, int time, int vol) {
WARNING("not implemented");
return NG;
}
int musbgm_getpos(int no) {
WARNING("not implemented");
return 0;
}
int musbgm_getlen(int no) {
WARNING("not implemented");
return 0;
}
int musbgm_isplaying(int no) {
WARNING("not implemented");
return 0;
}
int musbgm_stopall(int time) {
WARNING("not implemented");
return NG;
}
int musbgm_wait(int no, int timeout) {
WARNING("not implemented");
return NG;
}
+8 -11
View File
@@ -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)));
-238
View File
@@ -1,238 +0,0 @@
/*
* cdrom.FreeBSD.c CD-ROMアクセス
*
* 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: cdrom.FreeBSD.c,v 1.17 2002/08/18 09:35:29 chikama Exp $ */
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/cdio.h>
#include "portab.h"
#include "cdrom.h"
#include "music_private.h"
#include "system.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_bsd
cdromdevice_t cdrom = {
cdrom_init,
cdrom_exit,
cdrom_reset,
cdrom_start,
cdrom_stop,
cdrom_getPlayingInfo,
NULL,
NULL
};
static int cd_fd;
static boolean enabled = FALSE;
static struct cd_toc_entry toc_buffer[100];
static boolean msfmode = TRUE; /* default は MSFPLAY mode */
static int lastindex; /* 最終トラック */
/* ioctlがエラーで帰って来る場合 IOCTL_RETRY_TIME 回リトライする */
static int do_ioctl(int cmd, void *data) {
int i;
for (i = 0; i < CDROM_IOCTL_RETRY_TIME; i++) {
if (0 <= ioctl(cd_fd, cmd, data)) {
return 0;
}
usleep(CDROM_IOCTL_RETRY_INTERVAL * 100 * 1000);
}
return -1;
}
/* CD-ROM の目次を読み出しておく */
static int get_cd_entry() {
int endtrk, i;
struct ioc_toc_header tochdr;
struct ioc_read_toc_entry toc;
struct ioc_play_msf msf;
/* 最終トラック番号を得る */
if (do_ioctl(CDIOREADTOCHEADER, &tochdr) < 0) {
WARNING("CDIOREADTOCHEADER: %s", strerror(errno));
return NG;
}
lastindex = endtrk = tochdr.ending_track;
i = tochdr.ending_track - tochdr.starting_track + 1;
if (endtrk <= 1) { /* 2トラック以上ないとダメ */
WARNING("No CD-AUDIO in CD-ROM");
return NG;
}
prv.cd_maxtrk = lastindex;
/* すべてのトラックの目次を読みだしてキャッシュしておく */
toc.address_format = CD_MSF_FORMAT;
toc.starting_track = 0;
toc.data_len = (i + 1) * sizeof(struct cd_toc_entry);
toc.data = toc_buffer;
if (do_ioctl(CDIOREADTOCENTRYS, &toc) < 0) {
WARNING("CDIOREADTOCENTRYS: %s", strerror(errno));
return NG;
}
#ifdef CDROM_USE_TRKIND_ONLY
msfmode = FALSE;
return OK;
#endif
/* CDROMPLAYMSF が有効かチェック */
msf.start_m = toc_buffer[1].addr.msf.minute;
msf.start_s = toc_buffer[1].addr.msf.second;
msf.start_f = toc_buffer[1].addr.msf.frame;
msf.end_m = toc_buffer[2].addr.msf.minute;
msf.end_s = toc_buffer[2].addr.msf.second;
msf.end_f = toc_buffer[2].addr.msf.frame;
if (do_ioctl(CDIOCPLAYMSF, &msf) < 0) {
WARNING("CDIOPLAYMSF: %s", strerror(errno));
WARNING("CD-ROM: change TRKMODE");
msfmode = FALSE;
}
/* stop */
if (do_ioctl(CDIOCSTOP, NULL) < 0) {
WARNING("CDIOCSTOP: %s", strerror(errno));
return NG;
}
return OK;
}
/* デバイスの初期化 */
int cdrom_init(char *dev_cd) {
if (dev_cd == NULL) return NG;
if ((cd_fd = open(dev_cd, O_RDONLY, 0)) < 0) {
WARNING("CDROM_DEVICE OPEN: %s", strerror(errno));
enabled = FALSE;
return NG;
}
if (OK == get_cd_entry()) {
enabled = TRUE;
return OK;
}
enabled = FALSE;
return NG;
}
/* デバイスの後始末 */
int cdrom_exit(void) {
if (enabled) {
cdrom_stop();
close(cd_fd);
}
return OK;
}
int cdrom_reset(void) {
return cdrom_stop();
}
/* トラック番号 trk の演奏 trk = 1~ */
int cdrom_start(int trk, int loop) {
struct ioc_play_msf msf;
struct ioc_play_track track;
if (!enabled) return NG;
/* 曲数よりも多い指定は不可*/
if (trk > lastindex) {
return NG;
}
/* drive spin up */
if (do_ioctl(CDIOCSTART, NULL) < 0) {
WARNING("CDIOCSTART: %s", strerror(errno));
return NG;
}
if (msfmode) {
msf.start_m = toc_buffer[trk - 1].addr.msf.minute;
msf.start_s = toc_buffer[trk - 1].addr.msf.second;
msf.start_f = toc_buffer[trk - 1].addr.msf.frame;
msf.end_m = toc_buffer[trk].addr.msf.minute;
msf.end_s = toc_buffer[trk].addr.msf.second;
msf.end_f = toc_buffer[trk].addr.msf.frame;
if (do_ioctl(CDIOCPLAYMSF, &msf) < 0) {
WARNING("CDIOPLAYMSF: %s", strerror(errno));
return NG;
}
} else {
track.start_track = track.end_track = trk;
track.start_index = track.end_index = 0;
if (do_ioctl(CDIOCPLAYTRACKS, &track) < 0) {
WARNING("CDIOCPLAYTRACKS: %s", strerror(errno));
return NG;
}
}
return OK;
}
/* 演奏停止 */
int cdrom_stop() {
if (enabled) {
/* if (do_ioctl(CDIOCSTOP, NULL) < 0) { */
if (do_ioctl(CDIOCPAUSE, NULL) < 0) {
/* WARNING("CDIOCSTOP: %s", strerror(errno)); */
WARNING("CDIOCPAUSE: %s", strerror(errno));
}
return OK;
}
return NG;
}
/* 現在演奏中のトラック情報の取得 */
int cdrom_getPlayingInfo (cd_time *info) {
struct ioc_read_subchannel s;
struct cd_sub_channel_info data;
if (!enabled)
return NG;
memset(&s, 0, sizeof(s));
s.data = &data;
s.data_len = sizeof (data);
s.address_format = CD_MSF_FORMAT;
s.data_format = CD_CURRENT_POSITION;
if (do_ioctl(CDIOCREADSUBCHANNEL, &s) < 0) {
WARNING("CDIOCREADSUBCHANNEL: %s", strerror(errno));
return NG;
}
if (s.data->header.audio_status != CD_AS_PLAY_IN_PROGRESS) {
return NG;
}
info->t = s.data->what.position.track_number;
info->m = s.data->what.position.reladdr.msf.minute;
info->s = s.data->what.position.reladdr.msf.second;
info->f = s.data->what.position.reladdr.msf.frame;
return OK;
}
-268
View File
@@ -1,268 +0,0 @@
/*
* cdrom.Linux.c CD-ROMアクセス
*
* 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: cdrom.Linux.c,v 1.18 2002/08/18 09:35:29 chikama Exp $ */
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#if defined(sun)
#include <sys/cdio.h>
struct cdrom_msf0 {
unsigned char minute; /* minute */
unsigned char second; /* second */
unsigned char frame; /* frame */
};
#else
#include <linux/cdrom.h>
#endif /* sun */
#include "portab.h"
#include "cdrom.h"
#include "music_private.h"
#include "system.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_linux
cdromdevice_t cdrom = {
cdrom_init,
cdrom_exit,
cdrom_reset,
cdrom_start,
cdrom_stop,
cdrom_getPlayingInfo,
NULL,
NULL
};
static int cd_fd;
static boolean enabled = FALSE;
static struct cdrom_msf0 tocmsf[100];
static boolean msfmode = TRUE; /* default は MSFPLAY mode */
static int lastindex; /* 最終トラック */
/* ioctlがエラーで帰って来る場合 IOCTL_RETRY_TIME 回リトライする */
static int do_ioctl(int cmd, void *data) {
int i;
for (i = 0; i < CDROM_IOCTL_RETRY_TIME; i++) {
if (0 <= ioctl(cd_fd, cmd, data)) {
return 0;
}
usleep(CDROM_IOCTL_RETRY_INTERVAL * 100 * 1000);
}
return -1;
}
/* CD-ROM の目次を読み出しておく */
static int get_cd_entry() {
int endtrk, i;
struct cdrom_tochdr tochdr;
struct cdrom_tocentry toc;
struct cdrom_msf msf;
/* 最終トラック番号を得る */
if (do_ioctl(CDROMREADTOCHDR, &tochdr) < 0) {
WARNING("CDROMREADTOCHDR: %s", strerror(errno));
return NG;
}
lastindex = endtrk = tochdr.cdth_trk1;
if (endtrk <= 1) { /* 2トラック以上ないとダメ */
WARNING("No CD-AUDIO in CD-ROM");
return NG;
}
prv.cd_maxtrk = lastindex;
/* すべてのトラックの目次を読みだしてキャッシュしておく */
toc.cdte_format = CDROM_MSF;
for (i = 1; i <= endtrk; i++) {
toc.cdte_track = i;
if (do_ioctl(CDROMREADTOCENTRY, &toc) < 0) {
WARNING("CDROMREADTOCENTRY: %s", strerror(errno));
return NG;
}
tocmsf[i - 1].minute = toc.cdte_addr.msf.minute;
tocmsf[i - 1].second = toc.cdte_addr.msf.second;
tocmsf[i - 1].frame = toc.cdte_addr.msf.frame;
}
/* リードアウトを読み出す */
toc.cdte_track = CDROM_LEADOUT;
if (do_ioctl(CDROMREADTOCENTRY, &toc) < 0) {
WARNING("CDROMREADTOCENTRY: %s", strerror(errno));
return NG;
}
#ifdef PPC
/* Linux PPC 対策 ;last track -1 frame */
FRAMES_TO_MSF(MSF_TO_FRAMES(toc.cdte_addr.msf.minute,
toc.cdte_addr.msf.second,
toc.cdte_addr.msf.frame) - 1,
&tocmsf[endtrk].minute,
&tocmsf[endtrk].second,
&tocmsf[endtrk].frame);
#else
tocmsf[endtrk].minute = toc.cdte_addr.msf.minute;
tocmsf[endtrk].second = toc.cdte_addr.msf.second;
tocmsf[endtrk].frame = toc.cdte_addr.msf.frame;
#endif
#ifdef CDROM_USE_TRKIND_ONLY
msfmode = FALSE;
return OK;
#endif
/* CDROMPLAYMSF が有効かチェック */
msf.cdmsf_min0 = tocmsf[1].minute;
msf.cdmsf_sec0 = tocmsf[1].second;
msf.cdmsf_frame0 = tocmsf[1].frame;
msf.cdmsf_min1 = tocmsf[2].minute;
msf.cdmsf_sec1 = tocmsf[2].second;
msf.cdmsf_frame1 = tocmsf[2].frame;
if (do_ioctl(CDROMPLAYMSF, &msf) < 0) {
WARNING("CDROMPLAYMSF: %s", strerror(errno));
WARNING("CD-ROM: change TRKIND mode");
msfmode = FALSE;
}
/* stop */
if (do_ioctl(CDROMSTOP, NULL) < 0) {
WARNING("CDROMSTOP: %s", strerror(errno));
return NG;
}
return OK;
}
/* デバイスの初期化 */
static int cdrom_init(char *dev_cd) {
if (dev_cd == NULL) return NG;
if ((cd_fd = open(dev_cd, O_RDONLY, 0)) < 0) {
WARNING("CDROM_DEVICE OPEN: %s", strerror(errno));
enabled = FALSE;
return NG;
}
if (OK == get_cd_entry()) {
enabled = TRUE;
return OK;
}
enabled = FALSE;
return NG;
}
/* デバイスの後始末 */
static int cdrom_exit(void) {
if (enabled) {
cdrom_stop();
close(cd_fd);
}
return OK;
}
static int cdrom_reset(void) {
return cdrom_stop();
}
/* トラック番号 trk の演奏 trk = 1~ */
static int cdrom_start(int trk, int loop) {
struct cdrom_msf msf;
struct cdrom_ti ti;
if (!enabled) return NG;
/* 曲数よりも多い指定は不可*/
if (trk > lastindex) {
return NG;
}
/* drive spin up */
if (do_ioctl(CDROMSTART, NULL) < 0) {
WARNING("CDROMSTART: %s", strerror(errno));
return NG;
}
if (msfmode) {
msf.cdmsf_min0 = tocmsf[trk - 1].minute;
msf.cdmsf_sec0 = tocmsf[trk - 1].second;
msf.cdmsf_frame0 = tocmsf[trk - 1].frame;
msf.cdmsf_min1 = tocmsf[trk].minute;
msf.cdmsf_sec1 = tocmsf[trk].second;
msf.cdmsf_frame1 = tocmsf[trk].frame;
if (do_ioctl(CDROMPLAYMSF, &msf) < 0) {
WARNING("CDROMPLAYMSF: %s", strerror(errno));
return NG;
}
return OK;
} else {
ti.cdti_trk0 = ti.cdti_trk1 = trk;
ti.cdti_ind0 = ti.cdti_ind1 = 0;
if (do_ioctl(CDROMPLAYTRKIND, &ti) < 0) {
WARNING("CDROMPLAYTRKIND: %s", strerror(errno));
return NG;
}
return OK;
}
}
/* 演奏停止 */
static int cdrom_stop() {
if (enabled) {
/* if (do_ioctl(CDROMSTOP, NULL) < 0) { */
if (do_ioctl(CDROMPAUSE, NULL) < 0) {
/* WARNING("CDROMSTOP: %s", strerror(errno)); */
WARNING("CDROMPAUSE: %s", strerror(errno));
return NG;
}
return OK;
}
return NG;
}
/* 現在演奏中のトラック情報の取得 */
static int cdrom_getPlayingInfo (cd_time *info) {
struct cdrom_subchnl sc;
if (!enabled)
return NG;
sc.cdsc_format = CDROM_MSF;
if (do_ioctl(CDROMSUBCHNL, &sc) < 0) {
WARNING("CDROMSUBCHNL: %s", strerror(errno));
return NG;
}
if (sc.cdsc_audiostatus != CDROM_AUDIO_PLAY) {
return NG;
}
info->t = sc.cdsc_trk;
info->m = sc.cdsc_reladdr.msf.minute;
info->s = sc.cdsc_reladdr.msf.second;
info->f = sc.cdsc_reladdr.msf.frame;
return OK;
}
-102
View File
@@ -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;
}
+4 -1
View File
@@ -22,11 +22,14 @@
#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) {
static int cdrom_bgm_init(char *playlist) {
prv.cd_maxtrk = ald_get_maxno(DRIFILE_BGM) + 1;
return OK;
}
-75
View File
@@ -1,75 +0,0 @@
/*
* cdrom.c CD-ROM control wrapper
*
* Copyright (C) 2000- Masaki Chikama (Wren) <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: cdrom.c,v 1.20 2002/08/18 09:35:29 chikama Exp $ */
#include "config.h"
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include "portab.h"
#include "cdrom.h"
#include "system.h"
#if defined(ENABLE_CDROM_LINUX)
extern cdromdevice_t cdrom_linux;
#define NATIVE_CD_DEVICE &cdrom_linux
#elif defined(ENABLE_CDROM_BSD)
extern cdromdevice_t cdrom_bsd;
#define NATIVE_CD_DEVICE &cdrom_bsd
#elif defined(ENABLE_CDROM_EMSCRIPTEN)
extern cdromdevice_t cdrom_emscripten;
#define NATIVE_CD_DEVICE &cdrom_emscripten
#elif defined(ENABLE_CDROM_ANDROID)
extern cdromdevice_t cdrom_android;
#define NATIVE_CD_DEVICE &cdrom_android
#else
extern cdromdevice_t cdrom_empty;
#define NATIVE_CD_DEVICE &cdrom_empty
#endif
#ifdef ENABLE_CDROM_MP3
extern cdromdevice_t cdrom_mp3;
#endif
cdromdevice_t *cd_init(const char *dev) {
#if defined(ENABLE_CDROM_EMSCRIPTEN) || defined(ENABLE_CDROM_ANDROID)
return NATIVE_CD_DEVICE;
#else
struct stat st;
if (dev && stat(dev, &st) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
return NATIVE_CD_DEVICE;
#ifdef ENABLE_CDROM_MP3
return &cdrom_mp3;
#else
WARNING("no cdrom device available");
return NULL;
#endif
#endif // ENABLE_CDROM_EMSCRIPTEN || ENABLE_CDROM_ANDROID
}
-69
View File
@@ -1,69 +0,0 @@
/*
* cdrom.empty.c CD-ROMアクセス
*
* 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: cdrom.empty.c,v 1.8 2002/08/18 09:35:29 chikama Exp $ */
#include <unistd.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_empty
cdromdevice_t cdrom = {
cdrom_init,
cdrom_exit,
cdrom_reset,
cdrom_start,
cdrom_stop,
cdrom_getPlayingInfo,
NULL,
NULL
};
int cdrom_init(char *name) {
return NG;
}
int cdrom_exit(void) {
return OK;
}
int cdrom_reset(void) {
return OK;
}
int cdrom_start(int trk, int loop) {
return OK;
}
int cdrom_stop() {
return OK;
}
int cdrom_getPlayingInfo (cd_time *info) {
return NG;
}
+22 -30
View File
@@ -27,36 +27,7 @@
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();
int cdrom_init(char *playlist) {
return 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
};
-2
View File
@@ -51,8 +51,6 @@ typedef struct _cdromdevice cdromdevice_t;
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) { \
int value = f; \
+6 -1
View File
@@ -64,6 +64,9 @@ static int start_time;
static int cdrom_init(char *playlist_path) {
char buf[256];
if (!playlist_path || !playlist_path[0])
return NG;
FILE *fp = fopen(playlist_path, "r");
if (fp) {
// Skip the first line
@@ -72,7 +75,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;
}
+46 -16
View File
@@ -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;
@@ -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);
}
+8 -1
View File
@@ -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__ */
+38 -31
View File
@@ -42,14 +42,14 @@
#include "ald_manager.h"
#include "LittleEndian.h"
#include "hacks.h"
#if HAVE_UNAME
#include <sys/utsname.h>
#endif
#include "filecheck.h"
/* 選択 Window OPEN 時 callback */
static int cb_sel_init_page = 0;
static int cb_sel_init_address = 0;
static const char REGREADSTRING_RESULT[] = "*regReadString*";
extern INPUTSTRING_PARAM mi_param;
extern void commandH();
@@ -65,35 +65,41 @@ static fncall_table fnctbl[FCTBL_MAX];
void commands2F00() {
/* テキストカラーをスタックからポップして設定する */
sl_popState(TxxTEXTCOLOR);
sl_popState(STACK_TEXTCOLOR);
DEBUG_COMMAND("TOC:");
}
void commands2F01() {
/* テキストフォントサイズをスタックからポップして設定する */
sl_popState(TxxTEXTSIZE);
sl_popState(STACK_TEXTSIZE);
DEBUG_COMMAND("TOS:");
}
void commands2F02() {
/* 現在のテキストカラーをスタックにプッシュする */
int exp = getCaliValue();
int val = exp == 0 ? nact->msg.MsgFontColor : nact->sel.MsgFontColor;
sl_pushState(TxxTEXTCOLOR, exp, val);
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 val = exp == 0 ? nact->msg.MsgFontSize : nact->sel.MsgFontSize;
sl_pushState(TxxTEXTSIZE, exp, val);
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() {
/* テキスト表示位置をスタックからポップして設定する */
sl_popState(TxxTEXTLOC);
sl_popState(STACK_TEXTLOC);
DEBUG_COMMAND("TOP:");
}
@@ -101,7 +107,7 @@ void commands2F05() {
/* 現在のテキスト表示位置をスタックにプッシュする */
MyPoint loc;
msg_getMessageLocation(&loc);
sl_pushState(TxxTEXTLOC, loc.x, loc.y);
sl_pushTextLoc(loc.x, loc.y);
DEBUG_COMMAND("TPP:");
}
@@ -352,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();
@@ -458,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();
@@ -823,20 +829,9 @@ void commands2F52() {
int eNum = getCaliValue();
if (eNum <= 0) return;
#if HAVE_UNAME
struct utsname un;
char s[256];
if (uname(&un) < 0) return;
NOTICE("sysname %s nodename %s release %s version %s machine %s",
un.sysname, un.nodename, un.release, un.version, un.machine);
sprintf(s,"%s %s %s",
un.sysname, un.release, un.machine);
#else
const char *s = CMAKE_SYSTEM_NAME;
#endif
const char *s = SDL_GetPlatform();
svar_set(eNum, s);
DEBUG_COMMAND("sysGetOsName %d: %s", eNum, s);
DEBUG_COMMAND("sysGetOSName %d: %s", eNum, s);
}
void commands2F53() {
@@ -1449,7 +1444,10 @@ void commands2F87() {
int eBaneStrNum = getCaliValue();
int eResultStrNum = getCaliValue();
int *vResult = getCaliVariable();
// This command is used to check if the game is installed, so we always
// return 1 with the dummy string REGREADSTRING_RESULT.
svar_set(eResultStrNum, REGREADSTRING_RESULT);
*vResult = 1;
DEBUG_COMMAND("regReadString %d,%d,%d,%d:",
@@ -1459,8 +1457,17 @@ void commands2F87() {
void commands2F88() {
int eFileNameStrNum = getCaliValue();
int *vResult = getCaliVariable();
*vResult = 1;
const char *fname = svar_get(eFileNameStrNum);
if (strcmp(fname, REGREADSTRING_RESULT) == 0) {
// If this command is called with the result of regReadString, the game
// is checking if the game CD is inserted. We return 1 in this case.
*vResult = 1;
} else {
char *fname_utf8 = sjis2utf(fname);
*vResult = fc_exists(fname_utf8) ? 1 : 0;
free(fname_utf8);
}
DEBUG_COMMAND("fileCheckExist %d,%d:", eFileNameStrNum, *vResult);
}
+2 -2
View File
@@ -46,9 +46,9 @@ void commands2F60() {
SYSERROR("No DLL initilized");
}
if (dll + type == NULL) goto eexit;
if (type < 0 || type >= nact->ain.dllnum) goto eexit;
if (dll[type].function_num < fnum) goto eexit;
if (fnum < 0 || fnum >= dll[type].function_num) goto eexit;
if (dll[type].function[fnum].entrypoint == NULL) goto eexit;
+17 -17
View File
@@ -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
View File
@@ -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 (https://github.com/libsdl-org/SDL/issues/3364), 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
View File
@@ -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);
}
+3 -3
View File
@@ -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();
+5 -8
View File
@@ -33,7 +33,7 @@
#include "ags.h"
#include "message.h"
#include "hankaku.h"
#include "hacks.h"
/* MI 用パラメータ */
INPUTSTRING_PARAM mi_param;
@@ -60,7 +60,7 @@ void commandMP() {
char *str;
/* Patched English executable appends num2 spaces instead of truncating */
if (nact->game == GAME_RANCE3_ENG || nact->game == GAME_RANCE4_ENG) {
if (game_id == GAME_RANCE3_ENG || game_id == GAME_RANCE4_ENG) {
str = calloc(strlen(src) + num2 * strlen(fullwidth_blank[nact->encoding]) + 1, 1);
if (NULL == str) {
NOMEMERR();
@@ -249,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() {
@@ -329,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
View File
@@ -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
View File
@@ -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();
+2 -1
View File
@@ -26,6 +26,7 @@
#include "xsystem35.h"
#include "scenario.h"
#include "music.h"
#include "hacks.h"
/* ぱにょ〜ん 異常シナリオ対策 */
static boolean dummy_pcm_in_play = FALSE;
@@ -272,7 +273,7 @@ void commandSU() {
}
}
/* 闘神都市II 異常シナリオ対策 */
if (nact->game == GAME_TT2) {
if (game_id == GAME_TT2) {
*var1 = *var2 = 0;
}
+2 -1
View File
@@ -33,6 +33,7 @@
#include "cmd_check.h"
#include "sdl_core.h"
#include "music_cdrom.h"
#include "hacks.h"
unsigned Y3waitFlags = KEYWAIT_CANCELABLE;
@@ -126,7 +127,7 @@ void commandY() {
default:
if (p1 == 1003) {
sys_key_releasewait(SYS35KEY_RET, FALSE);
} else if (nact->game == GAME_RANCE4_V2 && p2 == 1) {
} else if (game_id == GAME_RANCE4_V2 && p2 == 1) {
// Return immediately if any key is pressed.
sysVar[0] = sys_getInputInfo();
if (sysVar[0])
+8 -9
View File
@@ -113,11 +113,12 @@ void commandZS() {
void commandZB() {
/* メッセージ文字を太さを設定 */
int size = getCaliValue();
nact->msg.MsgFontBoldSize = size;
DEBUG_COMMAND("ZB %d:",size);
int weight = getCaliValue();
if (nact->ags.enable_zb)
nact->ags.font_weight = weight;
DEBUG_COMMAND("ZB %d:", weight);
}
void commandZH() {
@@ -345,10 +346,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
View File
@@ -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_getStack(&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_getStack(&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)
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;
+4
View File
@@ -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
View File
@@ -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,
};
+1
View File
@@ -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;
+34 -34
View File
@@ -30,48 +30,48 @@
#include "LittleEndian.h"
#include "dri.h"
static bool read_index(int disk, drifiles *d, FILE *fp) {
static bool read_index(int volume, drifiles *d, FILE *fp) {
fseek(fp, 0L, SEEK_END);
int filesize = ftell(fp);
// Get ptrsize and mapsize
// Get the size of offsets table and link table.
uint8_t hdr[6];
fseek(fp, 0L, SEEK_SET);
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)
int ofssize = LittleEndian_get3B(hdr, 0) << 8;
int linksize = (LittleEndian_get3B(hdr, 3) << 8) - ofssize;
if (ofssize <= 0 || linksize <= 0 || ofssize + linksize > 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);
// Read the link table. In System 3.9, only the first volume's link table is
// valid. It's different in System 3.8 and earlier, and games that depend
// on the old behavior (e.g. Child Assassin in Alice CD 2.50) won't work.
if (!d->link) {
d->nr_files = linksize / 3;
d->link = calloc(1, linksize);
d->offset = calloc(sizeof(uint32_t), d->nr_files);
fseek(fp, ofssize, SEEK_SET);
if (fread(d->link, linksize, 1, fp) != 1)
return false;
}
// Read the offsets table.
uint8_t *otbl = malloc(ofssize);
fseek(fp, 0L, SEEK_SET);
if (fread(otbl, ofssize, 1, fp) != 1) {
free(otbl);
return false;
}
uint8_t *ltbl = ptbl + ptrsize;
// (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;
}
// Parse the index
for (int i = 0; i < nr_files; i++) {
if (disk != ltbl[i * 3] - 1)
for (int i = 0; i < d->nr_files; i++) {
if (d->link[i * 3] != volume)
continue;
d->disk[i] = ltbl[i * 3];
int ptr = LittleEndian_getW(ltbl, i * 3 + 1);
d->offset[i] = LittleEndian_get3B(ptbl, ptr * 3) << 8;
if (d->maxno < i)
d->maxno = i;
int offset_index = LittleEndian_getW(d->link, i * 3 + 1);
d->offset[i] = LittleEndian_get3B(otbl, offset_index * 3) << 8;
}
free(ptbl);
free(otbl);
return true;
}
@@ -88,7 +88,7 @@ drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
FILE *fp = fopen(file[i], "rb");
if (!fp)
SYSERROR("%s: %s", file[i], strerror(errno));
if (!read_index(i, d, fp)) {
if (!read_index(i + 1, d, fp)) {
// Only errors in *A.ALD are fatal, because some games have
// dummy (invalid) *[B-Z].ALD files.
if (i == 0)
@@ -115,18 +115,18 @@ drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
}
dridata *dri_getdata(drifiles *d, int no) {
if (no < 0 || no >= d->nr_files || !d->disk[no] || !d->offset[no])
if (no < 0 || no >= d->nr_files || !d->link[no * 3] || !d->offset[no])
return NULL;
int disk = d->disk[no] - 1;
int volume = d->link[no * 3];
uint8_t *data;
int ptr, size;
if (d->mmapped) {
data = d->mmap[disk]->addr + d->offset[no];
data = d->mmap[volume - 1]->addr + d->offset[no];
ptr = LittleEndian_getDW(data, 0);
size = LittleEndian_getDW(data, 4);
} else {
FILE *fp = fopen(d->fnames[disk], "rb");
FILE *fp = fopen(d->fnames[volume - 1], "rb");
if (!fp)
return NULL;
uint8_t entry_header[8];
+2 -1
View File
@@ -34,7 +34,8 @@ struct _drifiles {
mmap_t *mmap[DRIFILEMAX];
char *fnames[DRIFILEMAX];
int nr_files; // upper limit on how many files could be referenced by this archive
uint8_t *disk; // file numbers
int maxno;
uint8_t *link; // link table
uint32_t *offset; // offsets in file
};
typedef struct _drifiles drifiles;
+81 -2
View File
@@ -21,15 +21,18 @@
*/
/* $Id: filecheck.c,v 1.5 2006/04/21 16:40:48 chikama Exp $ */
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
#undef min
#undef max
#endif
#include "filecheck.h"
@@ -47,9 +50,65 @@ static char *get_fullpath(const char* dir, const char *filename) {
return fn;
}
#ifdef _WIN32
static int make_dir(const char *path)
{
wchar_t wpath[PATH_MAX + 1];
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, wpath, PATH_MAX + 1)) {
errno = EILSEQ;
return -1;
}
return _wmkdir(wpath);
}
#else
#define make_dir(path) mkdir(path, S_IRWXU)
#endif
// Adapted from http://stackoverflow.com/a/2336245/119527
static int mkdir_p(const char *path)
{
const size_t len = strlen(path);
char _path[PATH_MAX];
char *p;
errno = 0;
// Copy string so its mutable
if (len > sizeof(_path)-1) {
errno = ENAMETOOLONG;
return -1;
}
strcpy(_path, path);
// Iterate the string
for (p = _path + 1; *p; p++) {
if (*p == '/') {
// Temporarily truncate
*p = '\0';
if (make_dir(_path) != 0) {
if (errno != EEXIST)
return -1;
}
*p = '/';
}
}
if (make_dir(_path) != 0) {
if (errno != EEXIST)
return -1;
}
return 0;
}
/* list up file in current directory */
/* name : save/load directory */
void fc_init(const char *name) {
mkdir_p(name);
saveDataPath = strdup(name);
}
@@ -66,6 +125,18 @@ char *fc_get_path(const char *fname_utf8) {
return get_fullpath(saveDataPath, fname_utf8);
}
bool fc_exists(const char *fname_utf8)
{
char *path = fc_get_path(fname_utf8);
wchar_t wpath[PATH_MAX + 1];
bool result = false;
if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, wpath, PATH_MAX + 1)) {
result = _waccess(wpath, F_OK) != -1;
}
free(path);
return result;
}
FILE *fc_open(const char *fname_utf8, char type) {
char *path = fc_get_path(fname_utf8);
FILE *fp = fopen_utf8(path, type);
@@ -102,6 +173,14 @@ char *fc_get_path(const char *fname_utf8) {
return get_fullpath(saveDataPath, fname_utf8);
}
bool fc_exists(const char *fname_utf8)
{
char *path = fc_get_path(fname_utf8);
bool result = access(path, F_OK) != -1;
free(path);
return result;
}
FILE *fc_open(const char *fname_utf8, char type) {
char *fullpath = fc_search(fname_utf8, saveDataPath);
if (!fullpath) {
+7 -4
View File
@@ -24,9 +24,12 @@
#ifndef __FILECHECK_H__
#define __FILECHECK_H__
extern void fc_init(const char *name);
extern char *fc_get_path(const char *fname_utf8);
extern FILE *fc_open(const char *fname_utf8, char type);
extern void fc_backup_oldfile(const char *filename);
#include <stdbool.h>
void fc_init(const char *name);
char *fc_get_path(const char *fname_utf8);
bool fc_exists(const char *fname_utf8);
FILE *fc_open(const char *fname_utf8, char type);
void fc_backup_oldfile(const char *filename);
#endif /* !__FILECHECK_H__ */
+23 -3
View File
@@ -23,6 +23,11 @@
#include <math.h>
#include <SDL.h>
#include <SDL_ttf.h>
#ifdef _WIN32
#include "win/resources.h"
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
@@ -31,6 +36,7 @@
#include "system.h"
#include "font.h"
#include "sdl_private.h"
#include "hacks.h"
typedef struct {
int size;
@@ -73,7 +79,7 @@ static FontTable *font_lookup(int size, int type) {
return NULL;
}
void font_select(int type, int size) {
void font_select(int type, int size, int weight) {
FontTable *tbl;
if (NULL == (tbl = font_lookup(size, type))) {
@@ -89,6 +95,11 @@ void font_select(int type, int size) {
if (fp)
fs = TTF_OpenFontIndexRW(SDL_RWFromFP(fp, true), true, size, this.face[type]);
}
#endif
#ifdef _WIN32
SDL_RWops *r = open_resource(this.name[type], "fonts");
if (r)
fs = TTF_OpenFontIndexRW(r, true, size, this.face[type]);
#endif
if (!fs)
SYSERROR("Cannot open font %s", this.name[type]);
@@ -98,6 +109,7 @@ void font_select(int type, int size) {
} else {
fontset = tbl;
}
TTF_SetFontStyle(fontset->id, weight > 5 ? TTF_STYLE_BOLD : TTF_STYLE_NORMAL);
}
SDL_Surface *font_get_glyph(const char *str_utf8) {
@@ -164,7 +176,15 @@ SDL_Rect font_draw_glyph(int x, int y, const char *str_utf8, uint8_t cl) {
if (!fontset)
return r_dst;
if (this.antialiase_on) {
bool antialias = this.antialiase_on;
// The post-effect in Rance 3 opening does not work properly if colors other
// than the specified text color (32) are used.
// https://github.com/kichikuou/xsystem35-sdl2/issues/54
// In Rance 3, text color 32 is only used in the opening.
if ((game_id == GAME_RANCE3 || game_id == GAME_RANCE3_ENG) && cl == 32)
antialias = false;
if (antialias) {
fs = TTF_RenderUTF8_Blended(fontset->id, str_utf8, sdl_col[cl]);
} else {
fs = TTF_RenderUTF8_Solid(fontset->id, str_utf8, sdl_col[cl]);
@@ -179,7 +199,7 @@ SDL_Rect font_draw_glyph(int x, int y, const char *str_utf8, uint8_t cl) {
y -= (TTF_FontHeight(fontset->id) - fontset->size) / 2;
r_dst = (SDL_Rect){x, y, w, h};
if (sdl_dib->format->BitsPerPixel == 8 && this.antialiase_on) {
if (sdl_dib->format->BitsPerPixel == 8 && antialias) {
sdl_drawAntiAlias_8bpp(x, y, fs, cl);
} else {
r_src = (SDL_Rect){0, 0, w, h};
+4 -1
View File
@@ -31,11 +31,14 @@
/* font の種類 */
#define FONTTYPEMAX 2
#define FONT_WEIGHT_NORMAL 4
#define FONT_WEIGHT_BOLD 7
extern void font_init(void);
extern void font_set_name_and_index(int type, const char *name, int index);
extern void font_set_antialias(boolean enable);
extern boolean font_get_antialias(void);
extern void font_select(int type, int size);
extern void font_select(int type, int size, int weight);
extern struct SDL_Surface *font_get_glyph(const char *str_utf8);
extern SDL_Rect font_draw_glyph(int x, int y, const char *str_utf8, uint8_t col);
+40 -7
View File
@@ -63,9 +63,11 @@ static void storeSaveName(GameResource *gr, int no, char *src) {
if (path) free(path);
}
boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_readdir)(DIR *)) {
boolean initGameResourceFromDir(GameResource *gr, DIR *dir, const char *savedir, 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,40 @@ 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 && (savedir || !found_xsleep)) {
const char *dir = savedir ? savedir : "";
const char *sep = savedir ? "/" : "";
char *buf = malloc(strlen(dir) + strlen(sep) + strlen(basename) + 9);
#if defined(__ANDROID__) || defined(__EMSCRIPTEN__)
// Use lowercase 's[a-z].asd' in Android and Emscripten, for compatibility.
basename[strlen(basename) - 1] = 's';
int a = 'a';
#else
int a = basename[strlen(basename) - 1] == 'S' ? 'A' : 'a';
#endif
for (int i = 0; i < SAVE_MAXNUMBER; i++) {
sprintf(buf, "%s%s%s%c.asd", dir, sep, basename, a + i);
storeSaveName(gr, i, buf);
}
#ifdef __EMSCRIPTEN__
basename[strlen(basename) - 1] = '\0';
sprintf(buf, "%s%s%s.msgskip", dir, sep, basename);
gr->msgskip = buf;
#else
free(buf);
#endif
} 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;
}
@@ -201,7 +234,7 @@ static boolean initGameResourceFromFile(GameResource *gr, FILE *fp, const char *
return FALSE;
}
boolean initGameResource(GameResource *gr, const char *gr_fname) {
boolean initGameResource(GameResource *gr, const char *gr_fname, const char *savedir) {
FILE *fp = fopen(gr_fname, "r");
if (fp) {
boolean result = initGameResourceFromFile(gr, fp, gr_fname);
@@ -210,7 +243,7 @@ boolean initGameResource(GameResource *gr, const char *gr_fname) {
}
DIR *dir = opendir(".");
if (dir) {
boolean result = initGameResourceFromDir(gr, dir, readdir);
boolean result = initGameResourceFromDir(gr, dir, savedir, readdir);
closedir(dir);
return result;
}
+2 -2
View File
@@ -43,7 +43,7 @@ typedef struct {
const char *msgskip;
} GameResource;
boolean initGameResource(GameResource *gr, const char *gr_fname);
boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_readdir)(DIR *));
boolean initGameResource(GameResource *gr, const char *gr_fname, const char *savedir);
boolean initGameResourceFromDir(GameResource *gr, DIR *dir, const char *savedir, struct dirent *(*p_readdir)(DIR *));
#endif /* !__GAMERESOURCE_H__ */
+80 -44
View File
@@ -25,7 +25,7 @@
static void initGameResource_test(void) {
GameResource gr;
ASSERT_TRUE(initGameResource(&gr, "testdata/test.gr"));
ASSERT_TRUE(initGameResource(&gr, "testdata/test.gr", NULL));
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 1);
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "fooSA.ALD");
@@ -74,50 +74,86 @@ 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, NULL, 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[] = {
"foosa.ald",
NULL
};
const char **dir = files;
GameResource gr;
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, "~/save", mockReaddir));
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 1);
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "foosa.ald");
for (int i = 0; i < 26; i++) {
char buf[32];
sprintf(buf, "/home/kichikuou/save/foos%c.asd", 'a' + i);
ASSERT_STRCMP(gr.save_fname[i], buf);
}
ASSERT_STRCMP(gr.save_path, "/home/kichikuou/save");
}
{
const char *files[] = {
"ADISK.ALD",
"asleep.asd",
NULL
};
const char **dir = files;
GameResource gr;
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, NULL, 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) {
+4 -4
View File
@@ -28,10 +28,10 @@
#include <SDL_rect.h>
typedef struct {
uint8_t red[256];
uint8_t green[256];
uint8_t blue[256];
} Palette256;
uint8_t r;
uint8_t g;
uint8_t b;
} Color;
typedef struct {
uint8_t r,g,b;
+17 -9
View File
@@ -27,21 +27,27 @@
#define GT_TOSHIN2 "闘神都市Ⅱ for Win95 "
#define GT_RANCE4 "Rance4 -教団の遺産- For Win95 "
#define GT_RANCE4_V2 "RanceⅣ -教団の遺産- for Windows "
#define GT_RANCE3 "Rance3"
#define GT_RANCE3_ENG "Rance3"
#define GT_RANCE4_ENG "Rance4 -Legacy of the Sect- For Win95 "
/* defined by cmdy.c */
extern boolean Y3waitFlags;
enum gameId game_id;
bool daiakuji_cx_hack;
void enable_hack_by_gameid(const char *gameid) {
if (!strcmp(gameid, "toushin2"))
nact->game = GAME_TT2;
game_id = GAME_TT2;
else if (!strcmp(gameid, "rance3"))
game_id = GAME_RANCE3;
else if (!strcmp(gameid, "rance3_eng"))
nact->game = GAME_RANCE3_ENG;
game_id = GAME_RANCE3_ENG;
else if (!strcmp(gameid, "rance4_eng"))
nact->game = GAME_RANCE4_ENG;
game_id = GAME_RANCE4_ENG;
else if (!strcmp(gameid, "rance4_v2"))
nact->game = GAME_RANCE4_V2;
game_id = GAME_RANCE4_V2;
else
sys_error("Unknown game id \"%s\"", gameid);
}
@@ -50,15 +56,17 @@ void enable_hack_by_title(const char *title_utf8) {
if (!strcmp(title_utf8, GT_RANCE4))
Y3waitFlags = KEYWAIT_NONCANCELABLE;
if (nact->game != GAME_UNKNOWN)
if (game_id != GAME_UNKNOWN)
return;
if (!strcmp(title_utf8, GT_TOSHIN2))
nact->game = GAME_TT2;
game_id = GAME_TT2;
else if (!strcmp(title_utf8, GT_RANCE4_V2))
nact->game = GAME_RANCE4_V2;
game_id = GAME_RANCE4_V2;
else if (!strcmp(title_utf8, GT_RANCE3))
game_id = GAME_RANCE3;
else if (!strcmp(title_utf8, GT_RANCE3_ENG))
nact->game = GAME_RANCE3_ENG;
game_id = GAME_RANCE3_ENG;
else if (!strcmp(title_utf8, GT_RANCE4_ENG))
nact->game = GAME_RANCE4_ENG;
game_id = GAME_RANCE4_ENG;
}
+7
View File
@@ -20,15 +20,22 @@
#ifndef __HACKS_H_
#define __HACKS_H_
#include <stdbool.h>
enum gameId {
GAME_UNKNOWN = 0,
GAME_TT2,
GAME_RANCE3,
GAME_RANCE3_ENG,
GAME_RANCE4_ENG,
GAME_RANCE4_V2,
};
extern enum gameId game_id;
void enable_hack_by_gameid(const char *gameid);
void enable_hack_by_title(const char *game_title_utf8);
extern bool daiakuji_cx_hack;
#endif // __HACKS_H_
+117
View File
@@ -41,6 +41,123 @@
#define KEYWAIT_CANCELABLE 1
#define KEYWAIT_SKIPPABLE 2
// System3.x key codes (IG command, etc.)
// These are originated from Windows virtual key codes (VK_*).
#define NUM_KEYCODES 256
enum keycode {
KEY_MOUSE_LEFT = 0x01, // マウスの左ボタン
KEY_MOUSE_RIGHT = 0x02, // マウスの右ボタン
KEY_CONTROL = 0x03, // コントロール ブレーク処理に使用
KEY_MOUSE_MIDDLE = 0x04, // マウスの中央ボタン (3つボタンのマウス)
KEY_BACKSPACE = 0x08, // BackSpaceキー
KEY_TAB = 0x09, // Tabキー
KEY_CLEAR = 0x0c, // Clearキー
KEY_RETURN = 0x0d, // Enterキー
KEY_SHIFT = 0x10, // Shiftキー
KEY_CTRL = 0x11, // Ctrlキー
KEY_ALT = 0x12, // Altキー
KEY_PAUSE = 0x13, // Pauseキー
KEY_CAPSLOCK = 0x14, // Caps Lockキー
KEY_KANAKAN = 0x15, // 英数カナキー
KEY_ESCAPE = 0x1b, // Escキー
KEY_SPACE = 0x20, // Spaceキー
KEY_PAGEUP = 0x21, // Page Upキー
KEY_PAGEDOWN = 0x22, // Page Downキー
KEY_END = 0x23, // Endキー
KEY_HOME = 0x24, // Homeキー
KEY_LEFT = 0x25, // ←キー
KEY_UP = 0x26, // ↑キー
KEY_RIGHT = 0x27, // →キー
KEY_DOWN = 0x28, // ↓キー
KEY_SELECT = 0x29, // Selectキー
KEY_EXECUTE = 0x2b, // Executeキー
KEY_PRINTSCREEN = 0x2c, // Print Screenキー (Windows 3.0以降用)
KEY_INSERT = 0x2d, // Insキー
KEY_DELETE = 0x2e, // Delキー
KEY_HELP = 0x2f, // Helpキー
KEY_0 = 0x30, // 0キー
KEY_1 = 0x31, // 1キー
KEY_2 = 0x32, // 2キー
KEY_3 = 0x33, // 3キー
KEY_4 = 0x34, // 4キー
KEY_5 = 0x35, // 5キー
KEY_6 = 0x36, // 6キー
KEY_7 = 0x37, // 7キー
KEY_8 = 0x38, // 8キー
KEY_9 = 0x39, // 9キー
KEY_PAD_EQUALS = 0x3d,
KEY_A = 0x41, // Aキー
KEY_B = 0x42, // Bキー
KEY_C = 0x43, // Cキー
KEY_D = 0x44, // Dキー
KEY_E = 0x45, // Eキー
KEY_F = 0x46, // Fキー
KEY_G = 0x47, // Gキー
KEY_H = 0x48, // Hキー
KEY_I = 0x49, // Iキー
KEY_J = 0x4a, // Jキー
KEY_K = 0x4b, // Kキー
KEY_L = 0x4c, // Lキー
KEY_M = 0x4d, // Mキー
KEY_N = 0x4e, // Nキー
KEY_O = 0x4f, // Oキー
KEY_P = 0x50, // Pキー
KEY_Q = 0x51, // Qキー
KEY_R = 0x52, // Rキー
KEY_S = 0x53, // Sキー
KEY_T = 0x54, // Tキー
KEY_U = 0x55, // Uキー
KEY_V = 0x56, // Vキー
KEY_W = 0x57, // Wキー
KEY_X = 0x58, // Xキー
KEY_Y = 0x59, // Yキー
KEY_Z = 0x5a, // Zキー
KEY_PAD_0 = 0x60, // テンキーの0キー
KEY_PAD_1 = 0x61, // テンキーの1キー
KEY_PAD_2 = 0x62, // テンキーの2キー
KEY_PAD_3 = 0x63, // テンキーの3キー
KEY_PAD_4 = 0x64, // テンキーの4キー
KEY_PAD_5 = 0x65, // テンキーの5キー
KEY_PAD_6 = 0x66, // テンキーの6キー
KEY_PAD_7 = 0x67, // テンキーの7キー
KEY_PAD_8 = 0x68, // テンキーの8キー
KEY_PAD_9 = 0x69, // テンキーの9キー
KEY_PAD_MULTIPLY = 0x6a, // テンキーの*キー
KEY_PAD_PLUS = 0x6b, // テンキーの+キー
KEY_SEPARATOR = 0x6c, // Separatorキー
KEY_PAD_MINUS = 0x6d, // テンキーの-キー
KEY_PAD_PERIOD = 0x6e, // テンキーの.キー
KEY_PAD_DIVIDE = 0x6f, // テンキーの/キー
KEY_F1 = 0x70, // F1キー
KEY_F2 = 0x71, // F2キー
KEY_F3 = 0x72, // F3キー
KEY_F4 = 0x73, // F4キー
KEY_F5 = 0x74, // F5キー
KEY_F6 = 0x75, // F6キー
KEY_F7 = 0x76, // F7キー
KEY_F8 = 0x77, // F8キー
KEY_F9 = 0x78, // F9キー
KEY_F10 = 0x79, // F10キー
KEY_F11 = 0x7a, // F11キー
KEY_F12 = 0x7b, // F12キー
KEY_F13 = 0x7c, // F13キー
KEY_F14 = 0x7d, // F14キー
KEY_F15 = 0x7e, // F15キー
KEY_F16 = 0x7f, // F16キー
KEY_F17 = 0x80, // F17キー
KEY_F18 = 0x81, // F18キー
KEY_F19 = 0x82, // F19キー
KEY_F20 = 0x83, // F20キー
KEY_F21 = 0x84, // F21キー
KEY_F22 = 0x85, // F22キー
KEY_F23 = 0x86, // F23キー
KEY_F24 = 0x87, // F24キー
KEY_NUMLOCK = 0x90, // Num Lockキー
KEY_SCROLLLOCK = 0x91, // Scroll Lockキー
};
extern boolean RawKeyInfo[NUM_KEYCODES];
extern int sys_keywait(int msec, unsigned flags);
extern int sys_getMouseInfo(MyPoint *p, boolean is_dibgeo);
extern int sys_getInputInfo(void);
-153
View File
@@ -1,153 +0,0 @@
/*
* key.h keycode definition
*
* Copyright (C) 2000- Masaki Chikama (Wren) <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: key.h,v 1.2 2000/08/11 18:55:51 chikama Exp $ */
#ifndef __KEYCODE__
#define __KEYCODE__
#define KEY_UNDEFINED (0x00)
#define KEY_MOUSE_LEFT (0x01)
#define KEY_MOUSE_RIGHT (0x02)
#define KEY_CONTROL (0x03)
#define KEY_MOUSE_MIDDLE (0x04)
#define KEY_BS (0x08)
#define KEY_BACKSPACE (0x08)
#define KEY_TAB (0x09)
#define KEY_CLEAR (0x0c)
#define KEY_ENTER (0x0d)
#define KEY_PAD_ENTER (0x0d)
#define KEY_RETURN (0x0d)
#define KEY_SHIFT (0x10)
#define KEY_LSHIFT (0x10)
#define KEY_RSHIFT (0x10)
#define KEY_CTRL (0x11)
#define KEY_LCTRL (0x11)
#define KEY_RCTRL (0x11)
#define KEY_ALT (0x12)
#define KEY_LALT (0x12)
#define KEY_RALT (0x12)
#define KEY_PAUSE (0x13)
#define KEY_CAPSLOCK (0x14)
#define KEY_KANAKAN (0x15)
#define KEY_ESC (0x1b)
#define KEY_ESCAPE (0x1b)
#define KEY_SPACE (0x20)
#define KEY_PAGEUP (0x21)
#define KEY_PAGEDOWN (0x22)
#define KEY_END (0x23)
#define KEY_HOME (0x24)
#define KEY_LEFT (0x25)
#define KEY_UP (0x26)
#define KEY_RIGHT (0x27)
#define KEY_DOWN (0x28)
#define KEY_SELECT (0x29)
#define KEY_EXECUTE (0x2b)
#define KEY_PRINTSCREEN (0x2c)
#define KEY_INS (0x2d)
#define KEY_INSERT (0x2d)
#define KEY_DEL (0x2e)
#define KEY_DELETE (0x2e)
#define KEY_HELP (0x2f)
#define KEY_0 (0x30)
#define KEY_1 (0x31)
#define KEY_2 (0x32)
#define KEY_3 (0x33)
#define KEY_4 (0x34)
#define KEY_5 (0x35)
#define KEY_6 (0x36)
#define KEY_7 (0x37)
#define KEY_8 (0x38)
#define KEY_9 (0x39)
#define KEY_PAD_EQUALS (0x3d)
#define KEY_A (0x41)
#define KEY_B (0x42)
#define KEY_C (0x43)
#define KEY_D (0x44)
#define KEY_E (0x45)
#define KEY_F (0x46)
#define KEY_G (0x47)
#define KEY_H (0x48)
#define KEY_I (0x49)
#define KEY_J (0x4a)
#define KEY_K (0x4b)
#define KEY_L (0x4c)
#define KEY_M (0x4d)
#define KEY_N (0x4e)
#define KEY_O (0x4f)
#define KEY_P (0x50)
#define KEY_Q (0x51)
#define KEY_R (0x52)
#define KEY_S (0x53)
#define KEY_T (0x54)
#define KEY_U (0x55)
#define KEY_V (0x56)
#define KEY_W (0x57)
#define KEY_X (0x58)
#define KEY_Y (0x59)
#define KEY_Z (0x5a)
#define KEY_PAD_0 (0x60)
#define KEY_PAD_1 (0x61)
#define KEY_PAD_2 (0x62)
#define KEY_PAD_3 (0x63)
#define KEY_PAD_4 (0x64)
#define KEY_PAD_5 (0x65)
#define KEY_PAD_6 (0x66)
#define KEY_PAD_7 (0x67)
#define KEY_PAD_8 (0x68)
#define KEY_PAD_9 (0x69)
#define KEY_PAD_STAR (0x6a)
#define KEY_PAD_MULTIPLY (0x6a)
#define KEY_PAD_PLUS (0x6b)
#define KEY_PAD_SEP (0x6c)
#define KEY_PAD_MINUS (0x6d)
#define KEY_PAD_DOT (0x6e)
#define KEY_PAD_PERIOD (0x6e)
#define KEY_PAD_SLASH (0x6f)
#define KEY_PAD_DIVIDE (0x6f)
#define KEY_F1 (0x70)
#define KEY_F2 (0x71)
#define KEY_F3 (0x72)
#define KEY_F4 (0x73)
#define KEY_F5 (0x74)
#define KEY_F6 (0x75)
#define KEY_F7 (0x76)
#define KEY_F8 (0x77)
#define KEY_F9 (0x78)
#define KEY_F10 (0x79)
#define KEY_F11 (0x7a)
#define KEY_F12 (0x7b)
#define KEY_F13 (0x7c)
#define KEY_F14 (0x7d)
#define KEY_F15 (0x7e)
#define KEY_F16 (0x7f)
#define KEY_F17 (0x80)
#define KEY_F18 (0x81)
#define KEY_F19 (0x82)
#define KEY_F20 (0x83)
#define KEY_F21 (0x84)
#define KEY_F22 (0x85)
#define KEY_F23 (0x86)
#define KEY_F24 (0x87)
#define KEY_NUMLOCK (0x90)
#define KEY_SCROLL_LOCK (0x91)
#define KEY_SCROLLOCK (0x91)
#endif /* __KEYCODE__ */
+3 -2
View File
@@ -59,8 +59,9 @@ extern void menu_setSkipState(boolean enabled, boolean activated);
#ifdef _WIN32
struct SDL_SysWMmsg;
extern void win_menu_init(void);
extern void win_menu_onsyswmevent(struct SDL_SysWMmsg* msg);
void win_menu_init(void);
void win_menu_onSysWMEvent(struct SDL_SysWMmsg* msg);
void win_menu_onMouseMotion(int x, int y);
#endif
#endif /* !__MENULL */
+3 -5
View File
@@ -20,9 +20,7 @@
*/
/* $Id: menu_callback.c,v 1.11 2003/04/25 17:23:55 chikama Exp $ */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "config.h"
#include "portab.h"
#include "menu.h"
@@ -87,7 +85,7 @@ void
on_item5_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
nact->ags.mouse_movesw = MOUSE_WARP_SMOOTH;
nact->ags.mouse_warp_enabled = true;
gtk_menu_popdown(GTK_MENU(menu_window_popup));
}
@@ -97,7 +95,7 @@ void
on_item6_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
nact->ags.mouse_movesw = MOUSE_WARP_DISABLED;
nact->ags.mouse_warp_enabled = false;
gtk_menu_popdown(GTK_MENU(menu_window_popup));
}
+1 -3
View File
@@ -1,6 +1,4 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
+12 -10
View File
@@ -64,9 +64,8 @@ static void msgget_at_a();
void msg_init() {
/* メッセージフォントの大きさ */
msg.MsgFontSize = 16;
msg.MsgFontBoldSize = 0;
msg.MsgFont = FONT_GOTHIC;
msg.MsgFontSize = 16;
msg.MsgFont = FONT_GOTHIC;
/* 各種色 */
msg.MsgFontColor = 255;
@@ -93,13 +92,15 @@ void msg_init() {
}
memset(msg.wininfo, 0, sizeof(msg.wininfo));
for (int i = 0; i < MSGWINMAX; i++) {
msg.wininfo[i].x = 100;
msg.wininfo[i].y = 300;
msg.wininfo[i].width = 400;
msg.wininfo[i].height = 90;
}
msg.winno = 1;
msg.win = &msg.wininfo[0];
msg.wininfo[0].x = 8;
msg.wininfo[0].y = 311;
msg.wininfo[0].width = 616;
msg.wininfo[0].height = 80;
msg.wininfo[0].save = TRUE;
msg.win = &msg.wininfo[1];
msg.wininfo[1].save = TRUE;
// Private variables
msgDecorateColor = 0;
@@ -139,7 +140,8 @@ void msg_putMessage(const char *m) {
// fprintf(stdout, "x=%d, y = %d, msg=%s\n", msgcur.x,msgcur.y,msg);
if (!msg.mg_dspMsg) return;
ags_setFont(msg.MsgFont, msg.MsgFontSize);
ags_setFontWithWeight(msg.MsgFont, msg.MsgFontSize, nact->ags.font_weight);
switch(msgDecorateType) {
case 0:
default:
-1
View File
@@ -44,7 +44,6 @@ extern void msg_mg6_command(int cmd);
struct __message {
/* メッセージフォントの大きさ */
int MsgFontSize;
int MsgFontBoldSize;
int MsgFont;
/* 各種色 */
+1 -1
View File
@@ -90,7 +90,7 @@ int midi_init(mididevice_t *midi) {
return ret;
}
void midi_set_devicename(char *name) {
void midi_set_devicename(const char *name) {
if (dev) free(dev);
if (0 == strcmp("none", name)) dev = NULL;
else dev = strdup(name);
+22 -38
View File
@@ -24,43 +24,15 @@
#include "portab.h"
#include "midi.h"
static int midi_initilize(char *pname, int subdev);
static int midi_exit(void);
static int midi_reset(void);
static int midi_start(int no, int loop, char *data, int datalen);
static int midi_stop();
extern int midi_pause(void);
extern int midi_unpause(void);
static int midi_get_playing_info(midiplaystate *st);
static int midi_getflag(int mode, int index);
static int midi_setflag(int mode, int index, int val);
extern int midi_setvol(int vol);
extern int midi_getvol();
extern int midi_fadestart(int time, int volume, int stop);
extern boolean midi_fading();
#define midi midi_emscripten
mididevice_t midi = {
midi_initilize,
midi_exit,
midi_reset,
midi_start,
midi_stop,
midi_pause,
midi_unpause,
midi_get_playing_info,
midi_getflag,
midi_setflag,
midi_setvol,
midi_getvol,
midi_fadestart,
midi_fading
};
static int midi_initilize(char *pname, int subdev) {
return OK;
}
EM_JS(int, midi_stop, (void), {
xsystem35.midiPlayer.stop();
return xsystem35.Status.OK;
});
static int midi_exit(void) {
midi_stop();
return OK;
@@ -76,11 +48,6 @@ static int midi_start(int no, int loop, char *data, int datalen) {
return OK;
}
static int midi_stop() {
EM_ASM( xsystem35.midiPlayer.stop(); );
return OK;
}
EM_JS(int, midi_pause, (void), {
xsystem35.midiPlayer.pause();
return xsystem35.Status.OK;
@@ -127,3 +94,20 @@ EM_JS(int, midi_fadestart, (int time, int volume, int stop), {
EM_JS(boolean, midi_fading, (), {
return xsystem35.midiPlayer.isFading();
});
mididevice_t midi_emscripten = {
midi_initilize,
midi_exit,
midi_reset,
midi_start,
midi_stop,
midi_pause,
midi_unpause,
midi_get_playing_info,
midi_getflag,
midi_setflag,
midi_setvol,
midi_getvol,
midi_fadestart,
midi_fading
};
+1 -1
View File
@@ -52,7 +52,7 @@ struct mididevice {
};
extern int midi_init(mididevice_t *);
extern void midi_set_devicename(char *);
extern void midi_set_devicename(const char *);
extern void midi_set_output_device(int mode);
#endif /* __MIDI_H__ */
+4 -1
View File
@@ -89,10 +89,13 @@ static int midi_start(int no, int loop, char *data, int datalen) {
SDL_RWops *rwops = SDL_RWFromConstMem(data, datalen);
mix_music = Mix_LoadMUSType_RW(rwops, MUS_MID, SDL_TRUE /* freesrc */);
if (!mix_music)
if (!mix_music) {
WARNING("Cannot load MIDI: %s", SDL_GetError());
return NG;
}
if (Mix_PlayMusic(mix_music, loop ? loop : -1) != 0) {
WARNING("Cannot play MIDI: %s", SDL_GetError());
Mix_FreeMusic(mix_music);
mix_music = NULL;
return NG;

Some files were not shown because too many files have changed in this diff Show More