1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-08-30 10:24:51 +00:00

Compare commits

...

40 commits

Author SHA1 Message Date
N.E.C. 8b5406d941 Improve code generation when accessing BorrowedNPC's 2025-08-23 02:15:39 +02:00
N.E.C. c7160c9ea8 Use RefCells in NPCList to prevent Undefined Behavior 2025-08-23 02:15:39 +02:00
Alula 20f541d469 Fix apt install failing on ubuntu-latest sometimes 2025-08-23 02:15:39 +02:00
Alula f5d729c8a1 Refactor: Unify NPC AI handler signature 2025-08-23 02:15:39 +02:00
Alula 2335cf0064 Use HitExtents instead of Rect for hitboxes 2025-08-23 02:15:39 +02:00
biroder f4602687eb Fix editor compilation errors
The `--editor` flag has no practical use and has never been used, so it's been removed.
2025-08-04 23:42:59 +03:00
biroder f4b5df3640 Fix music fading out too quickly 2025-07-22 00:33:36 +03:00
biroder 37aa3f36aa Reduce log file size and fix the error window on Windows doesn't appear
Info that NPC is creating or a script successfuly compiled can be useful for debugging, but on a regular run it just clogs up the log file. If we need such specific info from users, they'll need to reproduce the issue using `--log-level debug` program argument.
2025-07-14 00:24:43 +03:00
biroder 896f43dc1e Fix build with CMake 4.x 2025-07-02 11:58:59 +03:00
biroder adb7a4dff6
Fix typo in default window height 2025-07-01 11:07:19 +03:00
biroder 7b588f0222 Always use a hi-res logo on the title screen for CS+ data (resolve #225, fix #171) 2025-06-30 15:57:06 +03:00
biroder d96f7054e3 Add cli args to set initial window size and fullscreen state (resolve #211)
Fully implemented only for SDL backend. For Glutin backend only the flag to run in fullscreen mode is implemented, since it's broken for PC anyway
2025-06-26 19:45:52 +03:00
Alula 5d68ea9f89 Add issue templates [ci skip] 2025-06-24 06:20:21 +02:00
Edward Stuckey 13e09e8679 Improve background colors
Background color is now set inside of engine_constants/mod.rs, and can be changed on a port-to-port basis, including intro background color.
2025-06-14 21:48:45 +02:00
Edward Stuckey 2f73066d12 Fix intro background color
The intro scene should have a black background, not dark blue.
2025-06-14 21:48:45 +02:00
biroder 5f517e6992
Stop noise when <ESC opcode is executed (fix #244) 2025-06-14 19:36:52 +03:00
biroder 2f1159c14f Add a drop in animation when acquiring an item (fix #277) 2025-05-30 12:59:41 +03:00
biroder 50ea506c53 Fix Android build (bump cpal) 2025-04-28 17:15:56 +03:00
biroder 8fce1cddbc
Update the release notes again
This item is more a project change rather than an application change, so it shouldn't be included in this list as it's unnoticeable to users
2025-04-28 14:51:17 +03:00
biroder a925c4e7e8 Update flatpak metadata [ci skip]
Update screenshots and homepage URL, add release notes and supported control types. Remove the shadow from the app icon, as required by Flathub Quality Guidelines. Also all flatpak-related files are moved to the  folder
2025-04-09 15:50:29 +03:00
Alula eb7bdf4313
ci: 0.102.0 2025-03-08 01:14:58 +01:00
Alula 36e21810df
ci: workflow for actual releases 2025-03-08 01:12:24 +01:00
Alula 70611a8957
fix: do not censor "doukutsu-rs" in CI output [ci skip] 2025-03-08 00:48:28 +01:00
Alula 8d1da15cfd
feat: implement get.doukutsu.rs support 2025-03-08 00:38:28 +01:00
Giantblargg 50cd0e54f5 Remove glFinish
glFinish waits until rendering is complete, there usually isn't a good reason to do this.
Removing it improves performance on (very) low end hardware.
2025-02-22 01:10:07 +01:00
biroder 6973573721 Modify app id for Android debug builds[ci skip]
Also debug builds have `(debug)` in the app name, documents provider label and authority. This is done to make it possible to install custom debug builds without uninstalling the official one.
2025-02-05 23:02:06 +02:00
biroder 71452113ac
Add link to Flatpak 2025-01-15 04:34:49 +02:00
alula a82a536e09
Before you ask, we're not enabling LTO [ci skip] 2025-01-13 11:56:30 +01:00
Tulip Blossom 60cfc47a21
fix: satisfy the flathub linter 😭 (#303)
* fix: satisfy the flathub linter 😭

* Fix the 0.99.0-beta4 release date 

This version was released on May 3, 2022, 1:46 AM UTC

* chore: add instructions on how to get the game data working

* Remove CS+ screenshots, add valid content rating and screenshots caption

The engine is not distributed with the CS+ game data, so this screenshots are not correct for the most of the flatpak users. The content rating is just copy-pasted from the NXEngine package and and should probably be changed in the future
2025-01-13 00:56:54 +00:00
Tulip Blossom 9a0fa2d0ad
feat: add flathub metadata (#302) 2025-01-12 23:16:10 +02:00
biroder 7376875151 Crop Sue properly 2025-01-10 14:13:27 +02:00
biroder deea09407b
Add missing target triple for Android CI 2025-01-10 03:42:41 +02:00
biroder 3ebb02be1d
Fix Android CI 2025-01-10 03:39:13 +02:00
biroder 11d5212f47 Change icon for all platforms 2025-01-10 03:30:09 +02:00
biroder 080bb43429 Add Cargo.lock for Android port and change file naming scheme for stable builds [ci skip]
Also enable support for x86_64 ABI and bump `versionCode` for Android builds. 'local.properties' has been removed, as it must not be tracked by git and can be unintentionally commited with other changes.
2025-01-10 01:31:18 +02:00
biroder 2fc564b498
Change macOS architecture in the release metadata[ci skip] 2025-01-09 01:50:44 +02:00
biroder 2214179e0e
Fix Linux CI 2025-01-08 17:32:38 +02:00
+KZ d9ad87323f
Add macOS Icon (#299) 2025-01-08 17:16:54 +02:00
biroder 8195097363
ci: fix ref_name templating for Android builds [ci skip] 2025-01-06 03:59:17 +02:00
biroder 1c0c68ce48
Remove Kotlin debug file from Android release builds [ci skip] 2025-01-05 00:47:23 +02:00
157 changed files with 8245 additions and 2418 deletions

View file

@ -1,158 +0,0 @@
version: "0.101.0-{build}-{branch}"
skip_commits:
files:
- README.md
- LICENSE
- app/
- drsandroid/
- drshorizon/
environment:
global:
PROJECT_NAME: doukutsu-rs
matrix:
- channel: stable
target: x86_64-pc-windows-msvc
target_name: win64
arch_name: x86_64
job_name: windows-x64
appveyor_build_worker_image: Visual Studio 2019
- channel: stable
target: i686-pc-windows-msvc
target_name: win32
arch_name: i686
job_name: windows-x32
appveyor_build_worker_image: Visual Studio 2019
- channel: stable
target: x86_64-unknown-linux-gnu
target_name: linux
job_name: linux-x64
appveyor_build_worker_image: Ubuntu
- channel: stable
target: x86_64-apple-darwin
target_name: mac-intel
job_name: mac-x64
appveyor_build_worker_image: macos-monterey
- channel: stable
target: aarch64-apple-darwin
target_name: mac-m1
job_name: mac-arm64
appveyor_build_worker_image: macos-monterey
matrix:
fast_finish: true
for:
-
matrix:
only:
- appveyor_build_worker_image: Visual Studio 2019
install:
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- rustup-init -yv --default-toolchain %channel% --default-host %target%
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
- rustup update
- rustup default %channel%
- rustc -vV
- cargo -vV
cache:
- '%USERPROFILE%\.cache'
- '%USERPROFILE%\.cargo\bin'
- '%USERPROFILE%\.cargo\registry\index'
- '%USERPROFILE%\.cargo\registry\cache'
- '%USERPROFILE%\.cargo\git\db'
- '%USERPROFILE%\.rustup'
- 'target'
build_script:
#- set DRS_BUILD_VERSION_OVERRIDE=%APPVEYOR_BUILD_VERSION%
- if "%APPVEYOR_REPO_TAG%" == "true" (set DRS_BUILD_VERSION_OVERRIDE=%APPVEYOR_REPO_TAG_NAME%) else (set DRS_BUILD_VERSION_OVERRIDE=%APPVEYOR_BUILD_VERSION%)
- set CARGO_INCREMENTAL=1
- cargo build --release --bin doukutsu-rs
- mkdir release
- copy LICENSE release\LICENSE
- copy target\release\doukutsu-rs.exe release\doukutsu-rs.%arch_name%.exe
- cd release
- 7z a ../doukutsu-rs_%target_name%.zip *
- appveyor PushArtifact ../doukutsu-rs_%target_name%.zip
-
matrix:
only:
- appveyor_build_worker_image: macos-monterey
init:
- ps: |
if ($env:APPVEYOR_REPO_TAG -eq "true")
{
Update-AppveyorBuild -Version "$env:APPVEYOR_REPO_TAG_NAME"
}
install:
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -yv --default-toolchain $channel
- export PATH=$PATH:$HOME/.cargo/bin
- rustup update
- rustup default $channel
- rustup target add $target
- rustc -vV
- cargo -vV
- cargo install cargo-bundle --force
cache:
- '$HOME/.cache'
- '$HOME/.cargo/bin'
- '$HOME/.cargo/registry/index'
- '$HOME/.cargo/registry/cache'
- '$HOME/.cargo/git/db'
- '$HOME/.rustup'
- 'target'
build_script:
#- export DRS_BUILD_VERSION_OVERRIDE=$APPVEYOR_BUILD_VERSION
- if [ "$APPVEYOR_REPO_TAG" = "true" ]; then export DRS_BUILD_VERSION_OVERRIDE=$APPVEYOR_REPO_TAG_NAME; else export DRS_BUILD_VERSION_OVERRIDE=$APPVEYOR_BUILD_VERSION; fi
- CARGO_INCREMENTAL=1 cargo bundle --release --target $target
- mkdir release
- cp LICENSE ./release/LICENSE
- cp -a target/$target/release/bundle/osx/doukutsu-rs.app ./release/doukutsu-rs.app
- cd release
- codesign -s - -f ./doukutsu-rs.app/Contents/MacOS/doukutsu-rs
- 7z a ../doukutsu-rs_$target_name.zip *
- appveyor PushArtifact ../doukutsu-rs_$target_name.zip
-
matrix:
only:
- appveyor_build_worker_image: Ubuntu
install:
- sudo apt-get update && sudo apt-get -y install libasound2-dev libudev-dev libgl1-mesa-dev pkg-config
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -yv --default-toolchain $channel --default-host $target
- export PATH=$PATH:$HOME/.cargo/bin
- rustup update
- rustup default $channel
- rustc -vV
- cargo -vV
cache:
- '$HOME/.cache'
- '$HOME/.cargo/bin'
- '$HOME/.cargo/registry/index'
- '$HOME/.cargo/registry/cache'
- '$HOME/.cargo/git/db'
- '$HOME/.rustup'
- 'target'
build_script:
#- export DRS_BUILD_VERSION_OVERRIDE=$APPVEYOR_BUILD_VERSION
- if [ "$APPVEYOR_REPO_TAG" = "true" ]; then export DRS_BUILD_VERSION_OVERRIDE=$APPVEYOR_REPO_TAG_NAME; else export DRS_BUILD_VERSION_OVERRIDE=$APPVEYOR_BUILD_VERSION; fi
- RUSTFLAGS="-C link-arg=-s" CARGO_INCREMENTAL=1 cargo build --release --bin doukutsu-rs
- mkdir release
- cp LICENSE ./release/LICENSE
- cp -a target/release/doukutsu-rs ./release/doukutsu-rs.x86_64.elf
- cd release
- 7z a ../doukutsu-rs_$target_name.zip *
- appveyor PushArtifact ../doukutsu-rs_$target_name.zip

View file

@ -0,0 +1,205 @@
name: Bug Report
description: Report a bug or issue with doukutsu-rs
type: "Bug"
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report a bug! Please fill out this form as completely as possible to help us reproduce and fix the issue.
- type: textarea
id: description
attributes:
label: Issue description
description: A clear and concise description of what the bug is.
placeholder: Describe the issue you're experiencing...
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Reproduction steps
description: Steps to reproduce the behavior
placeholder: |
1. Open the game and load the attached save file
2. Go to Mimiga Village
3. Do ...
4. See that ... happens
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
placeholder: What should have happened instead?
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: What **exact** version of doukutsu-rs are you using? For example, "0.102.0-beta7", "0.102.0-733" - you can find it at bottom of the main menu
placeholder: x.xxx.x-xxx
validations:
required: true
- type: dropdown
id: data-files
attributes:
label: Data files used
description: Which Cave Story data files are you using?
options:
- Vanilla Cave Story (1.0.0.6), Japanese
- Vanilla Cave Story (1.0.0.6), AGTP English translation
- Vanilla Cave Story - Another version or translation
- Cave Story+ - Steam version
- Cave Story+ - Epic Games version
- Cave Story+ - GOG version
- Cave Story+ - Humble Bundle DRM-free
- Cave Story+ - Mac App Store version
- Cave Story+ - 2011 Steam version
- Cave Story+ 1.2 - Nintendo Switch version
- Cave Story+ 1.3 - Nintendo Switch version
- Another version not on the list
validations:
required: true
- type: textarea
id: version-details
attributes:
label: Data files details (if applicable)
description: If you selected "Vanilla Cave Story - Another version or translation" or "Another version not on the list" above, please specify which version you're using. Also mention if you have altered data files in any way, such as installing translation mods.
placeholder: Please specify the exact version and any modifications...
validations:
required: false
- type: dropdown
id: platform
attributes:
label: Platform and Operating System
description: What platform and operating system are you using?
options:
- Windows
- Linux
- macOS
- Android
- iOS
- Nintendo Switch Homebrew
- Other (please specify in additional info)
validations:
required: true
- type: textarea
id: device-specs
attributes:
label: Device Model / Specs
description: Please provide your device specifications
placeholder: |
Examples:
- PC, i7-10700K, RTX 3060, 16GB RAM
- MacBook Pro, 14-inch, M3 Pro, 36GB RAM
- Samsung Galaxy S20
- iPhone 15 Pro
- Nintendo Switch OLED
validations:
required: true
- type: textarea
id: system-info
attributes:
label: System Information
description: Please see below for instructions on how to get this information.
placeholder: |
[paste output here, if you're uncomfortable with running commands, just specify everything manually]
Example output:
--- BEGIN SYSTEM INFO ---
OS Version: 15.5 24F74
CPU: Apple M2
RAM: 16384 MB
Manufacturer/Model: Mac14,2
GPUs:
- Apple
--- END SYSTEM INFO ---
render: shell
validations:
required: false
- type: markdown
attributes:
value: |
In case of a PC or Mac, the easiest way to get this is running a command in the command prompt or terminal app and pasting the output here.
For Windows, run the following command in command prompt:
```powershell
powershell.exe -NoProfile -Command "& {Write-Host ''; Write-Host ''; Write-Host '--- BEGIN SYSTEM INFO ---'; $os = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue; $cpu = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue; $computer = Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue; $gpus = Get-CimInstance Win32_VideoController -ErrorAction SilentlyContinue; Write-Host 'OS Version: $($os.Caption) $($os.OSArchitecture) Build $($os.BuildNumber)'; Write-Host 'CPU: $($cpu.Name)'; Write-Host 'Manufacturer: $($computer.Manufacturer)'; Write-Host 'Model: $($computer.Model)'; Write-Host 'RAM: $($computer.TotalPhysicalMemory / 1MB) MB'; if ($gpus) { $i=1; foreach ($gpu in $gpus) { Write-Host "GPU $($i): $($gpu.Caption)"; $i++ } } else { Write-Host 'GPU: Unknown' }; Write-Host '--- END SYSTEM INFO ---'; Write-Host ''; Write-Host ''}"
```
For Linux, run the following command in terminal and paste the output here:
```bash
printf "\n\n--- BEGIN SYSTEM INFO ---\n"; printf "OS Version: %s\n" "$(lsb_release -d -r -c 2>/dev/null | awk -F':\t' '{print $2}' | paste -s -d' ' || cat /etc/os-release 2>/dev/null | grep "PRETTY_NAME" | awk -F'=' '{print $2}' | tr -d '\"' || echo 'Unknown')"; printf "CPU Architecture: %s\n" "$(uname -m 2>/dev/null || echo 'Unknown')"; printf "CPU Model: %s\n" "$(lscpu 2>/dev/null | grep "Model name" | awk -F': *' '{print $2}' || echo 'Unknown')"; printf "RAM: %s MB\n" "$(grep MemTotal /proc/meminfo 2>/dev/null | awk '{print int($2 / 1024)}' || echo 'Unknown')"; printf "System Manufacturer/Model: %s\n" "$(cat /sys/class/dmi/id/board_vendor 2>/dev/null || echo 'Unknown') $(cat /sys/class/dmi/id/board_name 2>/dev/null || echo 'Unknown')"; printf "GPUs:\n%s\n" "$(lspci -vnn 2>/dev/null | grep -i 'VGA compatible controller\|3D controller' | awk -F': ' '{print " - " $2}' | sed 's/ (rev .*//' || echo ' - Unknown')"; printf "--- END SYSTEM INFO ---\n\n\n"
```
For macOS, run the following command in terminal and paste the output here:
```bash
printf "\n\n--- BEGIN SYSTEM INFO ---\n"; printf "OS Version: %s %s\n" "$(sw_vers -productVersion 2>/dev/null || echo 'Unknown')" "$(sw_vers -buildVersion 2>/dev/null || echo 'Unknown')"; printf "CPU: %s\n" "$(sysctl -n machdep.cpu.brand_string 2>/dev/null || echo 'Unknown')"; printf "RAM: %s MB\n" "$(sysctl -n hw.memsize 2>/dev/null | awk '{print int($1 / (1024*1024))}' || echo 'Unknown')"; printf "Manufacturer/Model: %s\n" "$(system_profiler SPHardwareDataType 2>/dev/null | awk '/Model Identifier/{print $3}' || echo 'Unknown')"; printf "GPUs:\n%s\n" "$(system_profiler SPDisplaysDataType 2>/dev/null | awk '/Chipset Model/{print " - " $3}' | sed 's/ - Unknown//g' || echo ' - Unknown')"; printf "--- END SYSTEM INFO ---\n\n\n"
```
If you're running macOS on non-Apple hardware (Hackintosh), please manually add relevant information.
In case of Android, iOS or Nintendo Switch, you need to fill out it manually.
Android:
```
Android Version: 15
[ROM / OEM UI Type and Version, as best as you can, for example:]
System: OneUI 6.1.1
System: MIUI Global 14.0.4.0(RKOMIXM)
System: Xiaomi HyperOS 1.0.5.0.UNLINXM
System: Google Pixel, Android 15, Security Update October 5, 2024
System: LineageOS 21-20250123-NIGHTLY-marble
```
iOS:
```
iOS Version: 18.5
```
Nintendo Switch:
```
System Version: 20.1.5
Atmosphere Version: 1.9.1
```
- type: textarea
id: screenshots
attributes:
label: Screenshots / Videos
description: If applicable, add screenshots or videos to help explain your problem. You can drag and drop files here.
placeholder: Drag and drop files here or click to upload...
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context about the problem here, such as error messages, logs, or anything else that might be helpful.
placeholder: Any additional information that might help us understand the issue...
validations:
required: false
- type: checkboxes
id: terms
attributes:
label: Verification
description: Please confirm the following
options:
- label: "I have searched for existing issues and this is not a duplicate."
required: true
- label: "I understand that 3rd party ports and modifications such as the RetroArch port or Cave Story: Encore are not supported within this repository."
required: true
- label: "I have provided all the requested information to the best of my ability."
required: true

View file

@ -0,0 +1,55 @@
name: Feature Request
description: Suggest a new feature or improvement for doukutsu-rs
type: "Feature"
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a feature! Please fill out this form to help us understand your idea and how it could improve doukutsu-rs.
- type: textarea
id: feature-description
attributes:
label: Feature description
description: A clear and concise description of the feature or improvement you are proposing.
placeholder: Describe the feature you want to see...
validations:
required: true
- type: textarea
id: motivation
attributes:
label: Motivation
description: Why do you want this feature? What problem does it solve or what value does it add?
placeholder: Explain why this feature would be useful...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Possible alternatives or workarounds
description: Have you considered any alternative solutions or workarounds?
placeholder: List any alternatives you've thought of, or say N/A...
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context, mockups, or screenshots about the feature request here.
placeholder: Any extra information, images, or context...
validations:
required: false
- type: checkboxes
id: terms
attributes:
label: Verification
description: Please confirm the following
options:
- label: "I have searched for existing issues and feature requests and this is not a duplicate."
required: true
- label: "I have described the feature clearly and provided all relevant information."
required: true

26
.github/ISSUE_TEMPLATE/003-todo.yml vendored Normal file
View file

@ -0,0 +1,26 @@
name: Task
description: This is a template for maintainers to use. Please do not submit issues using this template, unless asked by a maintainer.
type: "Task"
body:
- type: markdown
attributes:
value: |
Use this template to create a TO-DO task for the doukutsu-rs project.
- type: textarea
id: plan
attributes:
label: Plan
description: Describe the exact plan for what needs to be implemented or fixed.
placeholder: Describe the specific plan, implementation details, or approach...
validations:
required: true
- type: textarea
id: context
attributes:
label: Context
description: Any additional context, background information, or related issues.
placeholder: Add any relevant context, links to related issues, or background info...
validations:
required: false

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Submit a question, idea or discuss with the community
url: https://github.com/doukutsu-rs/doukutsu-rs/discussions
about: Get help using doukutsu-rs
- name: Join the Discord community
url: https://eslint.org/chat
about: Talk with the team

View file

@ -5,21 +5,25 @@ on:
branches-ignore:
- cpp-rewrite
- horizon-os
- refactor
paths-ignore:
- '.gitignore'
- '.github/*'
- '**.md'
- 'LICENSE'
- 'drshorizon/**'
- 'res/**'
- ".gitignore"
- ".github/*"
- "**.md"
- "LICENSE"
- "drshorizon/**"
- "res/**"
workflow_dispatch:
release:
types:
- released
defaults:
run:
shell: bash
env:
VERSION: "0.101.0"
VERSION: "0.102.0"
jobs:
build:
@ -52,17 +56,35 @@ jobs:
channel: stable
target: x86_64-apple-darwin
target_name: mac-x64
arch_name: x86_64
- name: macOS ARM64 (M1 Macs)
os: macos-latest
channel: stable
target: aarch64-apple-darwin
target_name: mac-arm64
arch_name: arm64
steps:
- uses: actions/checkout@v4
- name: Install dependencies
if: ${{ matrix.os == 'ubuntu-latest' }}
run: sudo apt install libasound2-dev libudev-dev libgl1-mesa-dev
run: |
sudo apt update
sudo apt install libasound2-dev libudev-dev libgl1-mesa-dev libxext-dev
- name: Set version
id: set_version
run: |
if [ "${{ github.ref_type }}" == "tag" ]; then
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
echo "channel=stable" >> $GITHUB_OUTPUT
elif [ "${{ github.ref_name }}" == "master" ]; then
echo "version=${{ env.VERSION }}-$((${{ github.run_number }} + 654))" >> $GITHUB_OUTPUT
echo "channel=nightly" >> $GITHUB_OUTPUT
else
echo "version=${{ env.VERSION }}-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
echo "channel=nightly" >> $GITHUB_OUTPUT
fi
- name: Restore cache
uses: actions/cache/restore@v4
@ -77,37 +99,39 @@ jobs:
run: |
rustup default ${{ matrix.channel }}
rustup target add ${{ matrix.target }}
rustc -vV
cargo -vV
if [ "${{ runner.os }}" == "macOS" ]; then
cargo install cargo-bundle
fi
- name: Build
run: |
if [ "${{ github.ref_type }}" == "tag" ]; then
export DRS_BUILD_VERSION_OVERRIDE="${{ github.ref_name }}"
elif [ "${{ github.ref_name }}" == "master"]; then
export DRS_BUILD_VERSION_OVERRIDE="${{ env.VERSION }}-$((${{ github.run_number }} + 654))"
else
export DRS_BUILD_VERSION_OVERRIDE="${{ env.VERSION }}-${GITHUB_SHA:0:7}"
if [ -z "${{ steps.set_version.outputs.version }}" ]; then
echo "version is not set"
exit 1
fi
export DRS_BUILD_VERSION_OVERRIDE="${{ steps.set_version.outputs.version }}"
mkdir release
cp LICENSE release
if [ "${{ runner.os }}" == "macOS" ]; then
CARGO_INCREMENTAL=1 cargo bundle --release --target ${{ matrix.target }}
cp -a ./target/${{ matrix.target }}/release/bundle/osx/doukutsu-rs.app release/doukutsu-rs.app
codesign -s - -f ./release/doukutsu-rs.app/Contents/MacOS/doukutsu-rs
cd release
zip -9r "doukutsu-rs_mac-${{ matrix.arch_name }}.zip" doukutsu-rs.app
rm -rf doukutsu-rs.app
cd ..
elif [ "${{ runner.os }}" == "Windows" ]; then
CARGO_INCREMENTAL=1 cargo build --release --bin doukutsu-rs --target ${{ matrix.target }}
CARGO_INCREMENTAL=1 cargo build --release --locked --bin doukutsu-rs --target ${{ matrix.target }}
cp ./target/${{ matrix.target }}/release/doukutsu-rs.exe release/doukutsu-rs.${{ matrix.arch_name }}.exe
elif [ "${{ runner.os }}" == "Linux" ]; then
RUSTFLAGS="-C link-args=-s" CARGO_INCREMENTAL=1 cargo build --release --bin doukutsu-rs
cp -a ./target/release/doukutsu-rs release/doukutsu-rs.${{ matrix.arch_name }}.elf
RUSTFLAGS="-C link-args=-s" CARGO_INCREMENTAL=1 cargo build --release --locked --bin doukutsu-rs --target ${{ matrix.target }}
cp -a ./target/${{ matrix.target }}/release/doukutsu-rs release/doukutsu-rs.${{ matrix.arch_name }}.elf
fi
- name: Upload artifact
@ -134,6 +158,11 @@ jobs:
APP_OUTPUTS_DIR: "app/app/build/outputs/apk/release"
strategy:
fail-fast: true
matrix:
include:
- name: Android
os: ubuntu-latest
channel: stable
steps:
- uses: actions/checkout@v4
- name: Restore cache
@ -152,7 +181,7 @@ jobs:
- name: Setup rust toolchain
run: |
rustup default stable
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
rustc -vV
cargo -vV
cargo install cargo-ndk
@ -161,31 +190,45 @@ jobs:
run: |
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install --package_file=app/app/packages.txt
- name: Build
- name: Set version
id: set_version
run: |
if [ "${{ github.ref_type }}" == "tag" ]; then
export DRS_BUILD_VERSION_OVERRIDE="{{ github.ref_name }}"
elif [ "${{ github.ref_name }}" == "master"]; then
export DRS_BUILD_VERSION_OVERRIDE="${{ env.VERSION }}-$((${{ github.run_number }} + 654))"
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
echo "channel=stable" >> $GITHUB_OUTPUT
elif [ "${{ github.ref_name }}" == "master" ]; then
echo "version=${{ env.VERSION }}-$((${{ github.run_number }} + 654))" >> $GITHUB_OUTPUT
echo "channel=nightly" >> $GITHUB_OUTPUT
else
export DRS_BUILD_VERSION_OVERRIDE="${{ env.VERSION }}-${GITHUB_SHA:0:7}"
echo "version=${{ env.VERSION }}-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
echo "channel=nightly" >> $GITHUB_OUTPUT
fi
- name: Build
run: |
if [ -z "${{ steps.set_version.outputs.version }}" ]; then
echo "version is not set"
exit 1
fi
export DRS_BUILD_VERSION_OVERRIDE="${{ steps.set_version.outputs.version }}"
cd app
touch local.properties
chmod +x ./gradlew
./gradlew assembleRelease
- name: Sign app
run: |
BUILD_TOOLS=$ANDROID_HOME/build-tools/33.0.0
echo "${{ secrets.ANDROID_SIGNING_KEYSTORE }}" | base64 --decode > keystore.jks
if [ "${{ secrets.ANDROID_SIGNING_KEY_PASS }}" != "" ]; then
$BUILD_TOOLS/apksigner sign --ks ./keystore.jks --ks-key-alias "${{ secrets.ANDROID_SIGNING_ALIAS }}" --ks-pass "pass:${{ secrets.ANDROID_SIGNING_KEYSTORE_PASS }}" --key-pass "pass:${{ secrets.ANDROID_SIGNING_KEY_PASS }}" --out $APP_OUTPUTS_DIR/app-signed.apk $APP_OUTPUTS_DIR/app-release-unsigned.apk
else
$BUILD_TOOLS/apksigner sign --ks ./keystore.jks --ks-key-alias "${{ secrets.ANDROID_SIGNING_ALIAS }}" --ks-pass "pass:${{ secrets.ANDROID_SIGNING_KEYSTORE_PASS }}" --out $APP_OUTPUTS_DIR/app-signed.apk $APP_OUTPUTS_DIR/app-release-unsigned.apk
fi
rm keystore.jks
- name: Prepare artifact
@ -218,25 +261,52 @@ jobs:
update_metadata:
name: Update metadata
runs-on: ubuntu-latest
if: ${{ github.ref_type != 'tag' && always() }}
if: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }}
needs: [build, build_android]
permissions:
contents: write
env:
CF_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
CF_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_BUCKET_NAME: "doukutsu-rs"
steps:
- uses: actions/checkout@v4
with:
repository: doukutsu-rs/metadata
token: ${{ secrets.METADATA_USER_TOKEN }}
- name: Set version
id: set_version
run: |
if [ "${{ github.ref_type }}" == "tag" ]; then
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
echo "channel=stable" >> $GITHUB_OUTPUT
elif [ "${{ github.ref_name }}" == "master" ]; then
echo "version=${{ env.VERSION }}-$((${{ github.run_number }} + 654))" >> $GITHUB_OUTPUT
echo "channel=nightly" >> $GITHUB_OUTPUT
else
echo "version=${{ env.VERSION }}-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
echo "channel=nightly" >> $GITHUB_OUTPUT
fi
mkdir -p releases/${{ steps.set_version.outputs.version }}
- name: Update metadata
id: metadata
run: |
export FILE="./metadata/nightly.json"
if [ "${{ github.ref_name }}" == "master" ]; then
export VERSION="${{ env.VERSION }}-$((${{ github.run_number }} + 654))"
else
export VERSION="${{ env.VERSION }}-${GITHUB_SHA:0:7}"
# fail early if ${{ steps.set_version.outputs.* }} is not set
if [ -z "${{ steps.set_version.outputs.channel }}" ]; then
echo "channel is not set"
exit 1
fi
if [ -z "${{ steps.set_version.outputs.version }}" ]; then
echo "version is not set"
exit 1
fi
export FILE="./metadata/${{ steps.set_version.outputs.channel }}.json"
export VERSION="${{ steps.set_version.outputs.version }}"
if [ "${{ needs.build.result }}" == "success" ]; then
node ./metadata.js --os linux --arch x86_64 --version $VERSION --commit $GITHUB_SHA --link https://nightly.link/doukutsu-rs/doukutsu-rs/actions/runs/${{ github.run_id }}/doukutsu-rs_linux-x64.zip $FILE
@ -250,13 +320,108 @@ jobs:
node ./metadata.js --os android --version $VERSION --commit $GITHUB_SHA --link https://nightly.link/doukutsu-rs/doukutsu-rs/actions/runs/${{ github.run_id }}/doukutsu-rs_android.zip $FILE
fi
mkdir -p release-binaries
echo "file=$FILE" >> "$GITHUB_OUTPUT"
# Windows x32 build
- name: Download Windows x32 artifact
if: ${{ needs.build.result == 'success' }}
uses: actions/download-artifact@v4
with:
name: doukutsu-rs_windows-x32
path: temp-windows-x32
- name: Process Windows x32 build
if: ${{ needs.build.result == 'success' }}
run: |
node ./uploadBuild.js update --channel ${{ steps.set_version.outputs.channel }} --version "${{ steps.set_version.outputs.version }}" --platform windows --arch i686 --commit $GITHUB_SHA --file "temp-windows-x32/doukutsu-rs.i686.exe"
cp ./temp-windows-x32/doukutsu-rs.i686.exe "./release-binaries/doukutsu-rs_windows_${{ steps.set_version.outputs.version }}.i686.exe"
# Windows x64 build
- name: Download Windows x64 artifact
if: ${{ needs.build.result == 'success' }}
uses: actions/download-artifact@v4
with:
name: doukutsu-rs_windows-x64
path: temp-windows-x64
- name: Process Windows x64 build
if: ${{ needs.build.result == 'success' }}
run: |
node ./uploadBuild.js update --channel ${{ steps.set_version.outputs.channel }} --version "${{ steps.set_version.outputs.version }}" --platform windows --arch x86_64 --commit $GITHUB_SHA --file "temp-windows-x64/doukutsu-rs.x86_64.exe"
cp ./temp-windows-x64/doukutsu-rs.x86_64.exe "./release-binaries/doukutsu-rs_windows_${{ steps.set_version.outputs.version }}.x86_64.exe"
# Linux x64 build
- name: Download Linux x64 artifact
if: ${{ needs.build.result == 'success' }}
uses: actions/download-artifact@v4
with:
name: doukutsu-rs_linux-x64
path: temp-linux-x64
- name: Process Linux x64 build
if: ${{ needs.build.result == 'success' }}
run: |
node ./uploadBuild.js update --channel ${{ steps.set_version.outputs.channel }} --version "${{ steps.set_version.outputs.version }}" --platform linux --arch x86_64 --commit $GITHUB_SHA --file "temp-linux-x64/doukutsu-rs.x86_64.elf"
cp ./temp-linux-x64/doukutsu-rs.x86_64.elf "./release-binaries/doukutsu-rs_linux_${{ steps.set_version.outputs.version }}.x86_64.elf"
# macOS x64 build
- name: Download macOS x64 artifact
if: ${{ needs.build.result == 'success' }}
uses: actions/download-artifact@v4
with:
name: doukutsu-rs_mac-x64
path: temp-mac-x64
- name: Process macOS x64 build
if: ${{ needs.build.result == 'success' }}
run: |
node ./uploadBuild.js update --channel ${{ steps.set_version.outputs.channel }} --version "${{ steps.set_version.outputs.version }}" --platform macos --arch x86_64 --commit $GITHUB_SHA --file "temp-mac-x64/doukutsu-rs_mac-x86_64.zip"
cp ./temp-mac-x64/doukutsu-rs_mac-x86_64.zip "./release-binaries/doukutsu-rs_macos_${{ steps.set_version.outputs.version }}.x86_64.zip"
# macOS ARM64 build
- name: Download macOS ARM64 artifact
if: ${{ needs.build.result == 'success' }}
uses: actions/download-artifact@v4
with:
name: doukutsu-rs_mac-arm64
path: temp-mac-arm64
- name: Process macOS ARM64 build
if: ${{ needs.build.result == 'success' }}
run: |
node ./uploadBuild.js update --channel ${{ steps.set_version.outputs.channel }} --version "${{ steps.set_version.outputs.version }}" --platform macos --arch arm64 --commit $GITHUB_SHA --file "temp-mac-arm64/doukutsu-rs_mac-arm64.zip"
cp ./temp-mac-arm64/doukutsu-rs_mac-arm64.zip "./release-binaries/doukutsu-rs_macos_${{ steps.set_version.outputs.version }}.arm64.zip"
# Android build
- name: Download Android artifact
if: ${{ needs.build_android.result == 'success' }}
uses: actions/download-artifact@v4
with:
name: doukutsu-rs_android
path: temp-android
- name: Process Android build
if: ${{ needs.build_android.result == 'success' }}
run: |
node ./uploadBuild.js update --channel ${{ steps.set_version.outputs.channel }} --version "${{ steps.set_version.outputs.version }}" --platform android --arch universal --commit $GITHUB_SHA --file "temp-android/doukutsu-rs.apk"
cp ./temp-android/doukutsu-rs.apk "./release-binaries/doukutsu-rs_android_${{ steps.set_version.outputs.version }}.universal.apk"
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
if: ${{ github.ref_type == 'tag' }}
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: release-binaries/*
tag: ${{ github.ref }}
overwrite: true
file_glob: true
- name: Upload metadata
run: |
git config user.name ${{ vars.METADATA_USER_NAME }}
git config user.email ${{ vars.METADATA_USER_EMAIL }}
git add ${{ steps.metadata.outputs.file }}
git commit -m "Update nightly builds metadata(CI)"
git commit -m "Update ${{ steps.set_version.outputs.channel }} builds metadata(CI)"
git push

View file

@ -1,46 +0,0 @@
name: Release
on:
release:
types:
- released
defaults:
run:
shell: bash
jobs:
update_metadata:
name: Update metadata
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
repository: doukutsu-rs/metadata
token: ${{ secrets.METADATA_USER_TOKEN }}
- name: Update metadata
id: metadata
run: |
export VERSION="${{ github.event.release.tag_name }}"
export FILE="./metadata/stable.json"
node ./metadata.js --os windows --arch x86_64 --version $VERSION --link https://github.com/doukutsu-rs/doukutsu-rs/releases/download/$VERSION/doukutsu-rs.windows.x86_64.$VERSION.exe $FILE
node ./metadata.js --os windows --arch i686 --version $VERSION --link https://github.com/doukutsu-rs/doukutsu-rs/releases/download/$VERSION/doukutsu-rs.windows.i686.$VERSION.exe $FILE
node ./metadata.js --os macos --arch x86_64 --version $VERSION --link https://github.com/doukutsu-rs/doukutsu-rs/releases/download/$VERSION/doukutsu-rs.macos.x86_64.$VERSION.zip $FILE
node ./metadata.js --os macos --arch arm64 --version $VERSION --link https://github.com/doukutsu-rs/doukutsu-rs/releases/download/$VERSION/doukutsu-rs.macos.arm64.$VERSION.zip $FILE
node ./metadata.js --os linux --arch x86_64 --version $VERSION --link https://github.com/doukutsu-rs/doukutsu-rs/releases/download/$VERSION/doukutsu-rs.linux.x86_64.$VERSION.elf $FILE
node ./metadata.js --os android --version $VERSION --link https://github.com/doukutsu-rs/doukutsu-rs/releases/download/$VERSION/doukutsu-rs.android.$VERSION.apk $FILE
echo "file=$FILE" >> "$GITHUB_OUTPUT"
- name: Upload metadata
run: |
git config user.name ${{ vars.METADATA_USER_NAME }}
git config user.email ${{ vars.METADATA_USER_EMAIL }}
git add ${{ steps.metadata.outputs.file }}
git commit -m "Update stable builds metadata(CI)"
git push

2
.gitignore vendored
View file

@ -61,3 +61,5 @@ ehthumbs_vista.db
$RECYCLE.BIN/
*.log
3rdparty/

1053
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
[package]
name = "doukutsu-rs"
description = "A re-implementation of Cave Story (Doukutsu Monogatari) engine"
version = "0.101.0"
version = "0.102.0"
authors = ["Alula", "dawnDus"]
edition = "2021"
rust-version = "1.65"
@ -17,10 +17,9 @@ bench = false
required-features = ["exe"]
[profile.release]
# This is intentional. Enabling LTO inflates build times and does not provide us any significant benefits.
lto = "off"
panic = "abort"
codegen-units = 256
incremental = true
split-debuginfo = "packed"
[profile.dev.package."*"]
@ -31,7 +30,8 @@ codegen-units = 256
[package.metadata.bundle]
name = "doukutsu-rs"
identifier = "io.github.doukutsu_rs"
version = "0.101.0"
icon = ["res/macos/16x16.png", "res/macos/16x16@2x.png", "res/macos/32x32.png", "res/macos/32x32@2x.png", "res/macos/128x128.png", "res/macos/128x128@2x.png", "res/macos/256x256.png", "res/macos/256x256@2x.png", "res/macos/512x512.png", "res/macos/512x512@2x.png"]
version = "0.102.0"
resources = ["data"]
copyright = "Copyright (c) 2020-2023 doukutsu-rs contributors"
category = "Game"
@ -58,9 +58,10 @@ android = []
#sdl2-sys = { path = "./3rdparty/rust-sdl2/sdl2-sys", optional = true, features = ["bundled", "static-link"] }
#cpal = { path = "./3rdparty/cpal" }
byteorder = "1.4"
clap = { version = "4.5.40", default_features = false, features = ["std", "help", "usage", "error-context", "cargo", "derive"] }
case_insensitive_hashmap = "1.0.0"
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
cpal = { git = "https://github.com/doukutsu-rs/cpal", rev = "9d269d8724102404e73a61e9def0c0cbc921b676" }
cpal = { git = "https://github.com/doukutsu-rs/cpal", rev = "ce731c58b7f4759a0f4007b392e2b7f4716a347c" }
directories = "3"
discord-rich-presence = { version = "0.2", optional = true }
downcast = "0.11"
@ -78,8 +79,8 @@ num-traits = "0.2"
open = "3.2"
paste = "1.0"
pelite = { version = ">=0.9.2", default-features = false, features = ["std"] }
sdl2 = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "f2f1e29a416bcc22f2faf411866db2c8d9536308", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
sdl2-sys = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "f2f1e29a416bcc22f2faf411866db2c8d9536308", optional = true, features = ["bundled", "static-link"] }
sdl2 = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "244ae85833cff4f97ab4b58331741be20e422bd7", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
sdl2-sys = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "244ae85833cff4f97ab4b58331741be20e422bd7", optional = true, features = ["bundled", "static-link"] }
rc-box = "1.2.0"
serde = { version = "1", features = ["derive"] }
serde_derive = "1"
@ -87,16 +88,12 @@ serde_cbor = { version = "0.11", optional = true }
serde_json = "1.0"
strum = "0.24"
strum_macros = "0.24"
# remove and replace when extract_if is in stable
# remove and replace with extract_if, when our MSRV is 1.87
vec_mut_scan = "0.4"
webbrowser = { version = "0.8.6", optional = true }
winit = { git = "https://github.com/doukutsu-rs/winit.git", rev = "878f206d19af01b0977277929eee5e32667453c0", optional = true, default_features = false, features = ["x11"] }
xmltree = "0.10"
#hack to not link SDL_image on Windows(causes a linker error)
[target.'cfg(not(target_os = "windows"))'.dependencies]
sdl2 = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "f2f1e29a416bcc22f2faf411866db2c8d9536308", optional = true, features = ["image", "unsafe_textures", "bundled", "static-link"] }
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winuser"] }

View file

@ -7,6 +7,11 @@ in [Rust](https://www.rust-lang.org/).
[![CI](https://github.com/doukutsu-rs/doukutsu-rs/actions/workflows/ci.yml/badge.svg?branch=master)](https://nightly.link/doukutsu-rs/doukutsu-rs/workflows/ci/master?preview)
- Get stable/beta builds from
- [get.doukutsu.rs](https://get.doukutsu.rs)
- [GitHub Releases](https://github.com/doukutsu-rs/doukutsu-rs/releases)
- [Flatpak](https://flathub.org/apps/io.github.doukutsu_rs.doukutsu-rs) (Linux only)
- [Get nightly builds](https://nightly.link/doukutsu-rs/doukutsu-rs/workflows/ci/master?preview) (recommended for now, has latest fixes and improvements)
Permalinks to latest builds from `master` branch:
@ -18,8 +23,6 @@ in [Rust](https://www.rust-lang.org/).
- [Linux (64-bit)](https://nightly.link/doukutsu-rs/doukutsu-rs/workflows/ci/master/doukutsu-rs_linux-x64.zip)
- [Android (armv7/arm64/x86)](https://nightly.link/doukutsu-rs/doukutsu-rs/workflows/ci/master/doukutsu-rs_android.zip)
- [Get stable/beta builds from GitHub Releases](https://github.com/doukutsu-rs/doukutsu-rs/releases)
> [!NOTE]
> macOS note: If you get a `"doukutsu-rs" can't be opened` message, right-click doukutsu-rs.app and click open.
@ -233,6 +236,7 @@ To change, use the control customization menu or edit `doukutsu-rs\data\settings
#### Credits
- Studio Pixel/Nicalis for Cave Story
- [AppleHair](https://github.com/AppleHair) - icon redesign for all platforms(`crabsue-icon`).
- [@Daedily](https://twitter.com/Daedliy) - brand artwork (Icon / Banner / Server), screenshots for this guide.
- [ggez](https://github.com/ggez/ggez) - parts of it are used in `crate::framework`, notably the VFS code.
- [Clownacy](https://github.com/Clownacy) - widescreen camera code.

View file

@ -19,8 +19,8 @@ android {
applicationId "io.github.doukutsu_rs"
minSdkVersion 24
targetSdkVersion 33
versionCode 2
versionName "0.101.0"
versionCode 3
versionName "0.102.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -36,13 +36,12 @@ android {
}
def documentsAuthorityValue = applicationId + ".documents"
manifestPlaceholders =
[documentsAuthority: documentsAuthorityValue]
manifestPlaceholders = [documentsAuthority: documentsAuthorityValue]
buildConfigField "String",
"DOCUMENTS_AUTHORITY",
"\"${documentsAuthorityValue}\""
resValue "string", "app_name", "doukutsu-rs"
}
buildTypes {
@ -51,13 +50,29 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
ndk {
abiFilters 'x86', 'arm64-v8a', 'armeabi-v7a'
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
stl = "c++_shared"
}
packagingOptions {
resources {
excludes += "**/DebugProbesKt.bin"
}
}
}
debug {
applicationIdSuffix ".debug"
resValue "string", "app_name", "doukutsu-rs (debug)"
jniDebuggable true
renderscriptDebuggable true
def documentsAuthorityValue =
android.defaultConfig.applicationId + applicationIdSuffix + ".documents"
manifestPlaceholders = [documentsAuthority: documentsAuthorityValue]
buildConfigField "String",
"DOCUMENTS_AUTHORITY",
"\"${documentsAuthorityValue}\""
}
}
@ -105,10 +120,12 @@ cargoNdk {
buildTypes {
release {
buildType = "release"
extraCargoBuildArguments = ["--locked"]
targets = [
"x86",
"arm64",
"arm",
"arm64"
"x86",
"x86_64"
]
}
debug {

View file

@ -21,7 +21,7 @@
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:label="doukutsu-rs"
android:label="@string/app_name"
android:launchMode="standard"
android:screenOrientation="sensorLandscape"
android:theme="@style/Theme.Doukutsurs.NoActionBar">
@ -51,7 +51,7 @@
<provider
android:name=".DoukutsuDocumentsProvider"
android:authorities="${documentsAuthority}"
android:authorities="${applicationId}.documents"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 254 KiB

View file

@ -5,22 +5,22 @@
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"

View file

@ -5,166 +5,6 @@
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:fillColor="@color/ic_launcher_background"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/icon_sue_background"/>
<foreground android:drawable="@mipmap/icon_sue_foreground"/>
</adaptive-icon>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/icon_sue_background"/>
<foreground android:drawable="@mipmap/icon_sue_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FD7F44</color>
<color name="icon_sue_background">#FD7F44</color>
</resources>

View file

@ -1,5 +1,4 @@
<resources>
<string name="app_name" translatable="false">doukutsu-rs</string>
<string name="app_description">A faithful and open-source remake of Cave Story engine written in Rust.</string>
<string name="missing_data_title">Missing data files</string>

View file

View file

@ -12,7 +12,7 @@ fn main() {
#[cfg(target_os = "windows")]
if target.contains("windows") {
let mut res = winres::WindowsResource::new();
res.set_icon("res/sue.ico");
res.set_icon("res/crabsue-icon.ico");
res.compile().unwrap();
if target.contains("i686") {

2756
drsandroid/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@ pub fn android_main() {
std::env::set_current_dir(&resource_dir).unwrap();
let options = doukutsu_rs::game::LaunchOptions { server_mode: false, editor: false };
let options = doukutsu_rs::game::LaunchOptions::default();
doukutsu_rs::game::init(options).unwrap();
}

1674
drshorizon/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@ rm -f target/aarch64-nintendo-switch/debug/drshorizon.nro
rm -f target/aarch64-nintendo-switch/debug/drshorizon.nacp
message "Creating NACP..."
nacptool --create 'doukutsu-rs' 'doukutsu-rs contributors' '0.101.0' target/aarch64-nintendo-switch/debug/drshorizon.nacp
nacptool --create 'doukutsu-rs' 'doukutsu-rs contributors' '0.102.0' target/aarch64-nintendo-switch/debug/drshorizon.nacp
message "Running elf2nro..."
elf2nro target/aarch64-nintendo-switch/debug/drshorizon.elf target/aarch64-nintendo-switch/debug/drshorizon.nro \
--icon=../res/nx_icon.jpg \
--icon=../res/crabsue-icon.jpg \
--nacp=target/aarch64-nintendo-switch/debug/drshorizon.nacp
message "done!"

View file

@ -23,11 +23,11 @@ rm -f target/aarch64-nintendo-switch/release/drshorizon.nro
rm -f target/aarch64-nintendo-switch/release/drshorizon.nacp
message "Creating NACP..."
nacptool --create 'doukutsu-rs' 'doukutsu-rs contributors' '0.101.0' target/aarch64-nintendo-switch/release/drshorizon.nacp
nacptool --create 'doukutsu-rs' 'doukutsu-rs contributors' '0.102.0' target/aarch64-nintendo-switch/release/drshorizon.nacp
message "Running elf2nro..."
elf2nro target/aarch64-nintendo-switch/release/drshorizon.elf target/aarch64-nintendo-switch/release/drshorizon.nro \
--icon=../res/nx_icon.jpg \
--icon=../res/crabsue-icon.jpg \
--nacp=target/aarch64-nintendo-switch/release/drshorizon.nacp
message "done!"

View file

@ -34,7 +34,7 @@ fn main() {
println!("__text_start = {:#x}", (&__text_start) as *const _ as usize);
let options = doukutsu_rs::game::LaunchOptions { server_mode: false, editor: false };
let options = doukutsu_rs::game::LaunchOptions::default();
let result = doukutsu_rs::game::init(options);
if let Err(e) = result {

BIN
res/crabsue-icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
res/crabsue-icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

BIN
res/crabsue-icon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View file

@ -0,0 +1,9 @@
[Desktop Entry]
Name=doukutsu-rs
Comment=A faithful and open-source remake of Cave Story's engine written in Rust
Exec=doukutsu-rs
Keywords=game;adventure;engine;action;platforms;
Terminal=false
Type=Application
Icon=io.github.doukutsu_rs.doukutsu-rs
Categories=Game;AdventureGame;ActionGame;

View file

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.doukutsu_rs.doukutsu-rs</id>
<metadata_license>CC0-1.0</metadata_license>
<name>doukutsu-rs</name>
<summary>A faithful and open-source remake of Cave Story's engine written in Rust</summary>
<description>
<p>doukutsu-rs initially started as a Rust learning project, but eventually evolved into semi-playable and compatible reimplementation of the engine of Cave Story - a great indie game created by Studio Pixel.</p>
<p>The project aims to deliver a decent alternative for the original engine, improving it with features such as multiplayer support, independent framerate (so the game runs at original speed and looks smooth regardless of monitor refresh rate), enhanced lightning and cutscenes skipping.</p>
<p>Furthermore, the engine supports game data from multiple game versions: original freeware, Cave Story+, and Nintendo Switch version.</p>
<p>NOTE: The default data files directory is under <code>$XDG_DATA_HOME/doukutsu-rs/data</code>. That being <code>$HOME/.var/app/io.github.doukutsu_rs.doukutsu-rs/data/doukutsu-rs/data</code> by default.</p>
</description>
<categories>
<category>Game</category>
</categories>
<url type="homepage">https://doukutsu.rs</url>
<url type="bugtracker">https://github.com/doukutsu-rs/doukutsu-rs/issues</url>
<url type="vcs-browser">https://github.com/doukutsu-rs/doukutsu-rs</url>
<project_license>MIT</project_license>
<developer id="io.github.doukutsu_rs">
<name>doukutsu-rs maintainers</name>
</developer>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">moderate</content_attribute>
<content_attribute id="language-profanity">mild</content_attribute>
</content_rating>
<screenshots>
<screenshot type="default">
<image>https://raw.githubusercontent.com/doukutsu-rs/doukutsu-rs/refs/heads/master/res/flatpak/screens/grassrown-lightning.png</image>
<caption>Enjoy lighting effects that are slightly fancier than those in the Switch version</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/doukutsu-rs/doukutsu-rs/refs/heads/master/res/flatpak/screens/cutscene-skipping.png</image>
<caption>Supports skipping cutscenes, a feature previously exclusive to the Switch version</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/doukutsu-rs/doukutsu-rs/refs/heads/master/res/flatpak/screens/core-fight.png</image>
<caption>Battle with one of the game bosses</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/doukutsu-rs/doukutsu-rs/refs/heads/master/res/flatpak/screens/snake-trading.png</image>
<caption>Another example of lighting effects</caption>
</screenshot>
</screenshots>
<releases>
<release version="0.102.0-beta7" date="2025-03-08">
<url type="details">https://github.com/doukutsu-rs/doukutsu-rs/releases/tag/0.102.0-beta7</url>
<description>
<ul>
<li>Introduce new app icon</li>
</ul>
</description>
</release>
<release version="0.101.0-beta6" date="2024-12-31">
<description>
<ul>
<li>Fix damage and expirience number popup inaccuracies</li>
<li>Add window icons for non-Windows systems</li>
<li>Fix Organya sampling bug</li>
<li>Fix Misery bubble going the wrong way</li>
<li>Fix Player gun desync bug and inventory inconsistencies</li>
<li>Add automatic cutscene skipping</li>
<li>Localize difficulty name in save menu and add support for custom text encoding</li>
<li>Fix button mapping icons for Nintendo controllers</li>
<li>Fix Pixel Birthday easter egg</li>
<li>Fix extraction of game data from vanilla executable, when the data is already extracted</li>
<li>Generate the correct amount of smoke on tile change</li>
</ul>
<p>Also have been fixed many inaccuracies of bosses and NPCs.</p>
</description>
</release>
<release version="0.100.0-beta5" date="2023-01-25">
<description>
<ul>
<li>Add gamepad support for PC</li>
<li>Add data extractor from the freeware executable</li>
<li>Add coop menu</li>
<li>Add screen shake intensity and pause on focus loss settings, add links menu</li>
<li>Render "=" in dialogs as white circle</li>
</ul>
<p>Some rendering issues and inaccuracies have also been fixed.</p>
</description>
</release>
<release version="0.99.0-beta4" date="2022-05-03">
<description>
<ul>
<li>Use CS+ Japanese font, if it's valid</li>
</ul>
</description>
</release>
<release version="0.99.0-beta3" date="2022-04-24">
<description>
<ul>
<li>Improved water rendering</li>
<li>Added CS+ difficulties</li>
<li>Added save slots for challenges</li>
<li>Added Jukebox when Switch CS+ data is used</li>
<li>Implement Wind Fortress NPCs (NPC 361-369)</li>
<li>Add dog stacking effect</li>
<li>Add game and menu localization support</li>
<li>Add support for fullscreen mode</li>
<li>Add V-Sync support</li>
</ul>
</description>
</release>
<release version="0.99.0-beta2" date="2022-02-11">
<description>
<ul>
<li>Added pause menu</li>
<li>Fixed Waterway noise</li>
<li>Added map system</li>
<li>Adjusted menu spacing to make it look better with default textbox decorations</li>
<li>Added support for GOG version</li>
<li>Fixed hissing in case when system sample rate doesn't match the sample rate of .ogg file</li>
<li>Added Waterway push tiles animation</li>
<li>Added pause menu confirm dialog</li>
<li>Added all remaining carets (Empty!/bubbler/droplet)</li>
<li>Added FPS counter</li>
<li>Added support for Switch version animated facepics</li>
<li>Added multiple saves support</li>
<li>Added support for CS+ Challenges</li>
</ul>
</description>
</release>
<release version="0.99.0-beta1" date="2022-01-15">
<description>
<p>First fully playable beta. The only missing gameplay feature is Map System.</p>
</description>
</release>
</releases>
<recommends>
<control>keyboard</control>
</recommends>
<supports>
<control>gamepad</control>
</supports>
<launchable type="desktop-id">io.github.doukutsu_rs.doukutsu-rs.desktop</launchable>
</component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
res/macos/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
res/macos/128x128@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
res/macos/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

BIN
res/macos/16x16@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
res/macos/256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
res/macos/256x256@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
res/macos/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
res/macos/32x32@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
res/macos/512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
res/macos/512x512@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

161
res/macos/crabsue.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 313 KiB

View file

@ -279,10 +279,20 @@ impl<T: Num + PartialOrd + Copy> Rect<T> {
Rect { left: x, top: y, right: x.add(width), bottom: y.add(height) }
}
pub fn has_point(&self, x: T, y: T) -> bool {
/**
* Returns true if the point (x, y) is inside the rectangle (inclusive).
*/
pub fn has_point_incl(&self, x: T, y: T) -> bool {
self.left.ge(&x) && self.right.le(&x) && self.top.ge(&y) && self.bottom.le(&y)
}
/**
* Returns true if the point (x, y) is inside the rectangle (exclusive).
*/
pub fn has_point_excl(&self, x: T, y: T) -> bool {
self.left.le(&x) && self.right.gt(&x) && self.top.le(&y) && self.bottom.gt(&y)
}
pub fn width(&self) -> T {
if self.left.gt(&self.right) {
self.left.sub(self.right)

View file

@ -5,7 +5,7 @@ use crate::framework::error::GameResult;
use crate::game::frame::Frame;
use crate::game::shared_game_state::SharedGameState;
use crate::game::npc::boss::BossNPC;
use crate::game::npc::list::NPCList;
use crate::game::npc::list::{NPCAccessToken, NPCList};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
@ -28,8 +28,10 @@ impl BossLifeBar {
BossLifeBar { target: BossLifeTarget::None, life: 0, max_life: 0, prev_life: 0, counter: 0 }
}
pub fn set_npc_target(&mut self, npc_id: u16, npc_list: &NPCList) {
pub fn set_npc_target(&mut self, npc_id: u16, npc_list: &NPCList, npc_token: &NPCAccessToken) {
if let Some(npc) = npc_list.get_npc(npc_id as usize) {
let npc = npc.borrow(npc_token);
self.target = BossLifeTarget::NPC(npc.id);
self.life = npc.life;
self.max_life = self.life;
@ -130,11 +132,13 @@ impl BossLifeBar {
}
}
impl GameEntity<(&NPCList, &BossNPC)> for BossLifeBar {
fn tick(&mut self, _state: &mut SharedGameState, (npc_list, boss): (&NPCList, &BossNPC)) -> GameResult<()> {
impl GameEntity<(&NPCList, &NPCAccessToken, &BossNPC)> for BossLifeBar {
fn tick(&mut self, _state: &mut SharedGameState, (npc_list, npc_token, boss): (&NPCList, &NPCAccessToken, &BossNPC)) -> GameResult<()> {
match self.target {
BossLifeTarget::NPC(npc_id) => {
if let Some(npc) = npc_list.get_npc(npc_id as usize) {
let npc = npc.borrow(npc_token);
self.life = npc.life;
}
}

View file

@ -42,7 +42,7 @@ impl GameEntity<()> for Credits {
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, _frame: &Frame) -> GameResult {
let rect = Rect::new(0, 0, (state.screen_size.0 / 2.0) as _, state.screen_size.1 as _);
graphics::draw_rect(ctx, rect, Color::from_rgb(0, 0, 32))?;
graphics::draw_rect(ctx, rect, state.constants.background_color)?;
if state.textscript_vm.illustration_state != IllustrationState::Hidden {
let x = match state.textscript_vm.illustration_state {

View file

@ -38,7 +38,7 @@ impl GameEntity<()> for FallingIsland {
(80.0 * state.scale) as _,
);
graphics::clear(ctx, Color::from_rgb(0, 0, 32));
graphics::clear(ctx, state.constants.intro_background_color);
graphics::set_clip_rect(ctx, Some(clip_rect))?;
static RECT_BG: Rect<u16> = Rect { left: 0, top: 0, right: 160, bottom: 80 };

View file

@ -10,6 +10,7 @@ use crate::game::shared_game_state::SharedGameState;
use crate::graphics::font::{Font, Symbols};
pub struct TextBoxes {
pub item_drop_in: u8,
pub slide_in: u8,
pub anim_counter: usize,
animated_face: AnimatedFace,
@ -21,6 +22,7 @@ const SWITCH_FACE_TEX: [&str; 5] = ["Face1", "Face2", "Face3", "Face4", "Face5"]
impl TextBoxes {
pub fn new() -> TextBoxes {
TextBoxes {
item_drop_in: 10,
slide_in: 7,
anim_counter: 0,
animated_face: AnimatedFace { face_id: 0, anim_id: 0, anim_frames: vec![(0, 0)] },
@ -55,6 +57,11 @@ impl GameEntity<()> for TextBoxes {
self.anim_counter = 0;
}
}
if state.textscript_vm.item != 0 {
self.item_drop_in = self.item_drop_in.saturating_sub(1);
}
Ok(())
}
@ -180,6 +187,7 @@ impl GameEntity<()> for TextBoxes {
}
if state.textscript_vm.item != 0 {
let item_offset = self.item_drop_in as f32 * 0.7;
let mut rect = Rect::new(0, 0, 0, 0);
if state.textscript_vm.item < 1000 {
@ -191,7 +199,7 @@ impl GameEntity<()> for TextBoxes {
rect.bottom = rect.top + 16;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "ArmsImage")?;
batch.add_rect((center - 12.0).floor(), state.canvas_size.1 - off_bottom - 104.0, &rect);
batch.add_rect((center - 12.0).floor(), state.canvas_size.1 - off_bottom - item_offset - 104.0, &rect);
batch.draw(ctx)?;
} else {
let item_id = state.textscript_vm.item as u16 - 1000;
@ -202,7 +210,7 @@ impl GameEntity<()> for TextBoxes {
rect.bottom = rect.top + 16;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "ItemImage")?;
batch.add_rect((center - 20.0).floor(), state.canvas_size.1 - off_bottom - 104.0, &rect);
batch.add_rect((center - 20.0).floor(), state.canvas_size.1 - off_bottom - item_offset - 104.0, &rect);
batch.draw(ctx)?;
}
}

View file

@ -11,7 +11,7 @@ use crate::game::map::{WaterParamEntry, WaterParams, WaterRegionType};
use crate::game::physics::PhysicalEntity;
use crate::game::shared_game_state::SharedGameState;
use crate::game::stage::{BackgroundType, Stage};
use crate::game::npc::list::NPCList;
use crate::game::npc::list::{NPCAccessToken, NPCList};
use crate::game::player::Player;
const TENSION: f32 = 0.03;
@ -100,7 +100,7 @@ impl DynamicWater {
}
}
pub fn interact(&mut self, players: &[&Player], npc_list: &NPCList) {
pub fn interact(&mut self, players: &[&Player], npc_list: &NPCList, npc_token: &NPCAccessToken) {
let cols_i32 = self.columns.len() as i32;
let mut tick_object = |obj: &dyn PhysicalEntity| {
@ -129,13 +129,13 @@ impl DynamicWater {
tick_object(*player);
}
for npc in npc_list.iter_alive() {
for npc in npc_list.iter_alive(npc_token) {
static NO_COLL_NPCS: [u16; 6] = [0, 3, 4, 18, 191, 195];
if NO_COLL_NPCS.contains(&npc.npc_type) {
continue;
}
tick_object(npc);
tick_object(&*npc);
}
}
}
@ -211,9 +211,9 @@ impl WaterRenderer {
}
}
pub fn tick(&mut self, state: &mut SharedGameState, (players, npc_list): (&[&Player], &NPCList)) -> GameResult<()> {
pub fn tick(&mut self, state: &mut SharedGameState, (players, npc_list, npc_token): (&[&Player], &NPCList, &NPCAccessToken)) -> GameResult<()> {
for surf in &mut self.water_surfaces {
surf.interact(players, npc_list);
surf.interact(players, npc_list, npc_token);
surf.tick();
}
@ -222,7 +222,7 @@ impl WaterRenderer {
core_water.y = level;
core_depth.rect.top = (level + 16.0).min(core_depth.rect.bottom);
core_water.interact(players, npc_list);
core_water.interact(players, npc_list, npc_token);
core_water.tick();
}

View file

@ -102,7 +102,9 @@ impl BuiltinFS {
FSNode::File("builtin_font_0.png", include_bytes!("builtin/builtin_font_0.png")),
FSNode::File("builtin_font_1.png", include_bytes!("builtin/builtin_font_1.png")),
FSNode::File("gamecontrollerdb.txt", include_bytes!("builtin/gamecontrollerdb.txt")),
FSNode::File("icon.bmp", include_bytes!("../../res/sue.bmp")),
#[cfg(not(any(target_os = "windows", target_os = "android", target_os = "horizon")))]
FSNode::File("icon.bmp", include_bytes!("../../res/crabsue-icon.bmp")),
FSNode::File(
"organya-wavetable-doukutsu.bin",
include_bytes!("builtin/organya-wavetable-doukutsu.bin"),

View file

@ -180,7 +180,7 @@ impl EditorInstance {
let (scale_x, scale_y) = batch.scale();
if let Some(tex) = batch.get_texture() {
let (width, height) = tex.dimensions();
let (width, height) = (width as f32 / scale_x, height as f32 / scale_y);
let (width, height) = (width as f32 * scale_x, height as f32 * scale_y);
if let Ok(tex_id) = graphics::imgui_texture_id(ctx, tex) {
Image::new(tex_id, [width, height]).build(ui);

View file

@ -262,9 +262,12 @@ pub struct EngineConstants {
pub npc: NPCConsts,
pub weapon: WeaponConsts,
pub tex_sizes: CaseInsensitiveHashMap<(u16, u16)>,
pub ignore_ogph_textures: Vec<String>,
pub textscript: TextScriptConsts,
pub title: TitleConsts,
pub inventory_dim_color: Color,
pub background_color: Color,
pub intro_background_color: Color,
pub font_path: String,
pub font_space_offset: f32,
pub soundtracks: Vec<ExtraSoundtrack>,
@ -1421,6 +1424,10 @@ impl EngineConstants {
"Title" => (320, 48),
"triangles" => (20, 5),
},
ignore_ogph_textures: vec![
// All in lowercase
"title".to_owned(),
],
textscript: TextScriptConsts {
encoding: TextScriptEncoding::ShiftJIS,
encrypted: true,
@ -1506,6 +1513,8 @@ impl EngineConstants {
],
},
inventory_dim_color: Color::from_rgba(0, 0, 0, 0),
background_color: Color::from_rgb(0, 0, 32),
intro_background_color: Color::from_rgb(0, 0, 0),
font_path: "csfont.fnt".to_owned(),
font_space_offset: 0.0,
soundtracks: vec![
@ -1682,6 +1691,7 @@ impl EngineConstants {
self.tex_sizes.insert("uimusic".to_owned(), (192, 144));
self.title.logo_rect = Rect { left: 0, top: 0, right: 214, bottom: 62 };
self.inventory_dim_color = Color::from_rgba(0, 0, 32, 150);
self.intro_background_color = Color::from_rgb(0, 0, 32);
self.textscript.encoding = TextScriptEncoding::UTF8;
self.textscript.encrypted = false;
self.textscript.animated_face_pics = true;

View file

@ -7,6 +7,7 @@ use crate::common::{Color, Rect};
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::graphics::{BlendMode, VSyncMode};
use crate::game::shared_game_state::WindowMode;
use crate::game::Game;
#[repr(C)]
@ -108,8 +109,23 @@ pub trait BackendGamepad {
fn instance_id(&self) -> u32;
}
#[derive(Clone, Copy)]
pub struct WindowParams {
pub size_hint: (u16, u16), // (width, height)
pub mode: WindowMode,
}
impl Default for WindowParams {
fn default() -> Self {
Self {
size_hint: (640, 480),
mode: WindowMode::Windowed,
}
}
}
#[allow(unreachable_code)]
pub fn init_backend(headless: bool, size_hint: (u16, u16)) -> GameResult<Box<dyn Backend>> {
pub fn init_backend(headless: bool, window_params: WindowParams) -> GameResult<Box<dyn Backend>> {
if headless {
return crate::framework::backend_null::NullBackend::new();
}
@ -121,12 +137,13 @@ pub fn init_backend(headless: bool, size_hint: (u16, u16)) -> GameResult<Box<dyn
#[cfg(all(feature = "backend-glutin"))]
{
//return crate::framework::backend_glutin::GlutinBackend::new(window_params);
return crate::framework::backend_glutin::GlutinBackend::new();
}
#[cfg(feature = "backend-sdl")]
{
return crate::framework::backend_sdl2::SDL2Backend::new(size_hint);
return crate::framework::backend_sdl2::SDL2Backend::new(window_params);
}
log::warn!("No backend compiled in, using null backend instead.");

View file

@ -324,9 +324,9 @@ impl BackendEventLoop for GlutinEventLoop {
#[cfg(not(any(target_os = "android", target_os = "horizon")))]
{
if state_ref.settings.window_mode.get_glutin_fullscreen_type() != window.window().fullscreen() {
let fullscreen_type = state_ref.settings.window_mode.get_glutin_fullscreen_type();
let cursor_visible = state_ref.settings.window_mode.should_display_mouse_cursor();
if ctx.window.mode.get_glutin_fullscreen_type() != window.window().fullscreen() {
let fullscreen_type = ctx.window.mode.get_glutin_fullscreen_type();
let cursor_visible = ctx.window.mode.should_display_mouse_cursor();
window.window().set_fullscreen(fullscreen_type);
window.window().set_cursor_visible(cursor_visible);

View file

@ -28,7 +28,7 @@ use sdl2::{controller, keyboard, pixels, EventPump, GameControllerSubsystem, Sdl
use crate::common::{Color, Rect};
use crate::framework::backend::{
Backend, BackendEventLoop, BackendGamepad, BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand,
VertexData,
VertexData, WindowParams,
};
use crate::framework::context::Context;
use crate::framework::error::{GameError, GameResult};
@ -45,16 +45,15 @@ use crate::game::GAME_SUSPENDED;
pub struct SDL2Backend {
context: Sdl,
size_hint: (u16, u16),
}
impl SDL2Backend {
pub fn new(size_hint: (u16, u16)) -> GameResult<Box<dyn Backend>> {
pub fn new(window_params: WindowParams) -> GameResult<Box<dyn Backend>> {
sdl2::hint::set("SDL_JOYSTICK_THREAD", "1");
let context = sdl2::init().map_err(GameError::WindowError)?;
let backend = SDL2Backend { context, size_hint };
let backend = SDL2Backend { context };
Ok(Box::new(backend))
}
@ -62,7 +61,7 @@ impl SDL2Backend {
impl Backend for SDL2Backend {
fn create_event_loop(&self, ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>> {
SDL2EventLoop::new(&self.context, self.size_hint, ctx)
SDL2EventLoop::new(&self.context, ctx)
}
fn as_any(&self) -> &dyn Any {
@ -159,7 +158,7 @@ struct SDL2Context {
}
impl SDL2EventLoop {
pub fn new(sdl: &Sdl, size_hint: (u16, u16), ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>> {
pub fn new(sdl: &Sdl, ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>> {
let event_pump = sdl.event_pump().map_err(GameError::WindowError)?;
let video = sdl.video().map_err(GameError::WindowError)?;
@ -172,10 +171,14 @@ impl SDL2EventLoop {
gl_attr.set_context_profile(GLProfile::Compatibility);
gl_attr.set_context_version(2, 1);
let mut win_builder = video.window("Cave Story (doukutsu-rs)", size_hint.0 as _, size_hint.1 as _);
let mut win_builder = video.window("Cave Story (doukutsu-rs)", ctx.window.size_hint.0 as _, ctx.window.size_hint.1 as _);
win_builder.position_centered();
win_builder.resizable();
if ctx.window.mode.is_fullscreen() {
win_builder.fullscreen();
}
#[cfg(feature = "render-opengl")]
win_builder.opengl();
@ -185,14 +188,14 @@ impl SDL2EventLoop {
let mut file = filesystem::open(&ctx, "/builtin/icon.bmp").unwrap();
let mut buf: Vec<u8> = Vec::new();
file.read_to_end(&mut buf)?;
let mut rwops = RWops::from_bytes(buf.as_slice()).unwrap();
let icon = Surface::load_bmp_rw(&mut rwops).unwrap();
window.set_icon(icon);
}
let opengl_available = if let Ok(v) = std::env::var("CAVESTORY_NO_OPENGL") { v != "1" } else { true };
let event_loop = SDL2EventLoop {
@ -303,7 +306,7 @@ impl BackendEventLoop for SDL2EventLoop {
if keymod.intersects(keyboard::Mod::RALTMOD | keyboard::Mod::LALTMOD)
&& drs_scan == ScanCode::Return
{
let new_mode = match state.settings.window_mode {
let new_mode = match ctx.window.mode {
WindowMode::Windowed => WindowMode::Fullscreen,
WindowMode::Fullscreen => WindowMode::Windowed,
};
@ -322,6 +325,7 @@ impl BackendEventLoop for SDL2EventLoop {
refs.fullscreen_type = fullscreen_type;
state.settings.window_mode = new_mode;
ctx.window.mode = new_mode;
}
}
ctx.keyboard_context.set_key(drs_scan, true);
@ -391,12 +395,12 @@ impl BackendEventLoop for SDL2EventLoop {
}
{
if state.settings.window_mode.get_sdl2_fullscreen_type() != self.refs.borrow().fullscreen_type {
if ctx.window.mode.get_sdl2_fullscreen_type() != self.refs.borrow().fullscreen_type {
let mut refs = self.refs.borrow_mut();
let window = refs.window.window_mut();
let fullscreen_type = state.settings.window_mode.get_sdl2_fullscreen_type();
let show_cursor = state.settings.window_mode.should_display_mouse_cursor();
let fullscreen_type = ctx.window.mode.get_sdl2_fullscreen_type();
let show_cursor = ctx.window.mode.should_display_mouse_cursor();
window.set_fullscreen(fullscreen_type);
window

View file

@ -1,4 +1,4 @@
use crate::framework::backend::{init_backend, BackendRenderer};
use crate::framework::backend::{init_backend, BackendRenderer, WindowParams};
use crate::framework::error::GameResult;
use crate::framework::filesystem::Filesystem;
use crate::framework::gamepad::GamepadContext;
@ -8,7 +8,7 @@ use crate::game::Game;
pub struct Context {
pub headless: bool,
pub size_hint: (u16, u16),
pub window: WindowParams,
pub(crate) filesystem: Filesystem,
pub(crate) renderer: Option<Box<dyn BackendRenderer>>,
pub(crate) gamepad_context: GamepadContext,
@ -23,7 +23,7 @@ impl Context {
pub fn new() -> Context {
Context {
headless: false,
size_hint: (640, 480),
window: WindowParams::default(),
filesystem: Filesystem::new(),
renderer: None,
gamepad_context: GamepadContext::new(),
@ -36,7 +36,7 @@ impl Context {
}
pub fn run(&mut self, game: &mut Game) -> GameResult {
let backend = init_backend(self.headless, self.size_hint)?;
let backend = init_backend(self.headless, self.window)?;
let mut event_loop = backend.create_event_loop(self)?;
self.renderer = Some(event_loop.new_renderer(self as *mut Context)?);

View file

@ -2,6 +2,7 @@
use std::error::Error;
use std::fmt;
use std::ops::ControlFlow;
use std::string::FromUtf8Error;
use std::sync::mpsc::SendError;
use std::sync::{Arc, PoisonError};
@ -74,6 +75,14 @@ impl Error for GameError {
/// A convenient result type consisting of a return type and a `GameError`
pub type GameResult<T = ()> = Result<T, GameError>;
/// Convert Result::Err(e) to ControlFlow::Break(e). Useful in try_for_each methods.
pub fn map_err_to_break<T, E>(result: Result<T, E>) -> ControlFlow<E, T> {
match result {
Result::Ok(t) => ControlFlow::Continue(t),
Result::Err(e) => ControlFlow::Break(e)
}
}
impl From<std::io::Error> for GameError {
fn from(e: std::io::Error) -> GameError {
GameError::IOError(Arc::new(e))

View file

@ -673,8 +673,6 @@ impl BackendRenderer for OpenGLRenderer {
self.render_data.surf_texture,
BackendShader::Texture,
)?;
gl.gl.Finish();
}
if let Some((context, _)) = self.get_context() {

View file

@ -5,17 +5,21 @@ use std::path::PathBuf;
use std::sync::Mutex;
use std::time::{Duration, Instant};
use clap::clap_derive::Parser;
use lazy_static::lazy_static;
use log::LevelFilter as LogLevel;
use scripting::tsc::text_script::ScriptMode;
use crate::framework::backend::WindowParams;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::graphics;
use crate::framework::graphics::VSyncMode;
use crate::framework::ui::UI;
use crate::game::filesystem_container::FilesystemContainer;
use crate::game::shared_game_state::{Fps, SharedGameState, TimingMode};
use crate::game::settings::Settings;
use crate::game::shared_game_state::{Fps, SharedGameState, TimingMode, WindowMode};
use crate::graphics::texture_set::{G_MAG, I_MAG};
use crate::scene::loading_scene::LoadingScene;
use crate::scene::Scene;
@ -35,9 +39,65 @@ pub mod shared_game_state;
pub mod stage;
pub mod weapon;
#[derive(Debug, Parser)]
#[command(version, about, long_about = None)]
pub struct LaunchOptions {
#[arg(long, hide = cfg!(not(feature = "netplay")))]
/// Do not create a window and skip audio initialization.
pub server_mode: bool,
pub editor: bool,
#[arg(long)]
/// Window height in pixels.
pub window_height: Option<u16>,
#[arg(long)]
/// Window width in pixels.
pub window_width: Option<u16>,
#[arg(long)]
/// Startup in fullscreen mode.
pub window_fullscreen: bool,
#[arg(long, default_value_t = Self::default().log_level)]
/// The minimum level of records that will be written to the log file.
///
/// Possible values: error, warn, info, debug, trace.
pub log_level: LogLevel,
}
impl Default for LaunchOptions {
fn default() -> Self {
Self {
server_mode: false,
window_height: None,
window_width: None,
window_fullscreen: false,
log_level: if cfg!(debug_assertions) { LogLevel::Debug } else { LogLevel::Info },
}
}
}
impl LaunchOptions {
pub fn apply_defaults(&mut self, ctx: &Context, settings: &Settings) {
self.window_width = Some(self.window_width.unwrap_or(ctx.window.size_hint.0));
self.window_height = Some(self.window_height.unwrap_or(ctx.window.size_hint.1));
if !self.window_fullscreen {
self.window_fullscreen = settings.window_mode.is_fullscreen();
}
}
pub fn window(&self) -> WindowParams {
let default = WindowParams::default();
let width = self.window_width.unwrap_or(default.size_hint.0);
let height = self.window_height.unwrap_or(default.size_hint.1);
WindowParams {
size_hint: (width, height),
mode: if self.window_fullscreen { WindowMode::Fullscreen } else { WindowMode::Windowed },
}
}
}
lazy_static! {
@ -215,14 +275,13 @@ impl Game {
}
}
// For the most part this is just a copy-paste of the code from FilesystemContainer because it logs
// For the most part this is just a copy-paste of the code from FilesystemContainer because it logs
// some messages during init, but the default logger cannot be replaced with another
// one or deinited(so we can't create the console-only logger and replace it by the
// console&file logger after FilesystemContainer has been initialized)
fn get_logs_dir() -> GameResult<PathBuf> {
let mut logs_dir: PathBuf;
#[cfg(target_os = "android")]
{
logs_dir = PathBuf::from(ndk_glue::native_activity().internal_data_path().to_string_lossy().to_string());
@ -250,45 +309,28 @@ fn get_logs_dir() -> GameResult<PathBuf> {
logs_dir.push("logs");
Ok(logs_dir)
}
fn init_logger() -> GameResult {
fn init_logger(options: &LaunchOptions) -> GameResult {
let logs_dir = get_logs_dir()?;
let _ = std::fs::create_dir_all(&logs_dir);
let mut dispatcher = fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"{} [{}] {}",
record.level(),
record.module_path().unwrap().to_owned(),
message
))
out.finish(format_args!("{} [{}] {}", record.level(), record.module_path().unwrap().to_owned(), message))
})
.level(log::LevelFilter::Debug)
.chain(
fern::Dispatch::new()
.chain(std::io::stderr())
);
.chain(fern::Dispatch::new().chain(std::io::stderr()));
let date = chrono::Utc::now();
let mut file = logs_dir.clone();
file.push(format!("log_{}", date.format("%Y-%m-%d")));
file.set_extension("txt");
dispatcher = dispatcher.chain(
fern::Dispatch::new()
.level(log::LevelFilter::Info)
.chain(fern::log_file(file).unwrap())
);
dispatcher =
dispatcher.chain(fern::Dispatch::new().level(options.log_level).chain(fern::log_file(file).unwrap()));
dispatcher.apply()?;
//log::info!("===GAME LAUNCH===");
Ok(())
}
@ -304,8 +346,8 @@ fn panic_hook(info: &PanicInfo<'_>) {
}
}
pub fn init(options: LaunchOptions) -> GameResult {
let _ = init_logger();
pub fn init(mut options: LaunchOptions) -> GameResult {
let _ = init_logger(&options);
std::panic::set_hook(Box::new(panic_hook));
let mut context = Box::pin(Context::new());
@ -321,12 +363,16 @@ pub fn init(options: LaunchOptions) -> GameResult {
let mut game = Box::pin(Game::new(&mut context)?);
game.state.get_mut().fs_container = Some(fs_container);
options.apply_defaults(&context, &game.state.get_mut().settings);
#[cfg(feature = "discord-rpc")]
if game.state.get_mut().settings.discord_rpc {
game.state.get_mut().discord_rpc.enabled = true;
game.state.get_mut().discord_rpc.start()?;
}
context.window = options.window();
game.state.get_mut().next_scene = Some(Box::new(LoadingScene::new()));
log::info!("Starting main loop...");
context.run(game.as_mut().get_mut())?;

View file

@ -1,13 +1,15 @@
use crate::common::Direction;
use crate::framework::error::GameResult;
use crate::game::npc::list::NPCList;
use crate::game::npc::NPC;
use crate::game::player::Player;
use crate::game::npc::{NPCContext, NPC};
use crate::game::shared_game_state::SharedGameState;
use crate::util::rng::RNG;
impl NPC {
pub(crate) fn tick_n254_helicopter(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
pub(crate) fn tick_n254_helicopter(
&mut self,
state: &mut SharedGameState,
NPCContext { npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 => {
self.action_num = 1;
@ -84,7 +86,7 @@ impl NPC {
pub(crate) fn tick_n255_helicopter_blades(
&mut self,
state: &mut SharedGameState,
npc_list: &NPCList,
NPCContext { npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
@ -99,7 +101,7 @@ impl NPC {
}
}
if let Some(parent) = self.get_parent_ref_mut(npc_list) {
if let Some(parent) = self.get_parent(npc_list) {
if parent.action_num >= 20 {
self.action_num = 10;
}
@ -116,7 +118,7 @@ impl NPC {
_ => (),
}
if let Some(parent) = self.get_parent_ref_mut(npc_list) {
if let Some(parent) = self.get_parent(npc_list) {
if self.direction == Direction::Left {
self.x = parent.x + 0x2400;
self.y = parent.y - 0x7200;
@ -136,8 +138,7 @@ impl NPC {
pub(crate) fn tick_n260_shovel_brigade_caged(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
NPCContext { players, npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
@ -190,7 +191,7 @@ impl NPC {
pub(crate) fn tick_n261_chie_caged(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
NPCContext { players, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
@ -231,7 +232,7 @@ impl NPC {
pub(crate) fn tick_n262_chaco_caged(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
NPCContext { players, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {

View file

@ -1,20 +1,18 @@
use num_traits::clamp;
use crate::common::{CDEG_RAD, Direction};
use crate::common::{Direction, CDEG_RAD};
use crate::framework::error::GameResult;
use crate::game::caret::CaretType;
use crate::game::npc::list::NPCList;
use crate::game::npc::NPC;
use crate::game::player::Player;
use crate::game::npc::list::BorrowedNPC;
use crate::game::npc::{NPCContext, NPC};
use crate::game::shared_game_state::SharedGameState;
use crate::game::stage::Stage;
use crate::util::rng::RNG;
impl NPC {
impl BorrowedNPC<'_> {
pub(crate) fn tick_n009_balrog_falling_in(
&mut self,
state: &mut SharedGameState,
npc_list: &NPCList,
NPCContext { npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
@ -81,8 +79,7 @@ impl NPC {
pub(crate) fn tick_n010_balrog_shooting(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
NPCContext { players, npc_list, .. }: NPCContext,
) -> GameResult {
let player = self.get_closest_player_mut(players);
@ -182,7 +179,7 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n011_balrogs_projectile(&mut self, state: &mut SharedGameState) -> GameResult {
pub(crate) fn tick_n011_balrogs_projectile(&mut self, state: &mut SharedGameState, _: NPCContext) -> GameResult {
if self.flags.hit_anything() {
self.cond.set_alive(false);
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
@ -207,9 +204,7 @@ impl NPC {
pub(crate) fn tick_n012_balrog_cutscene(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
stage: &mut Stage,
NPCContext { players, npc_list, stage, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
@ -452,8 +447,8 @@ impl NPC {
self.vel_y = -0x800;
self.npc_flags.set_ignore_solidity(true);
npc_list.kill_npcs_by_type(150, false, state);
npc_list.kill_npcs_by_type(117, false, state);
npc_list.kill_npcs_by_type(150, false, state, self);
npc_list.kill_npcs_by_type(117, false, state, self);
let mut npc = NPC::create(355, &state.npc_table);
npc.cond.set_alive(true);
@ -542,7 +537,11 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n019_balrog_bust_in(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
pub(crate) fn tick_n019_balrog_bust_in(
&mut self,
state: &mut SharedGameState,
NPCContext { npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
@ -619,7 +618,7 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n033_balrog_bouncing_projectile(&mut self, state: &mut SharedGameState) -> GameResult {
pub(crate) fn tick_n033_balrog_bouncing_projectile(&mut self, state: &mut SharedGameState, _: NPCContext) -> GameResult {
if self.flags.hit_left_wall() || self.flags.hit_right_wall() {
self.cond.set_alive(false);
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
@ -656,8 +655,7 @@ impl NPC {
pub(crate) fn tick_n036_balrog_hover(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
NPCContext { players, npc_list, .. }: NPCContext,
) -> GameResult {
let player = self.get_closest_player_mut(players);
@ -819,8 +817,7 @@ impl NPC {
pub(crate) fn tick_n068_balrog_running(
&mut self,
state: &mut SharedGameState,
mut players: [&mut Player; 2],
npc_list: &NPCList,
NPCContext { mut players, npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
@ -1000,8 +997,7 @@ impl NPC {
pub(crate) fn tick_n169_balrog_shooting_missiles(
&mut self,
state: &mut SharedGameState,
mut players: [&mut Player; 2],
npc_list: &NPCList,
NPCContext { mut players, npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 1 => {
@ -1217,8 +1213,7 @@ impl NPC {
pub(crate) fn tick_n170_balrog_missile(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
NPCContext { players, npc_list, .. }: NPCContext,
) -> GameResult {
if (self.direction == Direction::Left && self.flags.hit_left_wall())
|| (self.direction == Direction::Right && self.flags.hit_right_wall())
@ -1279,7 +1274,7 @@ impl NPC {
Ok(())
}
pub(crate) fn tick_n306_balrog_nurse(&mut self, state: &mut SharedGameState) -> GameResult {
pub(crate) fn tick_n306_balrog_nurse(&mut self, state: &mut SharedGameState, _: NPCContext) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {
@ -1315,8 +1310,7 @@ impl NPC {
pub(crate) fn tick_n356_balrog_rescuing(
&mut self,
state: &mut SharedGameState,
players: [&mut Player; 2],
npc_list: &NPCList,
NPCContext { players, npc_list, .. }: NPCContext,
) -> GameResult {
match self.action_num {
0 | 11 => {

View file

@ -1,11 +1,11 @@
use crate::common::Direction;
use crate::framework::error::GameResult;
use crate::game::npc::NPC;
use crate::game::npc::{NPCContext, NPC};
use crate::game::shared_game_state::SharedGameState;
use crate::util::rng::RNG;
impl NPC {
pub(crate) fn tick_n113_professor_booster(&mut self, state: &mut SharedGameState) -> GameResult {
pub(crate) fn tick_n113_professor_booster(&mut self, state: &mut SharedGameState, _: NPCContext) -> GameResult {
match self.action_num {
0 | 1 => {
if self.action_num == 0 {

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