Compare commits
40 commits
0.101.0-be
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
8b5406d941 | ||
|
c7160c9ea8 | ||
|
20f541d469 | ||
|
f5d729c8a1 | ||
|
2335cf0064 | ||
|
f4602687eb | ||
|
f4b5df3640 | ||
|
37aa3f36aa | ||
|
896f43dc1e | ||
|
adb7a4dff6 | ||
|
7b588f0222 | ||
|
d96f7054e3 | ||
|
5d68ea9f89 | ||
|
13e09e8679 | ||
|
2f73066d12 | ||
|
5f517e6992 | ||
|
2f1159c14f | ||
|
50ea506c53 | ||
|
8fce1cddbc | ||
|
a925c4e7e8 | ||
|
eb7bdf4313 | ||
|
36e21810df | ||
|
70611a8957 | ||
|
8d1da15cfd | ||
|
50cd0e54f5 | ||
|
6973573721 | ||
|
71452113ac | ||
|
a82a536e09 | ||
|
60cfc47a21 | ||
|
9a0fa2d0ad | ||
|
7376875151 | ||
|
deea09407b | ||
|
3ebb02be1d | ||
|
11d5212f47 | ||
|
080bb43429 | ||
|
2fc564b498 | ||
|
2214179e0e | ||
|
d9ad87323f | ||
|
8195097363 | ||
|
1c0c68ce48 |
158
.appveyor.yml
|
@ -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
|
||||
|
205
.github/ISSUE_TEMPLATE/001-bug_report.yml
vendored
Normal 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
|
55
.github/ISSUE_TEMPLATE/002-feature_request.yml
vendored
Normal 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
|
@ -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
|
@ -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
|
241
.github/workflows/ci.yml
vendored
|
@ -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
|
||||
|
|
46
.github/workflows/release.yml
vendored
|
@ -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
|
@ -61,3 +61,5 @@ ehthumbs_vista.db
|
|||
$RECYCLE.BIN/
|
||||
|
||||
*.log
|
||||
|
||||
3rdparty/
|
1053
Cargo.lock
generated
21
Cargo.toml
|
@ -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"] }
|
||||
|
||||
|
|
|
@ -7,6 +7,11 @@ in [Rust](https://www.rust-lang.org/).
|
|||
|
||||
[](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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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">
|
||||
|
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 254 KiB |
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
5
app/app/src/main/res/mipmap-anydpi-v26/icon_sue.xml
Normal 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>
|
|
@ -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>
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 9.1 KiB |
BIN
app/app/src/main/res/mipmap-hdpi/icon_sue.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
app/app/src/main/res/mipmap-hdpi/icon_sue_foreground.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
app/app/src/main/res/mipmap-hdpi/icon_sue_round.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.9 KiB |
BIN
app/app/src/main/res/mipmap-mdpi/icon_sue.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/app/src/main/res/mipmap-mdpi/icon_sue_foreground.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
app/app/src/main/res/mipmap-mdpi/icon_sue_round.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
BIN
app/app/src/main/res/mipmap-xhdpi/icon_sue.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
app/app/src/main/res/mipmap-xhdpi/icon_sue_foreground.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
app/app/src/main/res/mipmap-xhdpi/icon_sue_round.png
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 27 KiB |
BIN
app/app/src/main/res/mipmap-xxhdpi/icon_sue.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
app/app/src/main/res/mipmap-xxhdpi/icon_sue_foreground.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
app/app/src/main/res/mipmap-xxhdpi/icon_sue_round.png
Normal file
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 43 KiB |
BIN
app/app/src/main/res/mipmap-xxxhdpi/icon_sue.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
app/app/src/main/res/mipmap-xxxhdpi/icon_sue_foreground.png
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
app/app/src/main/res/mipmap-xxxhdpi/icon_sue_round.png
Normal file
After Width: | Height: | Size: 34 KiB |
|
@ -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>
|
|
@ -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>
|
||||
|
|
2
build.rs
|
@ -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
|
@ -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
|
@ -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!"
|
||||
|
|
|
@ -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!"
|
||||
|
|
|
@ -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
After Width: | Height: | Size: 3.1 KiB |
BIN
res/crabsue-icon.ico
Normal file
After Width: | Height: | Size: 219 KiB |
BIN
res/crabsue-icon.jpg
Normal file
After Width: | Height: | Size: 71 KiB |
9
res/flatpak/io.github.doukutsu_rs.doukutsu-rs.desktop
Normal 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;
|
138
res/flatpak/io.github.doukutsu_rs.doukutsu-rs.metainfo.xml
Normal 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>
|
BIN
res/flatpak/io.github.doukutsu_rs.doukutsu-rs.png
Normal file
After Width: | Height: | Size: 147 KiB |
BIN
res/flatpak/screens/core-fight.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
res/flatpak/screens/cutscene-skipping.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
res/flatpak/screens/grassrown-lightning.png
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
res/flatpak/screens/snake-trading.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
res/macos/128x128.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
res/macos/128x128@2x.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
res/macos/16x16.png
Normal file
After Width: | Height: | Size: 755 B |
BIN
res/macos/16x16@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
res/macos/256x256.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
res/macos/256x256@2x.png
Normal file
After Width: | Height: | Size: 152 KiB |
BIN
res/macos/32x32.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
res/macos/32x32@2x.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
res/macos/512x512.png
Normal file
After Width: | Height: | Size: 152 KiB |
BIN
res/macos/512x512@2x.png
Normal file
After Width: | Height: | Size: 453 KiB |
161
res/macos/crabsue.svg
Normal file
After Width: | Height: | Size: 313 KiB |
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)?);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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() {
|
||||
|
|
110
src/game/mod.rs
|
@ -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())?;
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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 {
|
||||
|
|