Compare commits

...
Author SHA1 Message Date
Stefan MaierandClaude Opus 5.5 35554cd243 Rename the mod to Mjolnir VR
"Ringfall" is another game's name. Every name players see is now
"Mjolnir VR": the app, the Steam Frame installer and shortcut, the logo
(tools/mjolnir_art.py, was ringfall_art.py), the release's title and
assets (MjolnirVR.apk, mjolnir-vr-android-*.zip,
mjolnir-vr-steam-frame.zip, Install-Mjolnir-VR.desktop), the docs. The
updaters look for Cesarus85/mjolnir-vr, the repository's new name
(GitHub forwards the old one).

Builds 302 to 313 keep working: every release also carries its assets
under their old names, which those builds' updaters and the links
already shared ask for. Kept as they were: the app id, the signing key's
alias, the Steam Frame's ~/Documents/RingfallMjolnirVR and the file
names inside its bundle (an installed game's Steam shortcut starts the
launcher there). The Frame installer now also refreshes the library
pictures of a shortcut that is there already, and says how to rename a
shortcut still called "Ringfall: Mjolnir VR".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:01:25 +02:00
Stefan MaierandClaude Opus 5.5 d4687b24e2 Merge feature/bots-ladders: OpenCE network version 32 (HDR off in VR, Ringfall's host bots kept), bots climb ladders and take partial paths
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 22:05:49 +02:00
Stefan MaierandClaude Opus 5.5 9d65e7e63f Roadmap: network version 32, bots' ladders and paths
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 22:05:48 +02:00
Stefan MaierandClaude Opus 5.5 f3ce8c3bf0 Bots: paths to as near the goal as the search reaches; the goal's floor looked for deeper; ladders for goals above
On Damnation two of three of the bots' path searches failed (1078 against
527 in 80 s), and the goal's floor was not found 357 times: a search had
to reach the goal's surface itself, and the floor under the goal was
looked for 3 world units down. As OpenCE's bots do (bots.c), a search now
goes to as near the goal as it reaches (the bot searches again from
there), and the floor is looked for 6 units down. A path that ends short
of a goal above the bot takes a ladder near it (now within 8 units).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:44:14 +02:00
Stefan MaierandClaude Opus 5.5 bce5c2b560 Bots climb ladders (Damnation's), which the game's pathfinding does not take
A bot whose way is not found twice running, or that is stuck, with the
foot of a ladder going up within 5 world units, walks to the foot, turns
to the ladder and walks into it (as a biped climbs a climbable surface,
bipeds.c), and on past its top a moment; then it finds its way anew. Ten
seconds without getting up, it gives that up for fifteen. The ladders are
the level's climbable upright surfaces, near ones facing alike merged,
found the first time one is wanted in a game. Reported: bots stuck in a
gap of Damnation's that only a ladder leads out of.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:29:10 +02:00
28 changed files with 368 additions and 92 deletions

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: How to install
url: https://github.com/Cesarus85/ringfall-mjolnir-vr#install-on-meta-quest-3--3s
url: https://github.com/Cesarus85/mjolnir-vr#install-on-meta-quest-3--3s
about: Step-by-step installation for the Quest 3 / 3S and the Steam Frame.
+23 -15
View File
@@ -13,7 +13,7 @@ name: Build
# - a newer push to the same branch cancels a run still going;
# - pushes that only change documentation do not build;
# - Windows, whose minutes cost twice Linux's, builds only Windows;
# - Ringfall: Mjolnir VR builds only Android (the VR app): the Linux and
# - Mjolnir VR builds only Android (the VR app): the Linux and
# Windows jobs are kept, off (if: false), so that upstream's changes to
# them still merge;
# - artifacts are kept for three days.
@@ -24,7 +24,7 @@ name: Build
# gives the latest build; the last five are kept. Its web build is then the
# site on GitHub Pages (https://halocombatevolved.com/, port/web/README.md).
on:
# (Ringfall: Mjolnir VR: main only; its branches are tried on the headsets
# (Mjolnir VR: main only; its branches are tried on the headsets
# from local builds)
push:
branches: [main]
@@ -52,7 +52,7 @@ env:
jobs:
linux:
# (off: Ringfall: Mjolnir VR ships the Android app only)
# (off: Mjolnir VR ships the Android app only)
if: ${{ false }}
# Arch Linux has what the build needs as packages: clang 22 (for the
# profile-guided optimisation in pgo/), and CMake, pkg-config and
@@ -203,7 +203,7 @@ jobs:
retention-days: 3
windows:
# (off: Ringfall: Mjolnir VR ships the Android app only)
# (off: Mjolnir VR ships the Android app only)
if: ${{ false }}
# The runner image has LLVM, Python and Visual Studio's x86 libraries and
# Windows SDK.
@@ -279,7 +279,7 @@ jobs:
retention-days: 3
web:
# (off: Ringfall: Mjolnir VR ships the Android app only)
# (off: Mjolnir VR ships the Android app only)
if: ${{ false }}
# Emscripten (emsdk, the version below, cached) builds the web port's
# site (port/web/README.md); the tests check its graph, the page's
@@ -389,18 +389,26 @@ jobs:
- name: Package
run: |
mkdir release
# (Ringfall: Mjolnir VR publishes its Android builds only, under
# (Mjolnir VR publishes its Android builds only, under
# its own name: Updater.java looks for them; the desktop ports are
# built to keep them building)
for config in debug release; do
(cd "artifacts/halo-android-$config" &&
zip -qr "$GITHUB_WORKSPACE/release/ringfall-mjolnir-vr-android-$config.zip" .)
zip -qr "$GITHUB_WORKSPACE/release/mjolnir-vr-android-$config.zip" .)
done
# the Steam Frame's installer (port/android/STEAM_FRAME.md): its
# bundle with the release APK, and the desktop file that fetches it
python3 tools/steam_frame_bundle.py artifacts/halo-android-release/app-release.apk release "$GH_REPO"
# the APK itself, for sideloading on the Quest (SideQuest, adb)
cp artifacts/halo-android-release/app-release.apk release/RingfallMjolnirVR.apk
cp artifacts/halo-android-release/app-release.apk release/MjolnirVR.apk
# the same under the names before "Mjolnir VR" (Ringfall: Mjolnir
# VR, builds 302 to 313): their updaters (Updater.java, the Frame's
# launcher) and the links already shared ask for them
cp release/mjolnir-vr-android-debug.zip release/ringfall-mjolnir-vr-android-debug.zip
cp release/mjolnir-vr-android-release.zip release/ringfall-mjolnir-vr-android-release.zip
cp release/mjolnir-vr-steam-frame.zip release/ringfall-mjolnir-vr-steam-frame.zip
cp release/Install-Mjolnir-VR.desktop release/Install-Ringfall-Mjolnir-VR.desktop
cp release/MjolnirVR.apk release/RingfallMjolnirVR.apk
ls -l release
- name: Publish
@@ -415,15 +423,15 @@ jobs:
readme="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
{
printf '%s\n\n' "$subject"
printf '**Ringfall: Mjolnir VR** is an unofficial VR mod for Halo: Combat Evolved. It needs a disc image of your own, purchased Xbox copy of the game; no game files are included.\n\n'
printf '**Mjolnir VR** is an unofficial VR mod for Halo: Combat Evolved. It needs a disc image of your own, purchased Xbox copy of the game; no game files are included.\n\n'
printf '| Headset | Download | How to install |\n| --- | --- | --- |\n'
printf '| Meta Quest 3 / 3S | `RingfallMjolnirVR.apk` | [Install on Quest](%s#install-on-meta-quest-3--3s) |\n' "$readme"
printf '| Steam Frame | `Install-Ringfall-Mjolnir-VR.desktop` (open it in Desktop Mode) | [Install on Steam Frame](%s#install-on-steam-frame) |\n\n' "$readme"
printf 'The other files are for the built-in updater and the Steam Frame installer.\n\n'
printf '| Meta Quest 3 / 3S | `MjolnirVR.apk` | [Install on Quest](%s#install-on-meta-quest-3--3s) |\n' "$readme"
printf '| Steam Frame | `Install-Mjolnir-VR.desktop` (open it in Desktop Mode) | [Install on Steam Frame](%s#install-on-steam-frame) |\n\n' "$readme"
printf 'The other files are for the built-in updater and the Steam Frame installer (those named `ringfall-…` / `Ringfall…`: the same, for the builds before the name Mjolnir VR).\n\n'
printf 'Commit: %s\nBuild: %s\n' "$COMMIT_URL" "$RUN_URL"
} > notes.md
gh release create "$tag" release/* --target "$GITHUB_SHA" --latest \
--title "Ringfall: Mjolnir VR, build $GITHUB_RUN_NUMBER (${GITHUB_SHA:0:7})" --notes-file notes.md
--title "Mjolnir VR, build $GITHUB_RUN_NUMBER (${GITHUB_SHA:0:7})" --notes-file notes.md
echo "tag=$tag" >> "$GITHUB_OUTPUT"
# The Windows builds' executables and PDBs to Sentry, which turns the
@@ -465,7 +473,7 @@ jobs:
done
pages:
# (off: Ringfall: Mjolnir VR ships the Android app only)
# (off: Mjolnir VR ships the Android app only)
if: ${{ false }}
# The release's web build to GitHub Pages, which serves it at
# https://halocombatevolved.com/ (port/web/README.md, "Hosting"). Only
@@ -586,7 +594,7 @@ jobs:
title="Build failed"; color=15548997
fi
latest="$SERVER/$REPOSITORY/releases/latest"
downloads="[Quest]($latest/download/ringfall-mjolnir-vr-android-release.zip) · [Steam Frame]($latest/download/Install-Ringfall-Mjolnir-VR.desktop) ([all builds]($latest))"
downloads="[Quest]($latest/download/mjolnir-vr-android-release.zip) · [Steam Frame]($latest/download/Install-Mjolnir-VR.desktop) ([all builds]($latest))"
if [ -n "$RELEASE_TAG" ]; then
release="[$RELEASE_TAG]($SERVER/$REPOSITORY/releases/tag/$RELEASE_TAG)"
if [ "$PAGES" = success ]; then
+15 -12
View File
@@ -1,22 +1,25 @@
<p align="center">
<img src="port/android/steam_frame_grid/library.png" width="640" alt="Ringfall: Mjolnir VR">
<img src="port/android/steam_frame_grid/library.png" width="640" alt="Mjolnir VR">
</p>
# Ringfall: Mjolnir VR
# Mjolnir VR
**A VR mod for Halo: Combat Evolved** (the original Xbox game) on the
**Meta Quest 3 / 3S** and the **Steam Frame**. Play the campaign and
multiplayer in full 6DoF virtual reality, with your hands in the game.
Ringfall: Mjolnir VR runs on your headset by itself, without a PC. It
Mjolnir VR runs on your headset by itself, without a PC. It
brings no game files: it uses a disc image of **your own, purchased copy**
of the game.
> **Unofficial fan project.** Ringfall: Mjolnir VR is a free,
> **Unofficial fan project.** Mjolnir VR is a free,
> non-commercial fan project. It is not affiliated with, endorsed,
> sponsored or approved by Microsoft, Xbox Game Studios, Halo Studios or
> Bungie. See [Legal](#legal).
Until build 313 it was called *Ringfall: Mjolnir VR*. Installed builds
update to the new name by themselves, and the old links lead here.
## Contents
- [What you get](#what-you-get)
@@ -86,14 +89,14 @@ that it updates itself.
2. **Install [SideQuest](https://sidequestvr.com/setup-howto)** (the
"Advanced Installer") on your computer and connect the Quest with a
USB cable. In the headset, allow USB debugging for this computer.
3. **Download `RingfallMjolnirVR.apk`** from the
3. **Download `MjolnirVR.apk`** from the
[latest release](../../releases/latest) and drag it onto the SideQuest
window. It installs the game.
4. **Copy your disc image** to the Quest's `Download` folder: in
SideQuest, open the file manager (the folder icon), go to `Download`
and drag the `.iso` file in.
5. **In the headset**, open your *Library*, choose *Unknown Sources* and
start **Ringfall: Mjolnir VR**. Select **Choose disc image** and pick
start **Mjolnir VR**. Select **Choose disc image** and pick
your file in `Download`. The game copies what it needs (about 1.8 GB,
a minute or two) and starts.
@@ -108,14 +111,14 @@ No computer and no keyboard needed.
*Switch to Desktop*.
2. **Put your disc image** in the `Downloads` folder (for example from a
USB stick or memory card with the file manager, Dolphin).
3. **Download `Install-Ringfall-Mjolnir-VR.desktop`** from the
3. **Download `Install-Mjolnir-VR.desktop`** from the
[latest release](../../releases/latest) with the web browser.
4. **Open it**: in Dolphin, open `Downloads` and double-click the file.
If you are asked whether to run it, choose to continue.
5. **Answer the dialogs.** The installer finds your disc image, copies
what the game needs, adds **Ringfall: Mjolnir VR** to your Steam
what the game needs, adds **Mjolnir VR** to your Steam
library and offers to switch back to Gaming Mode.
6. Start **Ringfall: Mjolnir VR** from your library (under *Non-Steam*).
6. Start **Mjolnir VR** from your library (under *Non-Steam*).
The game updates itself: when a new version is out, it is downloaded
while you play and used from the next start on. Your settings, saves and
@@ -155,7 +158,7 @@ telemetry.
## Credits
Ringfall: Mjolnir VR stands on the work of others:
Mjolnir VR stands on the work of others:
- **[OpenCE](https://github.com/OpenCommunityEdition/OpenCE)** (Open
Community Edition): the port of the decompiled game to Linux, Windows
@@ -186,7 +189,7 @@ port it is built on.
## Legal
Ringfall: Mjolnir VR is an unofficial, free, non-commercial fan project.
Mjolnir VR is an unofficial, free, non-commercial fan project.
It is not affiliated with, endorsed, sponsored or approved by Microsoft
Corporation, Xbox Game Studios, Halo Studios or Bungie. Halo, Halo: Combat
Evolved and Xbox are trademarks of Microsoft Corporation; they are named
@@ -201,7 +204,7 @@ their games.
### Licence
Ringfall: Mjolnir VR is free software: you can give it to others and change
Mjolnir VR is free software: you can give it to others and change
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License or (at your option)
any later version (`AGPL-3.0-or-later`), as OpenCE, which it builds on, is.
+1 -1
View File
@@ -1,6 +1,6 @@
# Third-party notices
Ringfall: Mjolnir VR is released under the GNU Affero General Public
Mjolnir VR is released under the GNU Affero General Public
License, version 3 or later ([LICENSE](LICENSE)); releases before build 312
were released under [CC0 1.0](LICENSES/CC0-1.0.txt). It includes or builds
on the following, under their own licenses; each license's full text is in
+1 -1
View File
@@ -1,5 +1,5 @@
> This is the README of [OpenCE](https://github.com/OpenCommunityEdition/OpenCE),
> the port Ringfall: Mjolnir VR is built on, kept for its build and
> the port Mjolnir VR is built on, kept for its build and
> development notes. Its download links are OpenCE's. For the VR mod, see
> the [main README](../README.md).
+2 -1
View File
@@ -1,6 +1,7 @@
# Android
The app of Ringfall: Mjolnir VR (application id `io.github.cesarus85.ringfall`;
The app of Mjolnir VR (application id `io.github.cesarus85.ringfall`, from
the name before, "Ringfall: Mjolnir VR", kept so that installed apps update;
its Java classes keep the decompilation's package, `com.halo.decomp`).
`ninja android` builds the game for 64-bit ARM Android (arm64-v8a).
`ninja android_apk` makes an app from it:
+8 -6
View File
@@ -10,10 +10,10 @@ On the Frame, in Desktop Mode (Steam menu > Power > Switch to Desktop):
1. Put your own disc image of Halo: Combat Evolved for the original Xbox (`.iso` or
`.xiso`, any version) in Downloads (or Documents, the Desktop, a memory
card).
2. Download `Install-Ringfall-Mjolnir-VR.desktop` from the latest release and open it
2. Download `Install-Mjolnir-VR.desktop` from the latest release and open it
(double-click; confirm running it).
3. Answer the dialogs: the installer finds the disc image (or asks for it),
copies the game data out of it, adds "Ringfall: Mjolnir VR" to the Steam library
copies the game data out of it, adds "Mjolnir VR" to the Steam library
and switches back to Gaming Mode. Start it from the library there.
The game updates itself: while it runs, its launcher looks for a newer
@@ -23,18 +23,20 @@ release, fetches it and puts it in place as the next start begins
too (settings, saves and game data stay).
The desktop file (`steam_frame_installer.desktop`) downloads the latest
release's `ringfall-mjolnir-vr-steam-frame.zip` (`tools/steam_frame_bundle.py`, made by
release's `mjolnir-vr-steam-frame.zip` (`tools/steam_frame_bundle.py`, made by
the release job of `.github/workflows/build.yml`) and runs its
`install.sh` (`steam_frame_install.sh`), with zenity dialogs:
- `~/Documents/RingfallMjolnirVR`: the launcher (`ringfall-mjolnir-vr.sh`)
and the release APK (`RingfallMjolnirVR.apk`); the folder of the builds
before the name, `~/Documents/HaloCE`, renamed to it, and their "Halo VR"
shortcut replaced;
shortcut replaced. (These keep the name of builds 302 to 313, "Ringfall:
Mjolnir VR": the Steam shortcut of an installed game starts the launcher
there, and the launcher's update looks for them in the bundle.);
- the maps folder out of the disc image (`steam_frame_xiso.py`, the app's
`XisoExtractor.java` in Python), unless `maps/ui.map` is there;
- the Steam shortcut, unless it is there: added by Steam itself
(`steam://addnonsteamgame`, as SteamOS's "Add to Steam" does) from
`Ringfall Mjolnir VR.desktop` beside the game, then the library pictures
`Mjolnir VR.desktop` beside the game, then the library pictures
under the id Steam gave it. Steam is not closed: on the Frame, Desktop
Mode runs inside Gaming Mode's session, and closing Steam ends it (and the
installer with it). An old "Halo VR" shortcut is left for the player to
@@ -83,7 +85,7 @@ dialogs, for testing over adb; it leaves Steam and its shortcuts alone.
## Starting it on the Frame
A button in the Steam library ("Ringfall: Mjolnir VR", a non-Steam game)
A button in the Steam library ("Mjolnir VR", a non-Steam game)
runs `~/Documents/RingfallMjolnirVR/ringfall-mjolnir-vr.sh` (`port/android/steam_frame_launch.sh`),
which starts the game as Steam starts an Android title of its own:
`lepton waitforexitandrun -- ~/Documents/RingfallMjolnirVR/RingfallMjolnirVR.apk`, in a container
+4 -3
View File
@@ -1,6 +1,6 @@
# VR roadmap
What Ringfall: Mjolnir VR (Quest 3, Steam Frame) has, and what comes next, in the
What Mjolnir VR (Quest 3, Steam Frame) has, and what comes next, in the
agreed order. Updated with every step: a step is **done** once the user has
tried it in the headset and it is merged into `main`; **built** means in a
branch, not yet tried in the headset.
@@ -24,8 +24,8 @@ named where code is taken over.
| Scores | The menu button held shows the scores on the Quest (a press pauses, as it is let go); the Steam Frame's View button as before; the text chat's lines where the desktop has them (2026-10-18) |
| Comfort | Snap or smooth turning, a comfort vignette in vehicles, VR options in the main and pause menus (Y), a page of every controller button |
| Menus | The PC version's menus in VR (`vr.menus`), clicked with a laser; text typed on the on-screen keyboard |
| Multiplayer | Up to date with OpenCE (network version 29, 2026-10-14): cross-play, its server browser, co-op campaign, password lobbies; join codes and the VR online list |
| Bots | Bots in multiplayer: on foot (paths, items, objectives), in vehicles and at turrets; they make room for a joining person, on the LAN too (a lobby they fill is advertised open, 2026-10-18) |
| Multiplayer | Up to date with OpenCE (network version 32, 2026-10-20; HDR kept off in VR): cross-play, its server browser, co-op campaign, password lobbies; join codes and the VR online list |
| Bots | Bots in multiplayer (`host_bots.c`; OpenCE's own, `bots.c`, are local split screen games' and off in VR): on foot (paths, items, objectives), in vehicles and at turrets; they make room for a joining person, on the LAN too (2026-10-18); they climb ladders (Damnation's) and take paths as near their goal as a search reaches, as OpenCE's do: on Damnation 0 searches of 1747 failed, 1078 of 1605 before (2026-10-20). Later: OpenCE's bots' aiming (lead, bursts, taps for the pistol and sniper rifle, field of view), learnt obstacles and map fixes into ours |
| Voice chat | Push to talk on any button (`vr.button_talk`, BUTTONS page; the free hand's grip by default, sending nothing while it reaches for the foregrip or the wheel), open mic, off (2026-10-13) |
| Builds | The Android build's assembly conversion (`tools/android_asm_convert.py`) keeps string data as it is: strings and tables starting with "_" or holding \" lost a "_" (Opus's pulse cache among them: the Steam Frame's crashes in online games while talking), 2026-10-13 |
| Languages | The European disc in Spanish and Italian (a maps folder for each, `maps_es` and `maps_it`, none called `maps`) imported on the Quest and the Steam Frame: the headset's language's, its language the game's and the menus' (`maps/language.txt`, unless `game.language` is set), 2026-10-17; not yet tried with that disc |
@@ -46,6 +46,7 @@ named where code is taken over.
| 4 | Later: disc image import in the launcher; moving by swinging the arms (in place of the stick, never faster than it: online too), and a sprint by swinging them harder (faster than the game allows: offline only) | import **done** (in `main` 2026-10-06): the app's import (tried on the Quest 3: all 24 maps; on the Frame kept in `~/Documents/RingfallMjolnirVR`), a Steam Frame installer from Desktop Mode (`STEAM_FRAME.md`; tried on the Frame: the old folder renamed, the shortcut added by Steam), a release signing key (CI and local builds the same). Arm swinging and its offline sprint still open |
| 5 | Later: multiview again (both eyes in one pass, half the drawing's CPU cost): find why its eyes do not fuse in big online games on the Quest 3 (and now and then on the Steam Frame), then turn it back on | open: off by default since 2026-10-16 (`debug.multiview`); findings in the open points |
| R | Release as **Ringfall: Mjolnir VR** (no "Halo" in the product's name): app name, id `io.github.cesarus85.ringfall`, icon and library pictures (`tools/ringfall_art.py`), Frame folder and installer, release assets, README; the repository renamed | **done** (in `main` 2026-10-06; Quest 3 and Steam Frame good) |
| R2 | Renamed **Mjolnir VR** ("Ringfall" is another game's name): app and Steam names, logo (`tools/mjolnir_art.py`), release assets (also under the old names for the updaters of builds 302 to 313), updaters, README; the repository renamed `Cesarus85/mjolnir-vr` (GitHub forwards the old links). Kept: the app id, the signing key's alias, the Frame's `~/Documents/RingfallMjolnirVR` and the names inside its bundle (installed games and their shortcuts) | in `feature/rename-mjolnir-vr` (2026-10-21) |
## Step 2, first part (done)
@@ -147,7 +147,7 @@ public class LauncherActivity extends Activity {
layout.setBackgroundColor(Color.rgb(12, 16, 20));
TextView title = new TextView(this);
title.setText("Ringfall: Mjolnir VR needs game data");
title.setText("Mjolnir VR needs game data");
title.setTextColor(Color.WHITE);
title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
title.setGravity(Gravity.CENTER);
@@ -36,7 +36,7 @@ import java.util.zip.ZipInputStream;
* the latest release when it starts, on a thread of its own, and if it is
* newer asks the player whether to update:
*
* - Yes: the release's app (ringfall-mjolnir-vr-android-release.zip or
* - Yes: the release's app (mjolnir-vr-android-release.zip or
* -debug.zip) is
* downloaded and handed to Android's package installer, which replaces the
* game (closing it) and offers to open the new version.
@@ -53,8 +53,8 @@ import java.util.zip.ZipInputStream;
final class Updater {
/* the VR port's own releases: the original's, made without VR, must
never replace it (they share the package name) */
private static final String APP_NAME = "Ringfall: Mjolnir VR";
private static final String REPOSITORY = "Cesarus85/ringfall-mjolnir-vr";
private static final String APP_NAME = "Mjolnir VR";
private static final String REPOSITORY = "Cesarus85/mjolnir-vr";
private static final String USER_AGENT = "halo-ce-universal-updater";
private static final int TIMEOUT_MILLISECONDS = 20000;
/** the most a download (a release's zip, about 35 MB) or the app in it may be */
@@ -240,7 +240,7 @@ final class Updater {
/* ---------- updating */
private static void update(Activity activity, int latest) {
String asset = "ringfall-mjolnir-vr-android-" + (BuildConfig.DEBUG ? "debug" : "release") + ".zip";
String asset = "mjolnir-vr-android-" + (BuildConfig.DEBUG ? "debug" : "release") + ".zip";
File directory = new File(activity.getCacheDir(), UpdateProvider.DIRECTORY);
LinearLayout layout = new LinearLayout(activity);
TextView status = new TextView(activity);
@@ -153,7 +153,7 @@ final class XisoExtractor {
break;
}
}
// (Ringfall: a European disc in two languages, Spanish and Italian,
// (Mjolnir VR: a European disc in two languages, Spanish and Italian,
// has no maps folder but one for each, maps_es and maps_it: the
// device's language's is taken, else English's, else the first, and
// its language written to maps/language.txt, which the game asks the
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Ringfall: Mjolnir VR</string>
<string name="app_name">Mjolnir VR</string>
</resources>
+2 -2
View File
@@ -65,7 +65,7 @@ void host_fatal(const char *format, ...)
vsnprintf(message, sizeof(message), format, arguments);
va_end(arguments);
__android_log_write(ANDROID_LOG_FATAL, "halo", message);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Ringfall: Mjolnir VR", message, NULL);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Mjolnir VR", message, NULL);
_exit(1);
}
@@ -540,7 +540,7 @@ int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
host_logf(HOST_LOG_INFO, "Ringfall: Mjolnir VR starting");
host_logf(HOST_LOG_INFO, "Mjolnir VR starting");
host_install_signal_handlers();
if (host_native_thread_create(game_main, NULL, MAIN_STACK_SIZE) != 0)
host_fatal("cannot start the game thread");
+2 -2
View File
@@ -1256,7 +1256,7 @@ with vr.log_performance: host_main.c) */
android.applicationVM = machine;
android.applicationActivity = activity;
instance.next = &android;
strcpy(instance.applicationInfo.applicationName, "Ringfall Mjolnir VR");
strcpy(instance.applicationInfo.applicationName, "Mjolnir VR");
instance.applicationInfo.applicationVersion = 1;
strcpy(instance.applicationInfo.engineName, "halo-ce-universal");
instance.applicationInfo.engineVersion = 1;
@@ -2275,7 +2275,7 @@ void host_xr_test(void)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
window = SDL_CreateWindow("Ringfall: Mjolnir VR", 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
window = SDL_CreateWindow("Mjolnir VR", 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
context = window ? SDL_GL_CreateContext(window) : NULL;
if (!context || !SDL_GL_MakeCurrent(window, context))
host_fatal("VR test: no OpenGL ES context: %s", SDL_GetError());
Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 70 KiB

+28 -12
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Ringfall: Mjolnir VR's installer for the Steam Frame, run in its Desktop
# Mode from the bundle the release's "Install Ringfall: Mjolnir VR" desktop
# Mjolnir VR's installer for the Steam Frame, run in its Desktop
# Mode from the bundle the release's "Install Mjolnir VR" desktop
# file downloads (steam_frame_installer.desktop; the bundle: this script,
# RingfallMjolnirVR.apk, ringfall-mjolnir-vr.sh = steam_frame_launch.sh,
# steam_frame_xiso.py and the library pictures in grid/). Everything is
@@ -19,28 +19,31 @@
# Steam Frame Desktop Mode runs inside Gaming Mode's session, which ends
# with Steam. The shortcut of the builds before the name ("Halo VR") is
# left for the player to remove (Steam would write it back).
# RINGFALL_UNATTENDED=1 answers every question with its default and prints
# instead of showing dialogs (RINGFALL_IMAGE: the disc image to use), for
# MJOLNIR_UNATTENDED=1 answers every question with its default and prints
# instead of showing dialogs (MJOLNIR_IMAGE: the disc image to use), for
# testing over adb; it never closes Steam.
BUNDLE="$(cd "$(dirname "$0")" && pwd)"
GAME_DIR="$HOME/Documents/RingfallMjolnirVR"
STEAM_DIR="$HOME/.local/share/Steam"
LEPTON="$STEAM_DIR/steamapps/common/Lepton/lepton"
TITLE="Ringfall: Mjolnir VR"
NAME="Ringfall: Mjolnir VR"
TITLE="Mjolnir VR"
NAME="Mjolnir VR"
APK_NAME="RingfallMjolnirVR.apk"
LAUNCHER="ringfall-mjolnir-vr.sh"
EXE="\"$GAME_DIR/$LAUNCHER\""
# (the desktop file Steam adds the game from)
NAME_FILE="Ringfall Mjolnir VR"
NAME_FILE="Mjolnir VR"
# the builds before the name: their folder and Steam shortcut
OLD_DIR="$HOME/Documents/HaloCE"
OLD_NAME="Halo VR"
# the name of builds 302 to 313, which their shortcut keeps (Steam writes
# its shortcuts back from memory: the player renames it)
FORMER_NAME="Ringfall: Mjolnir VR"
# what the installer did, for looking into problems: written to /tmp while
# it runs, then kept beside the game as install.log
LOG="/tmp/ringfall-mjolnir-vr-install.log"
LOG="/tmp/mjolnir-vr-install.log"
: > "$LOG"
log() { echo "$(date '+%F %T') $*" >> "$LOG"; }
keep_log() { [ -d "$GAME_DIR" ] && cp -f "$LOG" "$GAME_DIR/install.log" 2>/dev/null; }
@@ -59,7 +62,7 @@ steam_running()
pgrep -f 'ubuntu12_32/steam( |$)' >/dev/null || pgrep -x steam >/dev/null
}
unattended() { [ "${RINGFALL_UNATTENDED:-0}" = 1 ] || ! command -v zenity >/dev/null; }
unattended() { [ "${MJOLNIR_UNATTENDED:-0}" = 1 ] || ! command -v zenity >/dev/null; }
info()
{
@@ -185,7 +188,7 @@ PYTHON
# must run), from a desktop file beside the game; then its pictures
add_shortcut()
{
local desktop="$GAME_DIR/$NAME_FILE.desktop" url file id
local desktop="$GAME_DIR/$NAME_FILE.desktop" url
printf '[Desktop Entry]\nType=Application\nName=%s\nExec=%s\nPath=%s\nIcon=steam\nTerminal=false\n' \
"$NAME" "$GAME_DIR/$LAUNCHER" "$GAME_DIR" > "$desktop" && chmod 755 "$desktop" || return 1
url="steam://addnonsteamgame/$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$desktop")"
@@ -195,6 +198,16 @@ add_shortcut()
steam "$url" >/dev/null 2>&1 &
for _ in $(seq 30); do have_shortcut && break; sleep 1; done
have_shortcut || return 1
add_pictures
return 0
}
# the library pictures of the game's shortcut, for every Steam user who has
# it (again on an update: the builds before the name "Mjolnir VR" had
# Ringfall's)
add_pictures()
{
local file id
while read -r file; do
id="$(shortcut_id "$file" "$EXE")" || continue
log "shortcut $id in $file"
@@ -204,7 +217,6 @@ add_shortcut()
cp "$BUNDLE/grid/library_hero.png" "$(dirname "$file")/grid/${id}_hero.png"
cp "$BUNDLE/grid/library_logo.png" "$(dirname "$file")/grid/${id}_logo.png"
done < <(shortcut_files)
return 0
}
# --- the game
@@ -245,7 +257,7 @@ rm -rf "$GAME_DIR/update"
# --- the game data
if [ ! -f "$GAME_DIR/maps/ui.map" ]; then
image="${RINGFALL_IMAGE:-}"
image="${MJOLNIR_IMAGE:-}"
if [ -z "$image" ]; then
mapfile -t images < <(find_images)
for candidate in "${images[@]}"; do
@@ -271,6 +283,7 @@ fi
if have_shortcut; then
log "the Steam shortcut is there"
add_pictures
elif unattended; then
echo "info: the Steam shortcut is missing (not added unattended)"
elif ! steam_running; then
@@ -286,6 +299,9 @@ fi
if have_shortcut_to "$OLD_DIR/halo-vr.sh"; then
info "The library still shows the old \"$OLD_NAME\" from before the game's new name. It no longer starts: remove it in Steam (its gear or Manage > Remove non-Steam game)."
fi
if have_shortcut_to "$FORMER_NAME"; then
info "The library shows the game by its former name, \"$FORMER_NAME\". To call it $NAME there: its gear > Properties, then its name at the top."
fi
if ask "$NAME is installed.${image_note:-}\n\nSwitch to Gaming Mode now? Start $NAME from your library there (its pictures may show once Steam starts again)." yes; then
steamos-session-select gamescope >/dev/null 2>&1 ||
info "Switch to Gaming Mode yourself (the \"Return to Gaming Mode\" icon or the power menu)."
+5 -5
View File
@@ -1,14 +1,14 @@
[Desktop Entry]
# Ringfall: Mjolnir VR's installer for the Steam Frame
# Mjolnir VR's installer for the Steam Frame
# (port/android/STEAM_FRAME.md): a release asset,
# "Install-Ringfall-Mjolnir-VR.desktop", opened in Desktop Mode. It downloads
# "Install-Mjolnir-VR.desktop", opened in Desktop Mode. It downloads
# the latest release's bundle (tools/steam_frame_bundle.py, which fills in
# the repository) and runs its installer, steam_frame_install.sh.
# (no "$", "\" or "%" in Exec: the desktop entry format would need them
# escaped)
Type=Application
Name=Install Ringfall: Mjolnir VR
Comment=Installs Ringfall: Mjolnir VR for the Steam Frame, or updates it
Name=Install Mjolnir VR
Comment=Installs Mjolnir VR for the Steam Frame, or updates it
Icon=steam
Terminal=false
Exec=bash -c "if curl -fL --retry 3 -o /tmp/ringfall-mjolnir-vr-steam-frame.zip https://github.com/@REPOSITORY@/releases/latest/download/ringfall-mjolnir-vr-steam-frame.zip && rm -rf /tmp/ringfall-mjolnir-vr-install && python3 -m zipfile -e /tmp/ringfall-mjolnir-vr-steam-frame.zip /tmp/ringfall-mjolnir-vr-install; then exec bash /tmp/ringfall-mjolnir-vr-install/install.sh; else zenity --error --width=460 --title='Ringfall: Mjolnir VR' --text='Ringfall: Mjolnir VR could not be downloaded. Is the Steam Frame online?'; fi"
Exec=bash -c "if curl -fL --retry 3 -o /tmp/mjolnir-vr-steam-frame.zip https://github.com/@REPOSITORY@/releases/latest/download/mjolnir-vr-steam-frame.zip && rm -rf /tmp/mjolnir-vr-install && python3 -m zipfile -e /tmp/mjolnir-vr-steam-frame.zip /tmp/mjolnir-vr-install; then exec bash /tmp/mjolnir-vr-install/install.sh; else zenity --error --width=460 --title='Mjolnir VR' --text='Mjolnir VR could not be downloaded. Is the Steam Frame online?'; fi"
+2 -2
View File
@@ -1,5 +1,5 @@
#!/bin/bash
# Ringfall: Mjolnir VR on the Steam Frame: Lepton runs the APK in a container of its own,
# Mjolnir VR on the Steam Frame: Lepton runs the APK in a container of its own,
# and installs it anew whenever the APK is newer than the installed one
# (port/android/STEAM_FRAME.md). The game's data: ~/Documents/RingfallMjolnirVR.
# (a container of its own, not the shortcut's id: with that, SteamVR's
@@ -121,7 +121,7 @@ update_check()
log "update: build $latest found (this is $installed), fetching it"
rm -rf "$UPDATE" && mkdir -p "$UPDATE" || return 0
if curl -fsSL --retry 2 --max-time 900 -o "$UPDATE/bundle.zip" \
"https://github.com/$REPOSITORY/releases/download/build-$latest/ringfall-mjolnir-vr-steam-frame.zip" &&
"https://github.com/$REPOSITORY/releases/download/build-$latest/mjolnir-vr-steam-frame.zip" &&
python3 -I -m zipfile -e "$UPDATE/bundle.zip" "$UPDATE/bundle" &&
[ "$(cat "$UPDATE/bundle/build.txt" 2>/dev/null)" = "$latest" ] &&
[ -s "$UPDATE/bundle/RingfallMjolnirVR.apk" ] && [ -s "$UPDATE/bundle/ringfall-mjolnir-vr.sh" ]
+2 -2
View File
@@ -42,7 +42,7 @@ name that no file before it had (ignoring case).
A European disc in two languages (Spanish and Italian) has no maps folder
but one for each, maps_es and maps_it: the one for the language asked for
(RINGFALL_LANGUAGE, else the system's) is taken, else English's, else the
(MJOLNIR_LANGUAGE, else the system's) is taken, else English's, else the
first, and its language written to maps/language.txt, which the game takes
as the Xbox's language while game.language is unset.
"""
@@ -161,7 +161,7 @@ def choose_maps(folders):
if folder[0].lower() == "maps":
return folder, None
languages = [(maps_language(folder[0]), folder) for folder in folders if maps_language(folder[0])]
wanted = (os.environ.get("RINGFALL_LANGUAGE") or os.environ.get("LC_ALL") or
wanted = (os.environ.get("MJOLNIR_LANGUAGE") or os.environ.get("LC_ALL") or
os.environ.get("LC_MESSAGES") or os.environ.get("LANG") or "")[:2].lower()
for preferred in (wanted, "en"):
for language, folder in languages:
+251 -6
View File
@@ -67,6 +67,9 @@ nearest person on its team.
#include "game/player_queues_new.h"
#include "objects/objects.h"
#include "physics/collisions.h"
#include "physics/bsp3d.h"
#include "physics/collision_bsp.h"
#include "physics/collision_bsp_definitions.h"
#include "ai/path.h"
#include "units/bipeds.h"
#include "items/items.h"
@@ -127,6 +130,15 @@ enum
struct bot
{
long player_index;
/* the ladder it climbs (bot_ladders: its index and one, 0 none), how
long it has, how long past its top, and when it may take one again */
short ladder_plus_one;
/* its path ends short of its goal (no way all the way: the search's
nearest) */
boolean path_partial;
short ladder_ticks;
short ladder_top_ticks;
long ladder_again_time;
long target_unit_index;
short target_seen_ticks;
real yaw;
@@ -240,6 +252,11 @@ static struct
{
boolean map_logged;
boolean vehicles_logged;
/* the level's ladders (bot_ladders_find), found as the game began */
boolean ladders_found;
short ladder_count;
long climbs;
long partial_paths;
struct bot bots[MAXIMUM_BOTS];
long seed;
long logged_time;
@@ -497,7 +514,9 @@ static boolean bot_find_path(
/* (the goal's surface: under it, as a biped would stand there) */
{
struct collision_result collision;
real_vector3d down = { 0.0f, 0.0f, -3.0f };
/* (as far down as OpenCE's bots look, bots.c: a goal over a drop
was none) */
real_vector3d down = { 0.0f, 0.0f, -6.0f };
real_point3d above = goal;
above.z += 0.5f;
@@ -520,8 +539,17 @@ static boolean bot_find_path(
bot_path_debug.path_traverse_result = 0;
bot_path_debug.path_build_result = 0;
path_state_new(&input, &bot_path_state, &bot_path_debug);
path_state_destination(&bot_path_state, &goal, goal_surface, BOT_GOAL_RADIUS);
if (path_state_find(&bot_path_state) && !path_state_build_path(&bot_path_state, &bot->path) &&
/* (to as near the goal as the search reaches, as OpenCE's bots do,
bots.c: a long way across a large level is more surfaces than a search
holds, and a goal up where no walkable surface leads, as up a ladder,
is reached nearer; the bot searches again from there) */
path_state_destination(&bot_path_state, &goal, goal_surface, 1000.0f);
path_state_find(&bot_path_state);
bot->path_partial = bot_path_state.node_count > 0 &&
path_node_from_hash_table(&bot_path_state, goal_surface) == NONE;
if (bot->path_partial)
bots.partial_paths++;
if (bot_path_state.node_count > 0 && !path_state_build_path(&bot_path_state, &bot->path) &&
bot_path_debug.path_build_result == _path_build_result_obstacle_avoidance_failed &&
bot_path_debug.smoothed_step_count > 0)
{
@@ -2332,6 +2360,192 @@ static void bot_walk_to(
action->throttle.j = -dx * (real)sin(yaw) + dy * (real)cos(yaw);
}
/* ---------- ladders
The level's ladders (Damnation's): surfaces it marks climbable, which a
biped walking into, facing them, climbs (bipeds.c), and which the game's
pathfinding does not take. A bot whose way is not found, or that is stuck,
with the foot of one going up near it, climbs it: walks to the foot, turns
to it and walks into it, and past its top a little; then it finds its way
anew. Each ladder: the climbable surfaces of a near place and facing,
merged. */
#define BOT_LADDERS 64
/* collision_surface flags' climbable bit (collision_bsp.c) */
#define BOT_SURFACE_CLIMBABLE 0x04
/* how near its foot a bot takes a ladder (world units), and how long it
tries before giving up on it (ticks), and on ladders a while */
#define BOT_LADDER_RANGE 8.0f
#define BOT_LADDER_TIMEOUT_TICKS 300
#define BOT_LADDER_AGAIN_TICKS 450
static struct bot_ladder
{
/* the climbable surfaces' bounds, and the way into them (flat, unit) */
real_point3d low, high;
real into_x, into_y;
} bot_ladders[BOT_LADDERS];
static void bot_ladders_find(void)
{
struct collision_bsp *bsp = global_collision_bsp_get();
long surface_index;
bots.ladders_found = TRUE;
bots.ladder_count = 0;
if (!bsp)
return;
for (surface_index = 0; surface_index < bsp->surfaces.count; surface_index++)
{
struct collision_surface const *surface = TAG_BLOCK_GET_ELEMENT(&bsp->surfaces, surface_index,
struct collision_surface);
real_point3d points[MAXIMUM_VERTICES_PER_COLLISION_SURFACE];
real_point3d low, high;
real_plane3d plane;
real flat;
short count, point, ladder;
if (!(surface->flags & BOT_SURFACE_CLIMBABLE))
continue;
bsp3d_get_plane_from_designator(&bsp->bsp3d, surface->plane_designator, &plane);
/* (upright: a ladder's face, not its rungs' tops) */
flat = (real)sqrt(plane.n.i * plane.n.i + plane.n.j * plane.n.j);
if (flat < 0.7f)
continue;
count = collision_surface_polygon(bsp, surface_index, points);
if (count < 3)
continue;
low = high = points[0];
for (point = 1; point < count; point++)
{
low.x = MIN(low.x, points[point].x);
low.y = MIN(low.y, points[point].y);
low.z = MIN(low.z, points[point].z);
high.x = MAX(high.x, points[point].x);
high.y = MAX(high.y, points[point].y);
high.z = MAX(high.z, points[point].z);
}
/* (one of a ladder found already, near and facing alike: merged) */
for (ladder = 0; ladder < bots.ladder_count; ladder++)
{
struct bot_ladder *found = &bot_ladders[ladder];
if (low.x < found->high.x + 0.5f && high.x > found->low.x - 0.5f &&
low.y < found->high.y + 0.5f && high.y > found->low.y - 0.5f &&
low.z < found->high.z + 0.5f && high.z > found->low.z - 0.5f &&
found->into_x * -plane.n.i / flat + found->into_y * -plane.n.j / flat > 0.8f)
{
found->low.x = MIN(found->low.x, low.x);
found->low.y = MIN(found->low.y, low.y);
found->low.z = MIN(found->low.z, low.z);
found->high.x = MAX(found->high.x, high.x);
found->high.y = MAX(found->high.y, high.y);
found->high.z = MAX(found->high.z, high.z);
break;
}
}
if (ladder < bots.ladder_count || bots.ladder_count >= BOT_LADDERS)
continue;
bot_ladders[bots.ladder_count].low = low;
bot_ladders[bots.ladder_count].high = high;
bot_ladders[bots.ladder_count].into_x = -plane.n.i / flat;
bot_ladders[bots.ladder_count].into_y = -plane.n.j / flat;
bots.ladder_count++;
}
if (bots.ladder_count)
platform_log("bots: %d ladders on this map", bots.ladder_count);
}
/* a ladder's foot, before it on the floor its bottom is at */
static void bot_ladder_foot(
struct bot_ladder const *ladder,
real_point3d *foot)
{
foot->x = (ladder->low.x + ladder->high.x) * 0.5f - ladder->into_x * 0.4f;
foot->y = (ladder->low.y + ladder->high.y) * 0.5f - ladder->into_y * 0.4f;
foot->z = ladder->low.z;
}
/* the nearest ladder going up from where the bot stands, its foot in reach;
NONE */
static short bot_ladder_near(
real_point3d const *position)
{
short ladder, best = NONE;
real best_distance = BOT_LADDER_RANGE;
if (!bots.ladders_found)
bot_ladders_find();
for (ladder = 0; ladder < bots.ladder_count; ladder++)
{
real_point3d foot;
real distance;
bot_ladder_foot(&bot_ladders[ladder], &foot);
/* (its foot about the floor the bot is on, its top well above) */
if (fabsf(foot.z - position->z) > 1.0f || bot_ladders[ladder].high.z < position->z + 0.8f)
continue;
distance = (real)sqrt((foot.x - position->x) * (foot.x - position->x) +
(foot.y - position->y) * (foot.y - position->y));
if (distance < best_distance)
{
best_distance = distance;
best = ladder;
}
}
return best;
}
/* climbing: the way it walks and faces this tick; FALSE once it is up (or
gives up), its way to be found anew */
static boolean bot_climb(
struct bot *bot,
real_point3d const *position,
struct player_action *action,
real *wanted_yaw)
{
struct bot_ladder const *ladder = &bot_ladders[bot->ladder_plus_one - 1];
real_point3d foot;
real dx, dy, distance;
bot_ladder_foot(ladder, &foot);
dx = foot.x - position->x;
dy = foot.y - position->y;
distance = (real)sqrt(dx * dx + dy * dy);
if (++bot->ladder_ticks > BOT_LADDER_TIMEOUT_TICKS)
{
bot->ladder_again_time = game_time_get() + BOT_LADDER_AGAIN_TICKS;
return FALSE;
}
/* (up: on past the top a moment, onto the floor there) */
if (position->z > ladder->high.z - 0.25f || bot->ladder_top_ticks > 0)
{
if (++bot->ladder_top_ticks > 20)
{
bots.climbs++;
bot->ladder_again_time = game_time_get() + 90;
return FALSE;
}
*wanted_yaw = (real)atan2(ladder->into_y, ladder->into_x);
action->throttle.i = 1.0f;
action->throttle.j = 0.0f;
return TRUE;
}
/* (to its foot, then into it, facing it) */
if (distance > 0.35f && position->z < ladder->low.z + 0.4f)
{
*wanted_yaw = (real)atan2(dy, dx);
bot_walk_to(action, bot->yaw, position, &foot);
return TRUE;
}
*wanted_yaw = (real)atan2(ladder->into_y, ladder->into_x);
action->throttle.i = (real)cos(bot->yaw - *wanted_yaw);
action->throttle.j = 0.0f;
if (action->throttle.i < 0.3f)
action->throttle.i = 0.3f;
return TRUE;
}
static void bot_think(
struct bot *bot,
struct player_datum *player,
@@ -2751,6 +2965,35 @@ static void bot_think(
bot->has_goal = TRUE;
bot->goal_time = game_time_get();
}
/* (no way found, or stuck, by a ladder going up: up it) */
if (!bot->ladder_plus_one &&
(bot->path_failures >= 2 || bot->stuck_ticks >= 6 ||
(bot->path_partial && bot->has_goal && bot->goal.z > position.z + 0.8f)) &&
(game_time_get() >= bot->ladder_again_time || game_time_get() < bot->ladder_again_time - 1000))
{
short ladder = bot_ladder_near(&position);
if (ladder != NONE)
{
bot->ladder_plus_one = (short)(ladder + 1);
bot->ladder_ticks = 0;
bot->ladder_top_ticks = 0;
}
}
if (bot->ladder_plus_one)
{
if (bot_climb(bot, &position, action, &wanted_yaw))
{
bot->stuck_ticks = 0;
bot->sidestep_ticks = 0;
}
else
{
bot->ladder_plus_one = 0;
bot->path_failures = 0;
bot->path_time = game_time_get() - PATH_REFRESH_TICKS;
}
}
if (bot->stuck_ticks > 20)
{
/* (stuck: somewhere else) */
@@ -2954,6 +3197,8 @@ void bots_new_game(
bots.map_logged = FALSE;
bots.vehicles_logged = FALSE;
bots.ladders_found = FALSE;
bots.ladder_count = 0;
for (index = 0; index < MAXIMUM_BOTS; index++)
bots.bots[index].player_index = NONE;
bots.seed = 12345;
@@ -3025,12 +3270,12 @@ void bots_tick(
}
}
bots.logged_time = game_time_get();
platform_log("bots: driving %d; paths found %ld, not %ld; weapon swaps asked %ld; grenades %ld; changes %ld; stuck %ld, long %ld, gave up %ld (no start %ld, no goal %ld, no way %ld); vehicles: in %ld, out %ld",
(int)count, bots.paths_found, bots.paths_failed, bots.pickups, bots.grenades, bots.switches, bots.stucks, bots.long_stucks, bots.gave_up, bots.fail_start, bots.fail_goal, bots.fail_search,
platform_log("bots: driving %d; paths found %ld, not %ld; weapon swaps asked %ld; grenades %ld; changes %ld; stuck %ld, long %ld, gave up %ld (no start %ld, no goal %ld, no way %ld); ladders climbed %ld; partial paths %ld; vehicles: in %ld, out %ld",
(int)count, bots.paths_found, bots.paths_failed, bots.pickups, bots.grenades, bots.switches, bots.stucks, bots.long_stucks, bots.gave_up, bots.fail_start, bots.fail_goal, bots.fail_search, bots.climbs, bots.partial_paths,
bots.vehicle_entries, bots.vehicle_exits);
bots.vehicle_entries = bots.vehicle_exits = 0;
bots.fail_start = bots.fail_goal = bots.fail_search = 0;
bots.paths_found = bots.paths_failed = bots.pickups = bots.grenades = bots.switches = bots.stucks = bots.long_stucks = bots.gave_up = 0;
bots.paths_found = bots.paths_failed = bots.pickups = bots.grenades = bots.switches = bots.stucks = bots.long_stucks = bots.gave_up = bots.climbs = bots.partial_paths = 0;
for (index = 0; index < MAXIMUM_TRACKED_PLAYERS; index++)
{
struct player_datum *player = distributed_player(index);
+1 -1
View File
@@ -2290,7 +2290,7 @@ static void hdr_read(void)
exposure = config_real("display.hdr_exposure");
wanted = config_boolean("display.hdr");
#ifdef HALO_ANDROID
/* (port, Ringfall: never in VR, whose eyes' pictures go to the headset
/* (port, Mjolnir VR: never in VR, whose eyes' pictures go to the headset
as they are, and whose GPU time is short already) */
if (halo_vr_active())
wanted = FALSE;
+1 -1
View File
@@ -564,7 +564,7 @@ unsigned int hud_hires_png_texture(const void *png, unsigned long size, unsigned
return png_pixels_texture(pixels, width, height, levels);
}
/* (port, Ringfall: the same in two steps, the decode on any thread:
/* (port, Mjolnir VR: the same in two steps, the decode on any thread:
menu_files.c's menu pictures) */
unsigned char *hud_hires_png_pixels(const void *png, unsigned long size, unsigned long *width, unsigned long *height)
{
+1 -1
View File
@@ -648,7 +648,7 @@ static const struct config_setting config_settings[] =
"as CUSTOM SINGLEPLAYER and CUSTOM MULTIPLAYER. Their tags are checked\n"
"as the game's own maps' are before they run; false refuses them\n"
"(docs/custom_edition_caches.md)." },
/* (the desktop's local bots, bots.c; Ringfall's host bots have their own
/* (the desktop's local bots, bots.c; Mjolnir VR's host bots have their own
bots.count and bots.skill, Android's, below: host_bots.c) */
{ "bots.count", _config_integer, "0", "HALO_BOTS", _environment_value, _platform_desktop,
"Computer players (bots) in a local (split screen) Slayer game: 0 to 15\n"
+1 -1
View File
@@ -47,7 +47,7 @@ update.h's: posix_update.c on Linux, win32_update.c on Windows.
#endif
/* the VR port's own releases (the original's must not replace it) */
#define UPDATE_REPOSITORY "Cesarus85/ringfall-mjolnir-vr"
#define UPDATE_REPOSITORY "Cesarus85/mjolnir-vr"
#ifdef _WIN32
#define UPDATE_PLATFORM "windows"
#define PATH_SEPARATOR "\\"
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
"""
Ringfall: Mjolnir VR's pictures, drawn from nothing but shapes and the
Mjolnir VR's pictures, drawn from nothing but shapes and the
port's Overpass font (port/assets/fonts, SIL Open Font License):
python3 tools/ringfall_art.py
python3 tools/mjolnir_art.py
writes
- port/android/art/android-icon.png, the launcher icon's artwork (then run
@@ -99,11 +99,11 @@ def italic_text(text, height, fill):
def logo(width):
""""RINGFALL" over "MJOLNIR VR", as wide as asked, transparent"""
title = italic_text("RINGFALL", 200, LIGHT)
""""MJOLNIR" over "VR", as wide as asked, transparent"""
title = italic_text("MJOLNIR", 200, LIGHT)
title = title.resize((width, int(title.height * width / title.width)), Image.LANCZOS)
subtitle = italic_text("MJOLNIR VR", 200, ACCENT)
sub_width = int(width * 0.62)
subtitle = italic_text("VR", 200, ACCENT)
sub_width = int(width * 0.30)
subtitle = subtitle.resize((sub_width, int(subtitle.height * sub_width / subtitle.width)), Image.LANCZOS)
gap = int(title.height * 0.16)
image = Image.new("RGBA", (width, title.height + gap + subtitle.height), (0, 0, 0, 0))
+4 -4
View File
@@ -5,14 +5,14 @@ The Steam Frame's installer as release assets (port/android/STEAM_FRAME.md):
python3 tools/steam_frame_bundle.py <apk> <output folder> <owner/repository>
writes into the output folder
- ringfall-mjolnir-vr-steam-frame.zip: the installer (port/android/steam_frame_install.sh,
- mjolnir-vr-steam-frame.zip: the installer (port/android/steam_frame_install.sh,
as install.sh), the APK (RingfallMjolnirVR.apk), the launcher
(steam_frame_launch.sh, as ringfall-mjolnir-vr.sh, which updates the game
from the repository named), the build's number (build.txt: the workflow's
run number, HALO_BUILD_NUMBER or GITHUB_RUN_NUMBER; 0, which never
updates, without one), the disc image reader (steam_frame_xiso.py) and
the library pictures (grid/);
- Install-Ringfall-Mjolnir-VR.desktop (port/android/steam_frame_installer.desktop): what
- Install-Mjolnir-VR.desktop (port/android/steam_frame_installer.desktop): what
the player downloads and opens in Desktop Mode; it fetches the latest
release's zip from the repository named.
"""
@@ -44,7 +44,7 @@ def main():
build = os.environ.get("HALO_BUILD_NUMBER") or os.environ.get("GITHUB_RUN_NUMBER") or "0"
if not build.isdigit():
build = "0"
bundle = output / "ringfall-mjolnir-vr-steam-frame.zip"
bundle = output / "mjolnir-vr-steam-frame.zip"
with zipfile.ZipFile(bundle, "w", zipfile.ZIP_DEFLATED) as archive:
for path, name, mode in files:
info = zipfile.ZipInfo.from_file(path, name)
@@ -60,7 +60,7 @@ def main():
print(f"{bundle.relative_to(Path.cwd()) if bundle.is_relative_to(Path.cwd()) else bundle}")
desktop = (ANDROID / "steam_frame_installer.desktop").read_text().replace("@REPOSITORY@", repository)
installer = output / "Install-Ringfall-Mjolnir-VR.desktop"
installer = output / "Install-Mjolnir-VR.desktop"
installer.write_text(desktop)
installer.chmod(0o755)
print(installer)