Compare commits

...
95 Commits
Author SHA1 Message Date
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
kichikuou 70a940b216 Version 2.8.0 2023-02-12 09:33:29 +09:00
kichikuou db2bb03fdd Add -help description for -game option 2023-02-12 09:12:09 +09:00
kichikuou 5ef949ae14 Refactor ags_setWindowTitle() 2023-02-11 21:40:14 +09:00
kichikuou 043028cf7d Update game_compatibility.md 2023-02-11 16:18:09 +09:00
kichikuou eace5d1dbd Refactor game-specific hacks, add -game option
It's now possible to enable certain game-specific hacks by using the
`-game` command line option or the `game` property in the .xsys35rc
file.
2023-02-11 15:27:38 +09:00
kichikuou 878bea69d6 Add a test for stack commands 2023-02-10 21:30:02 +09:00
kichikuou ae8becc4a3 Fix menuReturnGoto when stack top is not a return address 2023-02-10 21:24:13 +09:00
kichikuou 1d863cfb2e Implement UR command 2023-02-10 20:56:53 +09:00
kichikuou 7bb2bee693 Label return should pop TPx 2023-02-10 20:56:53 +09:00
kichikuou 47e7f5542e Remove sl_retFar2
In System39.exe `%0` drops stack frames for label calls (Rance4 v2
relies on this behavior), so it's the same as `UD 1`.
2023-02-10 20:56:53 +09:00
kichikuou 8087d11b2b Fix UC command
* UC0 should restore values pushed by US/TPx
* UC1 should stop when the stack top is a page call
* UC1/2 should restore status pushes by TPx
* UC1/2 should not consume the count for non-call stack frames
* Add support for UC3 command
2023-02-10 20:56:53 +09:00
kichikuou 4f1521ac90 TOx commands are no-op if the stack top is of an unexpected type 2023-02-10 20:56:53 +09:00
kichikuou 99632397da Enable the hack in Rance4v2 recompiled with System3.9
The System3.9 compiler compiles `MT` command to `0x2F28`, so the hack
must be enabled in commands2F28().

Fixes https://github.com/kichikuou/xsystem35-sdl2/issues/36.
2023-02-10 20:50:12 +09:00
kichikuou 59283815d8 Properly implement Y 1900 command
It is the same as patchEC, but can be used in SCO files less than
version 390.
2023-02-08 10:43:06 +09:00
kichikuou a32c901eb8 Tweak the Rance4v2 hack
This fixes https://github.com/kichikuou/xsystem35-sdl2/issues/35.
2023-02-08 10:15:06 +09:00
kichikuou 03b84b8ba7 Make UR command safer
It's still unimplemented, but clears the output variables for safety.
2023-02-07 22:12:35 +09:00
kichikuou 720da4e42c Fix UC1 command 2023-02-07 22:05:00 +09:00
kichikuou c4dc799c94 Change the condition for applying Rance4v2 hack
Now it's determined by the MT command argument.
2023-02-07 21:31:03 +09:00
kichikuou ce271ae5eb Fix CG positioning issue in Rance 4.x (TOTO port)
G command should reset the effect of J0/J1, even if pixel extraction is
disabled by PC command.
2023-02-05 18:37:50 +09:00
kichikuou 526e5f8709 Fix VSP palette issue
This fixes a palette problem when drawing a VSP image on a non-8-bit
surface after executing `ZC 0` command.

cg->vsp_bank can be overridden by the `ZC 0` command.
2023-02-05 18:08:41 +09:00
kichikuou c967e63be9 Version 2.7.0 2023-01-28 16:22:24 +09:00
kichikuou d4a32aee17 Update game_compatibility.md 2023-01-28 16:13:25 +09:00
kichikuou 1191723612 Update emscripten to 3.1.27 2023-01-28 14:30:45 +09:00
kichikuou addf2e3728 Add BGM support for Rance4 v2
In Rance4 v2, `SS n` command plays the audio file n+999 stored in
WB.ald. Support this by reusing the CD->BGM bridge.
2023-01-28 14:24:26 +09:00
kichikuou 4785c8c77c Add cdrom.bgm.c and use it when DRIFILE_BGM exists
This enables BGM playback in the download edition of Daiakuji, where S*
commands are plumbed to the music system (*BA.ald).
2023-01-28 13:06:38 +09:00
kichikuou b1ac106057 Refactor bgm abstructions 2023-01-28 12:51:38 +09:00
kichikuou acdc40ec60 Refactor cdrom abstructions 2023-01-28 12:51:34 +09:00
kichikuou d9f635a6d0 Implement SV command 2023-01-28 09:53:44 +09:00
kichikuou e8357c4e6f Add a hack to improve map navigation of Rance4 v2 2023-01-28 09:53:41 +09:00
kichikuou 8e44a87069 Support Y1003 command
Used in Rance4 ver2.05. Similar to Y3, but waits for key release.
2023-01-26 21:44:29 +09:00
kichikuou d1befbd355 Add stub for SV command
Used in Rance4 ver2.05.
2023-01-26 18:35:55 +09:00
kichikuou ec0bae5490 Inline LittleEndian functions
Using memcpy(). Compilers are smart enough to eliminate memcpy()
completely.
2023-01-21 17:22:24 +09:00
kichikuou f5b3b1a936 Support ShSound module on WASM 2023-01-21 16:40:26 +09:00
kichikuou 1b546e3bab Update README.md 2023-01-15 13:52:00 +09:00
kichikuou d454899048 Add game compatibility table 2023-01-15 13:39:07 +09:00
kichikuou 7aa704b3f4 midi_sdlmixer: Check playing status in midi_get_playing_info()
This fixes an infinite loop in Buroburo waiting for MIDI playback to
finish.
2023-01-15 13:07:51 +09:00
kichikuou 50d7d7ee33 Fix handling of multi-volume ALD with inconsistent indexes
When contents of the index table differ between ALD files, System3.x
uses information from the file containing the entry.

For example, if link_table[k] in SA.ALD is { file_nr = 2, ptr_no = 10 }
and link_table[k] in SB.ALD is { file_nr = 2, ptr_no = 11 }, the entry
body is in SB.ALD, so ptr_no = 11 should be used.

CA_G*.ALD of Child Assassin has this issue.
2023-01-15 12:42:38 +09:00
kichikuou 586a9c855e Implement LXX 5 command
Used in Child Assassin.
2023-01-14 16:13:57 +09:00
kichikuou 9600e34229 Android: Upgrade AGP to 7.3.1 2023-01-08 13:35:51 +09:00
kichikuou 001c97ea00 Android: Include git revision in version string 2023-01-08 13:20:23 +09:00
kichikuou b100dbe26c Android CI: Generate signed apk 2023-01-08 13:19:01 +09:00
kichikuou 55e38f9db2 Android: Add activities to display open source notices 2023-01-06 14:21:32 +09:00
143 changed files with 3712 additions and 3379 deletions
+8 -3
View File
@@ -14,10 +14,15 @@ jobs:
- name: Build
run: |
cd android
ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk-bundle ./gradlew assembleRelease
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > keystore.jks
JAVA_HOME=$JAVA_HOME_17_X64 ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk-bundle ./gradlew assembleRelease
env:
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: xsystem35-release-unsigned-apk
path: android/app/build/outputs/apk/release/app-release-unsigned.apk
name: xsystem35-apk
path: android/app/build/outputs/apk/release/app-release.apk
+2 -2
View File
@@ -2,7 +2,7 @@ name: Emscripten Build
on: [push, pull_request]
env:
EM_VERSION: 3.1.15
EM_VERSION: 3.1.34
EM_CACHE_FOLDER: 'emsdk-cache'
jobs:
@@ -20,7 +20,7 @@ jobs:
key: ${{env.EM_VERSION}}-${{ runner.os }}
- name: Setup Emscripten toolchain
uses: mymindstorm/setup-emsdk@v11
uses: mymindstorm/setup-emsdk@v12
with:
version: ${{ env.EM_VERSION }}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
+2 -3
View File
@@ -8,7 +8,7 @@ jobs:
matrix:
include:
- { sys: MINGW32, installer: "xsystem35-32bit" }
- { sys: MINGW64, installer: "xsystem35-64bit" }
- { sys: UCRT64, installer: "xsystem35-64bit" }
defaults:
run:
shell: msys2 {0}
@@ -19,7 +19,6 @@ jobs:
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.sys }}
update: true
pacboy: >-
gcc:p
cmake:p
@@ -30,7 +29,7 @@ jobs:
libwebp:p
cjson:p
nsis:p
ntldd-git:p
ntldd:p
- name: Checkout
uses: actions/checkout@v3
+2
View File
@@ -2,7 +2,9 @@ out
android/.gradle
android/app/.externalNativeBuild
android/app/build
android/app/src/main/assets
android/build
android/keystore.jks
.ccls-cache
.dir-locals.el
compile_commands.json
+2 -5
View File
@@ -110,6 +110,7 @@ endif()
# CDROM
list(APPEND SRC_CDROM cdrom.bgm.c)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND SRC_CDROM cdrom.Linux.c)
list(APPEND SUMMARY_CDROM "Linux ioctl")
@@ -122,14 +123,10 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
list(APPEND SRC_CDROM cdrom.emscripten.c)
list(APPEND SUMMARY_CDROM "Emscripten")
set(ENABLE_CDROM_EMSCRIPTEN 1)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
list(APPEND SRC_CDROM cdrom.android.c)
list(APPEND SUMMARY_CDROM "Android")
set(ENABLE_CDROM_ANDROID 1)
else()
list(APPEND SRC_CDROM cdrom.empty.c)
endif()
if (SDL2MIXER_FOUND AND NOT ANDROID)
if (SDL2MIXER_FOUND)
list(APPEND SRC_CDROM cdrom.mp3.c)
list(APPEND SUMMARY_CDROM "SDL_mixer (wav|mp3|ogg...)")
set(ENABLE_CDROM_MP3 1)
+74 -49
View File
@@ -3,17 +3,22 @@
This is a multi-platform port of `xsystem35`, a free implementation of
AliceSoft's System 3.x game engine.
## Compatibility
See the [game compatibility table](game_compatibility.md) for a list of games
that can be played with xsystem35-sdl2.
## Unique Features
In addition to the original System 3.x's functionalities, xsystem35-sdl2 has
the following features.
In addition to the original System 3.x functionalities, xsystem35-sdl2 offers
the following features:
### Playing audio files as fake CD music
### Playing Audio Files as Virtual CD Music
Many System 3.x games had music as audio tracks on the CD-ROM. Xsystem35 can
play music from audio files instead, to avoid the hassle of inserting CDs. To
use ripped audio files, create a file named `playlist.txt` in the game
directory, and enter the paths to your tracks, one per line. For example:
Many System 3.x games feature music as audio tracks on the CD-ROM. xsystem35
can play music from audio files, eliminating the need to insert CDs. To use
ripped audio files, create a file named `playlist.txt` in the game directory
and list the paths to your tracks, one per line. For example:
```
# The first line is not used
@@ -22,89 +27,109 @@ BGM/track03.mp3
...
```
The first line is not used, because track 1 of game CD is usually a data track.
The first line is not used because the first track on a game CD is typically a
data track.
### Unicode translation support
Some games have integrated music as MIDI. In such cases, the music won't play
using the virtual CD feature. If you encounter a `Cannot load MIDI` error
message, you might need to set the `SDL_SOUNDFONTS` environment variable to
point to an `.sf2` file. For example:
The original System 3.x only supported Shift_JIS (a Japanese character
encoding), but xsystem35 supports Unicode and is able to run games translated
into languages other than Japanese and English.
```
SDL_SOUNDFONTS=/usr/share/soundfonts/GeneralUser.sf2 xsystem35
```
See [xsys35c](https://github.com/kichikuou/xsys35c)'s document for how to
build a game with Unicode mode.
### Unicode Translation Support
While the original System 3.x only supported Shift_JIS (a Japanese character
encoding), xsystem35 supports Unicode and can run games translated into
languages other than Japanese and English.
For instructions on how to build a game with Unicode support, see the
[xsys35c](https://github.com/kichikuou/xsys35c) documentation.
### Debugging
Xsystem35 has a built-in debugger that allows you to step through the game and
examine / modify variables in the game. There are two ways to use the debugger:
xsystem35 features a built-in debugger that allows you to step through the game
and examine or modify game variables. There are two ways to use the debugger:
- Through [Visual Studio Code](https://code.visualstudio.com/) (recommended):
The [vscode-system3x](https://github.com/kichikuou/vscode-system3x) extension
provides graphical debugging interface for System 3.x.
- Using CUI debugger: Running xsystem35 with `-debug` option will start the
debugger with console interface. Type `help` to see a list of available
commands.
provides a graphical debugging interface for System 3.x.
- Using the CLI Debugger: Running xsystem35 with the `-debug` option will
launch the debugger with a console interface. Type `help` to see a list of
available commands.
## Installing
## Installation
Prebuilt packages for Windows and Android can be downloaded from the
[Releases](https://github.com/kichikuou/xsystem35-sdl2/releases) page. For
other platforms, see the [Building](#building) section.
other platforms, refer to the [Building](#building) section.
## Running
### Windows
Execute `xsytem35`, and it will show a dialog to select a folder. Select the
game folder (where the ALD files are located).
Execute `xsystem35`, and a dialog will appear for you to select a folder.
Choose the game folder (where the ALD files are located).
### Android
See [android/README.md](https://github.com/kichikuou/xsystem35-sdl2/blob/master/android/README.md#use).
See [android/README.md](android/README.md#use).
### Other Platforms
Run xsystem35 from within the game directory.
cd /path/to/game_directory
xsystem35
```bash
$ cd /path/to/game_directory
$ xsystem35
```
## Building
### Linux (Debian / Ubuntu)
$ sudo apt install build-essential cmake libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libcjson-dev
$ mkdir -p out/debug
$ cd out/debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
$ make && make install
```bash
$ sudo apt install build-essential cmake libgtk-3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libwebp-dev libcjson-dev
$ mkdir -p out/debug
$ cd out/debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
$ make && make install
```
### MacOS
[Homebrew](https://brew.sh/index_ja) is needed.
[Homebrew](https://brew.sh/) is required.
$ brew install cmake pkg-config sdl2 sdl2_mixer sdl2_ttf webp cjson
$ mkdir -p out/debug
$ cd out/debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
$ make && make install
```bash
$ brew install cmake pkg-config sdl2 sdl2_mixer sdl2_ttf webp cjson
$ mkdir -p out/debug
$ cd out/debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ../../
$ make && make install
```
### Windows
[MSYS2](https://www.msys2.org) is needed.
[MSYS2](https://www.msys2.org) is required.
$ pacman -S cmake mingw-w64-x86_64-cmake mingw-w64-x86_64-SDL2 mingw-w64-x86_64-SDL2_ttf mingw-w64-x86_64-SDL2_mixer mingw-w64-x86_64-libwebp mingw-w64-x86_64-cjson
$ mkdir -p out/debug
$ cd out/debug
$ cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug ../../
$ make
```bash
$ pacman -S cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-SDL2_ttf mingw-w64-ucrt-x86_64-SDL2_mixer mingw-w64-ucrt-x86_64-libwebp mingw-w64-ucrt-x86_64-cjson
$ mkdir -p out/debug
$ cd out/debug
$ cmake -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug ../../
$ make
```
### Emscripten
$ mkdir -p out/wasm
$ cd out/wasm
$ emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../../
$ make
```bash
$ mkdir -p out/wasm
$ cd out/wasm
$ emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../../
$ make
```
To use the generated binary, checkout
To use the generated binary, check out
[Kichikuou on Web](https://github.com/kichikuou/web) and copy `out/xsystem35.*`
into its `docs` directory.
+34 -20
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.
+26 -11
View File
@@ -9,27 +9,38 @@ else {
apply plugin: 'kotlin-android'
android {
compileSdkVersion 31
if (buildAsApplication) {
namespace "io.github.kichikuou.xsystem35"
}
compileSdkVersion 34
defaultConfig {
if (buildAsApplication) {
applicationId "io.github.kichikuou.xsystem35"
}
minSdkVersion 19
targetSdkVersion 31
versionCode 11
versionName "2.6.0"
targetSdkVersion 34
versionCode 16
versionName "2.10.0" + gitRevision()
externalNativeBuild {
cmake {
arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static"
arguments "-DANDROID_APP_PLATFORM=android-19", "-DANDROID_STL=c++_static"
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
signingConfigs {
release {
storeFile rootProject.file('keystore.jks')
storePassword System.getenv('KEYSTORE_PASSWORD')
keyAlias System.getenv('KEY_ALIAS')
keyPassword System.getenv('KEY_PASSWORD')
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
if (rootProject.file('keystore.jks').exists()) {
signingConfig signingConfigs.release
}
}
}
applicationVariants.all { variant ->
@@ -39,7 +50,6 @@ android {
if (!project.hasProperty('EXCLUDE_NATIVE_LIBS')) {
sourceSets.main {
jniLibs.srcDir 'libs'
assets.srcDir '../../fonts'
}
aaptOptions {
// Disable asset compression for fonts.
@@ -54,10 +64,10 @@ android {
}
}
lintOptions {
lint {
abortOnError false
}
if (buildAsLibrary) {
libraryVariants.all { variant ->
variant.outputs.each { output ->
@@ -74,4 +84,9 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
}
static String gitRevision() {
' (git ' + "git rev-parse --short HEAD".execute().text.trim() + ')'
}
+18 -3
View File
@@ -1,12 +1,13 @@
cmake_minimum_required(VERSION 3.13)
project(GAME)
set(PROJECT_ROOT_DIR ../../..)
include(FetchContent)
FetchContent_Declare(
SDL
URL https://github.com/libsdl-org/SDL/releases/download/release-2.26.1/SDL2-2.26.1.tar.gz
URL_HASH SHA1=08a8cec21ffcebf44e4633a786d594a7811100d2
URL https://github.com/libsdl-org/SDL/releases/download/release-2.28.5/SDL2-2.28.5.tar.gz
URL_HASH SHA1=50af6b564890d702e57e2a72d6429b43778ed29a
)
FetchContent_Declare(
SDL_ttf
@@ -46,4 +47,18 @@ if(NOT sdl_mixer_POPULATED)
endif()
# The main CMakeLists.txt of xsystem35
add_subdirectory(../../.. xsystem35)
add_subdirectory(${PROJECT_ROOT_DIR} xsystem35)
# Copy asset files
set(ASSETS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/assets)
file(MAKE_DIRECTORY ${ASSETS_DIR}/licenses)
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/MTLc3m.ttf ${ASSETS_DIR}/MTLc3m.ttf)
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/mincho.otf ${ASSETS_DIR}/mincho.otf)
file(COPY_FILE ${PROJECT_ROOT_DIR}/COPYING ${ASSETS_DIR}/licenses/xsystem35)
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/MTLc3m.ttf.license ${ASSETS_DIR}/licenses/MTLc3m)
file(COPY_FILE ${PROJECT_ROOT_DIR}/fonts/mincho.otf.license ${ASSETS_DIR}/licenses/mincho)
file(COPY_FILE ${sdl_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL)
file(COPY_FILE ${sdl_ttf_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL_ttf)
file(COPY_FILE ${sdl_ttf_SOURCE_DIR}/external/freetype/docs/GPLv2.TXT ${ASSETS_DIR}/licenses/freetype)
file(COPY_FILE ${sdl_ttf_SOURCE_DIR}/external/harfbuzz/COPYING ${ASSETS_DIR}/licenses/harfbuzz)
file(COPY_FILE ${sdl_mixer_SOURCE_DIR}/LICENSE.txt ${ASSETS_DIR}/licenses/SDL_mixer)
+11 -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 -->
@@ -94,6 +93,17 @@
</intent-filter>
-->
</activity>
<activity android:name=".LicensesMenuActivity"
android:label="@string/action_licenses"
android:parentActivityName=".LauncherActivity"
android:exported="false">
</activity>
<activity android:name=".LicensesActivity"
android:parentActivityName=".LicensesMenuActivity"
android:exported="false">
</activity>
</application>
</manifest>
@@ -37,24 +37,20 @@ class GameActivity : SDLActivity() {
}
private lateinit var gameRoot: File
private lateinit var cdda: CddaPlayer
private val midi = MidiPlayer()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
gameRoot = File(intent.getStringExtra(EXTRA_GAME_ROOT)!!)
cdda = CddaPlayer(File(gameRoot, Launcher.PLAYLIST_FILE))
}
override fun onStop() {
super.onStop()
cdda.onActivityStop()
midi.onActivityStop()
}
override fun onResume() {
super.onResume()
cdda.onActivityResume()
midi.onActivityResume()
}
@@ -63,7 +59,9 @@ class GameActivity : SDLActivity() {
}
override fun getArguments(): Array<String> {
return arrayOf("-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!)
return arrayOf(
"-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!,
"-devcd", Launcher.PLAYLIST_FILE)
}
override fun setTitle(title: CharSequence?) {
@@ -120,9 +118,6 @@ class GameActivity : SDLActivity() {
}
// The functions below are called in the SDL thread by JNI.
@Suppress("unused") fun cddaStart(track: Int, loop: Boolean) = cdda.start(track, loop)
@Suppress("unused") fun cddaStop() = cdda.stop()
@Suppress("unused") fun cddaCurrentPosition() = cdda.currentPosition()
@Suppress("unused") fun midiStart(path: String, loop: Boolean) = midi.start(path, loop)
@Suppress("unused") fun midiStop() = midi.stop()
@Suppress("unused") fun midiCurrentPosition() = midi.currentPosition()
@@ -156,69 +151,6 @@ class GameActivity : SDLActivity() {
}
}
private class CddaPlayer(private val playlistPath: File) {
private val playlist =
try {
playlistPath.readLines()
} catch (e: IOException) {
Log.e("loadPlaylist", "Cannot load $playlistPath", e)
emptyList()
}
private var currentTrack = 0
private val player = MediaPlayer()
private var playerPaused = false
fun start(track: Int, loop: Boolean) {
val f = playlist.elementAtOrNull(track - 1)
if (f.isNullOrEmpty()) {
Log.w("cddaStart", "No playlist entry for track $track")
return
}
Log.v("cddaStart", "$f Loop:$loop")
try {
player.apply {
reset()
setDataSource(File(playlistPath.parent, f).path)
isLooping = loop
prepare()
start()
}
currentTrack = track
} catch (e: IOException) {
Log.e("cddaStart", "Cannot play $f", e)
player.reset()
}
}
fun stop() {
if (currentTrack > 0 && player.isPlaying) {
player.stop()
currentTrack = 0
}
}
fun currentPosition(): Int {
if (currentTrack == 0)
return 0
val frames = player.currentPosition * 75 / 1000
return currentTrack or (frames shl 8)
}
fun onActivityStop() {
if (currentTrack > 0 && player.isPlaying) {
player.pause()
playerPaused = true
}
}
fun onActivityResume() {
if (playerPaused) {
player.start()
playerPaused = false
}
}
}
private class MidiPlayer {
private val player = MediaPlayer()
private var playing = false
@@ -17,11 +17,13 @@
*/
package io.github.kichikuou.xsystem35
import android.annotation.SuppressLint
import android.os.Build
import android.os.Handler
import android.os.Message
import android.util.Log
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.*
import java.lang.StringBuilder
import java.nio.charset.Charset
@@ -40,9 +42,6 @@ interface LauncherObserver {
}
private const val SAVE_DIR = "save"
private const val PROGRESS = 0
private const val SUCCESS = 1
private const val FAILURE = 2
class Launcher private constructor(private val rootDir: File) {
companion object {
@@ -74,31 +73,28 @@ class Launcher private constructor(private val rootDir: File) {
updateGameList()
}
@OptIn(DelicateCoroutinesApi::class)
fun install(input: InputStream, archiveName: String?) {
val dir = createDirForGame()
@SuppressLint("HandlerLeak")
val handler = object : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
PROGRESS -> {
observer?.onInstallProgress(msg.obj as String)
}
SUCCESS -> {
isInstalling = false
observer?.onInstallSuccess(msg.obj as File, archiveName)
}
FAILURE -> {
isInstalling = false
observer?.onInstallFailure(msg.obj as Int)
isInstalling = true
GlobalScope.launch(Dispatchers.Main) {
try {
withContext(Dispatchers.IO) {
extractFiles(input, dir) { msg ->
GlobalScope.launch(Dispatchers.Main) {
observer?.onInstallProgress(msg)
}
}
}
observer?.onInstallSuccess(dir, archiveName)
} catch (e: InstallFailureException) {
observer?.onInstallFailure(e.msgId)
} catch (e: Exception) {
Log.e("launcher", "Failed to extract ZIP", e)
observer?.onInstallFailure(R.string.zip_extraction_error)
}
isInstalling = false
}
val t = Thread {
extractFiles(input, dir, handler)
}
t.start()
isInstalling = true
}
fun uninstall(id: Int) {
@@ -183,32 +179,26 @@ class Launcher private constructor(private val rootDir: File) {
}
}
private fun extractFiles(input: InputStream, outDir: File, handler: Handler) {
try {
val configWriter = GameConfigWriter()
val hadDecodeError = forEachZipEntry(input) { zipEntry, zip ->
Log.i("extractFiles", zipEntry.name)
val path = File(outDir, zipEntry.name)
if (zipEntry.isDirectory)
return@forEachZipEntry
path.parentFile?.mkdirs()
handler.sendMessage(handler.obtainMessage(PROGRESS, zipEntry.name))
FileOutputStream(path).buffered().use {
zip.copyTo(it)
}
configWriter.maybeAdd(zipEntry.name)
private fun extractFiles(input: InputStream, outDir: File, progressCallback: (String) -> Unit) {
val configWriter = GameConfigWriter()
val hadDecodeError = forEachZipEntry(input) { zipEntry, zip ->
Log.i("extractFiles", zipEntry.name)
val path = File(outDir, zipEntry.name)
if (zipEntry.isDirectory)
return@forEachZipEntry
path.parentFile?.mkdirs()
progressCallback(zipEntry.name)
FileOutputStream(path).buffered().use {
zip.copyTo(it)
}
if (!configWriter.readyToWrite()) {
val msgId = if (hadDecodeError) R.string.unsupported_zip else R.string.cannot_find_ald
handler.sendMessage(handler.obtainMessage(FAILURE, msgId))
return
}
configWriter.write(outDir)
handler.sendMessage(handler.obtainMessage(SUCCESS, outDir))
} catch (e: IOException) {
Log.e("launcher", "Failed to extract ZIP", e)
handler.sendMessage(handler.obtainMessage(FAILURE, R.string.zip_extraction_error))
configWriter.maybeAdd(zipEntry.name)
}
if (!configWriter.readyToWrite()) {
if (hadDecodeError)
throw InstallFailureException(R.string.unsupported_zip)
throw InstallFailureException(R.string.cannot_find_ald)
}
configWriter.write(outDir)
}
// Xsystem35-sdl2 <=2.2.0 had a bug where playlist had an extra empty line at
@@ -219,12 +209,14 @@ class Launcher private constructor(private val rootDir: File) {
if (!oldPlaylist.exists())
return
var tracks = oldPlaylist.readLines()
if (!tracks.isEmpty())
if (tracks.isNotEmpty())
tracks = tracks.subList(1, tracks.size)
File(dir, PLAYLIST_FILE).writeText(tracks.joinToString("\n"))
oldPlaylist.delete()
}
class InstallFailureException(val msgId: Int) : Exception()
// A helper class which generates xsystem35.gr and playlist.txt in the game root directory.
private class GameConfigWriter {
private val grb = StringBuilder()
@@ -27,6 +27,7 @@ import android.view.Menu
import android.view.MenuItem
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.TextView
import android.widget.Toast
import java.io.*
@@ -34,10 +35,11 @@ private const val CONTENT_TYPE_ZIP = "application/zip"
private const val INSTALL_REQUEST = 1
private const val SAVEDATA_EXPORT_REQUEST = 2
private const val SAVEDATA_IMPORT_REQUEST = 3
private const val STATE_PROGRESS_TEXT = "progressText"
class LauncherActivity : Activity(), LauncherObserver {
private lateinit var launcher: Launcher
private var progressDialog: ProgressDialogFragment? = null
private var progressDialog: Dialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -46,7 +48,7 @@ class LauncherActivity : Activity(), LauncherObserver {
launcher = Launcher.getInstance(filesDir)
launcher.observer = this
if (launcher.isInstalling) {
showProgressDialog()
showProgressDialog(savedInstanceState)
}
onGameListChange()
@@ -61,9 +63,17 @@ class LauncherActivity : Activity(), LauncherObserver {
override fun onDestroy() {
launcher.observer = null
dismissProgressDialog()
super.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle) {
progressDialog?.let {
outState.putCharSequence(STATE_PROGRESS_TEXT, it.findViewById<TextView>(R.id.text).text)
}
super.onSaveInstanceState(outState)
}
private fun onListItemClick(position: Int) {
if (position < launcher.games.size) {
startGame(launcher.games[position].path, null)
@@ -106,6 +116,11 @@ class LauncherActivity : Activity(), LauncherObserver {
SAVEDATA_IMPORT_REQUEST)
true
}
R.id.licenses -> {
val intent = Intent(this, LicensesMenuActivity::class.java)
startActivity(intent)
true
}
else -> super.onOptionsItemSelected(item)
}
}
@@ -148,7 +163,7 @@ class LauncherActivity : Activity(), LauncherObserver {
}
override fun onInstallProgress(path: String) {
progressDialog?.setProgress(getString(R.string.install_progress, path))
progressDialog?.findViewById<TextView>(R.id.text)?.text = getString(R.string.install_progress, path)
}
override fun onInstallSuccess(path: File, archiveName: String?) {
@@ -173,9 +188,17 @@ class LauncherActivity : Activity(), LauncherObserver {
launcher.uninstall(id)
}
private fun showProgressDialog() {
progressDialog = ProgressDialogFragment()
progressDialog!!.show(fragmentManager, "progress_dialog")
private fun showProgressDialog(savedInstanceState: Bundle? = null) {
progressDialog = Dialog(this)
progressDialog!!.apply {
setTitle(R.string.install_dialog_title)
setCancelable(false)
setContentView(R.layout.progress_dialog)
savedInstanceState?.let {
findViewById<TextView>(R.id.text)?.text = it.getCharSequence(STATE_PROGRESS_TEXT)
}
show()
}
}
private fun dismissProgressDialog() {
@@ -204,18 +227,3 @@ class LauncherActivity : Activity(), LauncherObserver {
return null
}
}
@Suppress("DEPRECATION") // for ProgressDialog
class ProgressDialogFragment : DialogFragment() {
private lateinit var dialog: ProgressDialog
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
dialog = ProgressDialog(activity)
return dialog.apply {
setTitle(R.string.install_dialog_title)
setCancelable(true)
}
}
fun setProgress(msg: String) {
dialog.setMessage(msg)
}
}
@@ -0,0 +1,23 @@
package io.github.kichikuou.xsystem35
import android.app.Activity
import android.os.Bundle
import android.widget.TextView
import java.io.BufferedReader
class LicensesActivity : Activity() {
companion object {
const val EXTRA_DISPLAY_NAME = "DISPLAY_NAME"
const val EXTRA_FILE_NAME = "FILE_NAME"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_licenses)
actionBar?.title = intent.getStringExtra(EXTRA_DISPLAY_NAME)
val path = "licenses/" + intent.getStringExtra(EXTRA_FILE_NAME)
val text = assets.open(path).bufferedReader().use(BufferedReader::readText)
findViewById<TextView>(R.id.license_text).text = text
}
}
@@ -0,0 +1,38 @@
package io.github.kichikuou.xsystem35
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.widget.ListView
import android.widget.SimpleAdapter
class LicensesMenuActivity : Activity() {
class Entry(val displayName: String, val fileName: String, val url: String)
private val entries: ArrayList<Entry> = arrayListOf(
Entry("xsystem35-sdl2", "xsystem35", "https://github.com/kichikuou/xsystem35-sdl2"),
Entry("SDL", "SDL", "https://www.libsdl.org/"),
Entry("SDL_mixer", "SDL_mixer", "https://github.com/libsdl-org/SDL_mixer"),
Entry("SDL_ttf", "SDL_ttf", "https://github.com/libsdl-org/SDL_ttf"),
Entry("FreeType", "freetype", "https://freetype.org/"),
Entry("HarfBuzz", "harfbuzz", "https://harfbuzz.github.io/"),
Entry("MotoyaLCedar W3 mono", "MTLc3m", "https://github.com/aosp-mirror/platform_frameworks_base/tree/lollipop-release/data/fonts"),
Entry("Source Han Serif", "mincho", "https://github.com/adobe-fonts/source-han-serif/"),
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_licenses_menu)
val items = entries.map { mapOf("name" to it.displayName, "url" to it.url)}
val listView = findViewById<ListView>(R.id.list)
listView.adapter = SimpleAdapter(this, items, android.R.layout.simple_list_item_2,
arrayOf("name", "url"), intArrayOf(android.R.id.text1, android.R.id.text2))
listView.setOnItemClickListener { _, _, pos, _ ->
val intent = Intent(this, LicensesActivity::class.java).apply {
putExtra(LicensesActivity.EXTRA_DISPLAY_NAME, entries[pos].displayName)
putExtra(LicensesActivity.EXTRA_FILE_NAME, entries[pos].fileName)
}
startActivity(intent)
}
}
}
@@ -186,7 +186,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
// Because on Chromebooks we show up as a dual-mode device, it will attempt to connect TRANSPORT_AUTO, which will use TRANSPORT_BREDR instead
// of TRANSPORT_LE. Let's force ourselves to connect low energy.
private BluetoothGatt connectGatt(boolean managed) {
if (Build.VERSION.SDK_INT >= 23) {
if (Build.VERSION.SDK_INT >= 23 /* Android 6.0 (M) */) {
try {
return mDevice.connectGatt(mManager.getContext(), managed, this, TRANSPORT_LE);
} catch (Exception e) {
@@ -429,7 +429,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
}
});
}
}
}
else if (newState == 0) {
mIsConnected = false;
}
@@ -170,7 +170,7 @@ public class HIDDeviceManager {
Log.i(TAG," Interface protocol: " + mUsbInterface.getInterfaceProtocol());
Log.i(TAG," Endpoint count: " + mUsbInterface.getEndpointCount());
// Get endpoint details
// Get endpoint details
for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
{
UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
@@ -251,6 +251,8 @@ public class HIDDeviceManager {
0x20d6, // PowerA
0x24c6, // PowerA
0x2c22, // Qanba
0x2dc8, // 8BitDo
0x9886, // ASTRO Gaming
};
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
@@ -271,14 +273,17 @@ public class HIDDeviceManager {
final int XB1_IFACE_SUBCLASS = 71;
final int XB1_IFACE_PROTOCOL = 208;
final int[] SUPPORTED_VENDORS = {
0x03f0, // HP
0x044f, // Thrustmaster
0x045e, // Microsoft
0x0738, // Mad Catz
0x0e6f, // PDP
0x0f0d, // Hori
0x10f5, // Turtle Beach
0x1532, // Razer Wildcat
0x20d6, // PowerA
0x24c6, // PowerA
0x2dc8, /* 8BitDo */
0x2dc8, // 8BitDo
0x2e24, // Hyperkin
};
@@ -353,13 +358,13 @@ public class HIDDeviceManager {
private void initializeBluetooth() {
Log.d(TAG, "Initializing Bluetooth");
if (Build.VERSION.SDK_INT <= 30 &&
if (Build.VERSION.SDK_INT <= 30 /* Android 11.0 (R) */ &&
mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
return;
}
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || (Build.VERSION.SDK_INT < 18)) {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || (Build.VERSION.SDK_INT < 18 /* Android 4.3 (JELLY_BEAN_MR2) */)) {
Log.d(TAG, "Couldn't initialize Bluetooth, this version of Android does not support Bluetooth LE");
return;
}
@@ -524,7 +529,7 @@ public class HIDDeviceManager {
for (HIDDevice device : mDevicesById.values()) {
device.setFrozen(frozen);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -573,7 +578,7 @@ public class HIDDeviceManager {
try {
final int FLAG_MUTABLE = 0x02000000; // PendingIntent.FLAG_MUTABLE, but don't require SDK 31
int flags;
if (Build.VERSION.SDK_INT >= 31) {
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
flags = FLAG_MUTABLE;
} else {
flags = 0;
@@ -52,7 +52,7 @@ class HIDDeviceUSB implements HIDDevice {
@Override
public String getSerialNumber() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
try {
result = mDevice.getSerialNumber();
}
@@ -74,7 +74,7 @@ class HIDDeviceUSB implements HIDDevice {
@Override
public String getManufacturerName() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
result = mDevice.getManufacturerName();
}
if (result == null) {
@@ -86,7 +86,7 @@ class HIDDeviceUSB implements HIDDevice {
@Override
public String getProductName() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
result = mDevice.getProductName();
}
if (result == null) {
@@ -29,6 +29,7 @@ public class SDL {
// This function stores the current activity (SDL or not)
public static void setContext(Context context) {
SDLAudioManager.setContext(context);
mContext = context;
}
@@ -60,8 +60,8 @@ import java.util.Locale;
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
private static final String TAG = "SDL";
private static final int SDL_MAJOR_VERSION = 2;
private static final int SDL_MINOR_VERSION = 26;
private static final int SDL_MICRO_VERSION = 1;
private static final int SDL_MINOR_VERSION = 28;
private static final int SDL_MICRO_VERSION = 5;
/*
// Display InputType.SOURCE/CLASS of events and devices
//
@@ -93,7 +93,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >= 23) {
tst = InputDevice.SOURCE_BLUETOOTH_STYLUS;
if ((s & tst) == tst) src += " BLUETOOTH_STYLUS";
s2 &= ~tst;
@@ -107,7 +107,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if ((s & tst) == tst) src += " GAMEPAD";
s2 &= ~tst;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= 21) {
tst = InputDevice.SOURCE_HDMI;
if ((s & tst) == tst) src += " HDMI";
s2 &= ~tst;
@@ -146,7 +146,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if ((s & tst) == tst) src += " TOUCHSCREEN";
s2 &= ~tst;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (Build.VERSION.SDK_INT >= 18) {
tst = InputDevice.SOURCE_TOUCH_NAVIGATION;
if ((s & tst) == tst) src += " TOUCH_NAVIGATION";
s2 &= ~tst;
@@ -170,7 +170,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
*/
public static boolean mIsResumedCalled, mHasFocus;
public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24);
public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */);
// Cursor types
// private static final int SDL_SYSTEM_CURSOR_NONE = -1;
@@ -224,9 +224,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
protected static SDLGenericMotionListener_API12 getMotionListener() {
if (mMotionListener == null) {
if (Build.VERSION.SDK_INT >= 26) {
if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
mMotionListener = new SDLGenericMotionListener_API26();
} else if (Build.VERSION.SDK_INT >= 24) {
} else if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
mMotionListener = new SDLGenericMotionListener_API24();
} else {
mMotionListener = new SDLGenericMotionListener_API12();
@@ -393,7 +393,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
mHIDDeviceManager = HIDDeviceManager.acquire(this);
// Set up the surface
mSurface = createSDLSurface(getApplication());
mSurface = createSDLSurface(this);
mLayout = new RelativeLayout(this);
mLayout.addView(mSurface);
@@ -404,7 +404,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
SDLActivity.onNativeOrientationChanged(mCurrentOrientation);
try {
if (Build.VERSION.SDK_INT < 24) {
if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) {
mCurrentLocale = getContext().getResources().getConfiguration().locale;
} else {
mCurrentLocale = getContext().getResources().getConfiguration().getLocales().get(0);
@@ -588,6 +588,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
mHIDDeviceManager = null;
}
SDLAudioManager.release(this);
if (SDLActivity.mBrokenLibraries) {
super.onDestroy();
return;
@@ -766,7 +768,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
}
break;
case COMMAND_CHANGE_WINDOW_STYLE:
if (Build.VERSION.SDK_INT >= 19) {
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
if (context instanceof Activity) {
Window window = ((Activity) context).getWindow();
if (window != null) {
@@ -841,7 +843,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
msg.obj = data;
boolean result = commandHandler.sendMessage(msg);
if (Build.VERSION.SDK_INT >= 19) {
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
if (command == COMMAND_CHANGE_WINDOW_STYLE) {
// Ensure we don't return until the resize has actually happened,
// or 500ms have passed.
@@ -969,15 +971,18 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
/* If set, hint "explicitly controls which UI orientations are allowed". */
if (hint.contains("LandscapeRight") && hint.contains("LandscapeLeft")) {
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
} else if (hint.contains("LandscapeRight")) {
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else if (hint.contains("LandscapeLeft")) {
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else if (hint.contains("LandscapeRight")) {
orientation_landscape = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
}
if (hint.contains("Portrait") && hint.contains("PortraitUpsideDown")) {
/* exact match to 'Portrait' to distinguish with PortraitUpsideDown */
boolean contains_Portrait = hint.contains("Portrait ") || hint.endsWith("Portrait");
if (contains_Portrait && hint.contains("PortraitUpsideDown")) {
orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
} else if (hint.contains("Portrait")) {
} else if (contains_Portrait) {
orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else if (hint.contains("PortraitUpsideDown")) {
orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
@@ -1090,7 +1095,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
// thus SDK version 27. If we are in DeX mode and not API 27 or higher, as a result,
// we should stick to relative mode.
//
if ((Build.VERSION.SDK_INT < 27) && isDeXMode()) {
if (Build.VERSION.SDK_INT < 27 /* Android 8.1 (O_MR1) */ && isDeXMode()) {
return false;
}
@@ -1180,7 +1185,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
* This method is called by SDL using JNI.
*/
public static boolean isDeXMode() {
if (Build.VERSION.SDK_INT < 24) {
if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) {
return false;
}
try {
@@ -1340,23 +1345,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
}
}
if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (isTextInputEvent(event)) {
if (ic != null) {
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
} else {
SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
}
}
onNativeKeyDown(keyCode);
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
onNativeKeyUp(keyCode);
return true;
}
}
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
// they are ignored here because sending them as mouse input to SDL is messy
@@ -1371,6 +1359,21 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
}
}
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (isTextInputEvent(event)) {
if (ic != null) {
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
} else {
SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
}
}
onNativeKeyDown(keyCode);
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
onNativeKeyUp(keyCode);
return true;
}
return false;
}
@@ -1617,7 +1620,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
private final Runnable rehideSystemUi = new Runnable() {
@Override
public void run() {
if (Build.VERSION.SDK_INT >= 19) {
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
@@ -1670,7 +1673,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
++mLastCursorID;
if (Build.VERSION.SDK_INT >= 24) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
try {
mCursors.put(mLastCursorID, PointerIcon.create(bitmap, hotSpotX, hotSpotY));
} catch (Exception e) {
@@ -1686,7 +1689,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
* This method is called by SDL using JNI.
*/
public static void destroyCustomCursor(int cursorID) {
if (Build.VERSION.SDK_INT >= 24) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
try {
mCursors.remove(cursorID);
} catch (Exception e) {
@@ -1700,7 +1703,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
*/
public static boolean setCustomCursor(int cursorID) {
if (Build.VERSION.SDK_INT >= 24) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
try {
mSurface.setPointerIcon(mCursors.get(cursorID));
} catch (Exception e) {
@@ -1755,7 +1758,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
cursor_type = 1002; //PointerIcon.TYPE_HAND;
break;
}
if (Build.VERSION.SDK_INT >= 24) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
try {
mSurface.setPointerIcon(PointerIcon.getSystemIcon(SDL.getContext(), cursor_type));
} catch (Exception e) {
@@ -1769,7 +1772,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
* This method is called by SDL using JNI.
*/
public static void requestPermission(String permission, int requestCode) {
if (Build.VERSION.SDK_INT < 23) {
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
nativePermissionResult(requestCode, true);
return;
}
@@ -1798,7 +1801,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
i.setData(Uri.parse(url));
int flags = Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
if (Build.VERSION.SDK_INT >= 21) {
if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
flags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
} else {
flags |= Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
@@ -2002,6 +2005,18 @@ class SDLInputConnection extends BaseInputConnection {
@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
if (Build.VERSION.SDK_INT <= 29 /* Android 10.0 (Q) */) {
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
if (beforeLength > 0 && afterLength == 0) {
// backspace(s)
while (beforeLength-- > 0) {
nativeGenerateScancodeForUnichar('\b');
}
return true;
}
}
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
return false;
}
@@ -1,5 +1,8 @@
package org.libsdl.app;
import android.content.Context;
import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
@@ -8,34 +11,67 @@ import android.media.MediaRecorder;
import android.os.Build;
import android.util.Log;
public class SDLAudioManager
{
import java.util.Arrays;
public class SDLAudioManager {
protected static final String TAG = "SDLAudio";
protected static AudioTrack mAudioTrack;
protected static AudioRecord mAudioRecord;
protected static Context mContext;
private static final int[] NO_DEVICES = {};
private static AudioDeviceCallback mAudioDeviceCallback;
public static void initialize() {
mAudioTrack = null;
mAudioRecord = null;
mAudioDeviceCallback = null;
if(Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */)
{
mAudioDeviceCallback = new AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
Arrays.stream(addedDevices).forEach(deviceInfo -> addAudioDevice(deviceInfo.isSink(), deviceInfo.getId()));
}
@Override
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
Arrays.stream(removedDevices).forEach(deviceInfo -> removeAudioDevice(deviceInfo.isSink(), deviceInfo.getId()));
}
};
}
}
public static void setContext(Context context) {
mContext = context;
if (context != null) {
registerAudioDeviceCallback();
}
}
public static void release(Context context) {
unregisterAudioDeviceCallback(context);
}
// Audio
protected static String getAudioFormatString(int audioFormat) {
switch (audioFormat) {
case AudioFormat.ENCODING_PCM_8BIT:
return "8-bit";
case AudioFormat.ENCODING_PCM_16BIT:
return "16-bit";
case AudioFormat.ENCODING_PCM_FLOAT:
return "float";
default:
return Integer.toString(audioFormat);
case AudioFormat.ENCODING_PCM_8BIT:
return "8-bit";
case AudioFormat.ENCODING_PCM_16BIT:
return "16-bit";
case AudioFormat.ENCODING_PCM_FLOAT:
return "float";
default:
return Integer.toString(audioFormat);
}
}
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
int channelConfig;
int sampleSize;
int frameSize;
@@ -43,14 +79,14 @@ public class SDLAudioManager
Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", requested " + desiredFrames + " frames of " + desiredChannels + " channel " + getAudioFormatString(audioFormat) + " audio at " + sampleRate + " Hz");
/* On older devices let's use known good settings */
if (Build.VERSION.SDK_INT < 21) {
if (Build.VERSION.SDK_INT < 21 /* Android 5.0 (LOLLIPOP) */) {
if (desiredChannels > 2) {
desiredChannels = 2;
}
}
/* AudioTrack has sample rate limitation of 48000 (fixed in 5.0.2) */
if (Build.VERSION.SDK_INT < 22) {
if (Build.VERSION.SDK_INT < 22 /* Android 5.1 (LOLLIPOP_MR1) */) {
if (sampleRate < 8000) {
sampleRate = 8000;
} else if (sampleRate > 48000) {
@@ -59,7 +95,7 @@ public class SDLAudioManager
}
if (audioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
int minSDKVersion = (isCapture ? 23 : 21);
int minSDKVersion = (isCapture ? 23 /* Android 6.0 (M) */ : 21 /* Android 5.0 (LOLLIPOP) */);
if (Build.VERSION.SDK_INT < minSDKVersion) {
audioFormat = AudioFormat.ENCODING_PCM_16BIT;
}
@@ -120,7 +156,7 @@ public class SDLAudioManager
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER;
break;
case 8:
if (Build.VERSION.SDK_INT >= 23) {
if (Build.VERSION.SDK_INT >= 23 /* Android 6.0 (M) */) {
channelConfig = AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
} else {
Log.v(TAG, "Requested " + desiredChannels + " channels, getting 5.1 surround");
@@ -201,6 +237,10 @@ public class SDLAudioManager
return null;
}
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */ && deviceId != 0) {
mAudioRecord.setPreferredDevice(getOutputAudioDeviceInfo(deviceId));
}
mAudioRecord.startRecording();
}
@@ -224,6 +264,10 @@ public class SDLAudioManager
return null;
}
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */ && deviceId != 0) {
mAudioTrack.setPreferredDevice(getInputAudioDeviceInfo(deviceId));
}
mAudioTrack.play();
}
@@ -238,11 +282,73 @@ public class SDLAudioManager
return results;
}
private static AudioDeviceInfo getInputAudioDeviceInfo(int deviceId) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
.filter(deviceInfo -> deviceInfo.getId() == deviceId)
.findFirst()
.orElse(null);
} else {
return null;
}
}
private static AudioDeviceInfo getOutputAudioDeviceInfo(int deviceId) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS))
.filter(deviceInfo -> deviceInfo.getId() == deviceId)
.findFirst()
.orElse(null);
} else {
return null;
}
}
private static void registerAudioDeviceCallback() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
audioManager.registerAudioDeviceCallback(mAudioDeviceCallback, null);
}
}
private static void unregisterAudioDeviceCallback(Context context) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
}
}
/**
* This method is called by SDL using JNI.
*/
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames);
public static int[] getAudioOutputDevices() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)).mapToInt(AudioDeviceInfo::getId).toArray();
} else {
return NO_DEVICES;
}
}
/**
* This method is called by SDL using JNI.
*/
public static int[] getAudioInputDevices() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).mapToInt(AudioDeviceInfo::getId).toArray();
} else {
return NO_DEVICES;
}
}
/**
* This method is called by SDL using JNI.
*/
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames, deviceId);
}
/**
@@ -254,6 +360,11 @@ public class SDLAudioManager
return;
}
if (android.os.Build.VERSION.SDK_INT < 21 /* Android 5.0 (LOLLIPOP) */) {
Log.e(TAG, "Attempted to make an incompatible audio call with uninitialized audio! (floating-point output is supported since Android 5.0 Lollipop)");
return;
}
for (int i = 0; i < buffer.length;) {
int result = mAudioTrack.write(buffer, i, buffer.length - i, AudioTrack.WRITE_BLOCKING);
if (result > 0) {
@@ -326,18 +437,22 @@ public class SDLAudioManager
/**
* This method is called by SDL using JNI.
*/
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames);
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames, deviceId);
}
/** This method is called by SDL using JNI. */
public static int captureReadFloatBuffer(float[] buffer, boolean blocking) {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
return 0;
} else {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
}
}
/** This method is called by SDL using JNI. */
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
if (Build.VERSION.SDK_INT < 23) {
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
return mAudioRecord.read(buffer, 0, buffer.length);
} else {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
@@ -346,7 +461,7 @@ public class SDLAudioManager
/** This method is called by SDL using JNI. */
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
if (Build.VERSION.SDK_INT < 23) {
if (Build.VERSION.SDK_INT < 23 /* Android 6.0 (M) */) {
return mAudioRecord.read(buffer, 0, buffer.length);
} else {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
@@ -391,4 +506,9 @@ public class SDLAudioManager
}
public static native int nativeSetupJNI();
public static native void removeAudioDevice(boolean isCapture, int deviceId);
public static native void addAudioDevice(boolean isCapture, int deviceId);
}
@@ -24,7 +24,7 @@ public class SDLControllerManager
public static native int nativeAddJoystick(int device_id, String name, String desc,
int vendor_id, int product_id,
boolean is_accelerometer, int button_mask,
int naxes, int nhats, int nballs);
int naxes, int axis_mask, int nhats, int nballs);
public static native int nativeRemoveJoystick(int device_id);
public static native int nativeAddHaptic(int device_id, String name);
public static native int nativeRemoveHaptic(int device_id);
@@ -42,7 +42,7 @@ public class SDLControllerManager
public static void initialize() {
if (mJoystickHandler == null) {
if (Build.VERSION.SDK_INT >= 19) {
if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
mJoystickHandler = new SDLJoystickHandler_API19();
} else {
mJoystickHandler = new SDLJoystickHandler_API16();
@@ -50,7 +50,7 @@ public class SDLControllerManager
}
if (mHapticHandler == null) {
if (Build.VERSION.SDK_INT >= 26) {
if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
mHapticHandler = new SDLHapticHandler_API26();
} else {
mHapticHandler = new SDLHapticHandler();
@@ -168,6 +168,32 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
arg1Axis = MotionEvent.AXIS_GAS;
}
// Make sure the AXIS_Z is sorted between AXIS_RY and AXIS_RZ.
// This is because the usual pairing are:
// - AXIS_X + AXIS_Y (left stick).
// - AXIS_RX, AXIS_RY (sometimes the right stick, sometimes triggers).
// - AXIS_Z, AXIS_RZ (sometimes the right stick, sometimes triggers).
// This sorts the axes in the above order, which tends to be correct
// for Xbox-ish game pads that have the right stick on RX/RY and the
// triggers on Z/RZ.
//
// Gamepads that don't have AXIS_Z/AXIS_RZ but use
// AXIS_LTRIGGER/AXIS_RTRIGGER are unaffected by this.
//
// References:
// - https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input
// - https://www.kernel.org/doc/html/latest/input/gamepad.html
if (arg0Axis == MotionEvent.AXIS_Z) {
arg0Axis = MotionEvent.AXIS_RZ - 1;
} else if (arg0Axis > MotionEvent.AXIS_Z && arg0Axis < MotionEvent.AXIS_RZ) {
--arg0Axis;
}
if (arg1Axis == MotionEvent.AXIS_Z) {
arg1Axis = MotionEvent.AXIS_RZ - 1;
} else if (arg1Axis > MotionEvent.AXIS_Z && arg1Axis < MotionEvent.AXIS_RZ) {
--arg1Axis;
}
return arg0Axis - arg1Axis;
}
}
@@ -210,7 +236,7 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
mJoysticks.add(joystick);
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
getVendorId(joystickDevice), getProductId(joystickDevice), false,
getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, 0);
}
}
}
@@ -291,6 +317,9 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
public int getVendorId(InputDevice joystickDevice) {
return 0;
}
public int getAxisMask(List<InputDevice.MotionRange> ranges) {
return -1;
}
public int getButtonMask(InputDevice joystickDevice) {
return -1;
}
@@ -308,6 +337,43 @@ class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
return joystickDevice.getVendorId();
}
@Override
public int getAxisMask(List<InputDevice.MotionRange> ranges) {
// For compatibility, keep computing the axis mask like before,
// only really distinguishing 2, 4 and 6 axes.
int axis_mask = 0;
if (ranges.size() >= 2) {
// ((1 << SDL_GAMEPAD_AXIS_LEFTX) | (1 << SDL_GAMEPAD_AXIS_LEFTY))
axis_mask |= 0x0003;
}
if (ranges.size() >= 4) {
// ((1 << SDL_GAMEPAD_AXIS_RIGHTX) | (1 << SDL_GAMEPAD_AXIS_RIGHTY))
axis_mask |= 0x000c;
}
if (ranges.size() >= 6) {
// ((1 << SDL_GAMEPAD_AXIS_LEFT_TRIGGER) | (1 << SDL_GAMEPAD_AXIS_RIGHT_TRIGGER))
axis_mask |= 0x0030;
}
// Also add an indicator bit for whether the sorting order has changed.
// This serves to disable outdated gamecontrollerdb.txt mappings.
boolean have_z = false;
boolean have_past_z_before_rz = false;
for (InputDevice.MotionRange range : ranges) {
int axis = range.getAxis();
if (axis == MotionEvent.AXIS_Z) {
have_z = true;
} else if (axis > MotionEvent.AXIS_Z && axis < MotionEvent.AXIS_RZ) {
have_past_z_before_rz = true;
}
}
if (have_z && have_past_z_before_rz) {
// If both these exist, the compare() function changed sorting order.
// Set a bit to indicate this fact.
axis_mask |= 0x8000;
}
return axis_mask;
}
@Override
public int getButtonMask(InputDevice joystickDevice) {
int button_mask = 0;
@@ -743,7 +809,7 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
@Override
public boolean supportsRelativeMouse() {
return (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27));
return (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */);
}
@Override
@@ -753,7 +819,7 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
@Override
public boolean setRelativeMouseEnabled(boolean enabled) {
if (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27)) {
if (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */) {
if (enabled) {
SDLActivity.getContentView().requestPointerCapture();
} else {
@@ -116,7 +116,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
int nDeviceHeight = height;
try
{
if (Build.VERSION.SDK_INT >= 17) {
if (Build.VERSION.SDK_INT >= 17 /* Android 4.2 (JELLY_BEAN_MR1) */) {
DisplayMetrics realMetrics = new DisplayMetrics();
mDisplay.getRealMetrics( realMetrics );
nDeviceWidth = realMetrics.widthPixels;
@@ -163,7 +163,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// Don't skip in MultiWindow.
if (skip) {
if (Build.VERSION.SDK_INT >= 24) {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
if (SDLActivity.mSingleton.isInMultiWindowMode()) {
Log.v("SDL", "Don't skip in Multi-Window");
skip = false;
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/license_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp" />
</ScrollView>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:padding="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ProgressBar
android:layout_marginEnd="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="16sp"/>
</LinearLayout>
@@ -6,4 +6,7 @@
<item
android:id="@+id/import_savedata"
android:title="@string/action_import_save_data" />
<item
android:id="@+id/licenses"
android:title="@string/action_licenses" />
</menu>
@@ -3,6 +3,7 @@
<string name="app_name">xsystem35</string>
<string name="action_export_save_data">セーブデータをエクスポート</string>
<string name="action_import_save_data">セーブデータをインポート</string>
<string name="action_licenses">オープンソースライセンス</string>
<string name="cancel">キャンセル</string>
<string name="cannot_find_ald">System 3.x のファイル (*.ald) が見つかりません。</string>
<string name="choose_a_file">ファイルを選択</string>
@@ -2,6 +2,7 @@
<string name="app_name">xsystem35</string>
<string name="action_export_save_data">Export Save Files</string>
<string name="action_import_save_data">Import Save Files</string>
<string name="action_licenses">Open source licenses</string>
<string name="cancel">Cancel</string>
<string name="cannot_find_ald">Cannot find System 3.x game files (*.ald).</string>
<string name="choose_a_file">Choose a file</string>
+2 -3
View File
@@ -1,14 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.6.20'
ext.kotlin_version = '1.7.21'
repositories {
mavenCentral()
google()
}
dependencies {
// AGP 7.1.x cannot be used due to https://issuetracker.google.com/issues/206099937
classpath 'com.android.tools.build:gradle:7.0.4'
classpath 'com.android.tools.build:gradle:8.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
+1 -1
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.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
+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"`
+1 -1
View File
@@ -1,5 +1,5 @@
#cmakedefine PACKAGE "@PACKAGE@"
#define VERSION "2.6.0"
#define VERSION "2.10.0"
#cmakedefine CMAKE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@"
-189
View File
@@ -1,189 +0,0 @@
それぞれのゲームに付いての注意書き
[鬼畜王ランス]
[ランス4(for Win95)]
[闘神都市2(for Win95)]
[いけないかつみ先生]
= 外字データには対応していません
[かえるにょぱにょ〜ん]
= フロアデータ(floor_1.map 〜 floor_16.map) はセーブデータと同じディレク
トリに置いてください。
= 一部のキャラの絵と説明が違う(金魚と????)
[戦巫女]
= 戦巫女は2枚組のCDで、Windows版では一部のデータをCD-ROMに置いたままゲーム
することになっていますが、xsystem35 では CD-Audio と CD-ROM上のデータを
同時に使用することは出来ません。ハードディスク等に全てのデータをインス
トールするか、あるいは CD-Audio 以外の演奏方法(MP3等)を使用してください。
CD-Audio を使う場合は2枚目の CD に音楽データが入っています。
[零式(アリスの館456版)]
= マップデータ(MAP_DATA.DAT, UR_DATA.DATA)はセーブデータと同じディレクトリに
置いてください。
[ATLACH=NACHA(アリスの館456版)]
[人間狩り(アリスの館456版)]
[アリスの館456]
- DALK
- 闘神都市
- DrStop!
- ランス1
- ランス2
- ランス3
[王道勇者]
[ディアボリカ]
[AmbivalenZ(for Win95)]
[夢幻泡影 (for Win95)]
[ぱすてるチャイム]
= ぱすてるチャイムでは明らかにシナリオにおかしいところがあります。
そこで、これに対するパッチを作成しました。
patch というディレクトリの下に pastel.diff というパッチ当てのスクリプト
がありますので、ゲームのシナリオデータのあるディレクトリにコピーして
そのディレクトリに移動した後、 ./pastel.diff (シナリオファイル名) と
実行してください。
(例)
> ./pastel.diff pastel_sa.ald
古いデータは pastel_sa.ald.org として保存されます。
シナリオデータは Ver 1.00 と Ver 1.01 に適用できます。
(廉価版では直っている?)
[ぷろすちゅーでんとGood]
[守り神様]
[ママトト]
[HushByBaby]
[Darcrows]
[PERSIOM]
= DirectSound(3D Sound) には対応していません。
[隠れ月]
[SeeIn青]
[廉価版・デアボリカ]
[廉価版・アトラクナクア]
[廉価版・かえるにょ・ぱにょん]
[廉価版・零式]
[かえるにょ国にょありす(20世紀アリス)]
= 外部MIDIプレイヤーモードでは音楽がリピートされません。
[これDPS?(20世紀アリス)]
[夜が来る!]
= 動きません
[王子さま Lv1]
[Only You 〜リ・クルス〜]
[大悪司]
= オープニングが動かない
[王子さま Lv1.5]
[妻みぐい]
= オープニングが動かない
[エスカレイヤー]
= オープニングが動かない
[Rance5D]
[妻みぐい2]
= オープニングが動かない
[DALK外伝]
[ままにょにょ]
= System4につき動きません
/*
* その他
*/
* センチメンタルシーズン (Aliceの館 CDをベースに UNITBASE が移植したもの)
= http://www4.big.or.jp/~unitbase/sys35sdk/games.html
* Intruder (Aliceの館 CDをベースに UNITBASE が移植したもの)
= まだ完了していません
* Crecent Moon がぁる (Aliceの館 CDをベースに UNITBASE が移植したもの)
= http://www4.big.or.jp/~unitbase/sys35sdk/games.html
* あぶない天狗伝説 (Aliceの館 CD2をベースに UNITBASE が移植したもの)
= 掲載許可が下りません
* OnlyYou (system3版をベースに TOTOさんが移植したもの)
= http://www1.interq.or.jp/t-takeda/index.html
* ランス4.1 (system3版をベースに TOTOさんが移植したもの)
= http://www1.interq.or.jp/t-takeda/index.html
= スプライトの色がおかしい
* ランス4.2 (system3版をベースに TOTOさんが移植したもの
= http://www1.interq.or.jp/t-takeda/index.html
= スプライトの色がおかしい
* アリスの館3 (system3版をベースに TOTOさんが移植したもの)
= http://www1.interq.or.jp/t-takeda/index.html
* 乙女戦記 (system3版をベースに TOTOさんが移植したもの)
= http://www1.interq.or.jp/t-takeda/index.html
* 闘神都市2外伝 (system3版をベースに TOTOさんが移植したもの)
= http://www1.interq.or.jp/t-takeda/index.html
* DPS全部 (system3版をベースに TOTOさんが移植したもの)
= http://www1.interq.or.jp/t-takeda/index.html
* ProStudentG (system3版をベースに TOTOさんが移植したもの)
= http://www1.interq.or.jp/t-takeda/index.html
* 学園KING (AliceCD Ver 1.??)
= CDが鳴らない
-> TOTOさんが、CD-DAに対応するためのシナリオパッチをつくっています。
http://www1.interq.or.jp/t-takeda/midi.html
* メイドのススメ (AliceCD Ver 1.02)
* ぶろぶろ (AliceCD Ver 1.02)
* 学園漂流戦記 (AliceCD Ver 1.02)
* 扉 (AliceCD Ver 2.02)
* 妖精 (AliceCD Ver 2.02)
/*
* 3rd party 製作 ゲーム
*/
#include "MISCGAME.TXT"
-58
View File
@@ -1,58 +0,0 @@
その他の SYSTEM 3.5 のゲームについて
README にある動作確認ゲーム以外にも、ネット上で公開されているSYSTEM3.5対応
のゲームのうち幾つかは動く事が確認されています。ここでは 1.4.0 preX での動作
状況です。1.4.0 公開時点で手に入るゲームを順次追加していっています。
また、XXXが動かないんだけど調べてください、XXXはちゃんと動きました、といった
情報もおよせください。
OKは問題なく動く。GOODが多少の問題あるもののゲームをやるぶんで気にはなるけど
耐えられる範囲のもの。BADは動かないものです。
(作者の敬称略)
【 ソフト名 】 【 ファイル名 】【 作者名 】【 動作 】
国立ファーブル図
書館司書〜
ブックルちゃん〜 SSYO_100.LZH 大塚ヒロ OK
バルーンぽっぷ BPOP_093.LZH 大塚ヒロ OK
Self self.lzh よこやまなおき OK
おせろっと othellotto.exe よこやまなおき OK
キャロル carol.lzh よこやまなおき GOOD(1)
積層四目並べ Te1.lzh 深叢 忍 OK
16Piece Puzzle 16p1.lzh 深叢 忍 OK
The Line Line0.lzh 深叢 忍 OK
Black Jack bj120.lzh かずき OK
マスカレイド (in AliceCD202) ちあぼう OK
戦娘ver2.12 ikusa212.lzh ちあぼう OK
できるかなー! (in AliceCD202) KIMM SOFT OK(2)
恋は計算どおり♪ koi.lzh SS OK
動体視力を鍛えるにょ game_191.lzh LazyRichField BAD(3)
集中力を鍛えるにょ game_22.lh LazyRichField GOOD(4)
1) 雪が降らない (grDrawFillCircle が未実装)
通信対戦が出来ない
2) メッセージサイズ300ドットの表示は 100 ドットに制限しています
3) DS 数字 となっている
4) 色がおかしい
最後にこれらのデータを公開している作者の方々のURLです。
大塚ヒロさん http://www.studioHIRO.com/
よこやまなおきさん http://www3.justnet.ne.jp/~naoki-yokoyama/
深叢 忍さん http://www2s.biglobe.ne.jp/~nin/
かずきさん http://www.din.or.jp/~kazuki/
桐ヶ屋 inc.(ちあぼう)さん http://www.eucaly.net/~kiri
KIMM SOFT/ネリワサヴィちーむ heavyd@syd.odn.ne.jp
SSさん http://www.sspzgr.net/
LazyRichFieldさん http://www2j.biglobe.ne.jp/~Lazy/staff/alice.htm
+83
View File
@@ -0,0 +1,83 @@
Game Compatibility
==================
| Game | Status | Notes |
| ------------------------------------------- | ----------- | ----- |
| 鬼畜王ランス | Supported | |
| Kichikuou Rance (EN) | Supported | |
| RanceIV -教団の遺産- | Supported | Win95 edition, [Ver2.05](https://hannylaboratory.blogspot.com/2023/01/blog-post_26.html) |
| Rance4 -Legacy of the Sect- (EN) | Supported | |
| 兰斯IV -教团的遗产- (CN) | Supported | |
| ランス4.1 | Supported | [Ver1.05](https://hannylaboratory.blogspot.com/2023/02/blog-post_9.html) |
| ランス4.2 | Supported | [Ver1.05](https://hannylaboratory.blogspot.com/2023/02/blog-post_9.html) |
| いけないかつみ先生 | Supported | Emojis are not supported |
| 闘神都市II | Supported | Win95 edition |
| かえるにょ・ぱにょ~ん | Supported | Normal / Low-priced edition |
| 戦巫女 | Supported | Normal / Low-priced edition |
| 零式 | Supported | From ALICEの館4・5・6 / Low-priced edition |
| アトラク=ナクア | Supported | From ALICEの館4・5・6 / Low-priced edition |
| Rance -光を求めて- | Supported | From ALICEの館4・5・6 |
| Rance II -反逆の少女達- | Supported | From ALICEの館4・5・6 |
| Rance III -リーザス陥落- | Supported | From ALICEの館4・5・6 |
| DALK | Supported | From ALICEの館4・5・6 |
| 闘神都市 | Supported | From ALICEの館4・5・6 |
| Dr.STOP | Supported | From ALICEの館4・5・6 |
| 人間狩り | Supported | From ALICEの館4・5・6 / アリスCD |
| 女の子図鑑 | Unknown | From ALICEの館4・5・6 |
| 恋のおわり | Unknown | |
| 王道勇者 | Supported | |
| AmbivalenZ | Supported | Win95 edition |
| DiaboLiQuE | Supported | Normal / Low-priced edition |
| 夢幻泡影 | Unknown | Win98 edition |
| ぱすてるチャイム | Supported | See [patch/README.TXT](patch/README.TXT) |
| ぷろすちゅーでんとGood | Supported | |
| 守り神様 | Supported | |
| ママトト | Supported | |
| HUSHABY BABY | Supported | |
| DARCROWS | Supported | |
| 隠れ月 | Supported | |
| PERSIOM | Supported | 3D sound is not supported |
| SeeIn青 | Supported | |
| かえるにょ国にょアリス | Supported | From 20世紀アリス |
| これD・P・S? | Supported | From 20世紀アリス |
| 夜が来る! | Unsupported | |
| Only you ~リ・クルス~ | Supported | |
| 大悪司 | Supported | Opening demo is not supported |
| 王子さまLv1 | Supported | |
| 王子さま1ヵ月後 | Supported | From 王子さまLV1.5 |
| 白鳳の子分叩き | Supported | From 王子さまLV1.5 |
| チェシャのお部屋1.5 | Supported | From 王子さまLV1.5 |
| 王子さま1/16 | Supported | From 王子さまLV1.5 |
| スパイ伊藤の「クイズ!俺にさぼらせろ」 | Supported | From 王子さまLV1.5 |
| 妻みぐい | Supported | Opening demo is not supported |
| 超昂天使エスカレイヤー | Supported | Opening demo is not supported |
| ランス5D | Supported | |
| Rance 5D - The Lonely Girl (MangaGamer) | Supported | |
| 俺の下であがけ | Unknown | |
| 楽園行 | Unknown | |
| 妻みぐい2 | Supported | Opening demo is not supported |
| シェル・クレイル | Supported | |
| ナイトデーモン | Supported | |
| 学園KING | Supported | From アリスCD |
| 学園KING 番外編 | Supported | From アリスCD |
| 蒼海に墜ちて | Supported | From アリスCD |
| ぶろぶろ | Supported | From アリスCD |
| 裸ぶろぶろ狂 | Supported | From アリスCD |
| メイドのススメ | Supported | From アリスCD |
| 学園漂流戦記 | Supported | From アリスCD |
| 学園漂流戦記2 | Supported | From アリスCD |
| 当たって!!KUDAKERO 予告編 | Supported | From アリスCD |
| 妖精 | Supported | From アリスCD |
| [扉] | Supported | From アリスCD |
| 叩き殺し太郎 | Supported | From アリスCD |
| バルーンぽっぷ | Supported | From アリスCD |
| 高速ひよこ2 | Supported | From アリスCD |
| おせろっと | Supported | From アリスCD |
| マスカレイド | Supported | From アリスCD |
| キャロル ~聖なる鐘が響く夜~ | Supported | From アリスCD, Online match is not supported |
| できるかなー? | Supported | From アリスCD |
| Child Assassin | Supported | From アリスCD |
| Klavier | Supported | From アリスCD |
| 弱肉狂食 | Supported | From アリスCD |
| 眼鏡大戦2 | Supported | From アリスCD |
| 妄想くん | Supported | From アリスCD |
-1
View File
@@ -26,7 +26,6 @@ add_library(modules STATIC
SACT/SACT.c
SACT/sactcg.c
SACT/sactsound.c
SACT/sactbgm.c
SACT/sacttimer.c
SACT/sactstring.c
SACT/sactcrypto.c
+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/メッセージスキップ/メッセージ枠消去の領域に
// マウスが移動したら、その部分のアイコンを変化させる
}
// メッセージ表示時に、キー入力を促すアニメーションの設定
+1 -1
View File
@@ -23,7 +23,7 @@ void nt_voice_set(int no) {
}
void nt_cd_play(int no) {
mus_cdrom_start(no +1, 0);
muscd_start(no + 1, 0);
}
void nt_cd_stop(int msec) {
+2 -2
View File
@@ -51,7 +51,7 @@ static void ndd_run(int demonum) {
int mus = ndemo_mus[demonum];
if (mus)
mus_bgm_play(mus, 0, 100);
musbgm_play(mus, 0, 100);
uint32_t start = sdl_getTicks();
while (!nact->is_quit) {
@@ -79,7 +79,7 @@ static void ndd_run(int demonum) {
}
if (mus)
mus_bgm_stop(ndemo_mus[demonum], 0);
musbgm_stop(ndemo_mus[demonum], 0);
alk_free(alk);
}
+16 -11
View File
@@ -25,22 +25,25 @@
#include <stdio.h>
#include <string.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include "portab.h"
#include "system.h"
#include "ald_manager.h"
#include "input.h"
#include "msgskip.h"
#include "xsystem35.h"
#include "gametitle.h"
#include "message.h"
#include "modules.h"
#include "music.h"
#include "nact.h"
#include "sact.h"
#include "sprite.h"
#include "sactcg.h"
#include "sactstring.h"
#include "sactsound.h"
#include "sactbgm.h"
#include "sactcrypto.h"
#include "sactchart.h"
#include "ngraph.h"
@@ -1790,7 +1793,9 @@ static void MusicCheck() {
int wNum = getCaliValue();
int *vRND = getCaliVariable();
*vRND = smus_check(wNum);
dridata *dfile = ald_getdata(DRIFILE_BGM, wNum - 1);
*vRND = dfile ? 1 : 0;
ald_freedata(dfile);
DEBUG_COMMAND_YET("SACT.MusicCheck %d,%p:", wNum, vRND);
}
@@ -1805,7 +1810,7 @@ static void MusicGetLength() {
int wNum = getCaliValue();
int *vRND = getCaliVariable();
*vRND = smus_getlength(wNum);
*vRND = musbgm_getlen(wNum);
DEBUG_COMMAND_YET("SACT.MusicGetLength %d,%d:", wNum, *vRND);
}
@@ -1820,7 +1825,7 @@ static void MusicGetPos() {
int wNum = getCaliValue();
int *vRND = getCaliVariable();
*vRND = smus_getpos(wNum);
*vRND = musbgm_getpos(wNum);
DEBUG_COMMAND_YET("SACT.MusicGetPos %d,%d:", wNum, *vRND);
}
@@ -1837,7 +1842,7 @@ static void MusicPlay() {
int wFadeTime = getCaliValue();
int wVolume = getCaliValue();
smus_play(wNum, wFadeTime, wVolume);
musbgm_play(wNum, wFadeTime, wVolume);
DEBUG_COMMAND_YET("SACT.MusicPlay %d,%d,%d:", wNum, wFadeTime, wVolume);
}
@@ -1852,7 +1857,7 @@ static void MusicStop() {
int wNum = getCaliValue();
int wFadeTime = getCaliValue();
smus_stop(wNum, wFadeTime);
musbgm_stop(wNum, wFadeTime);
DEBUG_COMMAND_YET("SACT.MusicStop %d,%d:", wNum, wFadeTime);
}
@@ -1865,7 +1870,7 @@ static void MusicStop() {
static void MusicStopAll() {
int wFadeTime = getCaliValue();
smus_stopall(wFadeTime);
musbgm_stopall(wFadeTime);
DEBUG_COMMAND_YET("SACT.MusicStopAll %d:", wFadeTime);
}
@@ -1882,7 +1887,7 @@ static void MusicFade() {
int wFadeTime = getCaliValue();
int wVolume = getCaliValue();
smus_fade(wNum, wFadeTime, wVolume);
musbgm_fade(wNum, wFadeTime, wVolume);
DEBUG_COMMAND_YET("SACT.MusicFade %d,%d,%d:", wNum, wFadeTime, wVolume);
}
@@ -1901,7 +1906,7 @@ static void MusicWait() {
nTimeOut = getCaliValue();
}
smus_wait(wNum, nTimeOut);
musbgm_wait(wNum, nTimeOut);
DEBUG_COMMAND_YET("SACT.MusicWait %d,%d:", wNum, nTimeOut);
}
@@ -1917,7 +1922,7 @@ static void MusicWaitPos() {
int wNum = getCaliValue();
int wIndex = getCaliValue();
smus_waitpos(wNum, wIndex);
WARNING("SACT.MusicWatiPos not implemented");
DEBUG_COMMAND_YET("SACT.MusicWaitPos %d,%d:", wNum, wIndex);
}
-93
View File
@@ -1,93 +0,0 @@
/*
* sactbgm.c: SACT Music 関連
*
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
* 1998- <masaki-c@is.aist-nara.ac.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* $Id: sactbgm.c,v 1.4 2003/08/30 21:29:16 chikama Exp $ */
#include "config.h"
#include <stdio.h>
#include "portab.h"
#include "system.h"
#include "ald_manager.h"
#include "music.h"
// 指定の番号の音楽が存在するかチェック
int smus_check(int no) {
dridata *dfile = ald_getdata(DRIFILE_BGM, no -1);
int st = 0;
if (dfile == NULL) {
st = 0;
} else {
st = 1;
ald_freedata(dfile);
}
return st;
}
// 指定の番号の音楽の長さを取得
int smus_getlength(int no) {
return mus_bgm_getlength(no);
}
// 指定の番号の音楽の再生位置を取得
int smus_getpos(int no) {
return mus_bgm_getpos(no);
}
// 指定の番号の音楽の再生開始
int smus_play(int no, int time, int vol) {
mus_bgm_play(no, time, vol);
return OK;
}
// 指定の番号の音楽の再生停止
int smus_stop(int no, int fadetime) {
mus_bgm_stop(no, fadetime);
return OK;
}
// 指定の番号の音楽のボリュームフェード
int smus_fade(int no, int time, int vol) {
mus_bgm_fade(no, time, vol);
return OK;
}
// 指定の番号の音楽が終了するのを待つ
int smus_wait(int no, int timeout) {
mus_bgm_wait(no, timeout);
return OK;
}
// 指定の番号の音楽が指定の位置まで再生されるのを待つ
int smus_waitpos(int no, int index) {
mus_bgm_waitpos(no, index);
return OK;
}
// 全ての音楽の再生を停止
int smus_stopall(int time) {
mus_bgm_stopall(time);
return OK;
}
-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]);
}
+89 -22
View File
@@ -26,8 +26,10 @@
#include <stdio.h>
#include <string.h>
#include <SDL.h>
#include "portab.h"
#include "LittleEndian.h"
#include "xsystem35.h"
#include "modules.h"
#include "nact.h"
@@ -35,12 +37,16 @@
#include "ald_manager.h"
#include "music.h"
#ifdef ENABLE_SDLMIXER
#include "pcm.sdlmixer.h"
#include "shpcmlib.c"
static struct {
SDL_AudioSpec spec; // must be 16-bit, stereo
uint8_t *buf;
uint32_t len;
} memwav;
static Mix_Chunk *chunk;
#endif
static void free_memory_wav(void) {
SDL_FreeWAV(memwav.buf);
memwav.buf = NULL;
}
static void Init() {
/*
@@ -117,10 +123,24 @@ static void wavLoadMemory() {
no:
*/
int no = getCaliValue();
#ifdef ENABLE_SDLMIXER
chunk = pcm_sdlmixer_load(no);
#endif
if (memwav.buf)
free_memory_wav();
dridata *dfile = ald_getdata(DRIFILE_WAVE, no - 1);
if (!dfile) {
WARNING("cannot open WAVE %d", no - 1);
return;
}
if (!SDL_LoadWAV_RW(SDL_RWFromConstMem(dfile->data, dfile->size), 1, &memwav.spec, &memwav.buf, &memwav.len)) {
WARNING("cannot load WAVE %d", no - 1);
return;
}
if (memwav.spec.channels != 2 || memwav.spec.format != AUDIO_S16LSB) {
WARNING("unexpected audio format");
free_memory_wav();
return;
}
DEBUG_COMMAND("ShSound.wavLoadMemory %d:", no);
}
@@ -133,12 +153,38 @@ static void wavSendMemory() {
*/
int slot = getCaliValue();
#ifdef ENABLE_SDLMIXER
if (chunk) {
pcm_sdlmixer_load_chunk(slot, chunk);
chunk = NULL;
if (!memwav.buf) {
WARNING("wave not loaded");
return;
}
#endif
const uint8_t wave_header[] = {
'R', 'I', 'F', 'F',
0, 0, 0, 0, // filesize - 8 (filled later)
'W', 'A', 'V', 'E',
'f', 'm', 't', ' ',
16, 0, 0, 0, // size of fmt chunk
1, 0, // PCM format
2, 0, // stereo
0, 0, 0, 0, // sampling rate (filled later)
0, 0, 0, 0, // bytes / sec (filled later)
4, 0, // block size
16, 0, // bits / sample
'd', 'a', 't', 'a',
0, 0, 0, 0, // size of data chunk (filled later)
};
uint32_t wav_size = sizeof(wave_header) + memwav.len;
uint8_t *wav_buf = malloc(wav_size);
memcpy(wav_buf, wave_header, sizeof(wave_header));
LittleEndian_putDW(wav_size - 8, wav_buf, 4);
LittleEndian_putDW(memwav.spec.freq, wav_buf, 24);
LittleEndian_putDW(memwav.spec.freq * 4, wav_buf, 28);
LittleEndian_putDW(memwav.len, wav_buf, 40);
memcpy(wav_buf + sizeof(wave_header), memwav.buf, memwav.len);
mus_wav_load_data(slot, wav_buf, wav_size);
free_memory_wav();
free(wav_buf);
DEBUG_COMMAND("ShSound.wavSendMemory %d:", slot);
}
@@ -153,11 +199,26 @@ static void wavFadeVolumeMemory() {
int start = getCaliValue();
int range = getCaliValue();
#ifdef ENABLE_SDLMIXER
if (chunk == NULL) return;
if (!memwav.buf)
return;
pcmlib_fade_volume_memory(chunk, start, range);
#endif
start *= memwav.spec.freq / 100; // 10ms -> sample
range *= memwav.spec.freq / 100; // 10ms -> sample
if (memwav.len / 4 < start + range)
return;
int16_t *buf = (int16_t*)memwav.buf + start * 2;
// 指定の場所から徐々に音量を下げる
for (int i = range; i > 0; i--) {
buf[0] = buf[0] * i / range;
buf[1] = buf[1] * i / range;
buf += 2;
}
// 残りは無音
memset(buf, 0, memwav.buf + memwav.len - (uint8_t*)buf);
DEBUG_COMMAND("ShSound.wavFadeVolumeMemory %d,%d:", start, range);
}
@@ -167,11 +228,17 @@ static void wavReversePanMemory() {
wavLoadMemoryで読み込んだデータの左右のチャンネルを反転
*/
#ifdef ENABLE_SDLMIXER
if (chunk == NULL) return;
if (!memwav.buf)
return;
pcmlib_reverse_pan_memory(chunk);
#endif
int16_t *buf = (int16_t*)memwav.buf;
int len = memwav.len / 4;
for (int i = 0; i < len; i++) {
int16_t tmp = buf[0];
buf[0] = buf[1];
buf[1] = tmp;
buf += 2;
}
DEBUG_COMMAND("ShSound.wavReversePanMemory:");
}
-70
View File
@@ -1,70 +0,0 @@
/*
* shpcmlib.c ShSound用 pcmlib
*
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
* 1998- <masaki-c@is.aist-nara.ac.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* $Id: shpcmlib.c,v 1.2 2003/08/02 13:10:32 chikama Exp $ */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <SDL_mixer.h>
#include "portab.h"
/*
*/
void pcmlib_reverse_pan_memory(Mix_Chunk *chunk) {
if (chunk == NULL) return;
short *buf = (short*)chunk->abuf;
int len = chunk->alen / 4;
for (int i = 0; i < len; i++) {
short tmp = buf[0];
buf[0] = buf[1];
buf[1] = tmp;
buf += 2;
}
}
/*
PCM
*/
void pcmlib_fade_volume_memory(Mix_Chunk *chunk, int start, int range) {
if (chunk == NULL) return;
start *= 441; // 10ms -> sample
range *= 441; // 10ms -> sample
if (chunk->alen / 4 < start + range)
return;
short *buf = (short*)chunk->abuf;
buf += start * 2;
// 指定の場所から徐々に音量を下げる
for (int i = range; i > 0; i--) {
buf[0] = buf[0] * i / range;
buf[1] = buf[1] * i / range;
buf += 2;
}
// 残りは無音
memset(buf, 0, chunk->abuf + chunk->alen - (Uint8*)buf);
}
+3 -1
View File
@@ -89,7 +89,9 @@ static void SetWindowTitle(void) { /* 6 */
int strno = getCaliValue();
int p2 = getCaliValue(); /* ISys3xSystem */
ags_setWindowTitle(svar_get(strno));
char *title_utf8 = toUTF8(svar_get(strno));
ags_setWindowTitle(title_utf8);
free(title_utf8);
DEBUG_COMMAND("ShString.SetWindowTitle: %d,%d:", strno, p2);
}
+2 -2
View File
@@ -49,14 +49,14 @@ static void Run() {
DEBUG_COMMAND_YET("dDemo.Run:");
#ifdef DDEMODEV
mus_cdrom_start(13, 1);
muscd_start(13, 1);
// ddemo_scene();
while(0 == sys_getInputInfo()) {
usleep(1000 * 100);
}
mus_cdrom_stop();
muscd_stop();
#endif
}
+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);
+4 -9
View File
@@ -53,7 +53,7 @@ target_sources(xsystem35 PRIVATE
# Misc
target_sources(xsystem35 PRIVATE
LittleEndian.c input.c profile.c mt19937-1.c filecheck.c mmap.c)
input.c profile.c mt19937-1.c filecheck.c mmap.c hacks.c)
# Scenario
target_sources(xsystem35 PRIVATE
@@ -84,6 +84,7 @@ if (EMSCRIPTEN)
"SHELL:-s USE_ZLIB=1"
"SHELL:-s USE_SDL=2"
"SHELL:-s USE_SDL_TTF=2")
target_compile_options(src_lib PRIVATE ${LIBS})
target_compile_options(xsystem35 PRIVATE ${LIBS})
target_link_options(xsystem35 PRIVATE ${LIBS})
target_link_libraries(xsystem35 PRIVATE idbfs.js)
@@ -95,10 +96,11 @@ if (EMSCRIPTEN)
"SHELL:-s ENVIRONMENT=web"
"SHELL:-s ASYNCIFY=1 -s ASYNCIFY_IGNORE_INDIRECT=1"
"SHELL:-s ASYNCIFY_REMOVE=SDL_Delay"
"SHELL:-s ASYNCIFY_IMPORTS=muspcm_load_no,muspcm_load_mixlr,muspcm_waitend,wait_vsync,load_mincho_font"
"SHELL:-s ASYNCIFY_IMPORTS=muspcm_load_no,muspcm_load_data,muspcm_load_mixlr,muspcm_waitend,wait_vsync,load_mincho_font"
"SHELL:-s ASYNCIFY_ADD=commands2F60,nact_main,send_agsevent,cb_waitkey_sprite"
"SHELL:-s ALLOW_MEMORY_GROWTH=1"
"SHELL:-s NO_EXIT_RUNTIME=1"
"SHELL:-s EXPORTED_FUNCTIONS=_main,_malloc"
"SHELL:-s EXPORTED_RUNTIME_METHODS=getValue,addRunDependency,removeRunDependency")
elseif (ANDROID)
@@ -140,10 +142,3 @@ else() # non-emscripten, non-android
add_test(NAME src_tests COMMAND src_tests)
configure_file(testdata/test.gr ${CMAKE_CURRENT_BINARY_DIR}/testdata/test.gr COPYONLY)
endif()
# FIXME: set up dependency for xsystem35 on this
if (NOT EMSCRIPTEN AND NOT ANDROID)
add_custom_target(sdl_keytable.h
COMMAND perl ../tools/xsyskey.pl ${SDL2_INCLUDE_DIRS} > sdl_keytable.h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
-62
View File
@@ -1,62 +0,0 @@
/*
* LittleEndian.c get little endian value
*
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
* 1998- <masaki-c@is.aist-nara.ac.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* @version 0.00 97/11/06
*/
/* $Id: LittleEndian.c,v 1.5 2000/11/25 13:08:56 chikama Exp $ */
#include "portab.h"
int LittleEndian_getDW(const uint8_t *b,int index) {
int c0, c1, c2, c3;
int d0, d1;
c0 = *(b + index + 0);
c1 = *(b + index + 1);
c2 = *(b + index + 2);
c3 = *(b + index + 3);
d0 = c0 + (c1 << 8);
d1 = c2 + (c3 << 8);
return (uint32_t)(d0 + (d1 << 16));
}
int LittleEndian_get3B(const uint8_t *b,int index) {
int c0, c1, c2;
c0 = *(b + index + 0);
c1 = *(b + index + 1);
c2 = *(b + index + 2);
return c0 + (c1 << 8) + (c2 << 16);
}
int LittleEndian_getW(const uint8_t *b,int index) {
int c0, c1;
c0 = *(b + index + 0);
c1 = *(b + index + 1);
return c0 + (c1 << 8);
}
void LittleEndian_putW(int num, uint8_t *b, int index) {
int c0, c1;
num %= 65536;
c0 = num % 256;
c1 = num / 256;
b[index] = c0; b[index+1] = c1;
}
+29 -5
View File
@@ -26,11 +26,35 @@
#ifndef __LITTLEENDIAN__
#define __LITTLEENDIAN__
#include "portab.h"
#include <string.h>
#include <SDL_endian.h>
extern int LittleEndian_getDW(const uint8_t *b,int index);
extern int LittleEndian_get3B(const uint8_t *b,int index);
extern int LittleEndian_getW(const uint8_t *b,int index);
extern void LittleEndian_putW(int num, uint8_t *b, int index);
static inline int LittleEndian_getDW(const uint8_t *b, int index) {
uint32_t t;
memcpy(&t, b + index, sizeof t);
return SDL_SwapLE32(t);
}
static inline int LittleEndian_get3B(const uint8_t *b, int index) {
uint32_t t = 0;
memcpy(&t, b + index, 3);
return SDL_SwapLE32(t);
}
static inline int LittleEndian_getW(const uint8_t *b, int index) {
uint16_t t;
memcpy(&t, b + index, sizeof t);
return SDL_SwapLE16(t);
}
static inline void LittleEndian_putW(uint16_t num, uint8_t *b, int index) {
num = SDL_SwapLE16(num);
memcpy(b + index, &num, sizeof(num));
}
static inline void LittleEndian_putDW(uint32_t num, uint8_t *b, int index) {
num = SDL_SwapLE32(num);
memcpy(b + index, &num, sizeof(num));
}
#endif /* !__LITTLEENDIAN__ */
+45 -48
View File
@@ -42,12 +42,18 @@
#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 palette_changed(void) {
nact->ags.pal_changed = TRUE;
dbg_on_palette_change();
}
static void initPal(Palette256 *pal) {
int i;
for (i = 0; i < 256; i++) {
@@ -58,7 +64,7 @@ static void initPal(Palette256 *pal) {
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);
nact->ags.pal_changed = TRUE;
palette_changed();
}
boolean ags_check_param(int *x, int *y, int *w, int *h) {
@@ -100,7 +106,7 @@ boolean ags_check_param_xy(int *x, int *y) {
}
void ags_init(const char *render_driver) {
nact->ags.mouse_movesw = MOUSE_WARP_SMOOTH;
nact->ags.mouse_warp_enabled = true;
nact->ags.pal = &pal_256;
nact->ags.world_size.width = SYS35_DEFAULT_WIDTH;
nact->ags.world_size.height = SYS35_DEFAULT_HEIGHT;
@@ -123,7 +129,7 @@ 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);
cg_reset();
@@ -151,7 +157,7 @@ void ags_setWorldSize(int width, int height, int depth) {
fade_outed = FALSE; /* thanx tajiri@wizard */
nact->ags.pal_changed = TRUE;
palette_changed();
}
void ags_setViewArea(int x, int y, int width, int height) {
@@ -162,19 +168,10 @@ void ags_setViewArea(int x, int y, int width, int height) {
sdl_setWindowSize(width, height);
}
void ags_setWindowTitle(const char *src) {
#define TITLEHEAD "XSystem35 Version "VERSION":"
uint8_t *utf, *d;
utf = toUTF8(src);
if (NULL == (d = malloc(strlen(utf) + strlen(TITLEHEAD) + 1))) {
NOMEMERR();
}
strcpy(d, TITLEHEAD);
strcat(d, utf);
sdl_setWindowTitle(d);
free(utf);
free(d);
void ags_setWindowTitle(const char *title_utf8) {
char buf[256];
snprintf(buf, sizeof(buf), "XSystem35 Version %s: %s", VERSION, title_utf8);
sdl_setWindowTitle(buf);
}
void ags_getDIBInfo(DispInfo *info) {
@@ -232,14 +229,14 @@ void ags_setPalettes(Palette256 *src_pal, int src, int dst, int cnt) {
nact->ags.pal->green[dst + i] = src_pal->green[src + i];
nact->ags.pal->blue [dst + i] = src_pal->blue [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;
palette_changed();
}
void ags_setPaletteToSystem(int src, int cnt) {
@@ -636,42 +633,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
+20 -24
View File
@@ -78,29 +78,26 @@ 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 {
@@ -113,11 +110,10 @@ struct _ags {
int world_depth; /* depth of off-screen (bits per pixel) */
enum mouse_warp_mode mouse_movesw;
agsurface_t *dib; /* main surface */
void (*eventcb)(agsevent_t *e); /* deliver event */
bool mouse_warp_enabled;
boolean noantialias; /* antialias を使用しない */
boolean noimagecursor; /* リソースファイルのカーソルを読みこまない */
};
@@ -133,7 +129,7 @@ void ags_reset(void);
/* ウィンド関係 */
extern void ags_setWorldSize(int width, int height, int depth);
extern void ags_setViewArea(int x, int y, int width, int height);
extern void ags_setWindowTitle(const char *str);
extern void ags_setWindowTitle(const char *title_utf8);
extern void ags_getDIBInfo(DispInfo *info);
extern void ags_getWindowInfo(DispInfo *info);
extern void ags_getViewAreaInfo(DispInfo *info);
@@ -208,7 +204,7 @@ extern agsurface_t *ags_drawStringToSurface(const char *str);
/* カーソル関係 */
extern void ags_setCursorType(int type);
extern void ags_loadCursor(int ,int);
extern void ags_setCursorLocation(int x, int y, boolean dibgeo);
extern void ags_setCursorLocation(int x, int y, bool is_dibgeo, bool for_selection);
extern void ags_setCursorMoveTime(int msec);
extern int ags_getCursorMoveTime();
+6 -5
View File
@@ -36,11 +36,6 @@ static drifiles *dri[DRIFILETYPEMAX];
/* cache handler for dri file */
static cacher *cacheid;
/*
* static maethods
*/
static void ald_free(dridata *dfile);
/*
* free dridata
* dfile: dridata to be free
@@ -109,3 +104,9 @@ void ald_init(int type, const char **file, int cnt, boolean use_mmap) {
cacheid = cache_new(ald_free);
}
}
int ald_get_maxno(DRIFILETYPE type) {
if (type >= DRIFILETYPEMAX || !dri[type])
return 0;
return dri[type]->maxno;
}
+4 -3
View File
@@ -38,9 +38,10 @@ typedef enum {
DRIFILE_BGM =6 /* stream music data */
} DRIFILETYPE;
extern void ald_init(int type, const char **file, int cnt, boolean use_mmap);
extern dridata *ald_getdata(DRIFILETYPE type, int no);
extern void ald_freedata(dridata *data);
void ald_init(int type, const char **file, int cnt, boolean use_mmap);
dridata *ald_getdata(DRIFILETYPE type, int no);
void ald_freedata(dridata *data);
int ald_get_maxno(DRIFILETYPE type);
#endif /* !__ALD_MANAGER__ */
+1 -1
View File
@@ -22,7 +22,7 @@
#include "portab.h"
#include "bgm.h"
int musbgm_init(void) {
int musbgm_init(DRIFILETYPE type, int base_no) {
return NG;
}
+6 -2
View File
@@ -26,8 +26,12 @@
#include "bgi.h"
#include "sdl_core.h"
int musbgm_init(void) {
return bgi_read(nact->files.bgi);
int musbgm_init(DRIFILETYPE type, int base_no) {
if (type == DRIFILE_BGM)
return bgi_read(nact->files.bgi);
else
EM_ASM({ xsystem35.cdPlayer.setBGMLoader($0, $1); }, type, base_no);
return OK;
}
int musbgm_exit(void) {
+3 -1
View File
@@ -19,7 +19,9 @@
#ifndef __BGM_H__
#define __BGM_H__
int musbgm_init(void);
#include "ald_manager.h"
int musbgm_init(DRIFILETYPE type, int base_no);
int musbgm_exit(void);
int musbgm_reset(void);
int musbgm_play(int no, int time, int vol);
+12 -5
View File
@@ -36,6 +36,8 @@
#include "music_private.h"
#include "ald_manager.h"
static DRIFILETYPE dri_type;
static int base_no;
static int current_no;
static Mix_Music *mix_music;
static dridata* dfile;
@@ -56,9 +58,10 @@ static void free_music() {
static Mix_Music *bgm_load(int no) {
free_music();
dfile = ald_getdata(DRIFILE_BGM, no -1);
int ald_no = no + base_no - 1;
dfile = ald_getdata(dri_type, ald_no);
if (dfile == NULL) {
WARNING("DRIFILE_BGM fail to open %d", no -1);
WARNING("Failed to open BGM %d", ald_no);
return NULL;
}
@@ -66,7 +69,7 @@ static Mix_Music *bgm_load(int no) {
mix_music = Mix_LoadMUS_RW(rwops, SDL_TRUE /* freesrc */);
if (mix_music == NULL) {
WARNING("Failed to load BGM %d: %s", no, SDL_GetError());
WARNING("Failed to load BGM %d: %s", ald_no, SDL_GetError());
free_music();
return NULL;
}
@@ -75,8 +78,12 @@ static Mix_Music *bgm_load(int no) {
return mix_music;
}
int musbgm_init(void) {
return bgi_read(nact->files.bgi);
int musbgm_init(DRIFILETYPE type, int base) {
dri_type = type;
base_no = base;
if (type == DRIFILE_BGM)
return bgi_read(nact->files.bgi);
return OK;
}
int musbgm_exit(void) {
-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;
}
+75
View File
@@ -0,0 +1,75 @@
/*
* cdrom.bgm.c CD->bgm bridge
*
* Copyright (C) 2023 <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stdio.h>
#include "cdrom.h"
#include "ald_manager.h"
#include "music.h"
#include "music_private.h"
static int current_track;
static int cdrom_bgm_init(char *dev) {
prv.cd_maxtrk = ald_get_maxno(DRIFILE_BGM) + 1;
return OK;
}
static int cdrom_bgm_exit(void) {
return OK;
}
static int cdrom_bgm_reset(void) {
return OK;
}
static int cdrom_bgm_start(int trk, int loop) {
if (musbgm_play(trk, 0, 100) != OK)
return NG;
current_track = trk;
return OK;
}
static int cdrom_bgm_stop(void) {
return musbgm_stop(current_track, 0);
}
static int cdrom_bgm_getPlayingInfo(cd_time *info) {
int t = musbgm_getpos(current_track); // in 10ms
if (!t)
return NG;
info->t = current_track;
info->m = t / (60*100); t %= (60*100);
info->s = t / 100; t %= 100;
info->f = t * CD_FPS / 100;
return OK;
}
cdromdevice_t cdrom_bgm = {
cdrom_bgm_init,
cdrom_bgm_exit,
cdrom_bgm_reset,
cdrom_bgm_start,
cdrom_bgm_stop,
cdrom_bgm_getPlayingInfo,
NULL,
NULL
};
+16 -58
View File
@@ -26,7 +26,6 @@
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "portab.h"
#include "cdrom.h"
@@ -34,80 +33,39 @@
#if defined(ENABLE_CDROM_LINUX)
extern cdromdevice_t cdrom_linux;
#define DEV_PLAY_MODE &cdrom_linux
#define NATIVE_CD_DEVICE &cdrom_linux
#elif defined(ENABLE_CDROM_BSD)
extern cdromdevice_t cdrom_bsd;
#define DEV_PLAY_MODE &cdrom_bsd
#define NATIVE_CD_DEVICE &cdrom_bsd
#elif defined(ENABLE_CDROM_EMSCRIPTEN)
extern cdromdevice_t cdrom_emscripten;
#define DEV_PLAY_MODE &cdrom_emscripten
#elif defined(ENABLE_CDROM_ANDROID)
extern cdromdevice_t cdrom_android;
#define DEV_PLAY_MODE &cdrom_android
#define NATIVE_CD_DEVICE &cdrom_emscripten
#else
extern cdromdevice_t cdrom_empty;
#define DEV_PLAY_MODE &cdrom_empty
#define NATIVE_CD_DEVICE &cdrom_empty
#endif
#ifdef ENABLE_CDROM_MP3
extern cdromdevice_t cdrom_mp3;
#endif
/*
temporary cdrom device name
default ... /dev/cdrom
FreeBSD ... /dev/acd0a
etc...
*/
static char *dev = CDROM_DEVICE;
/*
dev: cdromdevice
RET: 0
-1
*/
int cd_init(cdromdevice_t *cd) {
#if defined(ENABLE_CDROM_EMSCRIPTEN) || defined(ENABLE_CDROM_ANDROID)
memcpy(cd, DEV_PLAY_MODE, sizeof(cdromdevice_t));
return cd->init(dev);
cdromdevice_t *cd_init(const char *dev) {
#if defined(ENABLE_CDROM_EMSCRIPTEN)
return NATIVE_CD_DEVICE;
#else
struct stat st;
int ret = NG;
if (dev == NULL) return -1;
stat(dev, &st);
if (S_ISBLK(st.st_mode) | S_ISCHR(st.st_mode)) {
/* CDROM MODE */
memcpy(cd, DEV_PLAY_MODE, sizeof(cdromdevice_t));
ret = cd->init(dev);
}
else {
#ifdef ENABLE_CDROM_MP3
/* MP3 MODE */
memcpy(cd, &cdrom_mp3, sizeof(cdromdevice_t));
ret = cd->init(dev);
#else
/* error */
WARNING("no cdrom device available");
ret = NG;
#endif
}
return ret;
#endif // ENABLE_CDROM_EMSCRIPTEN || ENABLE_CDROM_ANDROID
}
if (dev && stat(dev, &st) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
return NATIVE_CD_DEVICE;
void cd_set_devicename(char *name) {
if (0 == strcmp("none", name)) dev = NULL;
else dev = strdup(name);
#ifdef ENABLE_CDROM_MP3
return &cdrom_mp3;
#else
WARNING("no cdrom device available");
return NULL;
#endif
#endif // ENABLE_CDROM_EMSCRIPTEN
}
+21 -29
View File
@@ -27,39 +27,10 @@
static int frame_of_getpos = -1;
static int cdrom_init(char *);
static int cdrom_exit(void);
static int cdrom_reset(void);
extern int cdrom_start(int, int);
extern int cdrom_stop();
static int cdrom_getPlayingInfo(cd_time *);
#define cdrom cdrom_emscripten
cdromdevice_t cdrom = {
cdrom_init,
cdrom_exit,
cdrom_reset,
cdrom_start,
cdrom_stop,
cdrom_getPlayingInfo,
NULL,
NULL
};
int cdrom_init(char *name) {
return OK;
}
int cdrom_exit(void) {
cdrom_stop();
return OK;
}
int cdrom_reset(void) {
cdrom_stop();
return OK;
}
EM_JS(int, cdrom_start, (int trk, int loop), {
xsystem35.cdPlayer.play(trk, loop == 0 ? 1 : 0);
return xsystem35.Status.OK;
@@ -70,6 +41,16 @@ EM_JS(int, cdrom_stop, (), {
return xsystem35.Status.OK;
});
int cdrom_exit(void) {
cdrom_stop();
return OK;
}
int cdrom_reset(void) {
cdrom_stop();
return OK;
}
int cdrom_getPlayingInfo(cd_time *info) {
if (nact->frame_count == frame_of_getpos)
nact->wait_vsync = TRUE;
@@ -82,3 +63,14 @@ int cdrom_getPlayingInfo(cd_time *info) {
FRAMES_TO_MSF(t >> 8, &info->m, &info->s, &info->f);
return OK;
}
cdromdevice_t cdrom_emscripten = {
cdrom_init,
cdrom_exit,
cdrom_reset,
cdrom_start,
cdrom_stop,
cdrom_getPlayingInfo,
NULL,
NULL
};
+3 -2
View File
@@ -49,8 +49,9 @@ struct _cdromdevice {
};
typedef struct _cdromdevice cdromdevice_t;
extern int cd_init(cdromdevice_t *);
extern void cd_set_devicename(char *);
extern cdromdevice_t cdrom_bgm;
extern cdromdevice_t *cd_init(const char *dev);
#define CD_FPS 75
#define FRAMES_TO_MSF(f, M,S,F) { \
+3 -1
View File
@@ -72,7 +72,9 @@ static int cdrom_init(char *playlist_path) {
fp = fopen("_inmm.ini", "r");
}
if (!fp) {
NOTICE("cdrom: Cannot open playlist %s", playlist_path);
// If the game has MIDI music, lack of the playlist is not a problem.
if (ald_get_maxno(DRIFILE_MIDI) == 0)
NOTICE("cdrom: Cannot open playlist %s", playlist_path);
return NG;
}
+39 -4
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のパレット展開バンク */
@@ -346,9 +346,9 @@ void cg_load(int no, int flg) {
}
/* draw cg pixel */
display_cg(cg, p.x, p.y, flg, flg != -1);
/* clear display offset */
clear_display_loc();
}
/* clear display offset */
clear_display_loc();
}
/*
@@ -391,6 +391,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 +440,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);
+7
View File
@@ -87,4 +87,11 @@ extern int cg_fflg;
extern int *cg_loadCountVar;
extern int cg_brightness;
static inline uint32_t rgb565_to_rgb888(uint16_t rgb) {
uint32_t r = rgb >> 11;
uint32_t g = (rgb >> 5) & 0x3f;
uint32_t b = rgb & 0x1f;
return (r << 19) | (r >> 2 << 16) | (g << 10) | (g >> 4 << 8) | (b << 3) | (b >> 2);
}
#endif /* !__CG__ */
+23 -62
View File
@@ -41,14 +41,11 @@
#include "sdl_core.h"
#include "ald_manager.h"
#include "LittleEndian.h"
#include "gametitle.h"
#include "hacks.h"
#if HAVE_UNAME
#include <sys/utsname.h>
#endif
/* defined by cmdm.c */
extern boolean have_eng_mp_patch;
/* 選択 Window OPEN 時 callback */
static int cb_sel_init_page = 0;
static int cb_sel_init_address = 0;
@@ -68,82 +65,49 @@ static fncall_table fnctbl[FCTBL_MAX];
void commands2F00() {
/* テキストカラーをスタックからポップして設定する */
int data[3];
sl_popData(data, 3);
if (data[0] == TxxTEXTCOLOR) {
if (data[1] == 0) {
nact->msg.MsgFontColor = data[2];
} else {
nact->sel.MsgFontColor = data[2];
}
}
sl_popState(STACK_TEXTCOLOR);
DEBUG_COMMAND("TOC:");
}
void commands2F01() {
/* テキストフォントサイズをスタックからポップして設定する */
int data[3];
sl_popData(data, 3);
if (data[0] == TxxTEXTSIZE) {
if (data[1] == 0) {
nact->msg.MsgFontSize = data[2];
} else {
nact->sel.MsgFontSize = data[2];
}
}
sl_popState(STACK_TEXTSIZE);
DEBUG_COMMAND("TOS:");
}
void commands2F02() {
/* 現在のテキストカラーをスタックにプッシュする */
int exp = getCaliValue();
int data[] = {TxxTEXTCOLOR,0,0};
data[1] = exp;
data[2] = (exp == 0 ? nact->msg.MsgFontColor : nact->sel.MsgFontColor);
sl_pushData(data, 3);
int type = getCaliValue();
switch (type) {
case 0: sl_pushTextColor(type, nact->msg.MsgFontColor); break;
case 1: sl_pushTextColor(type, nact->sel.MsgFontColor); break;
default: WARNING("TPC: unknown type %d", type); break;
}
DEBUG_COMMAND("TPC %d", exp);
}
void commands2F03() {
/* 現在のテキストフォントサイズをスタックにプッシュする */
int exp = getCaliValue();
int data[] = {TxxTEXTSIZE, 0, 0};
data[1] = exp;
data[2] = (exp == 0 ? nact->msg.MsgFontSize : nact->sel.MsgFontSize);
sl_pushData(data, 3);
DEBUG_COMMAND("TPS %d:%s", exp, "");
int type = getCaliValue();
switch (type) {
case 0: sl_pushTextSize(type, nact->msg.MsgFontSize); break;
case 1: sl_pushTextSize(type, nact->sel.MsgFontSize); break;
default: WARNING("TPS: unknown type %d", type); break;
}
DEBUG_COMMAND("TPS %d", exp);
}
void commands2F04() {
/* テキスト表示位置をスタックからポップして設定する */
int data[3];
sl_popData(data, 3);
if (data[0] == TxxTEXTLOC) {
msg_setMessageLocation(data[1], data[2]);
}
sl_popState(STACK_TEXTLOC);
DEBUG_COMMAND("TOP:");
}
void commands2F05() {
/* 現在のテキスト表示位置をスタックにプッシュする */
int data[] = {TxxTEXTLOC, 0, 0};
MyPoint loc;
msg_getMessageLocation(&loc);
data[1] = loc.x;
data[2] = loc.y;
sl_pushData(data, 3);
sl_pushTextLoc(loc.x, loc.y);
DEBUG_COMMAND("TPP:");
}
@@ -394,7 +358,7 @@ void commands2F24() {
case 1:
var = getCaliValue();
cnt = getCaliValue();
sysVar[0] = save_load_str_with_file(fname_utf8, var, cnt);
sysVar[0] = load_strs_from_file(fname_utf8, var, cnt);
break;
default:
var = getCaliValue();
@@ -461,12 +425,9 @@ void commands2F28() {
free(nact->game_title_utf8);
nact->game_title_utf8 = toUTF8(title);
ags_setWindowTitle(title);
ags_setWindowTitle(nact->game_title_utf8);
if (0 == strcmp(nact->game_title_utf8, GT_RANCE3_ENG) ||
0 == strcmp(nact->game_title_utf8, GT_RANCE4_ENG)) {
have_eng_mp_patch = TRUE;
}
enable_hack_by_title(nact->game_title_utf8);
DEBUG_COMMAND("MT(new) %s:",title);
}
@@ -503,7 +464,7 @@ void commands2F2A() {
case 1:
var = getCaliValue();
cnt = getCaliValue();
sysVar[0] = save_save_str_with_file(fname_utf8, var, cnt);
sysVar[0] = save_strs_to_file(fname_utf8, var, cnt);
break;
default:
var = getCaliValue();
@@ -1290,7 +1251,7 @@ void commands2F72() {
void commands2F73() {
int *vTrack = getCaliVariable();
*vTrack = mus_cdrom_get_maxtrack();
*vTrack = muscd_get_maxtrack();
DEBUG_COMMAND("cdGetMaxTrack %d:", *vTrack);
}
+4
View File
@@ -773,6 +773,8 @@ void exec_command(void) {
commandLXR(); break;
case 'W':
commandLXW(); break;
case 'X':
commandLXX(); break;
default:
undeferr();
}
@@ -974,6 +976,8 @@ void exec_command(void) {
commandST(); break;
case 'U':
commandSU(); break;
case 'V':
commandSV(); break;
case 'W':
commandSW(); break;
case 'X':
+2 -1
View File
@@ -135,7 +135,7 @@ extern void commandLXS();
extern void commandLXP();
extern void commandLXR();
extern void commandLXW();
extern void commandLXX();
/* defined by cmdm.c */
extern void commandMA();
@@ -220,6 +220,7 @@ extern void commandSR();
extern void commandSS();
extern void commandST();
extern void commandSU();
extern void commandSV();
extern void commandSW();
extern void commandSX();
extern void commandSI();
+17 -17
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 (blending #ff00ff and #ff00ff results in #fd00fd), so the
// resulting color may not match the colorkey of CX 1. To workaround
// this, specify a small alpha mod so that SDL will use a "slow path"
// that does accurate calculation.
if (daiakuji_cx_hack)
ags_copyArea_shadow_withrate(src_x, src_y, width, height, dst_x, dst_y, 254);
else
ags_copyArea_shadow(src_x, src_y, width, height, dst_x, dst_y);
ags_updateArea(dst_x, dst_y, width, height);
break;
case 1:
@@ -94,6 +104,7 @@ void commandCX() {
DEBUG_COMMAND_YET("CX %d,%d,%d,%d,%d,%d,%d,%d:", mode, src_x, src_y, width, height, dst_x, dst_y, col);
break;
}
daiakuji_cx_hack = false;
DEBUG_COMMAND("CX %d,%d,%d,%d,%d,%d,%d,%d:", mode, src_x, src_y, width, height, dst_x, dst_y, col);
}
+1 -1
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);
}
+62 -22
View File
@@ -72,13 +72,13 @@ void commandLT() {
struct stat buf;
struct tm *lc;
if (num <= 0) {
*var = 0;
*(var + 1) = 0;
*(var + 2) = 0;
*(var + 3) = 0;
*(var + 4) = 0;
*(var + 5) = 0;
if (num <= 0 || num > SAVE_MAXNUMBER) {
var[0] = 0;
var[1] = 0;
var[2] = 0;
var[3] = 0;
var[4] = 0;
var[5] = 0;
sysVar[0] = 255;
return;
}
@@ -86,21 +86,21 @@ void commandLT() {
status = stat(save_get_file(num - 1), &buf);
if (status) {
/* んなんどこにもかいてないやん! */
*var = 0;
*(var + 1) = 0;
*(var + 2) = 0;
*(var + 3) = 0;
*(var + 4) = 0;
*(var + 5) = 0;
var[0] = 0;
var[1] = 0;
var[2] = 0;
var[3] = 0;
var[4] = 0;
var[5] = 0;
sysVar[0] = 255;
} else {
lc = localtime(&buf.st_mtime);
*var = 1900 + lc->tm_year;
*(var + 1) = 1 + lc->tm_mon;
*(var + 2) = lc->tm_mday;
*(var + 3) = lc->tm_hour;
*(var + 4) = lc->tm_min;
*(var + 5) = lc->tm_sec;
var[0] = lc->tm_year + 1900;
var[1] = lc->tm_mon + 1;
var[2] = lc->tm_mday;
var[3] = lc->tm_hour;
var[4] = lc->tm_min;
var[5] = lc->tm_sec;
sysVar[0] = 0;
}
DEBUG_COMMAND("LT %d,%p",num, var);
@@ -114,16 +114,16 @@ void commandLE() {
char *fname_utf8 = toUTF8(filename);
switch (type) {
case 0: /* T2 */
case 0:
getCaliArray(&vref);
var = vref.var;
cnt = getCaliValue();
sysVar[0] = load_vars_from_file(fname_utf8, &vref, cnt);
break;
case 1: /* 456 */
case 1:
var = getCaliValue();
cnt = getCaliValue();
sysVar[0] = save_load_str_with_file(fname_utf8, var, cnt);
sysVar[0] = load_strs_from_file(fname_utf8, var, cnt);
break;
default:
var = getCaliValue();
@@ -336,3 +336,43 @@ void commandLXW() {
DEBUG_COMMAND_YET("LXW %d,%d,%d:",num,*var,size);
}
void commandLXX() {
/* Gets file timestamp to [var, var+6] */
int type = getCaliValue();
int num = getCaliValue();
int *var = getCaliVariable();
struct stat buf;
struct tm *lc;
switch (type) {
case 5: // save data
if (num <= 0 || num > SAVE_MAXNUMBER || stat(save_get_file(num - 1), &buf)) {
sysVar[0] = 255;
break;
}
lc = localtime(&buf.st_mtime);
var[0] = lc->tm_year + 1900;
var[1] = lc->tm_mon + 1;
var[2] = lc->tm_mday;
var[3] = lc->tm_hour;
var[4] = lc->tm_min;
var[5] = lc->tm_sec;
var[6] = lc->tm_wday;
sysVar[0] = 0;
break;
case 0: // scenario
case 1: // CG
case 2: // wave
case 3: // MIDI
case 4: // data
case 6: // resource
default:
DEBUG_COMMAND_YET("LXX %d,%d,%d:", type, num, *var);
return;
}
DEBUG_COMMAND("LXX %d,%d,%d:", type, num, *var);
}
+6 -26
View File
@@ -31,22 +31,13 @@
#include "utfsjis.h"
#include "menu.h"
#include "ags.h"
#include "input.h"
#include "message.h"
#include "gametitle.h"
#include "hankaku.h"
/* defined by cmds.c */
extern boolean dummy_pcm_su_flag;
/* defined by cmdy.c */
extern boolean Y3waitFlags;
/* MI 用パラメータ */
INPUTSTRING_PARAM mi_param;
boolean have_eng_mp_patch = FALSE;
void commandMS() {
/* Xコマンドで表示される文字列領域に文字列を入れる */
int num = getCaliValue();
@@ -69,7 +60,7 @@ void commandMP() {
char *str;
/* Patched English executable appends num2 spaces instead of truncating */
if (have_eng_mp_patch) {
if (nact->game == GAME_RANCE3_ENG || nact->game == GAME_RANCE4_ENG) {
str = calloc(strlen(src) + num2 * strlen(fullwidth_blank[nact->encoding]) + 1, 1);
if (NULL == str) {
NOMEMERR();
@@ -163,17 +154,9 @@ void commandMT() {
if (nact->game_title_utf8)
free(nact->game_title_utf8);
nact->game_title_utf8 = toUTF8(str);
ags_setWindowTitle(str);
ags_setWindowTitle(nact->game_title_utf8);
/* 闘神都市II 対策 */
if (0 == strcmp(nact->game_title_utf8, GT_TOSHIN2)) {
dummy_pcm_su_flag = TRUE;
}
/* Rance4 対策? */
if (0 == strcmp(nact->game_title_utf8, GT_RANCE4)) {
Y3waitFlags = KEYWAIT_NONCANCELABLE;
}
enable_hack_by_title(nact->game_title_utf8);
DEBUG_COMMAND("MT %s:",str);
}
@@ -266,16 +249,13 @@ void commandMF() {
void commandMZ0() {
/* 文字列変数の文字数・個数の設定の変更 */
int max_len = getCaliValue();
int max_len = getCaliValue(); // deprecated in System3.9
int max_num = getCaliValue();
int rsv = getCaliValue();
DEBUG_COMMAND("MZ0 %d,%d,%d:",max_len, max_num, rsv);
/* いつからか、文字列変数の最大長さは∞になったようだ */
if (max_len == 0) max_len = STRVAR_LEN * 2;
svar_init(max_num, max_len * 2 + 1);
svar_init(max_num);
}
void commandMG() {
@@ -346,7 +326,7 @@ void commandMJ() {
mj_param.h = h;
mj_param.oldstring = t1;
ags_setCursorLocation(x, y, FALSE); /* XXX */
ags_setCursorLocation(x, y, false, false);
menu_inputstring2(&mj_param);
if (mj_param.newstring == NULL) return;
+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();
+16 -8
View File
@@ -29,8 +29,6 @@
/* ぱにょ〜ん 異常シナリオ対策 */
static boolean dummy_pcm_in_play = FALSE;
/* 闘神都市II 異常シナリオ対策 */
boolean dummy_pcm_su_flag = FALSE;
/* 次の cdrom の loop 回数 */
static int next_cdrom_loopcnt = 0;
@@ -41,9 +39,9 @@ void commandSS() {
DEBUG_COMMAND("SS %d:",num);
if (num == 0) {
mus_cdrom_stop();
muscd_stop();
} else {
mus_cdrom_start(num + 1, next_cdrom_loopcnt);
muscd_start(num + 1, next_cdrom_loopcnt);
}
next_cdrom_loopcnt = 0;
@@ -54,7 +52,7 @@ void commandSC() {
int *var = getCaliVariable();
int t, m, s, f;
if (mus_cdrom_get_playposition(&t, &m, &s, &f) == OK) {
if (muscd_getpos(&t, &m, &s, &f) == OK) {
*var++ = t - 1;
*var++ = m;
*var++ = s;
@@ -97,7 +95,7 @@ void commandSR() {
if (num == 0) {
int t, m, s, f;
if (mus_cdrom_get_playposition(&t, &m, &s, &f) == OK) {
if (muscd_getpos(&t, &m, &s, &f) == OK) {
// System3.5 returns the music number (track_no - 1),
// while System3.6 and later return the track number.
if (!memcmp(sl_sco, "S350", 4))
@@ -135,7 +133,7 @@ void commandSI() {
} else if (type == 1) { /* PCM */
*var = mus_pcm_get_state() == TRUE ? 1 : 0;
} else if (type == 2) { /* CD */
*var = mus_cdrom_get_state() == TRUE ? 1 : 0;
*var = muscd_is_available() ? 1 : 0;
}
DEBUG_COMMAND("SI %d,%d:",type,*var);
@@ -273,13 +271,23 @@ void commandSU() {
dummy_pcm_in_play = dummy_pcm_in_play ? FALSE : TRUE;
}
}
if (dummy_pcm_su_flag) {
/* 闘神都市II 異常シナリオ対策 */
if (nact->game == GAME_TT2) {
*var1 = *var2 = 0;
}
DEBUG_COMMAND("SU %d,%d:",*var1, *var2);
}
void commandSV() {
// Set volume (Rance4 v2)
int device = getCaliValue();
int volume = getCaliValue();
mus_mixer_set_level(device, volume);
DEBUG_COMMAND("SV %d,%d", device, volume);
}
void commandSQ() {
/* 左右別々のPCMデータを合成して演奏する */
int noL = getCaliValue();
+19 -6
View File
@@ -33,12 +33,16 @@ void commandUC() { /* 王道勇者 */
switch(mode) {
case 0:
sl_stackClear_allCall(); break;
sl_clearStack(true);
break;
case 1:
sl_stackClear_labelCall(num); break;
sl_dropLabelCalls(num);
break;
case 2:
sl_stackClear_pageCall(num); break;
default:
sl_dropPageCalls(num);
break;
case 3:
sl_clearStack(false);
break;
}
DEBUG_COMMAND("UC %d,%d:",mode,num);
@@ -51,7 +55,7 @@ void commandUD() {
case 0:
sl_reinit(); break;
case 1:
sl_retFar2(); break;
sl_retFar(); break;
default:
WARNING("UnKnown UD command %d", mode);
}
@@ -62,8 +66,17 @@ void commandUD() {
void commandUR() {
/* 最後に積まれたスタックの属性をリード */
int *var = getCaliVariable();
struct stack_info info;
sl_getStackInfo(&info);
var[0] = info.top_attr;
var[1] = info.page_calls;
var[2] = info.label_calls;
var[3] = info.var_pushes;
var[4] = info.label_calls_after_page_call;
var[5] = info.var_pushes_after_call;
DEBUG_COMMAND_YET("UR %p:",var);
DEBUG_COMMAND("UR %p:",var);
}
void commandUS() {
+37 -10
View File
@@ -32,6 +32,7 @@
#include "scenario.h"
#include "cmd_check.h"
#include "sdl_core.h"
#include "music_cdrom.h"
unsigned Y3waitFlags = KEYWAIT_CANCELABLE;
@@ -63,6 +64,9 @@ unsigned Y3waitFlags = KEYWAIT_CANCELABLE;
*
* To fix this, this hack processes `Y 3, 1:` followed by the IM command without
* delay, when a button is pressed.
*
* For Rance4 v2, this does not work because the UI loop also checks keyboard
* status, so we use a different hack. See rance4v2_hack() in sdl_event.c.
*/
static void rance4_Y3_IM_hack() {
static int count;
@@ -82,7 +86,8 @@ void commandY() {
unsigned int p1 = getCaliValue();
unsigned int p2 = getCaliValue();
if (p1 == 1) {
switch (p1) {
case 1:
if (p2 == 0) {
/* メッセージ領域の初期化と、文字の表示位置を左上端にセットする */
msg_nextPage(TRUE);
@@ -90,18 +95,23 @@ void commandY() {
/* メッセージ領域の文字の表示位置を左上端にセットする */
msg_nextPage(FALSE);
}
} else if (p1 == 2) {
break;
case 2:
/*システム変数 D01〜D20 までを初期化する */
for (i = 0; i < 20; i++) {
sysVar[i + 1] = 0;
}
} else if (p1 == 3) {
int orig_pc = sl_getIndex();
if (p2 == 1 && sl_getc() == 'I' && sl_getc() == 'M') {
rance4_Y3_IM_hack();
return;
break;
case 3:
case 1003: // Rance4 ver2.05
{
int orig_pc = sl_getIndex();
if (p2 == 1 && sl_getc() == 'I' && sl_getc() == 'M') {
rance4_Y3_IM_hack();
return;
}
sl_jmpNear(orig_pc);
}
sl_jmpNear(orig_pc);
switch (p2) {
case 10000:
@@ -114,18 +124,35 @@ void commandY() {
sysVar[0] = sys_getInputInfo();
break;
default:
if (p1 == 1003) {
sys_key_releasewait(SYS35KEY_RET, FALSE);
} else if (nact->game == GAME_RANCE4_V2 && p2 == 1) {
// Return immediately if any key is pressed.
sysVar[0] = sys_getInputInfo();
if (sysVar[0])
break;
}
sysVar[0] = sys_keywait(16 * p2, Y3waitFlags | KEYWAIT_SKIPPABLE);
break;
}
} else if (p1 == 4) {
break;
case 4:
/* 1 〜 n までの乱数を RND に返す。*/
if (p2 == 0 || p2 == 1) {
sysVar[0] = p2;
} else {
sysVar[0] = (int)(genrand() * p2) +1;
}
} else {
break;
case 1900:
nact->patch_ec = p2;
// We're sure this game was built for System3.9 v5.50, which by default
// routes CD-DA commands to DRIFILE_WAVE.
muscd_init_bgm(DRIFILE_WAVE, 999);
break;
default:
WARNING("Y undefined command %d", p1);
break;
}
DEBUG_COMMAND("Y %d,%d:",p1,p2);
}
+2 -4
View File
@@ -345,10 +345,8 @@ void commandZZ0() {
sys_exit(sysVar[0]);
#endif
} else if (sw == 1) {
while (TRUE) {
usleep(1000*1000);
sys_getInputInfo();
}
while (!nact->is_quit)
sys_keywait(1000, 0);
}
}
+28 -43
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_getStackInfo(&stack_size);
int page = nact->current_page;
int cap = 16;
@@ -399,26 +398,17 @@ StackTrace *dbg_stack_trace(void) {
set_stack_frame(&trace->frames[0], page, nact->current_addr, false);
trace->nr_frame = 1;
const int *p = stack_base + stack_size - 1;
while (p >= stack_base) {
int addr = -1;
switch (*p) {
case STACK_NEARJMP:
addr = p[-2];
break;
case STACK_FARJMP:
page = p[-2];
addr = p[-3];
break;
struct stack_frame_info *sfi = NULL;
while ((sfi = sl_next_stack_frame(sfi)) != NULL) {
if (sfi->tag != STACK_NEARCALL && sfi->tag != STACK_FARCALL)
continue;
if (trace->nr_frame >= cap) {
cap *= 2;
trace = realloc(trace, sizeof(StackTrace) + cap * sizeof(StackFrame));
}
if (addr >= 0) {
if (trace->nr_frame >= cap) {
cap *= 2;
trace = realloc(trace, sizeof(StackTrace) + cap * sizeof(StackFrame));
}
set_stack_frame(&trace->frames[trace->nr_frame++], page, addr, true);
}
p -= p[-1] + 2;
if (sfi->tag == STACK_FARCALL)
page = sfi->page;
set_stack_frame(&trace->frames[trace->nr_frame++], page, sfi->addr, true);
}
return trace;
@@ -439,26 +429,16 @@ static boolean should_continue_step(void) {
void dbg_stepout(void) {
// Set an internal breakpoint at the return address of current frame.
int stack_size;
const int *stack_base = sl_getStackInfo(&stack_size);
const int *p = stack_base + stack_size - 1;
while (p >= stack_base) {
int page, addr = -1;
switch (*p) {
case STACK_NEARJMP:
page = nact->current_page;
addr = p[-2];
break;
case STACK_FARJMP:
page = p[-2];
addr = p[-3];
break;
}
if (addr >= 0) {
internal_breakpoint = dbg_set_breakpoint(page, addr, true);
struct stack_frame_info *sfi = NULL;
while ((sfi = sl_next_stack_frame(sfi)) != NULL) {
switch (sfi->tag) {
case STACK_NEARCALL:
internal_breakpoint = dbg_set_breakpoint(nact->current_page, sfi->addr, true);
return;
case STACK_FARCALL:
internal_breakpoint = dbg_set_breakpoint(sfi->page, sfi->addr, true);
return;
}
p -= p[-1] + 2;
}
// No parent frame found, continue execution.
}
@@ -550,6 +530,11 @@ void dbg_onsleep(void) {
dbg_impl->onsleep();
}
void dbg_on_palette_change(void) {
if (dbg_impl)
dbg_impl->on_palette_change();
}
boolean dbg_console_vprintf(int lv, const char *format, va_list ap) {
if (!dbg_impl || !dbg_impl->console_output)
return false;
+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->red[i] << 16 |
nact->ags.pal->green[i] << 8 |
nact->ags.pal->blue[i];
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;
+80 -181
View File
@@ -30,169 +30,78 @@
#include "LittleEndian.h"
#include "dri.h"
/*
* static maethods
*/
static long getfilesize(FILE *fp);
static boolean filecheck (FILE *fp);
static void get_filemap(drifiles *d, FILE *fp);
static void get_fileptr(drifiles *d, FILE *fp, int disk);
/*
* Get file size of FILE
* fp: FILE pointer
* return: filesize in byte
*/
static long getfilesize(FILE *fp) {
static bool read_index(int disk, drifiles *d, FILE *fp) {
fseek(fp, 0L, SEEK_END);
return ftell(fp);
}
int filesize = ftell(fp);
/*
* Check whether dri file type or not
* fp: FILE pointer
* return: TRUE if it's dri file
*/
static boolean filecheck (FILE *fp) {
uint8_t b[6];
int mapsize, ptrsize;
long filesize;
/* get filesize / 256 */
filesize = (getfilesize(fp) + 255) >> 8;
/* read top 6bytes */
// Get ptrsize and mapsize
uint8_t hdr[6];
fseek(fp, 0L, SEEK_SET);
fread(b, 1, 6, fp);
/* get ptrsize and mapsize */
ptrsize = LittleEndian_get3B(b, 0);
mapsize = LittleEndian_get3B(b, 3) - ptrsize;
/* must lager than 0 */
if (ptrsize < 0 || mapsize < 0) return FALSE;
/* must smaller than filesize */
if (ptrsize > (int)filesize || mapsize > (int)filesize ) {
return FALSE;
if (fread(hdr, 6, 1, fp) != 1)
return false;
int ptrsize = LittleEndian_get3B(hdr, 0) << 8;
int mapsize = (LittleEndian_get3B(hdr, 3) << 8) - ptrsize;
if (ptrsize <= 0 || mapsize <= 0 || ptrsize + mapsize > filesize)
return false;
// Read the pointer table and the link table
uint8_t *ptbl = malloc(ptrsize + mapsize);
memcpy(ptbl, hdr, 6);
if (fread(ptbl + 6, ptrsize + mapsize - 6, 1, fp) != 1) {
free(ptbl);
return false;
}
return TRUE;
}
uint8_t *ltbl = ptbl + ptrsize;
/*
* Get file map
* d : drifile object
* fp: FILE object
*/
static void get_filemap(drifiles *d, FILE *fp) {
uint8_t b[6], *_b;
int mapsize, ptrsize, i;
/* read top 6bytes */
fseek(fp, 0L, SEEK_SET);
fread(b, 1, 6, fp);
/* get ptrsize and mapsize */
ptrsize = LittleEndian_get3B(b, 0);
mapsize = LittleEndian_get3B(b, 3) - ptrsize;
/* allocate read buffer */
_b = malloc(sizeof(char) * (mapsize << 8));
/* read filemap */
fseek(fp, ptrsize << 8L , SEEK_SET);
fread(_b, 256, mapsize, fp);
/* get max file number from mapdata */
d->maxfile = (mapsize << 8) / 3;
/* map of disk */
d->map_disk = malloc(sizeof(char ) * d->maxfile);
/* map of data in disk */
d->map_ptr = malloc(sizeof(short) * d->maxfile);
for (i = 0; i < d->maxfile; i++) {
/* map_disk[?] and map_ptr[?] are from 0 */
*(d->map_disk + i) = _b[i * 3] - 1;
*(d->map_ptr + i) = LittleEndian_getW(_b, i * 3 + 1) - 1;
// (Re)allocate the index buffers
int nr_files = mapsize / 3;
if (d->nr_files < nr_files) {
d->disk = realloc(d->disk, nr_files);
d->offset = realloc(d->offset, sizeof(uint32_t) * nr_files);
memset(d->disk + d->nr_files, 0, nr_files - d->nr_files);
memset(d->offset + d->nr_files, 0, sizeof(uint32_t) * (nr_files - d->nr_files));
d->nr_files = nr_files;
}
free(_b);
return;
}
/*
* Get data pointer in file
* d : drifile object
* fp : FILE object
* disk: no in drifile object
*/
static void get_fileptr(drifiles *d, FILE *fp, int disk) {
char b[6], *_b;
int ptrsize, filecnt, i;
/* read top 6bytes */
fseek(fp, 0L, SEEK_SET);
fread(b, 1, 6, fp);
/* get pinter size */
ptrsize = LittleEndian_get3B(b,0);
/* estimate file number in file */
filecnt = (ptrsize << 8) / 3;
/* allocate read buffer */
_b = malloc(sizeof(char) * (ptrsize << 8));
/* read pointers */
fseek(fp, 0L, SEEK_SET);
fread(_b, 256, ptrsize, fp);
/* allocate pointers buffer */
d->fileptr[disk] = calloc(filecnt, sizeof(int));
/* store pointers */
for (i = 0; i < filecnt - 1; i++) {
*(d->fileptr[disk] + i) = (LittleEndian_get3B(_b, i * 3 + 3) << 8);
// Parse the index
for (int i = 0; i < nr_files; i++) {
if (disk != ltbl[i * 3] - 1)
continue;
if (d->maxno < i)
d->maxno = i;
d->disk[i] = ltbl[i * 3];
int ptr = LittleEndian_getW(ltbl, i * 3 + 1);
d->offset[i] = LittleEndian_get3B(ptbl, ptr * 3) << 8;
}
free(_b);
return;
free(ptbl);
return true;
}
drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
drifiles *d = calloc(1, sizeof(drifiles));
FILE *fp;
int i;
boolean gotmap = FALSE;
#ifndef HAVE_MEMORY_MAPPED_FILE
use_mmap = FALSE;
#endif
for (i = 0; i < cnt; i++) {
if (file[i] == NULL) continue;
/* open check */
if (NULL == (fp = fopen(file[i], "rb"))) {
SYSERROR("File %s is not found", file[i]);
for (int i = 0; i < cnt; i++) {
if (!file[i])
continue;
FILE *fp = fopen(file[i], "rb");
if (!fp)
SYSERROR("%s: %s", file[i], strerror(errno));
if (!read_index(i, d, fp)) {
// Only errors in *A.ALD are fatal, because some games have
// dummy (invalid) *[B-Z].ALD files.
if (i == 0)
SYSERROR("%s: not an ALD file", file[i]);
WARNING("%s: not an ALD file", file[i]);
fclose(fp);
continue;
}
/* check is drifile or noe */
if (!filecheck(fp)) {
SYSERROR("File %s is not dri file", file[i]);
}
/* get file map */
if (!gotmap) {
get_filemap(d, fp);
gotmap = TRUE;
}
/* get pointer */
get_fileptr(d, fp, i);
/* copy filenme */
d->fnames[i] = strdup(file[i]);
/* close */
fclose(fp);
/* mmap */
if (use_mmap) {
mmap_t *m = map_file(file[i]);
if (!m) {
@@ -207,54 +116,44 @@ drifiles *dri_init(const char **file, int cnt, boolean use_mmap) {
return d;
}
/*
* Get data
* d : drifile object
* no: drifile no ( >= 0 )
* return: dridata obhect
*/
dridata *dri_getdata(drifiles *d, int no) {
if (no < 0 || no >= d->nr_files || !d->disk[no] || !d->offset[no])
return NULL;
int disk = d->disk[no] - 1;
uint8_t *data;
dridata *dfile;
int disk, ptr, dataptr, dataptr2, size;
/* check no is lager than files which contains */
if (no > d->maxfile) return NULL;
/* check disk & ptr are negative, if negative, file does not exist */
disk = d->map_disk[no];
ptr = d->map_ptr[no];
if (disk < 0 || ptr < 0) return NULL;
/* no file registered */
if (d->fileptr[disk] == NULL) return NULL;
/* get pointer in file and size */
dataptr = *(d->fileptr[disk] + ptr);
dataptr2 = *(d->fileptr[disk] + ptr + 1);
if (dataptr == 0 || dataptr2 == 0) return NULL;
/* get data top */
int ptr, size;
if (d->mmapped) {
data = d->mmap[disk]->addr + dataptr;
data = d->mmap[disk]->addr + d->offset[no];
ptr = LittleEndian_getDW(data, 0);
size = LittleEndian_getDW(data, 4);
} else {
int readsize = dataptr2 - dataptr;
FILE *fp;
data = malloc(sizeof(char) * readsize);
fp = fopen(d->fnames[disk], "rb");
fseek(fp, dataptr, SEEK_SET);
fread(data, 1, readsize, fp);
FILE *fp = fopen(d->fnames[disk], "rb");
if (!fp)
return NULL;
uint8_t entry_header[8];
fseek(fp, d->offset[no], SEEK_SET);
if (fread(entry_header, sizeof(entry_header), 1, fp) != 1) {
fclose(fp);
return NULL;
}
ptr = LittleEndian_getDW(entry_header, 0);
size = LittleEndian_getDW(entry_header, 4);
data = malloc(ptr + size);
memcpy(data, entry_header, sizeof(entry_header));
if (fread(data + sizeof(entry_header), ptr + size - sizeof(entry_header), 1, fp) != 1) {
free(data);
fclose(fp);
return NULL;
}
fclose(fp);
}
/* get real data and size */
ptr = LittleEndian_getDW(data, 0);
size = LittleEndian_getDW(data, 4);
dfile = calloc(1, sizeof(dridata));
dridata *dfile = calloc(1, sizeof(dridata));
dfile->data_raw = data; /* dri data header */
dfile->data = data + ptr; /* real data */
dfile->size = size;
dfile->name = data + 16;
dfile->a = d; /* archive file */
return dfile;
}
+7 -13
View File
@@ -28,21 +28,15 @@
#include "mmap.h"
#define DRIFILEMAX 255 /* maximum file number for one data type */
#define DRIDATAMAX 65535 /* maximum file number in one file */
struct _drifiles {
/* for mmap */
boolean mmapped;
mmap_t *mmap[DRIFILEMAX];
/* for file access */
char *fnames[DRIFILEMAX];
/* max file number in files */
int maxfile;
/* file mapping */
char *map_disk;
short *map_ptr;
/* pointers in file */
int *fileptr[DRIFILEMAX];
boolean mmapped;
mmap_t *mmap[DRIFILEMAX];
char *fnames[DRIFILEMAX];
int nr_files; // upper limit on how many files could be referenced by this archive
int maxno;
uint8_t *disk; // file numbers
uint32_t *offset; // offsets in file
};
typedef struct _drifiles drifiles;
+23 -4
View File
@@ -66,6 +66,8 @@ static void storeSaveName(GameResource *gr, int no, char *src) {
boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_readdir)(DIR *)) {
memset(gr, 0, sizeof(GameResource));
char *basename = NULL;
bool found_xsleep = false;
struct dirent* d;
while ((d = p_readdir(dir))) {
char *filename = d->d_name;
@@ -91,6 +93,10 @@ boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_r
switch (toupper(filename[len - 6])) {
case 'S':
storeDataName(gr, DRIFILE_SCO, dno, filename);
if (!basename) {
basename = strdup(filename);
basename[len - 5] = '\0';
}
break;
case 'G':
storeDataName(gr, DRIFILE_CG, dno, filename);
@@ -111,13 +117,26 @@ boolean initGameResourceFromDir(GameResource *gr, DIR *dir, struct dirent *(*p_r
storeDataName(gr, DRIFILE_BGM, dno, filename);
break;
}
} else if (strcasecmp(filename + 1, "sleep.asd") == 0) {
found_xsleep = true;
}
}
for (int i = 0; i < SAVE_MAXNUMBER; i++) {
char buf[] = "asleep.asd";
buf[0] = 'a' + i;
storeSaveName(gr, i, buf);
if (basename && !found_xsleep) {
char *buf = malloc(strlen(basename) + 6);
int a = basename[strlen(basename) - 1] == 'S' ? 'A' : 'a';
for (int i = 0; i < SAVE_MAXNUMBER; i++) {
sprintf(buf, "%s%c.asd", basename, a + i);
storeSaveName(gr, i, buf);
}
free(buf);
} else {
for (int i = 0; i < SAVE_MAXNUMBER; i++) {
char buf[] = "asleep.asd";
buf[0] = 'a' + i;
storeSaveName(gr, i, buf);
}
}
free(basename);
return (gr->cnt[DRIFILE_SCO] > 0) ? TRUE : FALSE;
}
+62 -43
View File
@@ -74,50 +74,69 @@ static struct dirent *mockReaddir(DIR *dir) {
}
static void initGameResourceFromDir_test(void) {
const char *files[] = {
"ADISK.ALD",
"FOOSB.ALD",
"foogz.ald",
"WA.ALD",
"unknownXA.ald",
"a.ald",
".ald",
"a",
"SYSTEM39.AIN",
"foo_WA.WAI",
"foo_BA.BGI",
"SACTEFAM.KLD",
"System39.ini",
"foo1.alk",
"0.alk",
".alk",
NULL
};
const char **dir = files;
GameResource gr;
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, mockReaddir));
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 2);
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "ADISK.ALD");
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][1], "FOOSB.ALD");
ASSERT_EQUAL(gr.cnt[DRIFILE_CG], 26);
ASSERT_STRCMP(gr.game_fname[DRIFILE_CG][25], "foogz.ald");
ASSERT_EQUAL(gr.cnt[DRIFILE_WAVE], 1);
ASSERT_STRCMP(gr.game_fname[DRIFILE_WAVE][0], "WA.ALD");
for (int i = 0; i < 26; i++) {
char buf[16];
sprintf(buf, "%csleep.asd", 'a' + i);
ASSERT_STRCMP(gr.save_fname[i], buf);
{
const char *files[] = {
"FOOSA.ALD",
"FOOSB.ALD",
"foogz.ald",
"WA.ALD",
"unknownXA.ald",
"a.ald",
".ald",
"a",
"SYSTEM39.AIN",
"foo_WA.WAI",
"foo_BA.BGI",
"SACTEFAM.KLD",
"System39.ini",
"foo1.alk",
"0.alk",
".alk",
NULL
};
const char **dir = files;
GameResource gr;
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, mockReaddir));
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 2);
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "FOOSA.ALD");
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][1], "FOOSB.ALD");
ASSERT_EQUAL(gr.cnt[DRIFILE_CG], 26);
ASSERT_STRCMP(gr.game_fname[DRIFILE_CG][25], "foogz.ald");
ASSERT_EQUAL(gr.cnt[DRIFILE_WAVE], 1);
ASSERT_STRCMP(gr.game_fname[DRIFILE_WAVE][0], "WA.ALD");
for (int i = 0; i < 26; i++) {
char buf[16];
sprintf(buf, "FOOS%c.asd", 'A' + i);
ASSERT_STRCMP(gr.save_fname[i], buf);
}
ASSERT_STRCMP(gr.save_path, ".");
ASSERT_STRCMP(gr.ain, "SYSTEM39.AIN");
ASSERT_STRCMP(gr.wai, "foo_WA.WAI");
ASSERT_STRCMP(gr.bgi, "foo_BA.BGI");
ASSERT_STRCMP(gr.sact01, "SACTEFAM.KLD");
ASSERT_STRCMP(gr.init, "System39.ini");
ASSERT_STRCMP(gr.alk[0], "0.alk");
ASSERT_STRCMP(gr.alk[1], "foo1.alk");
for (int i = 2; i < 10; i++)
ASSERT_NULL(gr.alk[i]);
}
{
const char *files[] = {
"ADISK.ALD",
"asleep.asd",
NULL
};
const char **dir = files;
GameResource gr;
ASSERT_TRUE(initGameResourceFromDir(&gr, (DIR *)&dir, mockReaddir));
ASSERT_EQUAL(gr.cnt[DRIFILE_SCO], 1);
ASSERT_STRCMP(gr.game_fname[DRIFILE_SCO][0], "ADISK.ALD");
for (int i = 0; i < 26; i++) {
char buf[16];
sprintf(buf, "%csleep.asd", 'a' + i);
ASSERT_STRCMP(gr.save_fname[i], buf);
}
}
ASSERT_STRCMP(gr.save_path, ".");
ASSERT_STRCMP(gr.ain, "SYSTEM39.AIN");
ASSERT_STRCMP(gr.wai, "foo_WA.WAI");
ASSERT_STRCMP(gr.bgi, "foo_BA.BGI");
ASSERT_STRCMP(gr.sact01, "SACTEFAM.KLD");
ASSERT_STRCMP(gr.init, "System39.ini");
ASSERT_STRCMP(gr.alk[0], "0.alk");
ASSERT_STRCMP(gr.alk[1], "foo1.alk");
for (int i = 2; i < 10; i++)
ASSERT_NULL(gr.alk[i]);
}
void gameresource_test(void) {
-4
View File
@@ -1,4 +0,0 @@
#define GT_TOSHIN2 "闘神都市Ⅱ for Win95 "
#define GT_RANCE4 "Rance4 -教団の遺産- For Win95 "
#define GT_RANCE3_ENG "Rance3"
#define GT_RANCE4_ENG "Rance4 -Legacy of the Sect- For Win95 "
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2023 kichikuou <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 <string.h>
#include "hacks.h"
#include "system.h"
#include "nact.h"
#include "input.h"
// Game titles.
#define GT_TOSHIN2 "闘神都市Ⅱ for Win95 "
#define GT_RANCE4 "Rance4 -教団の遺産- For Win95 "
#define GT_RANCE4_V2 "RanceⅣ -教団の遺産- for Windows "
#define GT_RANCE3_ENG "Rance3"
#define GT_RANCE4_ENG "Rance4 -Legacy of the Sect- For Win95 "
/* defined by cmdy.c */
extern boolean Y3waitFlags;
bool daiakuji_cx_hack;
void enable_hack_by_gameid(const char *gameid) {
if (!strcmp(gameid, "toushin2"))
nact->game = GAME_TT2;
else if (!strcmp(gameid, "rance3_eng"))
nact->game = GAME_RANCE3_ENG;
else if (!strcmp(gameid, "rance4_eng"))
nact->game = GAME_RANCE4_ENG;
else if (!strcmp(gameid, "rance4_v2"))
nact->game = GAME_RANCE4_V2;
else
sys_error("Unknown game id \"%s\"", gameid);
}
void enable_hack_by_title(const char *title_utf8) {
if (!strcmp(title_utf8, GT_RANCE4))
Y3waitFlags = KEYWAIT_NONCANCELABLE;
if (nact->game != GAME_UNKNOWN)
return;
if (!strcmp(title_utf8, GT_TOSHIN2))
nact->game = GAME_TT2;
else if (!strcmp(title_utf8, GT_RANCE4_V2))
nact->game = GAME_RANCE4_V2;
else if (!strcmp(title_utf8, GT_RANCE3_ENG))
nact->game = GAME_RANCE3_ENG;
else if (!strcmp(title_utf8, GT_RANCE4_ENG))
nact->game = GAME_RANCE4_ENG;
}

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