misc: merge tr2 and libtrx codebases
12
.github/workflows/build_docker.yml
vendored
|
@ -10,8 +10,12 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- platform: win
|
- game_version: tr1
|
||||||
- platform: linux
|
platform: win
|
||||||
|
- game_version: tr1
|
||||||
|
platform: linux
|
||||||
|
- game_version: tr2
|
||||||
|
platform: win
|
||||||
steps:
|
steps:
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
|
@ -29,5 +33,5 @@ jobs:
|
||||||
|
|
||||||
- name: Build Docker image (${{ matrix.platform }})
|
- name: Build Docker image (${{ matrix.platform }})
|
||||||
run: |
|
run: |
|
||||||
just image-${{ matrix.platform }}
|
just ${{ matrix.game_version }}-image-${{ matrix.platform }}
|
||||||
just push-image-${{ matrix.platform }}
|
just ${{ matrix.game_version }}-push-image-${{ matrix.platform }}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name: Build the game and the installer
|
name: Build TR1X and the installer
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
@ -12,11 +12,11 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- platform: linux
|
- platform: linux
|
||||||
just_target: package-linux
|
just_target: tr1-package-linux
|
||||||
- platform: win
|
- platform: win
|
||||||
just_target: package-win-all
|
just_target: tr1-package-win-all
|
||||||
- platform: win-installer
|
- platform: win-installer
|
||||||
just_target: package-win-installer
|
just_target: tr1-package-win-installer
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
@ -30,7 +30,7 @@ jobs:
|
||||||
|
|
||||||
- id: vars
|
- id: vars
|
||||||
name: Prepare variables
|
name: Prepare variables
|
||||||
run: echo "version=$(just output-current-version)" >> $GITHUB_OUTPUT
|
run: echo "version=$(just output-current-version 1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Package asset (${{ matrix.platform }})
|
- name: Package asset (${{ matrix.platform }})
|
||||||
run: just ${{ matrix.just_target }}
|
run: just ${{ matrix.just_target }}
|
||||||
|
@ -38,7 +38,7 @@ jobs:
|
||||||
- name: Upload the artifact
|
- name: Upload the artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.repository.name }}-${{ steps.vars.outputs.version }}-${{ matrix.platform }}
|
name: TR1X-${{ steps.vars.outputs.version }}-${{ matrix.platform }}
|
||||||
path: |
|
path: |
|
||||||
*.zip
|
*.zip
|
||||||
*.exe
|
*.exe
|
|
@ -1,4 +1,4 @@
|
||||||
name: Build the game and the installer (macOS)
|
name: Build TR1X and the installer (macOS)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
@ -225,14 +225,14 @@ jobs:
|
||||||
- name: Build arm64 and create app bundle
|
- name: Build arm64 and create app bundle
|
||||||
run: |
|
run: |
|
||||||
BUILD_DIR=build-arm64
|
BUILD_DIR=build-arm64
|
||||||
BUILD_OPTIONS="--prefix=/tmp/TR1X.app --bindir=Contents/MacOS"
|
BUILD_OPTIONS="src/tr1 --prefix=/tmp/TR1X.app --bindir=Contents/MacOS"
|
||||||
meson setup $BUILD_DIR $BUILD_OPTIONS
|
meson setup $BUILD_DIR $BUILD_OPTIONS
|
||||||
meson install -C $BUILD_DIR
|
meson install -C $BUILD_DIR
|
||||||
|
|
||||||
- name: Build x86-64
|
- name: Build x86-64
|
||||||
run: |
|
run: |
|
||||||
BUILD_DIR=build-x86-64
|
BUILD_DIR=build-x86-64
|
||||||
BUILD_OPTIONS="--prefix=/tmp/TR1X.app --bindir=Contents/MacOS --cross-file tools/tr1/mac/x86-64_cross_file.txt"
|
BUILD_OPTIONS="src/tr1 --prefix=/tmp/TR1X.app --bindir=Contents/MacOS --cross-file tools/tr1/mac/x86-64_cross_file.txt"
|
||||||
meson setup $BUILD_DIR $BUILD_OPTIONS
|
meson setup $BUILD_DIR $BUILD_OPTIONS
|
||||||
meson compile -C $BUILD_DIR
|
meson compile -C $BUILD_DIR
|
||||||
|
|
||||||
|
@ -267,11 +267,11 @@ jobs:
|
||||||
/usr/bin/codesign --force --options runtime -s "${IDENTITY}" --keychain $KEYCHAIN_PATH -v TR1X-Installer.dmg
|
/usr/bin/codesign --force --options runtime -s "${IDENTITY}" --keychain $KEYCHAIN_PATH -v TR1X-Installer.dmg
|
||||||
xcrun notarytool submit --wait --apple-id "$MACOS_APPLEID" --password "$MACOS_APP_PWD" --team-id "$MACOS_TEAMID" TR1X-Installer.dmg
|
xcrun notarytool submit --wait --apple-id "$MACOS_APPLEID" --password "$MACOS_APP_PWD" --team-id "$MACOS_TEAMID" TR1X-Installer.dmg
|
||||||
xcrun stapler staple -v TR1X-Installer.dmg
|
xcrun stapler staple -v TR1X-Installer.dmg
|
||||||
mv TR1X-Installer.dmg "TR1X-$(tools/get_version)-Installer.dmg"
|
mv TR1X-Installer.dmg "TR1X-$(tools/get_version 1)-Installer.dmg"
|
||||||
|
|
||||||
- id: vars
|
- id: vars
|
||||||
name: Prepare variables
|
name: Prepare variables
|
||||||
run: echo "version=$(tools/get_version)" >> $GITHUB_OUTPUT
|
run: echo "version=$(tools/get_version 1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Upload signed+notarized installer image
|
- name: Upload signed+notarized installer image
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
40
.github/workflows/job_build_tr2.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
name: Build TR2X
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build release assets
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- platform: win
|
||||||
|
just_target: tr2-package-win-all
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
uses: taiki-e/install-action@just
|
||||||
|
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- id: vars
|
||||||
|
name: Prepare variables
|
||||||
|
run: echo "version=$(just output-current-version 2)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Package asset (${{ matrix.platform }})
|
||||||
|
run: just ${{ matrix.just_target }}
|
||||||
|
|
||||||
|
- name: Upload the artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: TR2X-${{ steps.vars.outputs.version }}-${{ matrix.platform }}
|
||||||
|
path: |
|
||||||
|
*.zip
|
||||||
|
*.exe
|
29
.github/workflows/job_release.yml
vendored
|
@ -3,6 +3,10 @@ name: Create a new release
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
|
changelog_game_version:
|
||||||
|
type: string
|
||||||
|
description: "Game version to build the changelog from"
|
||||||
|
required: true
|
||||||
draft:
|
draft:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: "Draft"
|
description: "Draft"
|
||||||
|
@ -13,11 +17,6 @@ on:
|
||||||
description: "Prerelease"
|
description: "Prerelease"
|
||||||
required: true
|
required: true
|
||||||
default: false
|
default: false
|
||||||
release_name:
|
|
||||||
type: string
|
|
||||||
description: "Release name"
|
|
||||||
required: true
|
|
||||||
default: "Release ${{ github.ref_name }}"
|
|
||||||
tag_name:
|
tag_name:
|
||||||
type: string
|
type: string
|
||||||
description: "Tag name"
|
description: "Tag name"
|
||||||
|
@ -39,19 +38,21 @@ jobs:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: "Prepare release data"
|
||||||
|
id: prepare_release_data
|
||||||
|
run: |
|
||||||
|
echo -n "release_name=" >> $GITHUB_OUTPUT
|
||||||
|
just output-release-name ${{ inputs.changelog_game_version }} >> $GITHUB_OUTPUT
|
||||||
|
echo "changelog<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
just output-current-changelog ${{ inputs.changelog_game_version }} >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: "Download built game assets"
|
- name: "Download built game assets"
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: artifacts/
|
path: artifacts/
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
||||||
- name: "Generate changelog"
|
|
||||||
run: |
|
|
||||||
hash=$(git log -1 --pretty=format:%H)
|
|
||||||
tag=$(just output-current-version)
|
|
||||||
echo -e "**Commit: $hash** \n**Tag: $tag**\n\n### Changes\n" > _changes.txt
|
|
||||||
just output-current-changelog >> _changes.txt
|
|
||||||
|
|
||||||
- name: "Get information on the latest pre-release"
|
- name: "Get information on the latest pre-release"
|
||||||
if: ${{ inputs.prerelease == true || inputs.prerelease == 'true' }}
|
if: ${{ inputs.prerelease == true || inputs.prerelease == 'true' }}
|
||||||
id: last_release
|
id: last_release
|
||||||
|
@ -77,9 +78,9 @@ jobs:
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
name: ${{ inputs.release_name }}
|
|
||||||
tag_name: ${{ inputs.tag_name }}
|
tag_name: ${{ inputs.tag_name }}
|
||||||
body_path: _changes.txt
|
name: ${{ steps.prepare_release_data.outputs.release_name }}
|
||||||
|
body: ${{ steps.prepare_release_data.outputs.changelog }}
|
||||||
draft: ${{ inputs.draft == true || inputs.draft == 'true' }}
|
draft: ${{ inputs.draft == true || inputs.draft == 'true' }}
|
||||||
prerelease: ${{ inputs.prerelease == true || inputs.prerelease == 'true' }}
|
prerelease: ${{ inputs.prerelease == true || inputs.prerelease == 'true' }}
|
||||||
fail_on_unmatched_files: true
|
fail_on_unmatched_files: true
|
||||||
|
|
17
.github/workflows/pr_builds.yml
vendored
|
@ -11,15 +11,20 @@ on:
|
||||||
- '!develop'
|
- '!develop'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
package_multiplatform:
|
package_tr1_multiplatform:
|
||||||
name: 'Create a test build'
|
name: Build TR1
|
||||||
uses: ./.github/workflows/job_build_game.yml
|
uses: ./.github/workflows/job_build_tr1.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
package_mac:
|
package_tr1_mac:
|
||||||
name: 'Create a test build (macOS)'
|
name: Build TR1
|
||||||
if: vars.MACOS_ENABLE == 'true'
|
if: vars.MACOS_ENABLE == 'true'
|
||||||
uses: ./.github/workflows/job_build_game_macos.yml
|
uses: ./.github/workflows/job_build_tr1_macos.yml
|
||||||
with:
|
with:
|
||||||
let_mac_fail: true
|
let_mac_fail: true
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
package_tr2_multiplatform:
|
||||||
|
name: Build TR2
|
||||||
|
uses: ./.github/workflows/job_build_tr2.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
25
.github/workflows/prerelease.yml
vendored
|
@ -9,31 +9,38 @@ on:
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
package_multiplatform:
|
package_tr1_multiplatform:
|
||||||
name: Build prerelease assets
|
name: Build TR1
|
||||||
if: vars.PRERELEASE_ENABLE == 'true'
|
if: vars.PRERELEASE_ENABLE == 'true'
|
||||||
uses: ./.github/workflows/job_build_game.yml
|
uses: ./.github/workflows/job_build_tr1.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
package_mac:
|
package_tr1_mac:
|
||||||
name: "Build prerelease assets (mac)"
|
name: Build TR1
|
||||||
if: |
|
if: |
|
||||||
vars.PRERELEASE_ENABLE == 'true' &&
|
vars.PRERELEASE_ENABLE == 'true' &&
|
||||||
vars.MACOS_ENABLE == 'true'
|
vars.MACOS_ENABLE == 'true'
|
||||||
uses: ./.github/workflows/job_build_game_macos.yml
|
uses: ./.github/workflows/job_build_tr1_macos.yml
|
||||||
with:
|
with:
|
||||||
let_mac_fail: true
|
let_mac_fail: true
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
package_tr2_multiplatform:
|
||||||
|
name: Build TR2
|
||||||
|
if: vars.PRERELEASE_ENABLE == 'true'
|
||||||
|
uses: ./.github/workflows/job_build_tr2.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
publish_prerelease:
|
publish_prerelease:
|
||||||
if: vars.PRERELEASE_ENABLE == 'true'
|
if: vars.PRERELEASE_ENABLE == 'true'
|
||||||
name: Create a prerelease
|
name: Create a prerelease
|
||||||
needs:
|
needs:
|
||||||
- package_multiplatform
|
- package_tr1_multiplatform
|
||||||
- package_mac
|
- package_tr1_mac
|
||||||
|
- package_tr2_multiplatform
|
||||||
with:
|
with:
|
||||||
release_name: 'Development snapshot'
|
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: true
|
prerelease: true
|
||||||
tag_name: 'latest'
|
tag_name: 'latest'
|
||||||
|
changelog_game_version: 'all'
|
||||||
uses: ./.github/workflows/job_release.yml
|
uses: ./.github/workflows/job_release.yml
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name: Publish a new release
|
name: Publish a new TR1X release
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
@ -7,7 +7,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branch: stable
|
branch: stable
|
||||||
tags:
|
tags:
|
||||||
- "v?[0-9]*"
|
- "tr1-*"
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
|
@ -21,11 +21,6 @@ on:
|
||||||
required: true
|
required: true
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
release_name:
|
|
||||||
description: "Release name"
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
default: "Release name"
|
|
||||||
tag_name:
|
tag_name:
|
||||||
description: "Tag name"
|
description: "Tag name"
|
||||||
required: false
|
required: false
|
||||||
|
@ -36,7 +31,7 @@ jobs:
|
||||||
package_multiplatform:
|
package_multiplatform:
|
||||||
name: Build release assets
|
name: Build release assets
|
||||||
if: vars.RELEASE_ENABLE == 'true'
|
if: vars.RELEASE_ENABLE == 'true'
|
||||||
uses: ./.github/workflows/job_build_game.yml
|
uses: ./.github/workflows/job_build_tr1.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
package_mac:
|
package_mac:
|
||||||
|
@ -44,7 +39,7 @@ jobs:
|
||||||
if: |
|
if: |
|
||||||
vars.RELEASE_ENABLE == 'true' &&
|
vars.RELEASE_ENABLE == 'true' &&
|
||||||
vars.MACOS_ENABLE == 'true'
|
vars.MACOS_ENABLE == 'true'
|
||||||
uses: ./.github/workflows/job_build_game_macos.yml
|
uses: ./.github/workflows/job_build_tr1_macos.yml
|
||||||
with:
|
with:
|
||||||
let_mac_fail: ${{ inputs.let_mac_fail == true || inputs.let_mac_fail == 'true' }}
|
let_mac_fail: ${{ inputs.let_mac_fail == true || inputs.let_mac_fail == 'true' }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
@ -56,8 +51,8 @@ jobs:
|
||||||
- package_multiplatform
|
- package_multiplatform
|
||||||
- package_mac
|
- package_mac
|
||||||
with:
|
with:
|
||||||
release_name: ${{ inputs.release_name }}
|
|
||||||
draft: ${{ inputs.draft || false }}
|
draft: ${{ inputs.draft || false }}
|
||||||
prerelease: ${{ inputs.draft || false }}
|
prerelease: ${{ inputs.draft || false }}
|
||||||
tag_name: ${{ inputs.tag_name || github.ref_name }}
|
tag_name: ${{ inputs.tag_name || github.ref_name }}
|
||||||
|
changelog_game_version: 1
|
||||||
uses: ./.github/workflows/job_release.yml
|
uses: ./.github/workflows/job_release.yml
|
47
.github/workflows/release_tr2.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
name: Publish a new TR2X release
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branch: stable
|
||||||
|
tags:
|
||||||
|
- "tr2-*"
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
draft:
|
||||||
|
description: "Draft"
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
prerelease:
|
||||||
|
description: "Prerelease"
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
tag_name:
|
||||||
|
description: "Tag name"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: github.ref_name
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
package_multiplatform:
|
||||||
|
name: Build release assets
|
||||||
|
if: vars.RELEASE_ENABLE == 'true'
|
||||||
|
uses: ./.github/workflows/job_build_tr2.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
publish_release:
|
||||||
|
if: vars.RELEASE_ENABLE == 'true'
|
||||||
|
name: Create a GitHub release
|
||||||
|
needs:
|
||||||
|
- package_multiplatform
|
||||||
|
with:
|
||||||
|
draft: ${{ inputs.draft || false }}
|
||||||
|
prerelease: ${{ inputs.draft || false }}
|
||||||
|
tag_name: ${{ inputs.tag_name || github.ref_name }}
|
||||||
|
changelog_game_version: 2
|
||||||
|
uses: ./.github/workflows/job_release.yml
|
12
.gitignore
vendored
|
@ -31,8 +31,10 @@ Release/
|
||||||
.dotnet/
|
.dotnet/
|
||||||
|
|
||||||
# libtrx artefacts
|
# libtrx artefacts
|
||||||
subprojects/packagecache/
|
**/subprojects/packagecache/
|
||||||
subprojects/dwarfstack-*/
|
**/subprojects/dwarfstack-*/
|
||||||
subprojects/dwarfstack.wrap
|
**/subprojects/uthash-*/
|
||||||
subprojects/uthash-*/
|
src/tr1/subprojects/dwarfstack.wrap
|
||||||
subprojects/uthash.wrap
|
src/tr1/subprojects/uthash.wrap
|
||||||
|
src/tr2/subprojects/dwarfstack.wrap
|
||||||
|
src/tr2/subprojects/uthash.wrap
|
||||||
|
|
|
@ -8,12 +8,6 @@ repos:
|
||||||
language: system
|
language: system
|
||||||
files: \.[ch](pp)?$
|
files: \.[ch](pp)?$
|
||||||
|
|
||||||
- id: update-gameflow
|
|
||||||
name: Update game flow files
|
|
||||||
entry: tools/update_gameflow
|
|
||||||
language: python
|
|
||||||
stages: [commit]
|
|
||||||
|
|
||||||
- id: additional-lint
|
- id: additional-lint
|
||||||
name: Run additional linters
|
name: Run additional linters
|
||||||
entry: tools/additional_lint
|
entry: tools/additional_lint
|
||||||
|
@ -25,3 +19,9 @@ repos:
|
||||||
entry: tools/sort_imports
|
entry: tools/sort_imports
|
||||||
language: system
|
language: system
|
||||||
files: \.[ch](pp)?$
|
files: \.[ch](pp)?$
|
||||||
|
|
||||||
|
- id: update-gameflow
|
||||||
|
name: Update game flow files
|
||||||
|
entry: tools/update_gameflow
|
||||||
|
language: python
|
||||||
|
stages: [commit]
|
||||||
|
|
713
README.md
|
@ -1,711 +1,128 @@
|
||||||
<p align="center">
|
<div align="center">
|
||||||
<img alt="TR1X logo" src="data/tr1/logo-light-theme.png#gh-light-mode-only" width="400"/>
|
<h1>TRX – Tomb Raider I & II: Community Edition</h1>
|
||||||
<img alt="TR1X logo" src="data/tr1/logo-dark-theme.png#gh-dark-mode-only" width="400"/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
This is an open source implementation of the classic Tomb Raider I game (1996),
|
<a href="https://github.com/rr-/TRX/releases?q=tr1x+prerelease%3Afalse&expanded=true">
|
||||||
made by reverse engineering the TombATI / GLRage variant of the original game
|
<img src="data/download_tr1x.svg"/>
|
||||||
and replacing proprietary audio/video libraries with open source variants.
|
</a>
|
||||||
|
<a href="https://github.com/rr-/TRX/releases?q=tr2x+prerelease%3Afalse&expanded=true">
|
||||||
|
<img src="data/download_tr2x.svg"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
See the [Tomb Raider Forums
|
<hr/>
|
||||||
topic](https://www.tombraiderforums.com/showthread.php?p=8286101).
|
|
||||||
|
|
||||||
## Showcase
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> We've merged TR1X and TR2X into a single codebase, now renamed **TRX**.
|
||||||
|
>
|
||||||
|
> - TR1 and TR2 remain distinct with their own release cycles.
|
||||||
|
> - Config tools and TR1 installer remain separate.
|
||||||
|
> - Simplifies internal code merges and feature sharing, replacing **libtrx**.
|
||||||
|
>
|
||||||
|
> Thanks for your support!
|
||||||
|
|
||||||
|
|
||||||
|
Welcome to **TRX** – an open-source reimplementation of **Tomb Raider 1** and **Tomb Raider 2**, respectively. Both projects aim to enhance these classic games through decompilation and the implementation of open-source alternatives to proprietary components.
|
||||||
|
|
||||||
|
## TR1X - Tomb Raider 1
|
||||||
|
### Showcase
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
Restored braid
|
Restored braid
|
||||||
<img src="docs/showcase/braid.jpg"/>
|
<img src="docs/tr1/showcase/braid.jpg"/>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Enemy health bar and UI scaling
|
Enemy health bar and UI scaling
|
||||||
<img src="docs/showcase/enemy_health_bar_and_scaling.jpg"/>
|
<img src="docs/tr1/showcase/enemy_health_bar_and_scaling.jpg"/>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
3D pickups
|
3D pickups
|
||||||
<img src="docs/showcase/3d_pickups.jpg"/>
|
<img src="docs/tr1/showcase/3d_pickups.jpg"/>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
|
||||||
Improved stats
|
|
||||||
<img src="docs/showcase/compass_stats.jpg"/>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>
|
<th>
|
||||||
Skybox support
|
Skybox support
|
||||||
<img src="docs/showcase/skybox.jpg"/>
|
<img src="docs/tr1/showcase/skybox.jpg"/>
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Customizable draw distance
|
|
||||||
<img src="docs/showcase/draw_distance.webp"/>
|
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
Fly cheat
|
Customizable draw distance
|
||||||
<img src="docs/showcase/fly_cheat.jpg"/>
|
<img src="docs/tr1/showcase/draw_distance.webp"/>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Developer console
|
Developer console
|
||||||
<img src="docs/showcase/console.webp"/>
|
<img src="docs/tr1/showcase/console.webp"/>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
Free camera
|
Free camera
|
||||||
<img src="docs/showcase/free_camera.jpg"/>
|
<img src="docs/tr1/showcase/free_camera.jpg"/>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
PS1 UI and new graphics options
|
PS1 UI and new graphics options
|
||||||
<img src="docs/showcase/ps1_ui_and_gfx.jpg"/>
|
<img src="docs/tr1/showcase/ps1_ui_and_gfx.jpg"/>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
## Windows / Linux
|
### Download
|
||||||
|
Download the latest release:
|
||||||
|
|
||||||
### Installing (simplified)
|
<a href="https://github.com/rr-/TRX/releases?q=tr1x+prerelease%3Afalse&expanded=true">
|
||||||
|
<img src="data/download_tr1x.svg"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
1. Head over to GitHub releases: https://github.com/LostArtefacts/TR1X/releases
|
See [the changelog](docs/tr1/CHANGELOG.md).
|
||||||
2. Download the installer. Your browser may complain that the .exe is unsafe, but it's OK to ignore this alert.
|
|
||||||
3. Mark the installer EXE as safe to run by right-clicking on the .exe, going to properties and clicking "Unblock".
|
|
||||||
4. Run the installer and proceed with the steps.
|
|
||||||
|
|
||||||
We hope that eventually these alerts will go away as the popularity of the project rises.
|
### Install Instructions
|
||||||
|
Please refer to the [detailed documentation](docs/tr1/).
|
||||||
|
|
||||||
### Installing (advanced / manual)
|
## TR2X - Tomb Raider 2
|
||||||
|
|
||||||
1. Head over to GitHub releases: https://github.com/LostArtefacts/TR1X/releases
|
### Overview
|
||||||
2. Download the zip file.
|
TR2X serves as a sequel to TR1X, currently focusing on the decompilation of Tomb Raider 2.
|
||||||
3. Extract the zip file into a directory of your choice.
|
|
||||||
Make sure you choose to overwrite existing directories and files
|
|
||||||
(`cfg/TR1X_config.json5` can remain, but new features will not be configurable).
|
|
||||||
4. (First time installation) Put your original game files into the target directory.
|
|
||||||
1. For Steam and GOG users, extract the original `GAME.BIN` file using a tool such as UltraISO to your target directory.
|
|
||||||
Note that neither the GOG nor the Steam releases ship the music files. You have a few options here:
|
|
||||||
- You can download the music files from the link below.
|
|
||||||
https://lostartefacts.dev/aux/tr1x/music.zip
|
|
||||||
The legality of this approach is disputable.
|
|
||||||
- Rip the assets yourself from a physical PlayStation/SegaSaturn disk.
|
|
||||||
|
|
||||||
Optionally you can also install the Unfinished Business expansion pack files.
|
### Decompilation Progress
|
||||||
- Either one of these these variants:
|

|
||||||
- https://lostartefacts.dev/aux/tr1x/trub-music.zip (fan-made patch to include music triggers)
|
|
||||||
- https://lostartefacts.dev/aux/tr1x/trub-vanilla.zip (original level files, which do not include music triggers)
|
|
||||||
- Or the more manual link: https://archive.org/details/tomb-raider-i-unfinished-business-pc-eng-full-version_20201225
|
|
||||||
2. For TombATI users this means copying the `data`, `fmv` and `music` directories.
|
|
||||||
5. To play the game, run `TR1X.exe`.
|
|
||||||
6. To play the Unfinished Expansion pack, run `TR1X.exe -gold`.
|
|
||||||
|
|
||||||
If you install everything correctly, your game directory should look more or
|
### Download
|
||||||
less like this (click to expand):
|
Download the latest release:
|
||||||
|
|
||||||
<details>
|
<a href="https://github.com/rr-/TRX/releases?q=tr2x+prerelease%3Afalse&expanded=true">
|
||||||
<p><em>* Will not be present until the game has been launched.</em></p>
|
<img src="data/download_tr2x.svg"/>
|
||||||
<pre>
|
</a>
|
||||||
.
|
|
||||||
├── cfg
|
|
||||||
│ ├── TR1X.json5 *
|
|
||||||
│ ├── TR1X_gameflow.json5
|
|
||||||
│ ├── TR1X_gameflow_demo_pc.json5
|
|
||||||
│ └── TR1X_gameflow_ub.json5
|
|
||||||
├── data
|
|
||||||
│ ├── cat.phd
|
|
||||||
│ ├── cred0.pcx
|
|
||||||
│ ├── cred1.pcx
|
|
||||||
│ ├── cred2.pcx
|
|
||||||
│ ├── cred3.pcx
|
|
||||||
│ ├── cut1.phd
|
|
||||||
│ ├── cut2.phd
|
|
||||||
│ ├── cut3.phd
|
|
||||||
│ ├── cut4.phd
|
|
||||||
│ ├── egypt.phd
|
|
||||||
│ ├── eidospc.pcx
|
|
||||||
│ ├── end2.phd
|
|
||||||
│ ├── end.pcx
|
|
||||||
│ ├── end.phd
|
|
||||||
│ ├── gym.phd
|
|
||||||
│ ├── install.pcx
|
|
||||||
│ ├── level10a.phd
|
|
||||||
│ ├── level10b.phd
|
|
||||||
│ ├── level10c.phd
|
|
||||||
│ ├── level1.phd
|
|
||||||
│ ├── level2.phd
|
|
||||||
│ ├── level3a.phd
|
|
||||||
│ ├── level3b.phd
|
|
||||||
│ ├── level4.phd
|
|
||||||
│ ├── level5.phd
|
|
||||||
│ ├── level6.phd
|
|
||||||
│ ├── level7a.phd
|
|
||||||
│ ├── level7b.phd
|
|
||||||
│ ├── level8a.phd
|
|
||||||
│ ├── level8b.phd
|
|
||||||
│ ├── level8c.phd
|
|
||||||
│ ├── titleh.pcx
|
|
||||||
│ ├── titleh_ub.pcx
|
|
||||||
│ │── title.phd
|
|
||||||
│ │── images
|
|
||||||
│ │ ├── atlantis.webp
|
|
||||||
│ │ ├── credits_1.webp
|
|
||||||
│ │ ├── credits_2.webp
|
|
||||||
│ │ ├── credits_3.webp
|
|
||||||
│ │ ├── credits_3_alt.webp
|
|
||||||
│ │ ├── credits_ps1.webp
|
|
||||||
│ │ ├── egypt.webp
|
|
||||||
│ │ ├── eidos.webp
|
|
||||||
│ │ ├── end.webp
|
|
||||||
│ │ ├── greece.webp
|
|
||||||
│ │ ├── greece_saturn.webp
|
|
||||||
│ │ ├── gym.webp
|
|
||||||
│ │ ├── install.webp
|
|
||||||
│ │ ├── peru.webp
|
|
||||||
│ │ ├── title.webp
|
|
||||||
│ │ ├── title_og_alt.webp
|
|
||||||
│ │ └── title_ub.webp
|
|
||||||
│ └── injections
|
|
||||||
│ ├── atlantis_fd.bin
|
|
||||||
│ ├── atlantis_textures.bin
|
|
||||||
│ ├── backpac.bin
|
|
||||||
│ └── etc...
|
|
||||||
├── fmv
|
|
||||||
│ ├── cafe.rpl
|
|
||||||
│ ├── canyon.rpl
|
|
||||||
│ ├── core.avi
|
|
||||||
│ ├── end.rpl
|
|
||||||
│ ├── escape.rpl
|
|
||||||
│ ├── lift.rpl
|
|
||||||
│ ├── mansion.rpl
|
|
||||||
│ ├── prison.rpl
|
|
||||||
│ ├── pyramid.rpl
|
|
||||||
│ ├── snow.rpl
|
|
||||||
│ └── vision.rpl
|
|
||||||
├── music
|
|
||||||
│ ├── track02.flac
|
|
||||||
│ ├── track03.flac
|
|
||||||
│ ├── track04.flac
|
|
||||||
│ ├── track05.flac
|
|
||||||
│ ├── track06.flac
|
|
||||||
│ ├── track07.flac
|
|
||||||
│ ├── track08.flac
|
|
||||||
│ ├── track09.flac
|
|
||||||
│ ├── track10.flac
|
|
||||||
│ ├── track11.flac
|
|
||||||
│ ├── track12.flac
|
|
||||||
│ ├── track13.flac
|
|
||||||
│ ├── track14.flac
|
|
||||||
│ ├── track15.flac
|
|
||||||
│ ├── track16.flac
|
|
||||||
│ ├── track17.flac
|
|
||||||
│ ├── track18.flac
|
|
||||||
│ ├── track19.flac
|
|
||||||
│ ├── track20.flac
|
|
||||||
│ ├── track21.flac
|
|
||||||
│ ├── track22.flac
|
|
||||||
│ ├── track23.flac
|
|
||||||
│ ├── track24.flac
|
|
||||||
│ ├── track25.flac
|
|
||||||
│ ├── track26.flac
|
|
||||||
│ ├── track27.flac
|
|
||||||
│ ├── track28.flac
|
|
||||||
│ ├── track29.flac
|
|
||||||
│ ├── track30.flac
|
|
||||||
│ ├── track31.flac
|
|
||||||
│ ├── track32.flac
|
|
||||||
│ ├── track33.flac
|
|
||||||
│ ├── track34.flac
|
|
||||||
│ ├── track35.flac
|
|
||||||
│ ├── track36.flac
|
|
||||||
│ ├── track37.flac
|
|
||||||
│ ├── track38.flac
|
|
||||||
│ ├── track39.flac
|
|
||||||
│ ├── track40.flac
|
|
||||||
│ ├── track41.flac
|
|
||||||
│ ├── track42.flac
|
|
||||||
│ ├── track43.flac
|
|
||||||
│ ├── track44.flac
|
|
||||||
│ ├── track45.flac
|
|
||||||
│ ├── track46.flac
|
|
||||||
│ ├── track47.flac
|
|
||||||
│ ├── track48.flac
|
|
||||||
│ ├── track49.flac
|
|
||||||
│ ├── track50.flac
|
|
||||||
│ ├── track51.flac
|
|
||||||
│ ├── track52.flac
|
|
||||||
│ ├── track53.flac
|
|
||||||
│ ├── track54.flac
|
|
||||||
│ ├── track55.flac
|
|
||||||
│ ├── track56.flac
|
|
||||||
│ ├── track57.flac
|
|
||||||
│ ├── track58.flac
|
|
||||||
│ ├── track59.flac
|
|
||||||
│ └── track60.flac
|
|
||||||
├── shaders
|
|
||||||
│ ├── 2d.glsl
|
|
||||||
│ ├── 3d.glsl
|
|
||||||
│ └── fbo.glsl
|
|
||||||
├── TR1X.exe
|
|
||||||
└── TR1X_ConfigTool.exe
|
|
||||||
</pre>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Configuring
|
See [the changelog](docs/tr2/CHANGELOG.md).
|
||||||
|
|
||||||
To configure TR1X, run the `TR1X_ConfigTool.exe` application. All the
|
### Install Instructions
|
||||||
configuration is explained in this tool. Alternatively, after running the game
|
Please refer to the [detailed documentation](docs/tr2/).
|
||||||
at least once, you can edit `TR1X.json5` manually in a text editor such
|
|
||||||
as Notepad.
|
|
||||||
|
|
||||||
## macOS
|
|
||||||
|
|
||||||
### Installing
|
|
||||||
|
|
||||||
1. Head over to GitHub releases: https://github.com/LostArtefacts/TR1X/releases
|
|
||||||
2. Download the `TR1X-Installer.dmg` installer image. Mount the image and drag TR1X to the Applications folder.
|
|
||||||
3. Run TR1X from the Applications folder. This will show you an error dialog about missing game data files. This is expected at this point, as you have not copied them in yet. However, it's important to run the app first to allow macOS to verify the app bundle's signature.
|
|
||||||
4. Find TR1X in your Applications folder. Right-click it and click "Show Package Contents".
|
|
||||||
5. Copy your Tomb Raider 1 game data files into `Contents/Resources`. (See the Windows / Linux instructions for retrieving game data from e.g. GOG.)
|
|
||||||
|
|
||||||
If you install everything correctly, your game directory should look more or
|
|
||||||
less like this (click to expand):
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<p><em>* Will not be present until the game has been launched.</em></p>
|
|
||||||
<pre>
|
|
||||||
.
|
|
||||||
└── Contents
|
|
||||||
├── _CodeSignature
|
|
||||||
├── Framworks
|
|
||||||
├── info.plist
|
|
||||||
├── MacOS
|
|
||||||
└── Resources
|
|
||||||
├── cfg
|
|
||||||
│ ├── TR1X.json5 *
|
|
||||||
│ ├── TR1X_gameflow.json5
|
|
||||||
│ ├── TR1X_gameflow_demo_pc.json5
|
|
||||||
│ └── TR1X_gameflow_ub.json5
|
|
||||||
├── data
|
|
||||||
│ ├── cat.phd
|
|
||||||
│ ├── cred0.pcx
|
|
||||||
│ ├── cred1.pcx
|
|
||||||
│ ├── cred2.pcx
|
|
||||||
│ ├── cred3.pcx
|
|
||||||
│ ├── cut1.phd
|
|
||||||
│ ├── cut2.phd
|
|
||||||
│ ├── cut3.phd
|
|
||||||
│ ├── cut4.phd
|
|
||||||
│ ├── egypt.phd
|
|
||||||
│ ├── eidospc.pcx
|
|
||||||
│ ├── end2.phd
|
|
||||||
│ ├── end.pcx
|
|
||||||
│ ├── end.phd
|
|
||||||
│ ├── gym.phd
|
|
||||||
│ ├── install.pcx
|
|
||||||
│ ├── level10a.phd
|
|
||||||
│ ├── level10b.phd
|
|
||||||
│ ├── level10c.phd
|
|
||||||
│ ├── level1.phd
|
|
||||||
│ ├── level2.phd
|
|
||||||
│ ├── level3a.phd
|
|
||||||
│ ├── level3b.phd
|
|
||||||
│ ├── level4.phd
|
|
||||||
│ ├── level5.phd
|
|
||||||
│ ├── level6.phd
|
|
||||||
│ ├── level7a.phd
|
|
||||||
│ ├── level7b.phd
|
|
||||||
│ ├── level8a.phd
|
|
||||||
│ ├── level8b.phd
|
|
||||||
│ ├── level8c.phd
|
|
||||||
│ ├── titleh.pcx
|
|
||||||
│ ├── titleh_ub.pcx
|
|
||||||
│ │── title.phd
|
|
||||||
│ │── images
|
|
||||||
│ │ ├── atlantis.webp
|
|
||||||
│ │ ├── credits_1.webp
|
|
||||||
│ │ ├── credits_2.webp
|
|
||||||
│ │ ├── credits_3.webp
|
|
||||||
│ │ ├── credits_3_alt.webp
|
|
||||||
│ │ ├── credits_ps1.webp
|
|
||||||
│ │ ├── egypt.webp
|
|
||||||
│ │ ├── eidos.webp
|
|
||||||
│ │ ├── end.webp
|
|
||||||
│ │ ├── greece.webp
|
|
||||||
│ │ ├── greece_saturn.webp
|
|
||||||
│ │ ├── gym.webp
|
|
||||||
│ │ ├── install.webp
|
|
||||||
│ │ ├── peru.webp
|
|
||||||
│ │ ├── title.webp
|
|
||||||
│ │ ├── title_og_alt.webp
|
|
||||||
│ │ └── title_ub.webp
|
|
||||||
│ └── injections
|
|
||||||
│ ├── atlantis_fd.bin
|
|
||||||
│ ├── atlantis_textures.bin
|
|
||||||
│ ├── backpac.bin
|
|
||||||
│ └── etc...
|
|
||||||
├── fmv
|
|
||||||
│ ├── cafe.rpl
|
|
||||||
│ ├── canyon.rpl
|
|
||||||
│ ├── core.avi
|
|
||||||
│ ├── end.rpl
|
|
||||||
│ ├── escape.rpl
|
|
||||||
│ ├── lift.rpl
|
|
||||||
│ ├── mansion.rpl
|
|
||||||
│ ├── prison.rpl
|
|
||||||
│ ├── pyramid.rpl
|
|
||||||
│ ├── snow.rpl
|
|
||||||
│ └── vision.rpl
|
|
||||||
├── icon.icns
|
|
||||||
├── music
|
|
||||||
│ ├── track02.flac
|
|
||||||
│ ├── track03.flac
|
|
||||||
│ ├── track04.flac
|
|
||||||
│ ├── track05.flac
|
|
||||||
│ ├── track06.flac
|
|
||||||
│ ├── track07.flac
|
|
||||||
│ ├── track08.flac
|
|
||||||
│ ├── track09.flac
|
|
||||||
│ ├── track10.flac
|
|
||||||
│ ├── track11.flac
|
|
||||||
│ ├── track12.flac
|
|
||||||
│ ├── track13.flac
|
|
||||||
│ ├── track14.flac
|
|
||||||
│ ├── track15.flac
|
|
||||||
│ ├── track16.flac
|
|
||||||
│ ├── track17.flac
|
|
||||||
│ ├── track18.flac
|
|
||||||
│ ├── track19.flac
|
|
||||||
│ ├── track20.flac
|
|
||||||
│ ├── track21.flac
|
|
||||||
│ ├── track22.flac
|
|
||||||
│ ├── track23.flac
|
|
||||||
│ ├── track24.flac
|
|
||||||
│ ├── track25.flac
|
|
||||||
│ ├── track26.flac
|
|
||||||
│ ├── track27.flac
|
|
||||||
│ ├── track28.flac
|
|
||||||
│ ├── track29.flac
|
|
||||||
│ ├── track30.flac
|
|
||||||
│ ├── track31.flac
|
|
||||||
│ ├── track32.flac
|
|
||||||
│ ├── track33.flac
|
|
||||||
│ ├── track34.flac
|
|
||||||
│ ├── track35.flac
|
|
||||||
│ ├── track36.flac
|
|
||||||
│ ├── track37.flac
|
|
||||||
│ ├── track38.flac
|
|
||||||
│ ├── track39.flac
|
|
||||||
│ ├── track40.flac
|
|
||||||
│ ├── track41.flac
|
|
||||||
│ ├── track42.flac
|
|
||||||
│ ├── track43.flac
|
|
||||||
│ ├── track44.flac
|
|
||||||
│ ├── track45.flac
|
|
||||||
│ ├── track46.flac
|
|
||||||
│ ├── track47.flac
|
|
||||||
│ ├── track48.flac
|
|
||||||
│ ├── track49.flac
|
|
||||||
│ ├── track50.flac
|
|
||||||
│ ├── track51.flac
|
|
||||||
│ ├── track52.flac
|
|
||||||
│ ├── track53.flac
|
|
||||||
│ ├── track54.flac
|
|
||||||
│ ├── track55.flac
|
|
||||||
│ ├── track56.flac
|
|
||||||
│ ├── track57.flac
|
|
||||||
│ ├── track58.flac
|
|
||||||
│ ├── track59.flac
|
|
||||||
│ └── track60.flac
|
|
||||||
└── shaders
|
|
||||||
├── 2d.glsl
|
|
||||||
├── 3d.glsl
|
|
||||||
└── fbo.glsl
|
|
||||||
</pre>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Improvements over original game
|
|
||||||
|
|
||||||
Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for details.
|
|
||||||
|
|
||||||
#### UI
|
|
||||||
- added proper UI and bar scaling
|
|
||||||
- added enemy health bars
|
|
||||||
- added PS1 style UI
|
|
||||||
- added fade effects to displayed images
|
|
||||||
- added an option to use PS1 loading screens
|
|
||||||
- added a wireframe mode
|
|
||||||
- improved support for windowed mode
|
|
||||||
|
|
||||||
#### Gameplay
|
|
||||||
- added ability to set user-defined FOV
|
|
||||||
- added ability to select weapons / using items with numeric keys
|
|
||||||
- added ability to look around while running
|
|
||||||
- added ability to forward and backward jump while looking
|
|
||||||
- added ability to look up and down while hanging
|
|
||||||
- added ability to sidestep like in TR3
|
|
||||||
- added ability to jump-twist and somersault like in TR2+
|
|
||||||
- added ability to cancel ledge-swinging animation like in TR2+
|
|
||||||
- added ability to jump at any point while running like in TR2+
|
|
||||||
- added ability to automatically walk to items when nearby
|
|
||||||
- added ability to roll while underwater like in TR2+
|
|
||||||
- added ability to use Lara's underwater swimming physics from TR2+
|
|
||||||
- added a pause screen
|
|
||||||
- added a choice whether to play NG or NG+ without having to play the entire game
|
|
||||||
- added Japanese mode (guns deal twice the damage, inspired by JP release of TR3); available for both NG and NG+
|
|
||||||
- added ability to restart level on death
|
|
||||||
- added ability to restart the adventure from any level when loading a game
|
|
||||||
- added the "Story so far..." option in the select level menu to view cutscenes and FMVs
|
|
||||||
- added graphics effects, lava emitters, flame emitters, and waterfalls to the savegame so they now persist on load
|
|
||||||
- added an option to restore the mummy in City of Khamoon room 25, similar to the PS version
|
|
||||||
- added a flag indicating if new game plus is unlocked to the player config which allows the player to select new game plus or not when making a new game
|
|
||||||
- added weapons to Lara's empty holsters on pickup
|
|
||||||
- added options to quiet or mute music while underwater
|
|
||||||
- changed weapon pickup behavior when unarmed to set any weapon as the default weapon, not just pistols
|
|
||||||
- fixed keys and items not working when drawing guns immediately after using them
|
|
||||||
- fixed counting the secret in The Great Pyramid
|
|
||||||
- fixed running out of ammo forcing Lara to equip pistols even if she doesn't carry them
|
|
||||||
- fixed a crash when Lara is on fire and goes too far away from where she caught fire
|
|
||||||
- fixed flames not being drawn when Lara is on fire and leaves the room where she caught fire
|
|
||||||
- fixed settings not being saved when exiting the game with Alt+F4
|
|
||||||
- fixed settings not persisting chosen layout (default vs. user keys)
|
|
||||||
- fixed the infamous Tihocan crocodile bug (integer overflow causing creatures to deal damage across the entire level)
|
|
||||||
- fixed missiles damaging Lara when she is far beyond their damage range
|
|
||||||
- fixed Lara not being able to grab parts of some bridges
|
|
||||||
- fixed Lara voiding if a badly placed timed door closes on her (doesn't occur in OG levels)
|
|
||||||
- fixed bats being positioned too high
|
|
||||||
- fixed alligators dealing no damage if Lara remains still in the water
|
|
||||||
- fixed shotgun shooting when a locked target moves out of Lara's sight
|
|
||||||
- fixed shotgun shooting too fast when not aiming at a target
|
|
||||||
- fixed Lara grabbing ledges she shouldn't in stacked rooms (mainly St. Francis Folly tower)
|
|
||||||
- fixed rare cases of Lara getting set on fire on a bridge over lava
|
|
||||||
- fixed saving the game near Bacon Lara breaking her movement
|
|
||||||
- fixed Lara glitching through static objects into a black void
|
|
||||||
- fixed Lara pushing blocks through doors
|
|
||||||
- fixed Lara switching to pistols when completing a level with other guns
|
|
||||||
- fixed empty mutant shells in Unfinished Business spawning Lara's hips
|
|
||||||
- fixed gun pickups disappearing in rare circumstances on save load (#406)
|
|
||||||
- fixed broken dart ricochet effect
|
|
||||||
- fixed exploded mutant pods sometimes appearing unhatched on reload
|
|
||||||
- fixed bridges at floor level appearing under the floor
|
|
||||||
- fixed underwater currents breaking in rare cases
|
|
||||||
- fixed Lara loading inside a movable block if she's on a stack near a room portal
|
|
||||||
- fixed a game crash on shutdown if the action button is held down
|
|
||||||
- fixed Scion 1 respawning on load
|
|
||||||
- fixed triggered flip effects not working if there are no sound devices
|
|
||||||
- fixed ceiling heights at times being miscalculated, resulting in camera issues and Lara being able to jump into the ceiling
|
|
||||||
- fixed the camera being thrown through doors for one frame when looked at from fixed camera positions
|
|
||||||
- fixed the ape not performing the vault animation when climbing
|
|
||||||
- fixed Natla's gun moving while she is in her semi death state
|
|
||||||
- fixed the bear pat attack so it does not miss Lara
|
|
||||||
- fixed dead centaurs exploding again after saving and reloading
|
|
||||||
- fixed the following floor data issues:
|
|
||||||
- **St. Francis' Folly**: moved the music trigger for track 3 in room 4 behind the Neptune door, and restored track 15 to play after using the 4 keys
|
|
||||||
- **The Cistern**: missing trigger in room 56 which could result in a softlock
|
|
||||||
- **Tomb of Tihocan**: missing trigger in room 62 for enemy 34
|
|
||||||
- **City of Khamoon**: incorrect trapdoor trigger types in rooms 31 and 34
|
|
||||||
- **Obelisk of Khamoon**: missing switch trigger type in room 66
|
|
||||||
- **Natla's Mines**: incorrect flipmap indices in room 85
|
|
||||||
- **Atlantean Stronghold**: fixed poorly configured portals between rooms 74 and 12
|
|
||||||
- fixed various bugs with falling movable blocks
|
|
||||||
- fixed bugs when trying to stack multiple movable blocks
|
|
||||||
- fixed Midas's touch having unrestricted vertical range
|
|
||||||
- fixed Lara saying "no" when taking valid actions in front of a key item receptacle
|
|
||||||
- fixed Lara not saying "no" when using the Scion incorrectly
|
|
||||||
- fixed flickering in bats' death animations and rapid shooting if Lara continues to fire when they are killed
|
|
||||||
- fixed looking forward too far causing an upside down camera frame
|
|
||||||
- fixed the Scion being extremely difficult to shoot with the shotgun
|
|
||||||
- fixed collision issues with drawbridges, trapdoors, and bridges when stacked over each other, over slopes, and near the ground
|
|
||||||
- fixed a potential softlock when killing the Torso boss in Great Pyramid
|
|
||||||
|
|
||||||
#### Cheats
|
|
||||||
- added a fly cheat
|
|
||||||
- added a level skip cheat
|
|
||||||
- added a door open cheat (while in fly mode)
|
|
||||||
- added a cheat to increase the game speed
|
|
||||||
- added a cheat to explode Lara like in TR2 and TR3
|
|
||||||
|
|
||||||
#### Input
|
|
||||||
- added ability to move camera around with W,A,S,D
|
|
||||||
- added additional custom control schemes
|
|
||||||
- added the ability to unbind unessential keys
|
|
||||||
- added the ability to reset control schemes to default
|
|
||||||
- added customizable controller support
|
|
||||||
- added an inverted look camera option
|
|
||||||
- added the ability to move the look camera while targeting an enemy in combat
|
|
||||||
- fixed freeze when holding the Action key during end of level
|
|
||||||
- fixed inability to switch Control keys when shimmying
|
|
||||||
- fixed setting user keys being very difficult
|
|
||||||
- fixed skipping FMVs triggering inventory
|
|
||||||
- fixed skipping credits working too fast
|
|
||||||
- fixed not being able to close level stats with Escape
|
|
||||||
- fixed Lara jumping forever when alt+tabbing out of the game
|
|
||||||
- stopped the default controls from functioning when the user unbound them
|
|
||||||
- added the option to change weapon targets by tapping the new target change key
|
|
||||||
- added three targeting lock options:
|
|
||||||
- full lock: always keep target lock even if the enemy moves out of sight or dies (OG TR1)
|
|
||||||
- semi lock: keep target lock if the enemy moves out of sight but lose target lock if the enemy dies
|
|
||||||
- no lock: lose target lock if the enemy goes out of sight or dies (TR4+)
|
|
||||||
|
|
||||||
#### Statistics
|
|
||||||
- added ability to keep timer on in inventory
|
|
||||||
- added optional compass level stats
|
|
||||||
- added optional final statistics screen
|
|
||||||
- added optional deaths counter
|
|
||||||
- added optional total pickups and kills per level
|
|
||||||
- added unobtainable pickups, kills, and secrets stats support in the gameflow
|
|
||||||
|
|
||||||
#### Visuals
|
|
||||||
- added optional shotgun flash sprites
|
|
||||||
- added optional rendering of pickups on the ground as 3D meshes
|
|
||||||
- added Lara's braid to each level
|
|
||||||
- added support for displaying more than 3 pickup sprites
|
|
||||||
- added more control over when to show health bar and air bar
|
|
||||||
- added customizable health bar and air bar
|
|
||||||
- added rounded shadows (instead of the default octagon)
|
|
||||||
- added adjustable in-game brightness
|
|
||||||
- added support for HD FMVs
|
|
||||||
- added fanmade 16:9 menu backgrounds
|
|
||||||
- added optional fade effects
|
|
||||||
- added a vsync option
|
|
||||||
- added contextual arrows to menu options
|
|
||||||
- added support for animated room sprites, which also restores intended behavior in, for example, The Cistern room 0
|
|
||||||
- added skybox support, with a default option provided for Lost Valley, Colosseum and Obelisk of Khamoon; custom level builders can use object slot `184`
|
|
||||||
- added reflections of Midas Hand death animation and savegame crystals
|
|
||||||
- changed the Scion in The Great Pyramid from spawning blood when hit to a richochet effect
|
|
||||||
- fixed thin black lines between polygons
|
|
||||||
- fixed black screen flashing when navigating the inventory
|
|
||||||
- fixed detail levels text flashing with any option change
|
|
||||||
- fixed underwater caustics animating at 2x speed
|
|
||||||
- fixed inconsistencies in some enemy textures
|
|
||||||
- fixed the animation of Lara's left arm when the shotgun is equipped
|
|
||||||
- fixed the following room texture issues:
|
|
||||||
- **Gym**: incorrect textures in room 9
|
|
||||||
- **Caves**: an incorrect texture in room 6 and missing textures in rooms 1, 10, 14 and 30
|
|
||||||
- **City of Vilcabamba**: an incorrect texture in room 26, and a missing texture and a stretched texture in room 15
|
|
||||||
- **Lost Valley**: incorrect textures in rooms 6, 9, 16, 34 and 35, missing textures in rooms 6, 9, 25, 26, 27, 51, and 90, and stretched textures in room 63
|
|
||||||
- **Tomb of Qualopec**: an incorrect and missing textures in room 8, and a misaligned texture in room 5
|
|
||||||
- **St. Francis' Folly**: incorrect textures in rooms 1, 4, 18 and 35, and a misaligned texture in room 3
|
|
||||||
- **Colosseum**: incorrect Midas textures appearing at the roof, incorrect textures in rooms 37, 67, 75 and 82, and missing textures in rooms 2 and 7
|
|
||||||
- **Palace Midas**: incorrect textures in rooms 31, 34, 40 and 45, missing textures in rooms 2, 5, 9, 13, 30, and 53, and stretched textures in rooms 7 and 20
|
|
||||||
- **The Cistern**: missing textures in rooms 3 and 9 and a stretched texture in room 102
|
|
||||||
- **Tomb of Tihocan**: incorrect textures in rooms 75 and 89 and a misaligned texture in room 104
|
|
||||||
- **City of Khamoon**: incorrect textures in rooms 47, 48, 51, 60 and 64, and a missing texture in room 58
|
|
||||||
- **Obelisk of Khamoon**: incorrect textures in rooms 22, 23, 42 and 65; added shading to the gaps into City of Khamoon in rooms 8 and 20/21
|
|
||||||
- **Sanctuary of the Scion**: missing textures in rooms 1, 11, 21, 52, 53, and 54
|
|
||||||
- **Natla's Mines**: a missing texture in room 35, overlapping textures in room 55, an incorrect texture in room 69, and stretched textures in rooms 23 and 24
|
|
||||||
- **Pre-Atlantis Cutscene**: stretched textures in rooms 6 and 21
|
|
||||||
- **Atlantis**: incorrect textures in rooms 5, 18, 36, 43, 50, 52, 53, 54, 58, 78, 85 and 87, a missing texture in room 27, and stretched textures in rooms 13, 49 and 50
|
|
||||||
- **Atlantis Cutscene**: incorrect and stretched textures in room 16
|
|
||||||
- **The Great Pyramid**: incorrect textures in rooms 2, 5, 31, 36, 50, 52, 53, 54, 65 and 66, missing textures in rooms 21, 25, 26, and 66, and stretched textures in rooms 49 and 50
|
|
||||||
- **Return to Egypt**: incorrect textures in rooms 46 and 47, a missing texture in room 98, and a stretched texture in room 47
|
|
||||||
- **Temple of the Cat**: incorrect textures in rooms 50, 70, 71, 76, 78, 87 and 96, and a missing texture in 75
|
|
||||||
- **Atlantean Stronghold**: incorrect textures in rooms 2, 6, 7 and 75, and missing textures in rooms 5, 13, 19, 63 and 74
|
|
||||||
- **The Hive**: incorrect textures in room 8, 13 and 18
|
|
||||||
- improved vertex movement when looking through water portals
|
|
||||||
|
|
||||||
#### Audio
|
|
||||||
- added music during the credits
|
|
||||||
- added an option to turn off sound effect pitching
|
|
||||||
- added an option to use the PlayStation Uzi sound effects
|
|
||||||
- added the current music track and timestamp to the savegame so they now persist on load
|
|
||||||
- added the triggered music tracks to the savegame so one shot tracks don't replay on load
|
|
||||||
- added detection for animation commands to play SFX on land, water or both
|
|
||||||
- fixed the sound of collecting a secret killing the music
|
|
||||||
- fixed audio mixer stopping playing sounds on big explosions
|
|
||||||
- fixed game audio not muting when game is minimized
|
|
||||||
- fixed underwater ambient sound effect not playing
|
|
||||||
- fixed sound effects playing rapidly in sound menu if input held down
|
|
||||||
- fixed sounds stopping instead of pausing when using the inventory or pausing
|
|
||||||
- fixed the following music triggers:
|
|
||||||
- **Caves**: converted track 9 in room 34 to one shot
|
|
||||||
- **Tomb of Qualopec**: converted track 17 in room 25 to one shot
|
|
||||||
- **St. Francis' Folly**: converted track 7 in room 18 to one shot
|
|
||||||
- **Obelisk of Khamoon**: converted track 3 in room 12 and track 4 in room 32 to one shot
|
|
||||||
- **Sanctuary of the Scion**: converted track 10 in room 0 to one shot
|
|
||||||
- **Natla's Mines**: converted track 3 in room 86 to one shot
|
|
||||||
- **Atlantis**: converted track 8 in room 59 to one shot
|
|
||||||
- **The Great Pyramid**: converted track 8 in room 36 to one shot
|
|
||||||
- **Return to Egypt**: converted track 19 in room 0, track 14 in room 15, track 15 in room 19, track 16 in room 22, track 6 in room 61, and track 11 in room 93 to one shot
|
|
||||||
- **Temple of the Cat**: converted track 12 in room 14, track 7 in room 98, and track 20 in room 100 to one shot
|
|
||||||
- **Atlantean Stronghold**: converted track 20 in room 4, track 19 in room 13, track 11 in room 17, track 15 in room 20, and track 12 in room 25 to one shot
|
|
||||||
- **The Hive**: converted track 9 in room 8, track 6 in room 18, track 12 in room 30, track 18 in room 31, track 3 in room 32, and track 20 in room 35 to one shot
|
|
||||||
|
|
||||||
#### Mods
|
|
||||||
- added developer console (accessible with `/`, see [COMMANDS.md] for details)
|
|
||||||
- added ability to adjust Lara's starting health (easy no damage mod)
|
|
||||||
- added ability to disable healing between levels
|
|
||||||
- added ability to disable certain item pickups (all medpacks, shotgun, Magnums and/or UZIs)
|
|
||||||
- added ability to disable main menu demos, FMVs and/or cutscenes
|
|
||||||
- added external game flow (no longer 2 different .exes for TR1 and TR1UB). Refer to [GAMEFLOW.md](GAMEFLOW.md) for details
|
|
||||||
- added automatic calculation of secret counts (no longer having to fiddle with the .exe to get correct secret stats)
|
|
||||||
- added save game crystals game mode (enabled via gameflow)
|
|
||||||
- added per-level customizable water color (with customizable blue component)
|
|
||||||
- added per-level customizable fog distance
|
|
||||||
- added deadly water feature from TR2+
|
|
||||||
|
|
||||||
#### Miscellaneous
|
|
||||||
- added Linux builds
|
|
||||||
- added macOS builds
|
|
||||||
- added .jpeg/.png screenshots
|
|
||||||
- added an option to pause sound in the inventory screen
|
|
||||||
- added ability to skip FMVs with the Action key
|
|
||||||
- added ability to make freshly triggered (runaway) Pierre replace an already existing (runaway) Pierre
|
|
||||||
- expanded internal game memory limit from 3.5 MB to 16 MB
|
|
||||||
- expanded moveable limit from 256 to 10240
|
|
||||||
- expanded maximum textures from 2048 to 8192
|
|
||||||
- expanded maximum texture pages from 32 to 128
|
|
||||||
- expanded maximum vertices of a single drawable object from 1500 to unlimited
|
|
||||||
- expanded the number of visible enemies from 8 to 32
|
|
||||||
- ported audio decoding library to ffmpeg
|
|
||||||
- ported video decoding library to ffmpeg
|
|
||||||
- ported image decoding library to ffmpeg
|
|
||||||
- ported audio output library to SDL
|
|
||||||
- ported input method to SDL
|
|
||||||
- changed saves to be put in the saves/ directory
|
|
||||||
- fixed playing the secret sound in Tomb of Tihocan
|
|
||||||
- fixed reading user settings not restoring the volume
|
|
||||||
|
|
||||||
## Q&A
|
## Q&A
|
||||||
|
|
||||||
1. **Is the game fully playable from beginning to the end?**
|
1. **Is the game fully playable from beginning to the end?**
|
||||||
|
|
||||||
Yes. If you encounter a bug, please file a ticket.
|
By all means! If you encounter a bug, please file a ticket.
|
||||||
|
|
||||||
2. **Can we get HD textures? Reflections? Other visual updates?**
|
2. **Can we get HD textures? Reflections? Other visual updates?**
|
||||||
|
|
||||||
Eventually, probably yes, but we'd really appreciate help with these.
|
We hope so! Being able to introduce skyboxes to TR1 showed that quite
|
||||||
|
literally sky is the limit. But great stuff takes time.
|
||||||
3. **Can we get braid in every level? Skyboxes? Flyby cameras? New animations? etc.**
|
|
||||||
|
|
||||||
The difficulty here is that these features often require inserting a
|
|
||||||
completely new animation, a textured mesh or a sound file and pretend
|
|
||||||
they're always been a part of the original game. Work is underway on an
|
|
||||||
injection framework, and the braid is now supported in each level.
|
|
||||||
|
|
||||||
4. **Can I play this on Mac, Linux, Android...?**
|
4. **Can I play this on Mac, Linux, Android...?**
|
||||||
|
|
||||||
Currently supported platforms include Windows, Linux and macOS. In the
|
Currently supported platforms include Windows, Linux and macOS for TR1X,
|
||||||
future, it might be possible to run the game on Android as well –
|
and Windows for TR2X.
|
||||||
contributions are welcome!
|
|
||||||
|
|
||||||
5. **What's the relation to TR2Main?**
|
5. **What's the relation to TR2Main?**
|
||||||
|
|
||||||
Initially established as TR1Main in 2021, our project's development paths
|
Originally founded as TR1Main in 2021, our project flourished independently
|
||||||
deviated, leading us to recognize the need for a distinct name. As a
|
without sharing the code, with the shared brand concept existing only as an
|
||||||
result, we rebranded the project as Tomb1Main. However, to further
|
idea. To better represent this, we rebranded to Tomb1Main. In 2023, we
|
||||||
differentiate ourselves, we underwent another rebranding in 2023,
|
further refined our identity by adopting the name TR1X. Meanwhile, TR2Main
|
||||||
ultimately adopting the name TR1X. TR2Main is a separate project with its
|
follows a completely separate and unique path, unconnected to our
|
||||||
own unique trajectory and not directly related to our development efforts.
|
development work.
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is licensed under the GNU General Public License - see the
|
|
||||||
[COPYING.md](COPYING.md) file for details.
|
|
||||||
|
|
||||||
## Copyright
|
|
||||||
|
|
||||||
(c) 2021 Marcin Kurczewski. All rights reserved. Original game is created by
|
|
||||||
Core Design Ltd. in 1996. Lara Croft and Tomb Raider are trademarks of Square
|
|
||||||
Enix Ltd. Title image by Kidd Bowyer. Loading screens and high quality images
|
|
||||||
by goblan_oldnewpixel and Posix.
|
|
||||||
|
|
53
data/download_tr1x.svg
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="80" viewBox="0 0 700 260">
|
||||||
|
<rect width="700" height="260" fill="dodgerblue" rx="50" ry="50"/>
|
||||||
|
<g transform="translate(60 32) scale(0.7)" style="fill:none;stroke:white;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1">
|
||||||
|
<path transform="translate(238.843 238.343)" d="m0 0-15.683-27.165-31.495.074L-62.99.148l15.684 27.164 31.495-.074z"/>
|
||||||
|
<path transform="translate(0.62 143.116)" d="m0 0 15.811-27.238 31.495-.074L62.99-.148 47.178 27.091l-31.495.074Z"/>
|
||||||
|
<path transform="translate(227.585 11.457)" d="m0 0 15.683 27.165L-.128 54.403l-31.495.074-15.683-27.165L-31.495.074Z"/>
|
||||||
|
<path transform="translate(90.487 173.112)" d="M0 0c-18.457-31.969-6.844-73.227 25.938-92.154s74.319-8.354 92.776 23.614c16.17 28.007 9.261 63.144-14.742 84.149a70.5 70.5 0 0 1-11.195 8.005C59.995 42.541 18.457 31.969 0 0Z"/>
|
||||||
|
<path transform="translate(121.04 155.472)" d="M0 0c-8.956-15.513-3.321-35.534 12.586-44.718s36.064-4.054 45.021 11.459c7.846 13.59 4.493 30.641-7.154 40.833a34 34 0 0 1-5.433 3.885C29.113 20.643 8.956 15.513 0 0Z"/>
|
||||||
|
<path transform="translate(155.441 148.537)" d="m0 0 10.619 18.393"/>
|
||||||
|
<path transform="translate(167.18 110.679)" d="m0 0-11.352 18.443"/>
|
||||||
|
<path transform="translate(138.435 139.17)" d="m0 0-21.649.62"/>
|
||||||
|
<path transform="translate(16.438 115.878)" d="M0 0c7.407-37.351 30.63-71.733 66.706-92.562 35.871-20.71 76.995-23.723 112.9-11.704"/>
|
||||||
|
<path transform="translate(189.827 266.3)" d="M0 0c-59.824 19.518-126.482-3.692-158.449-59.062a130.3 130.3 0 0 1-14.4-36.959"/>
|
||||||
|
<path transform="translate(243.017 39.056)" d="M0 0a130.3 130.3 0 0 1 25.294 31.39C57.566 87.287 43.776 157.415-4.13 199.337"/>
|
||||||
|
<path transform="translate(226.142 189.922)" d="m0 0 25.677 17.19"/>
|
||||||
|
<path transform="translate(232.51 178.697)" d="m0 0 27.842 13.447"/>
|
||||||
|
<path transform="translate(237.254 166.706)" d="m0 0 29.466 9.443"/>
|
||||||
|
<path transform="translate(240.28 154.18)" d="m0 0 30.516 5.255"/>
|
||||||
|
<path transform="translate(241.533 141.365)" d="m0 0 30.973.965"/>
|
||||||
|
<path transform="translate(240.985 128.51)" d="m0 0 30.826-3.344"/>
|
||||||
|
<path transform="translate(238.648 115.863)" d="m0 0 30.08-7.588"/>
|
||||||
|
<path transform="translate(234.567 103.672)" d="m0 0 28.748-11.684"/>
|
||||||
|
<path transform="translate(106.63 118.008)" d="m0 0-14.554-7.029"/>
|
||||||
|
<path transform="translate(101.914 137.523)" d="m0 0-16.191-.504"/>
|
||||||
|
<path transform="translate(105.555 157.227)" d="m0 0-15.028 6.108"/>
|
||||||
|
<path transform="translate(117.474 174.222)" d="m0 0-11.039 11.886"/>
|
||||||
|
<path transform="translate(103.146 127.855)" d="m0 0-15.731-3.713"/>
|
||||||
|
<path transform="translate(102.765 147.929)" d="m0 0-15.916 3.012"/>
|
||||||
|
<path transform="translate(110.584 166.377)" d="m0 0-13.35 9.216"/>
|
||||||
|
<path transform="translate(125.9 180.39)" d="m0 0-8.204 13.994"/>
|
||||||
|
<path transform="translate(170.852 95.687)" d="m0 0 7.07-14.523"/>
|
||||||
|
<path transform="translate(158.037 91.59)" d="m0 0 2.788-15.933"/>
|
||||||
|
<path transform="translate(144.61 91.181)" d="m0 0-1.71-16.108"/>
|
||||||
|
<path transform="translate(131.608 94.494)" d="m0 0-6.075-15.036"/>
|
||||||
|
<path transform="translate(188.497 167.256)" d="m0 0 13.016 9.582"/>
|
||||||
|
<path transform="translate(194.844 155.404)" d="m0 0 15.177 5.629"/>
|
||||||
|
<path transform="translate(197.67 142.28)" d="m0 0 16.161 1.24"/>
|
||||||
|
<path transform="translate(196.755 128.9)" d="m0 0 15.894-3.245"/>
|
||||||
|
<path transform="translate(168.151 201.816)" d="m0 0-4.128-13.097a52 52 0 0 0 10.851-4.712C32.064-32.44 40.444-65.366 25.441-91.352a56 56 0 0 0-4.414-6.536l11.459-9.126"/>
|
||||||
|
<path transform="translate(71.284 193.486)" d="m0 0-23.488 16.337"/>
|
||||||
|
<path transform="translate(164.392 246.075)" d="M0 0c-43.231 6.616-87.586-12.632-110.29-51.956a106 106 0 0 1-5.84-11.746"/>
|
||||||
|
<path transform="translate(129.087 258.778)" d="m0 0 4.777-27.605"/>
|
||||||
|
<path transform="translate(83.466 64.807)" d="M0 0a104.7 104.7 0 0 1 16.709-11.992"/>
|
||||||
|
<path transform="translate(100.175 52.814)" d="M0 0a104.7 104.7 0 0 1 18.74-8.475"/>
|
||||||
|
<path transform="translate(113.99 29.288)" d="m0 0 4.926 15.051"/>
|
||||||
|
<path transform="translate(157.752 21.836)" d="m0 0-1.159 17.144a102.7 102.7 0 0 0-37.677 5.359"/>
|
||||||
|
<path transform="translate(72.894 53.015)" d="m0 0 10.572 11.792"/>
|
||||||
|
<path transform="translate(90.333 35.767)" d="m0 0 9.842 17.047"/>
|
||||||
|
<path transform="translate(44.56 87.188)" d="m0 0 15.426 7.568a102.7 102.7 0 0 1 23.481-29.949"/>
|
||||||
|
</g>
|
||||||
|
<text fill="white" dominant-baseline="middle" text-anchor="middle" x="475" y="75" style="font-family:sans-serif;font-size:70px">Download</text>
|
||||||
|
<text fill="white" dominant-baseline="middle" text-anchor="middle" x="475" y="175" style="font-family:sans-serif;font-size:120px">TR1X</text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.6 KiB |
13
data/download_tr2x.svg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="80" viewBox="0 0 700 260">
|
||||||
|
<rect width="700" height="260" fill="dodgerblue" rx="50" ry="50"/>
|
||||||
|
<g stroke="none" fill="white" transform="translate(40 5) scale(0.25)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024">
|
||||||
|
<path d="M554 242c17.61-19.23 46.09-38.73 58.75-61.25 12.66-22.53 50.09-54.77 26-83.5C614.66 68.51 596.24 132.21 582 144c-9.06-30.38-31.78-15.94-30.01 5.99 1.78 21.94-15.85 33.96-27.74 48.26-11.9 14.3-33.49 18.86-49.25 25.75 8.71-14.41 21.25-25.84 31.25-39.75 10-13.92 21.04-28.04 26.43-44.57S542.83 97.09 519 92s-18.65 33.26-30.08 40.92-26.49 48.13-6.67 34.33c19.81-13.8 14.11-20.07 26.44-43.56 12.34-23.49 14.3.54 5.23 20.23-9.06 19.69-16.9 26.96-28.67 42.33S463.98 209.54 454 225c-13.53 1.59-26.99 3.56-40 7 28.62-18.64 48.75-50.26 55.22-82.78 6.48-32.52-19.36-20.35-17.29-.29 2.07 20.05-12.36 32.1-21.18 46.82-8.81 14.73-24.66 21.61-37.67 31.33-13.01 9.73-26.36 19.83-40.38 28.62-14.03 8.78-30.09 13.94-40.4 28.6s-11.66 37.75-2.3 53.7c-22.49 16.24-48.74 10.38-73 6s-46.84 29.25-56.07.07c-9.24-29.17-8.12-52.66 3.82-76.32 11.93-23.67 28.28-32.44 51.02-41.98s45.31-18.29 72.21-19.79c26.89-1.5 35.22-47.9 10.02-17.98-28.16 7.45-63.81 12.06-89.92 24.08-26.12 12.01-48.1 27.13-59.3 53.7-11.21 26.57-16.6 68.04 1.97 92.47 18.56 24.43 14.19 52.74 40.25 72.75-4.9 6.17-12.91 19.36-3 24-3.09 19.45-4.89 91.92 24 63 11.78 18.02 13.44 30.43 27.69 48.31 14.26 17.87-4.54 44.36-5.35 60.01-.81 15.66 36.01-9.15 37.74-24.24 1.72-15.1 17.53-46.07 5.92-64.08 19.87 8.24 33.83 11.94 56.93 6.93 23.09-5.02-3.16-21.48-12.93-29.93 15.04 3.77 30.08-1.73 43-8 17.02-21.51 31.83 1.73 60.93-8.07 29.1-9.81 11.28-22.85-13.93-9.93-25.2 12.93-41.2-7.78-62-14 18.37-14.52 39.19-19.97 63-25s45.9 22.21 69 15c-14.59-12.72-24.18-25.73-43.78-31.22s-43.73 1.26-63 8.44c-19.27 7.19-29.99 17.37-51.2 23.8-21.21 6.44 14 26.67 28.98 24.98-15.5 18.05-43.77-.99-59.33-2.67C298.12 486.66 326.33 529 335 530c-22.94-4.24-34.84-1.21-52.75-23.25s-23.18 2.87-7.02 21.02S286.37 570.08 281 590c-1.21-23.03-15.39-46.71-27.75-65.25C240.9 506.2 237.32 460.11 226 504c-7.21-16.9-5.09-40.51 2-57 21.07 3.59 33.05 19.6 56 19s34.45-10.07 56.77-18.23 24.17-14.73 52.01-21.99c27.84-7.27 8.83-27.47-14.09-15.09-22.91 12.39-32.03 10.82-50.99 23.01-18.97 12.18-36.04 18.18-56.68 12.28-20.63-5.91-31.79-21.8-52.02-11.98 20.23-5.96 16.02-37.14 34.08-18.08 18.07 19.06 30.16-21.18 8-25-22.17-3.81-35.61-2.05-39.08 22.08-25.39-1.11-26.85-40.82-5.23-49.23 21.63-8.41 45.62.96 60.98 16.48 15.37 15.52 35.89 33.11 58.23 25.73 22.33-7.39 44.71-19.12 67.8-14.76 23.08 4.36 40.33 15.12 57.47 28.53 17.15 13.4 29.12 27.63 46.67 38.33C525.47 468.79 552.35 479.7 572 479s54.84-.69 64.25-21.75c9.4-21.07-33.87-.69-51.25 1.75s-52.6-4.84-68.25-17.75c-15.66-12.9-31.99-22.84-48.5-36.5s-35.48-23.62-57.58-28.42-50.28 2.39-70.99 11.35S295.32 380.22 284 363c39.05-3.15 46.22-17.86 37-48s34.68-38.47 52.31-52.69C390.93 248.08 435.2 245.17 458 242c-4.08 5.07-9.39 9.56-11 16 26.9-1.63 52.88-24.81 78.75-40.25 25.88-15.44 40.88-51.96 47.25-77.75 5.48 5.28-7.5 43.23 10.75 27.75 18.26-15.47 28.3-39.45 37.25-60.75 16.14 30.51-17.76 60.25-42.25 88.75-24.49 28.51-46.02 40.65-71.5 74.5C481.76 304.1 556.98 322.33 585 296c10.58 22.53 45.72 10.82 66.99 9.99 21.28-.83 43.1-7.83 59.01-22.99-12.76 28.4-35.14 36.81-61.93 50.07-26.78 13.27-68.93-3.36-92.07 4.93-3.65-11.82-16.18-27.6-30-21 28.09 30.18 13.13 74.86-17.3 96.7-30.43 21.83 22.03 4.84 31.28 14.32 9.24 9.49 44.2 11.12 60.02 12.98s47.03-.56 63.78-7.22c16.74-6.66 40.58-13.16 59.22-13.78 18.63-.63 42.84-3.91 56.75-16.25 13.92-12.34 28.12-18.67 34.27-38.73 6.16-20.06-21.23 1.11-38 5-16.76 3.9-48.63-1.04-67.02-2.02 24.89-23.32 59.6-39.83 71.08-73.92 11.47-34.1-.46-29-15.33-12.33S735.58 299.88 716 304c14.63-4.33 30.58-69.09 11.92-59.08-18.66 10-28.03 41.29-55.25 39.75S617.05 303.01 588 294c14.12-19.54 35.08-20.2 54.98-25.02 19.89-4.83 26.42-27.38 42.77-39.23C702.11 217.91 722.2 209.57 742 205c19.79-4.58 48.73 1.35 62.25 15.75 13.53 14.39 33.82 33.4 25.75 55.25s-11.05 48.12 8.7 24.7c19.74-23.43 3.15-44.98-2.78-65.62-5.92-20.64-25.58-29.08-42.89-39.1-17.32-10.03-49.17-9.19-68.35-3.3s-38.56 14.76-53.43 28.57C656.37 235.06 645.34 252.33 625 256c12.22-15.94 20.81-38.82 17-59-26.9 18.29-54.35 44.65-88 45m68-11c-13.38 43.35-62.82 68.05-107 59 21.24-37.25 77.33-28.33 107-59m137 74c-17.51 27.89-53.81 35.93-78 50 6.56 1.7 14.27.97 20 2-42.9 27.57-95 30.57-143 19 3.64-11.7 2.13-25.19 0-37 29.03 15.1 77.47 26.29 107.69 4.69C695.92 322.1 726.59 321.7 759 305m21 82c-36.17 23.22-80.28 12.53-118.68 30.32S572.88 421.28 536 409c15.34-34.47 38.29-17.58 68.07-10.07 29.79 7.5 59.64-12.51 86.01-19.85S751.83 400.63 780 387Z"/>
|
||||||
|
<path d="M392 287c-20.32-10.09-49.2 7.61-52.67 27.33S358.07 368.34 373 346c9.67 28.21 53.03 19.82 58-7 19.26 15.56 52.57-34.42 40.22-39.22-12.34-4.81-33.03 40.53-54.14 17.14-21.12-23.38-45.66-2.3-56.08 14.08-14.33-21.72 13.63-39.32 31-44m2 38c17.55 1.67 14.69 23.14-2 22-16.69-1.15-16.17-23.73 2-22Z"/>
|
||||||
|
<path d="M490 348c-12.99-1.62-23.01 7.92-28.22 18.78-5.22 10.86 16.25 30.36 16.22 8.22-.03-22.13 19.52-5.95 17.32 3.32s-26.86 27.6-1.55 19.45S517.62 351.45 490 348Z"/>
|
||||||
|
<path d="M674 441c-40.33 11.24-42.76 69.89-73.25 99.75S540.04 597.72 502 615c27.72-31.09 59.82-60.86 77.23-98.77S558.91 500.55 558 524c-13.08-6.32-21.74-21.77-37-24 3.55-6.21 7.89-11.71 13-17-8.15-3.56-15.71-9.78-25-10 .82 25.91-27.5 45.1-49.77 59.23s-51.06 24.71-74 39-42.75 30.47-60.48 52.52c-17.72 22.06-29.92 48.2-36.77 76.23-6.86 28.02-3.41 71.04 8.25 96.79s24.8 48.46 46.07 66.93c21.28 18.47 48.6 33.02 75.7 37.3 27.1 4.29 72.2 3.76 92.75-16.25 20.55-20 32.25-40.86 45.27-66.73 13.03-25.86 3.18-64.3-19.79-83.25s-58.57-22.78-83.98-8.52-23.27 74.33 13 52c36.27-22.34 41.09 30.39 4.97 35.97s-59.64-1.36-75.9-31.54c-16.26-30.19-1.87-61.91 14.43-85.93 16.3-24.01 38.04-38.35 62.56-50.44 24.51-12.1 52.5-22.87 75.44-37.56C569.7 594.07 588.44 576.36 609 559c-1.39 9.25-12.56 14.2-12 24 33.57-1.74 27.76-36.49 38.7-57.3 10.93-20.82 24.46-44.39 30.3-66.7 1.84 18.26 22.11 35.43 14 53 8.89-14.12-25.65-35.74-21.97-17.02 3.67 18.71 13.1 21.57 14.04 42.95.95 21.37 22.13 10.43 21.6-7.26s4.6-35.06-.89-51.45c-5.49-16.38-14.2-22.27-18.78-38.22m-160 67c24.5 10.25 43.09 26.66 23.25 47.25s-29.62 32.3-50.48 47.52-36.06 27.16-55.47 42.53c-19.4 15.38-30.8 34.17-44.22 53.78s-23.51 55.69-16.3 79.14c7.2 23.45 23.42 40.9 41.47 56.53 18.05 15.64 55.11 22.14 73.5 6 18.39-16.15 38.3-38.33 30.47-63.97-7.82-25.65-45.39-28.55-63.22-11.78-.94-56.2 91.16-27.42 89.99 16.01-1.16 43.43-26.47 87.36-69.67 100.31-43.19 12.95-96.76-7.24-126.32-39.32 10.92-1.33 21.38-4.38 32-7-2.12-26.28-36.97.92-47.92-12.08-10.94-13-16.39-29.78-23.08-44.92 8.41-2.09 51.28 14.81 50.97-1.02-.3-15.84-36.68-6.46-48.19-15.76-11.52-9.3-8.78-35.99-6.78-53.22 21.9-3.24 28.92 20.42 50.22 20.78 21.31.35 3.51-21.47-18.9-25.1-22.41-3.64-26.87-15.53-18.4-36.76 8.48-21.22 26.51-21.3 38.33-6.17 11.81 15.14 39.09 27.45 32.98 10.02s-27.52-20.03-39.48-32.52C336.8 625.75 359.27 611.44 371 602c10.99 12.33 52.93 61.18 49.23 34.77-3.71-26.41-64.67-41.3-14.23-55.77 14.17 11.5 30 42.33 48 40-2.7-21.51-25.55-32.32-39-47 27.66-18.95 39.59-11.81 60.25 13.75C495.92 613.3 485.64 555.21 458 555c5.15-7.51 16.07-10.94 23-17 17-4.6 29.56 34.8 42.08 28.08 12.51-6.73-18.91-36.56-30.08-36.08 5.57-7.94 12.64-16.51 21-22m-46 325c-6.5-.66-14.33 1.32-20-1 6.54-.17 13.93-1.72 20 1Z"/>
|
||||||
|
</svg>
|
||||||
|
</g>
|
||||||
|
<text fill="white" dominant-baseline="middle" text-anchor="middle" x="475" y="75" style="font-family:sans-serif;font-size:70px">Download</text>
|
||||||
|
<text fill="white" dominant-baseline="middle" text-anchor="middle" x="475" y="175" style="font-family:sans-serif;font-size:120px">TR2X</text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.5 KiB |
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
// NOTE: bad changes to this file may result in crashes.
|
// NOTE: bad changes to this file may result in crashes.
|
||||||
// Lines starting with double slashes are comments and are ignored.
|
// Lines starting with double slashes are comments and are ignored.
|
||||||
// Refer to https://github.com/LostArtefacts/TR1X/blob/stable/GAMEFLOW.md
|
// Refer to https://github.com/LostArtefacts/TRX/blob/stable/docs/tr1/GAMEFLOW.md
|
||||||
// for usage.
|
// for usage.
|
||||||
|
|
||||||
"main_menu_picture": "data/images/title.webp",
|
"main_menu_picture": "data/images/title.webp",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
// NOTE: bad changes to this file may result in crashes.
|
// NOTE: bad changes to this file may result in crashes.
|
||||||
// Lines starting with double slashes are comments and are ignored.
|
// Lines starting with double slashes are comments and are ignored.
|
||||||
// Refer to https://github.com/LostArtefacts/TR1X/blob/stable/GAMEFLOW.md
|
// Refer to https://github.com/LostArtefacts/TRX/blob/stable/docs/tr1/GAMEFLOW.md
|
||||||
// for usage.
|
// for usage.
|
||||||
|
|
||||||
"main_menu_picture": "data/images/title_ub.webp",
|
"main_menu_picture": "data/images/title_ub.webp",
|
||||||
|
|
|
@ -2,17 +2,9 @@
|
||||||
|
|
||||||
## Build workflow
|
## Build workflow
|
||||||
|
|
||||||
Initial build:
|
|
||||||
|
|
||||||
- Compile the project (described in the next section)
|
- Compile the project (described in the next section)
|
||||||
- Copy all executable files from `build/` to your game directory
|
- Copy all .dll and .exe files from `build/` to your game directory
|
||||||
- Copy the contents of `data/tr1/ship/` to your game directory
|
- Copy the contents of `data/…/ship/` to your game directory
|
||||||
|
|
||||||
Subsequent builds:
|
|
||||||
|
|
||||||
- Compile the project
|
|
||||||
- Copy all executable files from `build/` to your game directory
|
|
||||||
(we recommend making a script file to do this)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,14 +14,16 @@ Subsequent builds:
|
||||||
|
|
||||||
- **With Docker**:
|
- **With Docker**:
|
||||||
|
|
||||||
Make sure to install Docker and [just](https://github.com/casey/just), then
|
Make sure to install Docker and [just](https://github.com/casey/just).
|
||||||
run `just`. The binaries should appear in the `build/` directory.
|
To see the list of all possible build targets, run `just -l`. To build the
|
||||||
To see list of possible build targets, run `just -l`.
|
images, use the `just *-build-*` commands relevant to the game and platform
|
||||||
|
you want to build for. The binaries should appear in the `build/`
|
||||||
|
directory.
|
||||||
|
|
||||||
- **Without Docker**:
|
- **Without Docker**:
|
||||||
|
|
||||||
This scenario is not officially supported, but you can see how it's done by
|
This scenario is not officially supported, but you can see how it's done by
|
||||||
examining the files in the `tools/docker/` directory for the external
|
examining the files in the `tools/*/docker/` directory for the external
|
||||||
dependencies and `meson.build` for the local files, then tailoring your
|
dependencies and `meson.build` for the local files, then tailoring your
|
||||||
system to match the process.
|
system to match the process.
|
||||||
|
|
||||||
|
@ -53,8 +47,7 @@ Subsequent builds:
|
||||||
|
|
||||||
Please be advised that any build systems that are not the one we use for
|
Please be advised that any build systems that are not the one we use for
|
||||||
automating releases (= mingw-w64) come at user's own risk. They might crash or
|
automating releases (= mingw-w64) come at user's own risk. They might crash or
|
||||||
even refuse to compile. Pull requests are welcome, but those other toolchains
|
even refuse to compile.
|
||||||
will be always considered supplementary.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,8 +93,9 @@ guidelines:
|
||||||
|
|
||||||
- Variables are `lower_snake_case`
|
- Variables are `lower_snake_case`
|
||||||
- Global variables are `g_PascalCase`
|
- Global variables are `g_PascalCase`
|
||||||
- Module variables are `m_PascalCase`
|
- Module-scoped global variables are `m_PascalCase` and static
|
||||||
- Function names are `Module_PascalCase`
|
- Function names are `Module_PascalCase`
|
||||||
|
- Module-scoped function names are `M_PascalCase` and static
|
||||||
- Macros are `UPPER_SNAKE_CASE`
|
- Macros are `UPPER_SNAKE_CASE`
|
||||||
- Struct names are `UPPER_SNAKE_CASE`
|
- Struct names are `UPPER_SNAKE_CASE`
|
||||||
- Struct members are `lower_snake_case`
|
- Struct members are `lower_snake_case`
|
||||||
|
@ -151,29 +145,27 @@ a review from the interested parties.
|
||||||
|
|
||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
We keep a changelog in `CHANGELOG.md`. Anything other than an internal change
|
We keep a changelog for each game in a relevant `CHANGELOG.md` file. Anything other than an internal change
|
||||||
or refactor needs an entry there. Furthermore, new features and OG bugfixes
|
or refactor needs an entry there. Furthermore, new features and OG bugfixes
|
||||||
should be documented in README as well. If your change modifies gameflow
|
should be documented in the `README.md` file as well.
|
||||||
behavior, make sure to update `GAMEFLOW.md` as appropriate.
|
|
||||||
|
|
||||||
|
|
||||||
### Commit scope
|
### Commit scope
|
||||||
|
|
||||||
Either you can make a lot of throwaway commits such as 'test' 'continue
|
There are two options for handling commits. One approach involves making
|
||||||
testing' 'fix 1' 'fix 2' 'fix of the fix' and then squash your pull request as
|
temporary commits with messages like 'test,' 'continue testing,' 'fix 1,' 'fix
|
||||||
a whole, or you can craft a nice history with proper commit messages and then
|
2,' and 'fix of the fix,' followed by squashing all of them when creating a
|
||||||
merge-rebase. The first case is mostly acceptable for isolated features, but in
|
pull request. The other approach is to maintain a clean commit history with
|
||||||
general we prefer the latter approach. As a principle, refactors should made in
|
meaningful messages and use merge-rebase. While the first approach can be
|
||||||
separate commits. Code review changes are best made incrementally and then
|
suitable for isolated features, the latter is generally preferred.
|
||||||
squashed prior to merging, for easing the review process.
|
|
||||||
|
|
||||||
|
|
||||||
### Commit messages
|
### Commit messages
|
||||||
|
|
||||||
**The most important thing to remember:** bug fixes and feature implementations
|
**The most important thing to remember:** bug fixes and feature implementations
|
||||||
should always include the phrase `Resolves #123`. If there's no ticket and the
|
should always include the phrase `Resolves #123`. If there's no ticket and the
|
||||||
pull request you're making contains player-facing changes, a ticket needs
|
submitted pull request contains player-facing changes, a ticket needs to be
|
||||||
to be created first – no exceptions.
|
created first.
|
||||||
|
|
||||||
Anything else is just for consistency and general neatness. Our commit messages
|
Anything else is just for consistency and general neatness. Our commit messages
|
||||||
aim to respect the 50/72 rule and have the following form:
|
aim to respect the 50/72 rule and have the following form:
|
||||||
|
@ -259,7 +251,7 @@ released ahead of unpublished work in `develop` are merged directly to
|
||||||
### Tooling
|
### Tooling
|
||||||
|
|
||||||
We try to code all of our internal tools in a reasonably recent version of
|
We try to code all of our internal tools in a reasonably recent version of
|
||||||
Python. Avoid bash, shell and other similar languages.
|
Python and tend to avoid bash, shell and other similar languages.
|
||||||
|
|
||||||
|
|
||||||
### Releasing a new version
|
### Releasing a new version
|
||||||
|
@ -273,13 +265,16 @@ a specific version. See git history for details.
|
||||||
|
|
||||||
## Glossary
|
## Glossary
|
||||||
|
|
||||||
|
|
||||||
- Tomb1Main: the previous name of this project
|
- Tomb1Main: the previous name of this project
|
||||||
- T1M: short hand of Tomb1Main
|
- T1M: short hand of Tomb1Main
|
||||||
- OG: original game, most often TombATI
|
- OG: original game, most often TombATI
|
||||||
- PS: PlayStation version of the game
|
|
||||||
- Vole: a rat that swims
|
- Vole: a rat that swims
|
||||||
- Pod: a mutant egg (including the big egg)
|
- Pod: a mutant egg (including the big egg)
|
||||||
- Cabin: the room with the pistols from Natla's Mines
|
- Cabin: the room with the pistols from Natla's Mines
|
||||||
- Statue: centaur statues from the entrance of Tihocan's Tomb
|
- Statue: centaur statues from the entrance of Tihocan's Tomb
|
||||||
- Bacon Lara: the doppelgänger Lara in the Atlantis level
|
- Bacon Lara: the doppelgänger Lara in the Atlantis level
|
||||||
- Torso/Adam: the big boss mutant from The Great Pyramid level
|
- Torso/Adam: the big boss mutant from The Great Pyramid level
|
||||||
|
- UK Box: the version of TR2 released on discs in the UK
|
||||||
|
- Multipatch: the version of TR2 released on Steam
|
||||||
|
- PS: PlayStation version of the game
|
|
@ -1,4 +1,4 @@
|
||||||
## [Unreleased](https://github.com/LostArtefacts/TR1X/compare/stable...develop) - ××××-××-××
|
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/stable...develop) - ××××-××-××
|
||||||
- added `/sfx` command
|
- added `/sfx` command
|
||||||
- added `/nextlevel` alias to `/endlevel` console command
|
- added `/nextlevel` alias to `/endlevel` console command
|
||||||
- added `/quit` alias to `/exit` console command
|
- added `/quit` alias to `/exit` console command
|
|
@ -1412,6 +1412,14 @@ provided with the game achieves.
|
||||||
PS1 version but not the PC.
|
PS1 version but not the PC.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td>
|
||||||
|
<code>explosion.bin</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Injects explosion sprites for certain console commands.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<td>
|
<td>
|
||||||
<code>lara_animations.bin</code>
|
<code>lara_animations.bin</code>
|
604
docs/tr1/README.md
Normal file
|
@ -0,0 +1,604 @@
|
||||||
|
<p align="center">
|
||||||
|
<img alt="TR1X logo" src="/data/tr1/logo-light-theme.png#gh-light-mode-only" width="400"/>
|
||||||
|
<img alt="TR1X logo" src="/data/tr1/logo-dark-theme.png#gh-dark-mode-only" width="400"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Windows / Linux
|
||||||
|
|
||||||
|
### Installing (simplified)
|
||||||
|
|
||||||
|
1. Head over to GitHub releases: https://github.com/LostArtefacts/TRX/releases
|
||||||
|
2. Download the TR1X installer. Your browser may complain that the .exe is unsafe, but it's OK to ignore this alert.
|
||||||
|
3. Mark the installer EXE as safe to run by right-clicking on the .exe, going to properties and clicking "Unblock".
|
||||||
|
4. Run the installer and proceed with the steps.
|
||||||
|
|
||||||
|
We hope that eventually these alerts will go away as the popularity of the project rises.
|
||||||
|
|
||||||
|
### Installing (advanced / manual)
|
||||||
|
|
||||||
|
1. Head over to GitHub releases: https://github.com/LostArtefacts/TRX/releases
|
||||||
|
2. Download the TR1X zip file.
|
||||||
|
3. Extract the zip file into a directory of your choice.
|
||||||
|
Make sure you choose to overwrite existing directories and files.
|
||||||
|
4. (First time installation) Put your original game files into the target directory.
|
||||||
|
1. For Steam and GOG users, extract the original `GAME.BIN` file using a tool such as UltraISO to your target directory.
|
||||||
|
Note that neither the GOG nor the Steam releases ship the music files. You have a few options here:
|
||||||
|
- You can download the music files from the link below.
|
||||||
|
https://lostartefacts.dev/aux/tr1x/music.zip
|
||||||
|
The legality of this approach is disputable.
|
||||||
|
- Rip the assets yourself from a physical PlayStation/SegaSaturn disk.
|
||||||
|
|
||||||
|
Optionally you can also install the Unfinished Business expansion pack files.
|
||||||
|
- Either one of these these variants:
|
||||||
|
- https://lostartefacts.dev/aux/tr1x/trub-music.zip (fan-made patch to include music triggers)
|
||||||
|
- https://lostartefacts.dev/aux/tr1x/trub-vanilla.zip (original level files, which do not include music triggers)
|
||||||
|
- Or the more manual link: https://archive.org/details/tomb-raider-i-unfinished-business-pc-eng-full-version_20201225
|
||||||
|
2. For TombATI users this means copying the `data`, `fmv` and `music` directories.
|
||||||
|
5. To play the game, run `TR1X.exe`.
|
||||||
|
6. To play the Unfinished Expansion pack, run `TR1X.exe -gold`.
|
||||||
|
|
||||||
|
If you install everything correctly, your game directory should look more or
|
||||||
|
less like this (click to expand):
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<p><em>* Will not be present until the game has been launched.</em></p>
|
||||||
|
<pre>
|
||||||
|
.
|
||||||
|
├── cfg
|
||||||
|
│ ├── TR1X.json5 *
|
||||||
|
│ ├── TR1X_gameflow.json5
|
||||||
|
│ ├── TR1X_gameflow_demo_pc.json5
|
||||||
|
│ └── TR1X_gameflow_ub.json5
|
||||||
|
├── data
|
||||||
|
│ ├── cat.phd
|
||||||
|
│ ├── cred0.pcx
|
||||||
|
│ ├── cred1.pcx
|
||||||
|
│ ├── cred2.pcx
|
||||||
|
│ ├── cred3.pcx
|
||||||
|
│ ├── cut1.phd
|
||||||
|
│ ├── cut2.phd
|
||||||
|
│ ├── cut3.phd
|
||||||
|
│ ├── cut4.phd
|
||||||
|
│ ├── egypt.phd
|
||||||
|
│ ├── eidospc.pcx
|
||||||
|
│ ├── end2.phd
|
||||||
|
│ ├── end.pcx
|
||||||
|
│ ├── end.phd
|
||||||
|
│ ├── gym.phd
|
||||||
|
│ ├── install.pcx
|
||||||
|
│ ├── level10a.phd
|
||||||
|
│ ├── level10b.phd
|
||||||
|
│ ├── level10c.phd
|
||||||
|
│ ├── level1.phd
|
||||||
|
│ ├── level2.phd
|
||||||
|
│ ├── level3a.phd
|
||||||
|
│ ├── level3b.phd
|
||||||
|
│ ├── level4.phd
|
||||||
|
│ ├── level5.phd
|
||||||
|
│ ├── level6.phd
|
||||||
|
│ ├── level7a.phd
|
||||||
|
│ ├── level7b.phd
|
||||||
|
│ ├── level8a.phd
|
||||||
|
│ ├── level8b.phd
|
||||||
|
│ ├── level8c.phd
|
||||||
|
│ ├── titleh.pcx
|
||||||
|
│ ├── titleh_ub.pcx
|
||||||
|
│ │── title.phd
|
||||||
|
│ │── images
|
||||||
|
│ │ ├── atlantis.webp
|
||||||
|
│ │ ├── credits_1.webp
|
||||||
|
│ │ ├── credits_2.webp
|
||||||
|
│ │ ├── credits_3.webp
|
||||||
|
│ │ ├── credits_3_alt.webp
|
||||||
|
│ │ ├── credits_ps1.webp
|
||||||
|
│ │ ├── egypt.webp
|
||||||
|
│ │ ├── eidos.webp
|
||||||
|
│ │ ├── end.webp
|
||||||
|
│ │ ├── greece.webp
|
||||||
|
│ │ ├── greece_saturn.webp
|
||||||
|
│ │ ├── gym.webp
|
||||||
|
│ │ ├── install.webp
|
||||||
|
│ │ ├── peru.webp
|
||||||
|
│ │ ├── title.webp
|
||||||
|
│ │ ├── title_og_alt.webp
|
||||||
|
│ │ └── title_ub.webp
|
||||||
|
│ └── injections
|
||||||
|
│ ├── atlantis_fd.bin
|
||||||
|
│ ├── atlantis_textures.bin
|
||||||
|
│ ├── backpac.bin
|
||||||
|
│ └── etc...
|
||||||
|
├── fmv
|
||||||
|
│ ├── cafe.rpl
|
||||||
|
│ ├── canyon.rpl
|
||||||
|
│ ├── core.avi
|
||||||
|
│ ├── end.rpl
|
||||||
|
│ ├── escape.rpl
|
||||||
|
│ ├── lift.rpl
|
||||||
|
│ ├── mansion.rpl
|
||||||
|
│ ├── prison.rpl
|
||||||
|
│ ├── pyramid.rpl
|
||||||
|
│ ├── snow.rpl
|
||||||
|
│ └── vision.rpl
|
||||||
|
├── music
|
||||||
|
│ ├── track02.flac
|
||||||
|
│ ├── track03.flac
|
||||||
|
│ ├── track04.flac
|
||||||
|
│ ├── track05.flac
|
||||||
|
│ ├── track06.flac
|
||||||
|
│ ├── track07.flac
|
||||||
|
│ ├── track08.flac
|
||||||
|
│ ├── track09.flac
|
||||||
|
│ ├── track10.flac
|
||||||
|
│ ├── track11.flac
|
||||||
|
│ ├── track12.flac
|
||||||
|
│ ├── track13.flac
|
||||||
|
│ ├── track14.flac
|
||||||
|
│ ├── track15.flac
|
||||||
|
│ ├── track16.flac
|
||||||
|
│ ├── track17.flac
|
||||||
|
│ ├── track18.flac
|
||||||
|
│ ├── track19.flac
|
||||||
|
│ ├── track20.flac
|
||||||
|
│ ├── track21.flac
|
||||||
|
│ ├── track22.flac
|
||||||
|
│ ├── track23.flac
|
||||||
|
│ ├── track24.flac
|
||||||
|
│ ├── track25.flac
|
||||||
|
│ ├── track26.flac
|
||||||
|
│ ├── track27.flac
|
||||||
|
│ ├── track28.flac
|
||||||
|
│ ├── track29.flac
|
||||||
|
│ ├── track30.flac
|
||||||
|
│ ├── track31.flac
|
||||||
|
│ ├── track32.flac
|
||||||
|
│ ├── track33.flac
|
||||||
|
│ ├── track34.flac
|
||||||
|
│ ├── track35.flac
|
||||||
|
│ ├── track36.flac
|
||||||
|
│ ├── track37.flac
|
||||||
|
│ ├── track38.flac
|
||||||
|
│ ├── track39.flac
|
||||||
|
│ ├── track40.flac
|
||||||
|
│ ├── track41.flac
|
||||||
|
│ ├── track42.flac
|
||||||
|
│ ├── track43.flac
|
||||||
|
│ ├── track44.flac
|
||||||
|
│ ├── track45.flac
|
||||||
|
│ ├── track46.flac
|
||||||
|
│ ├── track47.flac
|
||||||
|
│ ├── track48.flac
|
||||||
|
│ ├── track49.flac
|
||||||
|
│ ├── track50.flac
|
||||||
|
│ ├── track51.flac
|
||||||
|
│ ├── track52.flac
|
||||||
|
│ ├── track53.flac
|
||||||
|
│ ├── track54.flac
|
||||||
|
│ ├── track55.flac
|
||||||
|
│ ├── track56.flac
|
||||||
|
│ ├── track57.flac
|
||||||
|
│ ├── track58.flac
|
||||||
|
│ ├── track59.flac
|
||||||
|
│ └── track60.flac
|
||||||
|
├── shaders
|
||||||
|
│ ├── 2d.glsl
|
||||||
|
│ ├── 3d.glsl
|
||||||
|
│ └── fbo.glsl
|
||||||
|
├── TR1X.exe
|
||||||
|
└── TR1X_ConfigTool.exe
|
||||||
|
</pre>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Configuring
|
||||||
|
|
||||||
|
To configure TR1X, run the `TR1X_ConfigTool.exe` application. All the
|
||||||
|
configuration is explained in this tool. Alternatively, after running the game
|
||||||
|
at least once, you can edit `TR1X.json5` manually in a text editor such
|
||||||
|
as Notepad.
|
||||||
|
|
||||||
|
## macOS
|
||||||
|
|
||||||
|
### Installing
|
||||||
|
|
||||||
|
1. Head over to GitHub releases: https://github.com/LostArtefacts/TR1X/releases
|
||||||
|
2. Download the `TR1X-Installer.dmg` installer image. Mount the image and drag TR1X to the Applications folder.
|
||||||
|
3. Run TR1X from the Applications folder. This will show you an error dialog about missing game data files. This is expected at this point, as you have not copied them in yet. However, it's important to run the app first to allow macOS to verify the app bundle's signature.
|
||||||
|
4. Find TR1X in your Applications folder. Right-click it and click "Show Package Contents".
|
||||||
|
5. Copy your Tomb Raider 1 game data files into `Contents/Resources`. (See the Windows / Linux instructions for retrieving game data from e.g. GOG.)
|
||||||
|
|
||||||
|
If you install everything correctly, your game directory should look more or
|
||||||
|
less like this (click to expand):
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<p><em>* Will not be present until the game has been launched.</em></p>
|
||||||
|
<pre>
|
||||||
|
.
|
||||||
|
└── Contents
|
||||||
|
├── _CodeSignature
|
||||||
|
├── Framworks
|
||||||
|
├── info.plist
|
||||||
|
├── MacOS
|
||||||
|
└── Resources
|
||||||
|
├── cfg
|
||||||
|
│ ├── TR1X.json5 *
|
||||||
|
│ ├── TR1X_gameflow.json5
|
||||||
|
│ ├── TR1X_gameflow_demo_pc.json5
|
||||||
|
│ └── TR1X_gameflow_ub.json5
|
||||||
|
├── data
|
||||||
|
│ ├── cat.phd
|
||||||
|
│ ├── cred0.pcx
|
||||||
|
│ ├── cred1.pcx
|
||||||
|
│ ├── cred2.pcx
|
||||||
|
│ ├── cred3.pcx
|
||||||
|
│ ├── cut1.phd
|
||||||
|
│ ├── cut2.phd
|
||||||
|
│ ├── cut3.phd
|
||||||
|
│ ├── cut4.phd
|
||||||
|
│ ├── egypt.phd
|
||||||
|
│ ├── eidospc.pcx
|
||||||
|
│ ├── end2.phd
|
||||||
|
│ ├── end.pcx
|
||||||
|
│ ├── end.phd
|
||||||
|
│ ├── gym.phd
|
||||||
|
│ ├── install.pcx
|
||||||
|
│ ├── level10a.phd
|
||||||
|
│ ├── level10b.phd
|
||||||
|
│ ├── level10c.phd
|
||||||
|
│ ├── level1.phd
|
||||||
|
│ ├── level2.phd
|
||||||
|
│ ├── level3a.phd
|
||||||
|
│ ├── level3b.phd
|
||||||
|
│ ├── level4.phd
|
||||||
|
│ ├── level5.phd
|
||||||
|
│ ├── level6.phd
|
||||||
|
│ ├── level7a.phd
|
||||||
|
│ ├── level7b.phd
|
||||||
|
│ ├── level8a.phd
|
||||||
|
│ ├── level8b.phd
|
||||||
|
│ ├── level8c.phd
|
||||||
|
│ ├── titleh.pcx
|
||||||
|
│ ├── titleh_ub.pcx
|
||||||
|
│ │── title.phd
|
||||||
|
│ │── images
|
||||||
|
│ │ ├── atlantis.webp
|
||||||
|
│ │ ├── credits_1.webp
|
||||||
|
│ │ ├── credits_2.webp
|
||||||
|
│ │ ├── credits_3.webp
|
||||||
|
│ │ ├── credits_3_alt.webp
|
||||||
|
│ │ ├── credits_ps1.webp
|
||||||
|
│ │ ├── egypt.webp
|
||||||
|
│ │ ├── eidos.webp
|
||||||
|
│ │ ├── end.webp
|
||||||
|
│ │ ├── greece.webp
|
||||||
|
│ │ ├── greece_saturn.webp
|
||||||
|
│ │ ├── gym.webp
|
||||||
|
│ │ ├── install.webp
|
||||||
|
│ │ ├── peru.webp
|
||||||
|
│ │ ├── title.webp
|
||||||
|
│ │ ├── title_og_alt.webp
|
||||||
|
│ │ └── title_ub.webp
|
||||||
|
│ └── injections
|
||||||
|
│ ├── atlantis_fd.bin
|
||||||
|
│ ├── atlantis_textures.bin
|
||||||
|
│ ├── backpac.bin
|
||||||
|
│ └── etc...
|
||||||
|
├── fmv
|
||||||
|
│ ├── cafe.rpl
|
||||||
|
│ ├── canyon.rpl
|
||||||
|
│ ├── core.avi
|
||||||
|
│ ├── end.rpl
|
||||||
|
│ ├── escape.rpl
|
||||||
|
│ ├── lift.rpl
|
||||||
|
│ ├── mansion.rpl
|
||||||
|
│ ├── prison.rpl
|
||||||
|
│ ├── pyramid.rpl
|
||||||
|
│ ├── snow.rpl
|
||||||
|
│ └── vision.rpl
|
||||||
|
├── icon.icns
|
||||||
|
├── music
|
||||||
|
│ ├── track02.flac
|
||||||
|
│ ├── track03.flac
|
||||||
|
│ ├── track04.flac
|
||||||
|
│ ├── track05.flac
|
||||||
|
│ ├── track06.flac
|
||||||
|
│ ├── track07.flac
|
||||||
|
│ ├── track08.flac
|
||||||
|
│ ├── track09.flac
|
||||||
|
│ ├── track10.flac
|
||||||
|
│ ├── track11.flac
|
||||||
|
│ ├── track12.flac
|
||||||
|
│ ├── track13.flac
|
||||||
|
│ ├── track14.flac
|
||||||
|
│ ├── track15.flac
|
||||||
|
│ ├── track16.flac
|
||||||
|
│ ├── track17.flac
|
||||||
|
│ ├── track18.flac
|
||||||
|
│ ├── track19.flac
|
||||||
|
│ ├── track20.flac
|
||||||
|
│ ├── track21.flac
|
||||||
|
│ ├── track22.flac
|
||||||
|
│ ├── track23.flac
|
||||||
|
│ ├── track24.flac
|
||||||
|
│ ├── track25.flac
|
||||||
|
│ ├── track26.flac
|
||||||
|
│ ├── track27.flac
|
||||||
|
│ ├── track28.flac
|
||||||
|
│ ├── track29.flac
|
||||||
|
│ ├── track30.flac
|
||||||
|
│ ├── track31.flac
|
||||||
|
│ ├── track32.flac
|
||||||
|
│ ├── track33.flac
|
||||||
|
│ ├── track34.flac
|
||||||
|
│ ├── track35.flac
|
||||||
|
│ ├── track36.flac
|
||||||
|
│ ├── track37.flac
|
||||||
|
│ ├── track38.flac
|
||||||
|
│ ├── track39.flac
|
||||||
|
│ ├── track40.flac
|
||||||
|
│ ├── track41.flac
|
||||||
|
│ ├── track42.flac
|
||||||
|
│ ├── track43.flac
|
||||||
|
│ ├── track44.flac
|
||||||
|
│ ├── track45.flac
|
||||||
|
│ ├── track46.flac
|
||||||
|
│ ├── track47.flac
|
||||||
|
│ ├── track48.flac
|
||||||
|
│ ├── track49.flac
|
||||||
|
│ ├── track50.flac
|
||||||
|
│ ├── track51.flac
|
||||||
|
│ ├── track52.flac
|
||||||
|
│ ├── track53.flac
|
||||||
|
│ ├── track54.flac
|
||||||
|
│ ├── track55.flac
|
||||||
|
│ ├── track56.flac
|
||||||
|
│ ├── track57.flac
|
||||||
|
│ ├── track58.flac
|
||||||
|
│ ├── track59.flac
|
||||||
|
│ └── track60.flac
|
||||||
|
└── shaders
|
||||||
|
├── 2d.glsl
|
||||||
|
├── 3d.glsl
|
||||||
|
└── fbo.glsl
|
||||||
|
</pre>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Improvements over original game
|
||||||
|
|
||||||
|
Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for details.
|
||||||
|
|
||||||
|
#### UI
|
||||||
|
- added proper UI and bar scaling
|
||||||
|
- added enemy health bars
|
||||||
|
- added PS1 style UI
|
||||||
|
- added fade effects to displayed images
|
||||||
|
- added an option to use PS1 loading screens
|
||||||
|
- added a wireframe mode
|
||||||
|
- improved support for windowed mode
|
||||||
|
|
||||||
|
#### Gameplay
|
||||||
|
- added ability to set user-defined FOV
|
||||||
|
- added ability to select weapons / using items with numeric keys
|
||||||
|
- added ability to look around while running
|
||||||
|
- added ability to forward and backward jump while looking
|
||||||
|
- added ability to look up and down while hanging
|
||||||
|
- added ability to sidestep like in TR3
|
||||||
|
- added ability to jump-twist and somersault like in TR2+
|
||||||
|
- added ability to cancel ledge-swinging animation like in TR2+
|
||||||
|
- added ability to jump at any point while running like in TR2+
|
||||||
|
- added ability to automatically walk to items when nearby
|
||||||
|
- added ability to roll while underwater like in TR2+
|
||||||
|
- added ability to use Lara's underwater swimming physics from TR2+
|
||||||
|
- added a pause screen
|
||||||
|
- added a choice whether to play NG or NG+ without having to play the entire game
|
||||||
|
- added Japanese mode (guns deal twice the damage, inspired by JP release of TR3); available for both NG and NG+
|
||||||
|
- added ability to restart level on death
|
||||||
|
- added ability to restart the adventure from any level when loading a game
|
||||||
|
- added the "Story so far..." option in the select level menu to view cutscenes and FMVs
|
||||||
|
- added graphics effects, lava emitters, flame emitters, and waterfalls to the savegame so they now persist on load
|
||||||
|
- added an option to restore the mummy in City of Khamoon room 25, similar to the PS version
|
||||||
|
- added a flag indicating if new game plus is unlocked to the player config which allows the player to select new game plus or not when making a new game
|
||||||
|
- added weapons to Lara's empty holsters on pickup
|
||||||
|
- added options to quiet or mute music while underwater
|
||||||
|
- changed weapon pickup behavior when unarmed to set any weapon as the default weapon, not just pistols
|
||||||
|
- fixed keys and items not working when drawing guns immediately after using them
|
||||||
|
- fixed counting the secret in The Great Pyramid
|
||||||
|
- fixed running out of ammo forcing Lara to equip pistols even if she doesn't carry them
|
||||||
|
- fixed a crash when Lara is on fire and goes too far away from where she caught fire
|
||||||
|
- fixed flames not being drawn when Lara is on fire and leaves the room where she caught fire
|
||||||
|
- fixed settings not being saved when exiting the game with Alt+F4
|
||||||
|
- fixed settings not persisting chosen layout (default vs. user keys)
|
||||||
|
- fixed the infamous Tihocan crocodile bug (integer overflow causing creatures to deal damage across the entire level)
|
||||||
|
- fixed missiles damaging Lara when she is far beyond their damage range
|
||||||
|
- fixed Lara not being able to grab parts of some bridges
|
||||||
|
- fixed Lara voiding if a badly placed timed door closes on her (doesn't occur in OG levels)
|
||||||
|
- fixed bats being positioned too high
|
||||||
|
- fixed alligators dealing no damage if Lara remains still in the water
|
||||||
|
- fixed shotgun shooting when a locked target moves out of Lara's sight
|
||||||
|
- fixed shotgun shooting too fast when not aiming at a target
|
||||||
|
- fixed Lara grabbing ledges she shouldn't in stacked rooms (mainly St. Francis Folly tower)
|
||||||
|
- fixed rare cases of Lara getting set on fire on a bridge over lava
|
||||||
|
- fixed saving the game near Bacon Lara breaking her movement
|
||||||
|
- fixed Lara glitching through static objects into a black void
|
||||||
|
- fixed Lara pushing blocks through doors
|
||||||
|
- fixed Lara switching to pistols when completing a level with other guns
|
||||||
|
- fixed empty mutant shells in Unfinished Business spawning Lara's hips
|
||||||
|
- fixed gun pickups disappearing in rare circumstances on save load (#406)
|
||||||
|
- fixed broken dart ricochet effect
|
||||||
|
- fixed exploded mutant pods sometimes appearing unhatched on reload
|
||||||
|
- fixed bridges at floor level appearing under the floor
|
||||||
|
- fixed underwater currents breaking in rare cases
|
||||||
|
- fixed Lara loading inside a movable block if she's on a stack near a room portal
|
||||||
|
- fixed a game crash on shutdown if the action button is held down
|
||||||
|
- fixed Scion 1 respawning on load
|
||||||
|
- fixed triggered flip effects not working if there are no sound devices
|
||||||
|
- fixed ceiling heights at times being miscalculated, resulting in camera issues and Lara being able to jump into the ceiling
|
||||||
|
- fixed the camera being thrown through doors for one frame when looked at from fixed camera positions
|
||||||
|
- fixed the ape not performing the vault animation when climbing
|
||||||
|
- fixed Natla's gun moving while she is in her semi death state
|
||||||
|
- fixed the bear pat attack so it does not miss Lara
|
||||||
|
- fixed dead centaurs exploding again after saving and reloading
|
||||||
|
- fixed the following floor data issues:
|
||||||
|
- **St. Francis' Folly**: moved the music trigger for track 3 in room 4 behind the Neptune door, and restored track 15 to play after using the 4 keys
|
||||||
|
- **The Cistern**: missing trigger in room 56 which could result in a softlock
|
||||||
|
- **Tomb of Tihocan**: missing trigger in room 62 for enemy 34
|
||||||
|
- **City of Khamoon**: incorrect trapdoor trigger types in rooms 31 and 34
|
||||||
|
- **Obelisk of Khamoon**: missing switch trigger type in room 66
|
||||||
|
- **Natla's Mines**: incorrect flipmap indices in room 85
|
||||||
|
- **Atlantean Stronghold**: fixed poorly configured portals between rooms 74 and 12
|
||||||
|
- fixed various bugs with falling movable blocks
|
||||||
|
- fixed bugs when trying to stack multiple movable blocks
|
||||||
|
- fixed Midas's touch having unrestricted vertical range
|
||||||
|
- fixed Lara saying "no" when taking valid actions in front of a key item receptacle
|
||||||
|
- fixed Lara not saying "no" when using the Scion incorrectly
|
||||||
|
- fixed flickering in bats' death animations and rapid shooting if Lara continues to fire when they are killed
|
||||||
|
- fixed looking forward too far causing an upside down camera frame
|
||||||
|
- fixed the Scion being extremely difficult to shoot with the shotgun
|
||||||
|
- fixed collision issues with drawbridges, trapdoors, and bridges when stacked over each other, over slopes, and near the ground
|
||||||
|
- fixed a potential softlock when killing the Torso boss in Great Pyramid
|
||||||
|
|
||||||
|
#### Cheats
|
||||||
|
- added a fly cheat
|
||||||
|
- added a level skip cheat
|
||||||
|
- added a door open cheat (while in fly mode)
|
||||||
|
- added a cheat to increase the game speed
|
||||||
|
- added a cheat to explode Lara like in TR2 and TR3
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
- added ability to move camera around with W,A,S,D
|
||||||
|
- added additional custom control schemes
|
||||||
|
- added the ability to unbind unessential keys
|
||||||
|
- added the ability to reset control schemes to default
|
||||||
|
- added customizable controller support
|
||||||
|
- added an inverted look camera option
|
||||||
|
- added the ability to move the look camera while targeting an enemy in combat
|
||||||
|
- fixed freeze when holding the Action key during end of level
|
||||||
|
- fixed inability to switch Control keys when shimmying
|
||||||
|
- fixed setting user keys being very difficult
|
||||||
|
- fixed skipping FMVs triggering inventory
|
||||||
|
- fixed skipping credits working too fast
|
||||||
|
- fixed not being able to close level stats with Escape
|
||||||
|
- fixed Lara jumping forever when alt+tabbing out of the game
|
||||||
|
- stopped the default controls from functioning when the user unbound them
|
||||||
|
- added the option to change weapon targets by tapping the new target change key
|
||||||
|
- added three targeting lock options:
|
||||||
|
- full lock: always keep target lock even if the enemy moves out of sight or dies (OG TR1)
|
||||||
|
- semi lock: keep target lock if the enemy moves out of sight but lose target lock if the enemy dies
|
||||||
|
- no lock: lose target lock if the enemy goes out of sight or dies (TR4+)
|
||||||
|
|
||||||
|
#### Statistics
|
||||||
|
- added ability to keep timer on in inventory
|
||||||
|
- added optional compass level stats
|
||||||
|
- added optional final statistics screen
|
||||||
|
- added optional deaths counter
|
||||||
|
- added optional total pickups and kills per level
|
||||||
|
- added unobtainable pickups, kills, and secrets stats support in the gameflow
|
||||||
|
|
||||||
|
#### Visuals
|
||||||
|
- added optional shotgun flash sprites
|
||||||
|
- added optional rendering of pickups on the ground as 3D meshes
|
||||||
|
- added Lara's braid to each level
|
||||||
|
- added support for displaying more than 3 pickup sprites
|
||||||
|
- added more control over when to show health bar and air bar
|
||||||
|
- added customizable health bar and air bar
|
||||||
|
- added rounded shadows (instead of the default octagon)
|
||||||
|
- added adjustable in-game brightness
|
||||||
|
- added support for HD FMVs
|
||||||
|
- added fanmade 16:9 menu backgrounds
|
||||||
|
- added optional fade effects
|
||||||
|
- added a vsync option
|
||||||
|
- added contextual arrows to menu options
|
||||||
|
- added support for animated room sprites, which also restores intended behavior in, for example, The Cistern room 0
|
||||||
|
- added skybox support, with a default option provided for Lost Valley, Colosseum and Obelisk of Khamoon; custom level builders can use object slot `184`
|
||||||
|
- added reflections of Midas Hand death animation and savegame crystals
|
||||||
|
- changed the Scion in The Great Pyramid from spawning blood when hit to a richochet effect
|
||||||
|
- fixed thin black lines between polygons
|
||||||
|
- fixed black screen flashing when navigating the inventory
|
||||||
|
- fixed detail levels text flashing with any option change
|
||||||
|
- fixed underwater caustics animating at 2x speed
|
||||||
|
- fixed inconsistencies in some enemy textures
|
||||||
|
- fixed the animation of Lara's left arm when the shotgun is equipped
|
||||||
|
- fixed the following room texture issues:
|
||||||
|
- **Gym**: incorrect textures in room 9
|
||||||
|
- **Caves**: an incorrect texture in room 6 and missing textures in rooms 1, 10, 14 and 30
|
||||||
|
- **City of Vilcabamba**: an incorrect texture in room 26, and a missing texture and a stretched texture in room 15
|
||||||
|
- **Lost Valley**: incorrect textures in rooms 6, 9, 16, 34 and 35, missing textures in rooms 6, 9, 25, 26, 27, 51, and 90, and stretched textures in room 63
|
||||||
|
- **Tomb of Qualopec**: an incorrect and missing textures in room 8, and a misaligned texture in room 5
|
||||||
|
- **St. Francis' Folly**: incorrect textures in rooms 1, 4, 18 and 35, and a misaligned texture in room 3
|
||||||
|
- **Colosseum**: incorrect Midas textures appearing at the roof, incorrect textures in rooms 37, 67, 75 and 82, and missing textures in rooms 2 and 7
|
||||||
|
- **Palace Midas**: incorrect textures in rooms 31, 34, 40 and 45, missing textures in rooms 2, 5, 9, 13, 30, and 53, and stretched textures in rooms 7 and 20
|
||||||
|
- **The Cistern**: missing textures in rooms 3 and 9 and a stretched texture in room 102
|
||||||
|
- **Tomb of Tihocan**: incorrect textures in rooms 75 and 89 and a misaligned texture in room 104
|
||||||
|
- **City of Khamoon**: incorrect textures in rooms 47, 48, 51, 60 and 64, and a missing texture in room 58
|
||||||
|
- **Obelisk of Khamoon**: incorrect textures in rooms 22, 23, 42 and 65; added shading to the gaps into City of Khamoon in rooms 8 and 20/21
|
||||||
|
- **Sanctuary of the Scion**: missing textures in rooms 1, 11, 21, 52, 53, and 54
|
||||||
|
- **Natla's Mines**: a missing texture in room 35, overlapping textures in room 55, an incorrect texture in room 69, and stretched textures in rooms 23 and 24
|
||||||
|
- **Pre-Atlantis Cutscene**: stretched textures in rooms 6 and 21
|
||||||
|
- **Atlantis**: incorrect textures in rooms 5, 18, 36, 43, 50, 52, 53, 54, 58, 78, 85 and 87, a missing texture in room 27, and stretched textures in rooms 13, 49 and 50
|
||||||
|
- **Atlantis Cutscene**: incorrect and stretched textures in room 16
|
||||||
|
- **The Great Pyramid**: incorrect textures in rooms 2, 5, 31, 36, 50, 52, 53, 54, 65 and 66, missing textures in rooms 21, 25, 26, and 66, and stretched textures in rooms 49 and 50
|
||||||
|
- **Return to Egypt**: incorrect textures in rooms 46 and 47, a missing texture in room 98, and a stretched texture in room 47
|
||||||
|
- **Temple of the Cat**: incorrect textures in rooms 50, 70, 71, 76, 78, 87 and 96, and a missing texture in 75
|
||||||
|
- **Atlantean Stronghold**: incorrect textures in rooms 2, 6, 7 and 75, and missing textures in rooms 5, 13, 19, 63 and 74
|
||||||
|
- **The Hive**: incorrect textures in room 8, 13 and 18
|
||||||
|
- improved vertex movement when looking through water portals
|
||||||
|
|
||||||
|
#### Audio
|
||||||
|
- added music during the credits
|
||||||
|
- added an option to turn off sound effect pitching
|
||||||
|
- added an option to use the PlayStation Uzi sound effects
|
||||||
|
- added the current music track and timestamp to the savegame so they now persist on load
|
||||||
|
- added the triggered music tracks to the savegame so one shot tracks don't replay on load
|
||||||
|
- added detection for animation commands to play SFX on land, water or both
|
||||||
|
- fixed the sound of collecting a secret killing the music
|
||||||
|
- fixed audio mixer stopping playing sounds on big explosions
|
||||||
|
- fixed game audio not muting when game is minimized
|
||||||
|
- fixed underwater ambient sound effect not playing
|
||||||
|
- fixed sound effects playing rapidly in sound menu if input held down
|
||||||
|
- fixed sounds stopping instead of pausing when using the inventory or pausing
|
||||||
|
- fixed the following music triggers:
|
||||||
|
- **Caves**: converted track 9 in room 34 to one shot
|
||||||
|
- **Tomb of Qualopec**: converted track 17 in room 25 to one shot
|
||||||
|
- **St. Francis' Folly**: converted track 7 in room 18 to one shot
|
||||||
|
- **Obelisk of Khamoon**: converted track 3 in room 12 and track 4 in room 32 to one shot
|
||||||
|
- **Sanctuary of the Scion**: converted track 10 in room 0 to one shot
|
||||||
|
- **Natla's Mines**: converted track 3 in room 86 to one shot
|
||||||
|
- **Atlantis**: converted track 8 in room 59 to one shot
|
||||||
|
- **The Great Pyramid**: converted track 8 in room 36 to one shot
|
||||||
|
- **Return to Egypt**: converted track 19 in room 0, track 14 in room 15, track 15 in room 19, track 16 in room 22, track 6 in room 61, and track 11 in room 93 to one shot
|
||||||
|
- **Temple of the Cat**: converted track 12 in room 14, track 7 in room 98, and track 20 in room 100 to one shot
|
||||||
|
- **Atlantean Stronghold**: converted track 20 in room 4, track 19 in room 13, track 11 in room 17, track 15 in room 20, and track 12 in room 25 to one shot
|
||||||
|
- **The Hive**: converted track 9 in room 8, track 6 in room 18, track 12 in room 30, track 18 in room 31, track 3 in room 32, and track 20 in room 35 to one shot
|
||||||
|
|
||||||
|
#### Mods
|
||||||
|
- added developer console (accessible with `/`, see [COMMANDS.md](COMMANDS.md) for details)
|
||||||
|
- added ability to adjust Lara's starting health (easy no damage mod)
|
||||||
|
- added ability to disable healing between levels
|
||||||
|
- added ability to disable certain item pickups (all medpacks, shotgun, Magnums and/or UZIs)
|
||||||
|
- added ability to disable main menu demos, FMVs and/or cutscenes
|
||||||
|
- added external game flow (no longer 2 different .exes for TR1 and TR1UB). Refer to [GAMEFLOW.md](GAMEFLOW.md) for details
|
||||||
|
- added automatic calculation of secret counts (no longer having to fiddle with the .exe to get correct secret stats)
|
||||||
|
- added save game crystals game mode (enabled via gameflow)
|
||||||
|
- added per-level customizable water color (with customizable blue component)
|
||||||
|
- added per-level customizable fog distance
|
||||||
|
- added deadly water feature from TR2+
|
||||||
|
|
||||||
|
#### Miscellaneous
|
||||||
|
- added Linux builds
|
||||||
|
- added macOS builds
|
||||||
|
- added .jpeg/.png screenshots
|
||||||
|
- added an option to pause sound in the inventory screen
|
||||||
|
- added ability to skip FMVs with the Action key
|
||||||
|
- added ability to make freshly triggered (runaway) Pierre replace an already existing (runaway) Pierre
|
||||||
|
- expanded internal game memory limit from 3.5 MB to 16 MB
|
||||||
|
- expanded moveable limit from 256 to 10240
|
||||||
|
- expanded maximum textures from 2048 to 8192
|
||||||
|
- expanded maximum texture pages from 32 to 128
|
||||||
|
- expanded maximum vertices of a single drawable object from 1500 to unlimited
|
||||||
|
- expanded the number of visible enemies from 8 to 32
|
||||||
|
- ported audio decoding library to ffmpeg
|
||||||
|
- ported video decoding library to ffmpeg
|
||||||
|
- ported image decoding library to ffmpeg
|
||||||
|
- ported audio output library to SDL
|
||||||
|
- ported input method to SDL
|
||||||
|
- changed saves to be put in the saves/ directory
|
||||||
|
- fixed playing the secret sound in Tomb of Tihocan
|
||||||
|
- fixed reading user settings not restoring the volume
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 223 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 241 KiB |
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 196 KiB After Width: | Height: | Size: 196 KiB |
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 195 KiB |
|
@ -1,55 +1,21 @@
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="TR2X logo" src="data/logo-light-theme.png#gh-light-mode-only" width="400"/>
|
<img alt="TR2X logo" src="/data/tr2/logo-light-theme.png#gh-light-mode-only" width="400"/>
|
||||||
<img alt="TR2X logo" src="data/logo-dark-theme.png#gh-dark-mode-only" width="400"/>
|
<img alt="TR2X logo" src="/data/tr2/logo-dark-theme.png#gh-dark-mode-only" width="400"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
TR2X is an open-source decompilation project for Tomb Raider 2, created as a
|
|
||||||
sequel to the successful [TR1X](https://github.com/LostArtefacts/TR1X/) project
|
|
||||||
for Tomb Raider 1. Our project is in the early stages, and our main focus is on
|
|
||||||
decompiling as much of the game as possible.
|
|
||||||
|
|
||||||
## The situation
|
|
||||||
|
|
||||||
TR2X draws inspiration from existing decompilation efforts, including the
|
|
||||||
achievements of [TR2Main](https://github.com/Arsunt/TR2Main) developed by
|
|
||||||
[Arsunt](https://github.com/Arsunt/). However, we emphasize that TR2X is an
|
|
||||||
independent project and does not directly copy code from TR2Main.
|
|
||||||
|
|
||||||
## Our Mission
|
|
||||||
|
|
||||||
Our mission is to fully decompile Tomb Raider 2 and to eventually enhance the
|
|
||||||
overall gameplay experience.
|
|
||||||
|
|
||||||
### Key Goals
|
|
||||||
|
|
||||||
- **Comprehensive Decompilation:**
|
|
||||||
Our primary objective is to achieve a thorough decompilation of Tomb Raider
|
|
||||||
2, enabling a deeper understanding of its inner workings.
|
|
||||||
|
|
||||||
- **Enhancement of UK Box Version:**
|
|
||||||
Our work is based on the UK Box version of Tomb Raider 2. Eventually we hope
|
|
||||||
to reach feature parity with the Steam/multipatch version, and possibly
|
|
||||||
TR2Main as well.
|
|
||||||
|
|
||||||
- **Cross-platform Compatibility:**
|
|
||||||
We are committed to making Tomb Raider 2 run natively on Linux, with the
|
|
||||||
possibility of supporting Mac systems in the future.
|
|
||||||
|
|
||||||
- **Transparent Development Process:**
|
|
||||||
We value transparency and aim to maintain a transparent development process,
|
|
||||||
ensuring regular updates and engagement with the community.
|
|
||||||
|
|
||||||
- **Changelog and Progress Updates:**
|
|
||||||
We strive to provide detailed and reliable changelogs, documenting
|
|
||||||
significant updates and changes made to TR2X. Additionally, we will keep
|
|
||||||
the community informed about the progress of the project.
|
|
||||||
|
|
||||||
TR2X is currently in the early stages of development, focusing on the
|
TR2X is currently in the early stages of development, focusing on the
|
||||||
decompilation process. We recognize that there is much work to be done.
|
decompilation process. We recognize that there is much work to be done.
|
||||||
|
|
||||||
## Decompilation progress
|
## Windows
|
||||||
|
|
||||||

|
### Installing (manual)
|
||||||
|
|
||||||
|
1. Head over to GitHub releases: https://github.com/LostArtefacts/TRX/releases
|
||||||
|
2. Download the TR2X zip file.
|
||||||
|
3. Extract the TR2X zip file into a directory of your choice.
|
||||||
|
Make sure you choose to overwrite existing directories and files.
|
||||||
|
4. (First time installation) Put your original game files into the target directory.
|
||||||
|
5. To play the game, run `TR2X.exe`.
|
||||||
|
|
||||||
## Improvements over original game
|
## Improvements over original game
|
||||||
|
|
||||||
|
@ -58,6 +24,10 @@ decompilation process. We recognize that there is much work to be done.
|
||||||
- added an option to fix M16 accuracy while running
|
- added an option to fix M16 accuracy while running
|
||||||
- fixed killing the T-Rex with a grenade launcher crashing the game
|
- fixed killing the T-Rex with a grenade launcher crashing the game
|
||||||
- fixed secret rewards not displaying shotgun ammo
|
- fixed secret rewards not displaying shotgun ammo
|
||||||
|
- fixed numeric keys interfering with the demos
|
||||||
|
- fixed explosions sometimes being drawn too dark
|
||||||
|
- fixed controls dialog remapping being too sensitive
|
||||||
|
- fixed the distorted skybox in room 5 of Barkhang Monastery
|
||||||
|
|
||||||
#### Visuals
|
#### Visuals
|
||||||
|
|
||||||
|
@ -68,14 +38,4 @@ decompilation process. We recognize that there is much work to be done.
|
||||||
- fixed music not playing with certain game versions
|
- fixed music not playing with certain game versions
|
||||||
|
|
||||||
#### Mods
|
#### Mods
|
||||||
- added developer console (accessible with `/`, see [COMMANDS.md] for details)
|
- added developer console (accessible with `/`, see [COMMANDS.md](COMMANDS.md) for details)
|
||||||
|
|
||||||
## Contributions
|
|
||||||
|
|
||||||
Please refer to our [CONTRIBUTING.md](CONTRIBUTING.md) file for more
|
|
||||||
information on how to contribute to the project.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
TR2X follows the GPL license. Please refer to the [COPYING.md](COPYING.md) file
|
|
||||||
for further details.
|
|
||||||
|
|
56
justfile
|
@ -2,7 +2,7 @@ CWD := `pwd`
|
||||||
HOST_USER_UID := `id -u`
|
HOST_USER_UID := `id -u`
|
||||||
HOST_USER_GID := `id -g`
|
HOST_USER_GID := `id -g`
|
||||||
|
|
||||||
default: (build-win "debug")
|
default: (tr1-build-win "debug")
|
||||||
|
|
||||||
_docker_push tag:
|
_docker_push tag:
|
||||||
docker push {{tag}}
|
docker push {{tag}}
|
||||||
|
@ -10,7 +10,7 @@ _docker_push tag:
|
||||||
_docker_build dockerfile tag force="0":
|
_docker_build dockerfile tag force="0":
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
if [ "{{force}}" = "0" ]; then
|
if [ "{{force}}" = "0" ]; then
|
||||||
docker images --format '{''{.Repository}}' | grep '^{{tag}}$'
|
docker images --format '{''{.Repository}}' | grep '^{{tag}}$' >/dev/null
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Docker image {{tag}} found"
|
echo "Docker image {{tag}} found"
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -41,34 +41,48 @@ _docker_run *args:
|
||||||
{{args}}
|
{{args}}
|
||||||
|
|
||||||
|
|
||||||
image-linux force="1": (_docker_build "tools/tr1/docker/game-linux/Dockerfile" "rrdash/tr1x-linux" force)
|
tr1-image-linux force="1": (_docker_build "tools/tr1/docker/game-linux/Dockerfile" "rrdash/tr1x-linux" force)
|
||||||
image-win force="1": (_docker_build "tools/tr1/docker/game-win/Dockerfile" "rrdash/tr1x" force)
|
tr1-image-win force="1": (_docker_build "tools/tr1/docker/game-win/Dockerfile" "rrdash/tr1x" force)
|
||||||
image-win-config force="1": (_docker_build "tools/tr1/docker/config/Dockerfile" "rrdash/tr1x-config" force)
|
tr1-image-win-config force="1": (_docker_build "tools/tr1/docker/config/Dockerfile" "rrdash/tr1x-config" force)
|
||||||
image-win-installer force="1": (_docker_build "tools/tr1/docker/installer/Dockerfile" "rrdash/tr1x-installer" force)
|
tr1-image-win-installer force="1": (_docker_build "tools/tr1/docker/installer/Dockerfile" "rrdash/tr1x-installer" force)
|
||||||
|
|
||||||
push-image-linux: (image-linux "0") (_docker_push "rrdash/tr1x-linux")
|
tr1-push-image-linux: (tr1-image-linux "0") (_docker_push "rrdash/tr1x-linux")
|
||||||
push-image-win: (image-win "0") (_docker_push "rrdash/tr1x")
|
tr1-push-image-win: (tr1-image-win "0") (_docker_push "rrdash/tr1x")
|
||||||
|
|
||||||
build-linux target='debug': (image-linux "0") (_docker_run "-e" "TARGET="+target "rrdash/tr1x-linux")
|
tr1-build-linux target='debug': (tr1-image-linux "0") (_docker_run "-e" "TARGET="+target "rrdash/tr1x-linux")
|
||||||
build-win target='debug': (image-win "0") (_docker_run "-e" "TARGET="+target "rrdash/tr1x")
|
tr1-build-win target='debug': (tr1-image-win "0") (_docker_run "-e" "TARGET="+target "rrdash/tr1x")
|
||||||
build-win-config: (image-win-config "0") (_docker_run "rrdash/tr1x-config")
|
tr1-build-win-config: (tr1-image-win-config "0") (_docker_run "rrdash/tr1x-config")
|
||||||
build-win-installer: (image-win-installer "0") (_docker_run "rrdash/tr1x-installer")
|
tr1-build-win-installer: (tr1-image-win-installer "0") (_docker_run "rrdash/tr1x-installer")
|
||||||
|
|
||||||
package-linux: (build-linux "release") (_docker_run "rrdash/tr1x-linux" "package")
|
tr1-package-linux: (tr1-build-linux "release") (_docker_run "rrdash/tr1x-linux" "package")
|
||||||
package-win: (build-win "release") (_docker_run "rrdash/tr1x" "package")
|
tr1-package-win: (tr1-build-win "release") (_docker_run "rrdash/tr1x" "package")
|
||||||
package-win-all: (build-win "release") (build-win-config) (_docker_run "rrdash/tr1x" "package")
|
tr1-package-win-all: (tr1-build-win "release") (tr1-build-win-config) (_docker_run "rrdash/tr1x" "package")
|
||||||
package-win-installer: (build-win "release") (build-win-config) (_docker_run "rrdash/tr1x" "package" "-o" "tools/tr1/installer/Installer/Resources/release.zip") (build-win-installer)
|
tr1-package-win-installer: (tr1-build-win "release") (tr1-build-win-config) (_docker_run "rrdash/tr1x" "package" "-o" "tools/tr1/installer/Installer/Resources/release.zip") (tr1-build-win-installer)
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
git checkout "tools/tr1/installer/Installer/Resources/release.zip"
|
git checkout "tools/tr1/installer/Installer/Resources/release.zip"
|
||||||
exe_name=TR1X-$(tools/get_version)-Installer.exe
|
exe_name=TR1X-$(tools/get_version 1)-Installer.exe
|
||||||
cp tools/tr1/installer/out/TR1X_Installer.exe "${exe_name}"
|
cp tools/tr1/installer/out/TR1X_Installer.exe "${exe_name}"
|
||||||
echo "Created ${exe_name}"
|
echo "Created ${exe_name}"
|
||||||
|
|
||||||
output-current-version:
|
tr2-image-win force="1": (_docker_build "tools/tr2/docker/game-win/Dockerfile" "rrdash/tr2x" force)
|
||||||
tools/get_version
|
tr2-image-win-config force="1": (_docker_build "tools/tr2/docker/config/Dockerfile" "rrdash/tr2x-config" force)
|
||||||
|
|
||||||
output-current-changelog:
|
tr2-push-image-win: (tr2-image-win "0") (_docker_push "rrdash/tr2x")
|
||||||
tools/output_current_changelog
|
|
||||||
|
tr2-build-win target='debug': (tr2-image-win "0") (_docker_run "-e" "TARGET="+target "rrdash/tr2x")
|
||||||
|
tr2-build-win-config: (tr2-image-win-config "0") (_docker_run "rrdash/tr2x-config")
|
||||||
|
|
||||||
|
tr2-package-win target='release': (tr2-build-win target) (_docker_run "rrdash/tr2x" "package")
|
||||||
|
tr2-package-win-all target='release': (tr2-build-win target) (tr2-build-win-config) (_docker_run "rrdash/tr2x" "package")
|
||||||
|
|
||||||
|
output-release-name tr_version:
|
||||||
|
tools/output_release_name {{tr_version}}
|
||||||
|
|
||||||
|
output-current-version tr_version:
|
||||||
|
tools/get_version {{tr_version}}
|
||||||
|
|
||||||
|
output-current-changelog tr_version:
|
||||||
|
tools/output_current_changelog {{tr_version}}
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-find build/ -type f -delete
|
-find build/ -type f -delete
|
||||||
|
|
319
meson.build
|
@ -1,319 +0,0 @@
|
||||||
project(
|
|
||||||
'TR1X',
|
|
||||||
'c',
|
|
||||||
default_options: [
|
|
||||||
'c_std=c2x',
|
|
||||||
'warning_level=2',
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
if host_machine.system() == 'darwin'
|
|
||||||
gfx_gl_default_backend = 'GFX_GL_33C'
|
|
||||||
else
|
|
||||||
gfx_gl_default_backend = 'GFX_GL_21'
|
|
||||||
endif
|
|
||||||
|
|
||||||
trx = subproject('libtrx', default_options: {
|
|
||||||
'tr_version': '1',
|
|
||||||
'gfx_gl_default_backend': gfx_gl_default_backend,
|
|
||||||
})
|
|
||||||
c_compiler = meson.get_compiler('c')
|
|
||||||
|
|
||||||
build_opts = [
|
|
||||||
'-Wno-unused',
|
|
||||||
'-DMESON_BUILD',
|
|
||||||
'-DTR_VERSION=1',
|
|
||||||
'-fno-omit-frame-pointer',
|
|
||||||
'-ffile-prefix-map=../../src/tr1/=',
|
|
||||||
] + trx.get_variable('defines')
|
|
||||||
|
|
||||||
add_project_arguments(build_opts, language: 'c')
|
|
||||||
|
|
||||||
staticdeps = get_option('staticdeps')
|
|
||||||
|
|
||||||
# Always dynamically link on macOS
|
|
||||||
if host_machine.system() == 'darwin'
|
|
||||||
staticdeps = false
|
|
||||||
endif
|
|
||||||
|
|
||||||
null_dep = dependency('', required: false)
|
|
||||||
|
|
||||||
dep_trx = trx.get_variable('dep_trx')
|
|
||||||
dep_avcodec = dependency('libavcodec', static: staticdeps)
|
|
||||||
dep_avformat = dependency('libavformat', static: staticdeps)
|
|
||||||
dep_avutil = dependency('libavutil', static: staticdeps)
|
|
||||||
dep_mathlibrary = c_compiler.find_library('m', static: staticdeps, required : false)
|
|
||||||
dep_swscale = dependency('libswscale', static: staticdeps)
|
|
||||||
dep_swresample = dependency('libswresample', static: staticdeps)
|
|
||||||
dep_sdl2 = dependency('SDL2', static: staticdeps)
|
|
||||||
dep_zlib = null_dep
|
|
||||||
|
|
||||||
if not staticdeps
|
|
||||||
dep_zlib = dependency('zlib', static: staticdeps)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# autogenerated files
|
|
||||||
resources = []
|
|
||||||
python3 = find_program('python3', required: true)
|
|
||||||
git = find_program('git', required: true)
|
|
||||||
|
|
||||||
init = custom_target(
|
|
||||||
'fake_init',
|
|
||||||
output: ['init.c'],
|
|
||||||
command: [python3, meson.source_root() + '/tools/generate_init', '-o', meson.current_build_dir() / '@OUTPUT0@'],
|
|
||||||
build_always_stale: true,
|
|
||||||
)
|
|
||||||
|
|
||||||
version_rc = custom_target(
|
|
||||||
'fake_version',
|
|
||||||
output: ['version.rc'],
|
|
||||||
command: [python3, meson.source_root() + '/tools/generate_rcfile', '-o', '@OUTPUT0@'],
|
|
||||||
build_always_stale: true,
|
|
||||||
)
|
|
||||||
|
|
||||||
icon_rc = custom_target(
|
|
||||||
'fake_icon',
|
|
||||||
output: ['icon.rc'],
|
|
||||||
command: [python3, meson.source_root() + '/tools/generate_rcfile', '-o', '@OUTPUT0@'],
|
|
||||||
)
|
|
||||||
|
|
||||||
link_args = []
|
|
||||||
|
|
||||||
if host_machine.system() == 'windows'
|
|
||||||
windows = import('windows')
|
|
||||||
|
|
||||||
resources = [
|
|
||||||
windows.compile_resources(version_rc),
|
|
||||||
windows.compile_resources(icon_rc),
|
|
||||||
]
|
|
||||||
|
|
||||||
link_args += ['-static']
|
|
||||||
endif
|
|
||||||
|
|
||||||
sources = [
|
|
||||||
init,
|
|
||||||
'src/tr1/config.c',
|
|
||||||
'src/tr1/config_map.c',
|
|
||||||
'src/tr1/game/anim.c',
|
|
||||||
'src/tr1/game/backpack.c',
|
|
||||||
'src/tr1/game/box.c',
|
|
||||||
'src/tr1/game/camera.c',
|
|
||||||
'src/tr1/game/carrier.c',
|
|
||||||
'src/tr1/game/clock.c',
|
|
||||||
'src/tr1/game/collide.c',
|
|
||||||
'src/tr1/game/console/cmd/easy_config.c',
|
|
||||||
'src/tr1/game/console/cmd/speed.c',
|
|
||||||
'src/tr1/game/console/common.c',
|
|
||||||
'src/tr1/game/console/setup.c',
|
|
||||||
'src/tr1/game/creature.c',
|
|
||||||
'src/tr1/game/effect_routines/bubbles.c',
|
|
||||||
'src/tr1/game/effect_routines/chain_block.c',
|
|
||||||
'src/tr1/game/effect_routines/dino_stomp.c',
|
|
||||||
'src/tr1/game/effect_routines/earthquake.c',
|
|
||||||
'src/tr1/game/ui/common.c',
|
|
||||||
'src/tr1/game/ui/widgets/label.c',
|
|
||||||
'src/tr1/game/ui/widgets/prompt.c',
|
|
||||||
'src/tr1/game/ui/widgets/window.c',
|
|
||||||
'src/tr1/game/effect_routines/explosion.c',
|
|
||||||
'src/tr1/game/effect_routines/finish_level.c',
|
|
||||||
'src/tr1/game/effect_routines/flicker.c',
|
|
||||||
'src/tr1/game/effect_routines/flipmap.c',
|
|
||||||
'src/tr1/game/effect_routines/flood.c',
|
|
||||||
'src/tr1/game/effect_routines/lara_effects.c',
|
|
||||||
'src/tr1/game/effect_routines/powerup.c',
|
|
||||||
'src/tr1/game/effect_routines/raising_block.c',
|
|
||||||
'src/tr1/game/effect_routines/sand.c',
|
|
||||||
'src/tr1/game/effect_routines/stairs2slope.c',
|
|
||||||
'src/tr1/game/effect_routines/turn_180.c',
|
|
||||||
'src/tr1/game/effects.c',
|
|
||||||
'src/tr1/game/effects/blood.c',
|
|
||||||
'src/tr1/game/effects/exploding_death.c',
|
|
||||||
'src/tr1/game/effects/gun.c',
|
|
||||||
'src/tr1/game/effects/gunshot.c',
|
|
||||||
'src/tr1/game/fmv.c',
|
|
||||||
'src/tr1/game/game/game.c',
|
|
||||||
'src/tr1/game/game/game_draw.c',
|
|
||||||
'src/tr1/game/game/game_main_menu.c',
|
|
||||||
'src/tr1/game/game_string.c',
|
|
||||||
'src/tr1/game/gamebuf.c',
|
|
||||||
'src/tr1/game/gameflow.c',
|
|
||||||
'src/tr1/game/gun/gun.c',
|
|
||||||
'src/tr1/game/gun/gun_misc.c',
|
|
||||||
'src/tr1/game/gun/gun_pistols.c',
|
|
||||||
'src/tr1/game/gun/gun_rifle.c',
|
|
||||||
'src/tr1/game/inject.c',
|
|
||||||
'src/tr1/game/input.c',
|
|
||||||
'src/tr1/game/interpolation.c',
|
|
||||||
'src/tr1/game/inventory/inventory.c',
|
|
||||||
'src/tr1/game/inventory/inventory_func.c',
|
|
||||||
'src/tr1/game/inventory/inventory_ring.c',
|
|
||||||
'src/tr1/game/inventory/inventory_vars.c',
|
|
||||||
'src/tr1/game/items.c',
|
|
||||||
'src/tr1/game/lara/cheat.c',
|
|
||||||
'src/tr1/game/lara/col.c',
|
|
||||||
'src/tr1/game/lara/common.c',
|
|
||||||
'src/tr1/game/lara/control.c',
|
|
||||||
'src/tr1/game/lara/draw.c',
|
|
||||||
'src/tr1/game/lara/hair.c',
|
|
||||||
'src/tr1/game/lara/look.c',
|
|
||||||
'src/tr1/game/lara/misc.c',
|
|
||||||
'src/tr1/game/lara/state.c',
|
|
||||||
'src/tr1/game/level.c',
|
|
||||||
'src/tr1/game/los.c',
|
|
||||||
'src/tr1/game/lot.c',
|
|
||||||
'src/tr1/game/music.c',
|
|
||||||
'src/tr1/game/objects/common.c',
|
|
||||||
'src/tr1/game/objects/creatures/ape.c',
|
|
||||||
'src/tr1/game/objects/creatures/bacon_lara.c',
|
|
||||||
'src/tr1/game/objects/creatures/baldy.c',
|
|
||||||
'src/tr1/game/objects/creatures/bat.c',
|
|
||||||
'src/tr1/game/objects/creatures/bear.c',
|
|
||||||
'src/tr1/game/objects/creatures/centaur.c',
|
|
||||||
'src/tr1/game/objects/creatures/cowboy.c',
|
|
||||||
'src/tr1/game/objects/creatures/crocodile.c',
|
|
||||||
'src/tr1/game/objects/creatures/cutscene_player.c',
|
|
||||||
'src/tr1/game/objects/creatures/larson.c',
|
|
||||||
'src/tr1/game/objects/creatures/lion.c',
|
|
||||||
'src/tr1/game/objects/creatures/mummy.c',
|
|
||||||
'src/tr1/game/objects/creatures/mutant.c',
|
|
||||||
'src/tr1/game/objects/creatures/natla.c',
|
|
||||||
'src/tr1/game/objects/creatures/pierre.c',
|
|
||||||
'src/tr1/game/objects/creatures/pod.c',
|
|
||||||
'src/tr1/game/objects/creatures/raptor.c',
|
|
||||||
'src/tr1/game/objects/creatures/rat.c',
|
|
||||||
'src/tr1/game/objects/creatures/skate_kid.c',
|
|
||||||
'src/tr1/game/objects/creatures/statue.c',
|
|
||||||
'src/tr1/game/objects/creatures/torso.c',
|
|
||||||
'src/tr1/game/objects/creatures/trex.c',
|
|
||||||
'src/tr1/game/objects/creatures/wolf.c',
|
|
||||||
'src/tr1/game/objects/effects/blood.c',
|
|
||||||
'src/tr1/game/objects/effects/body_part.c',
|
|
||||||
'src/tr1/game/objects/effects/bubble.c',
|
|
||||||
'src/tr1/game/objects/effects/dart_effect.c',
|
|
||||||
'src/tr1/game/objects/effects/ember.c',
|
|
||||||
'src/tr1/game/objects/effects/explosion.c',
|
|
||||||
'src/tr1/game/objects/effects/flame.c',
|
|
||||||
'src/tr1/game/objects/effects/gunshot.c',
|
|
||||||
'src/tr1/game/objects/effects/missile.c',
|
|
||||||
'src/tr1/game/objects/effects/natla_gun.c',
|
|
||||||
'src/tr1/game/objects/effects/ricochet.c',
|
|
||||||
'src/tr1/game/objects/effects/splash.c',
|
|
||||||
'src/tr1/game/objects/effects/twinkle.c',
|
|
||||||
'src/tr1/game/objects/general/boat.c',
|
|
||||||
'src/tr1/game/objects/general/bridge_common.c',
|
|
||||||
'src/tr1/game/objects/general/bridge_flat.c',
|
|
||||||
'src/tr1/game/objects/general/bridge_tilt1.c',
|
|
||||||
'src/tr1/game/objects/general/bridge_tilt2.c',
|
|
||||||
'src/tr1/game/objects/general/cabin.c',
|
|
||||||
'src/tr1/game/objects/general/camera_target.c',
|
|
||||||
'src/tr1/game/objects/general/cog.c',
|
|
||||||
'src/tr1/game/objects/general/door.c',
|
|
||||||
'src/tr1/game/objects/general/drawbridge.c',
|
|
||||||
'src/tr1/game/objects/general/earthquake.c',
|
|
||||||
'src/tr1/game/objects/general/keyhole.c',
|
|
||||||
'src/tr1/game/objects/general/moving_bar.c',
|
|
||||||
'src/tr1/game/objects/general/pickup.c',
|
|
||||||
'src/tr1/game/objects/general/puzzle_hole.c',
|
|
||||||
'src/tr1/game/objects/general/save_crystal.c',
|
|
||||||
'src/tr1/game/objects/general/scion1.c',
|
|
||||||
'src/tr1/game/objects/general/scion2.c',
|
|
||||||
'src/tr1/game/objects/general/scion3.c',
|
|
||||||
'src/tr1/game/objects/general/scion4.c',
|
|
||||||
'src/tr1/game/objects/general/scion_holder.c',
|
|
||||||
'src/tr1/game/objects/general/switch.c',
|
|
||||||
'src/tr1/game/objects/general/trapdoor.c',
|
|
||||||
'src/tr1/game/objects/general/waterfall.c',
|
|
||||||
'src/tr1/game/objects/setup.c',
|
|
||||||
'src/tr1/game/objects/traps/damocles_sword.c',
|
|
||||||
'src/tr1/game/objects/traps/dart.c',
|
|
||||||
'src/tr1/game/objects/traps/dart_emitter.c',
|
|
||||||
'src/tr1/game/objects/traps/ember_emitter.c',
|
|
||||||
'src/tr1/game/objects/traps/falling_block.c',
|
|
||||||
'src/tr1/game/objects/traps/falling_ceiling.c',
|
|
||||||
'src/tr1/game/objects/traps/flame_emitter.c',
|
|
||||||
'src/tr1/game/objects/traps/lava_wedge.c',
|
|
||||||
'src/tr1/game/objects/traps/lightning_emitter.c',
|
|
||||||
'src/tr1/game/objects/traps/midas_touch.c',
|
|
||||||
'src/tr1/game/objects/traps/movable_block.c',
|
|
||||||
'src/tr1/game/objects/traps/pendulum.c',
|
|
||||||
'src/tr1/game/objects/traps/rolling_ball.c',
|
|
||||||
'src/tr1/game/objects/traps/sliding_pillar.c',
|
|
||||||
'src/tr1/game/objects/traps/spikes.c',
|
|
||||||
'src/tr1/game/objects/traps/teeth_trap.c',
|
|
||||||
'src/tr1/game/objects/traps/thors_hammer_handle.c',
|
|
||||||
'src/tr1/game/objects/traps/thors_hammer_head.c',
|
|
||||||
'src/tr1/game/objects/vars.c',
|
|
||||||
'src/tr1/game/option/option.c',
|
|
||||||
'src/tr1/game/option/option_compass.c',
|
|
||||||
'src/tr1/game/option/option_control.c',
|
|
||||||
'src/tr1/game/option/option_control_pick.c',
|
|
||||||
'src/tr1/game/option/option_graphics.c',
|
|
||||||
'src/tr1/game/option/option_passport.c',
|
|
||||||
'src/tr1/game/option/option_sound.c',
|
|
||||||
'src/tr1/game/output.c',
|
|
||||||
'src/tr1/game/overlay.c',
|
|
||||||
'src/tr1/game/packer.c',
|
|
||||||
'src/tr1/game/phase/phase.c',
|
|
||||||
'src/tr1/game/phase/phase_cutscene.c',
|
|
||||||
'src/tr1/game/phase/phase_demo.c',
|
|
||||||
'src/tr1/game/phase/phase_game.c',
|
|
||||||
'src/tr1/game/phase/phase_inventory.c',
|
|
||||||
'src/tr1/game/phase/phase_pause.c',
|
|
||||||
'src/tr1/game/phase/phase_picture.c',
|
|
||||||
'src/tr1/game/phase/phase_stats.c',
|
|
||||||
'src/tr1/game/random.c',
|
|
||||||
'src/tr1/game/requester.c',
|
|
||||||
'src/tr1/game/room.c',
|
|
||||||
'src/tr1/game/room_draw.c',
|
|
||||||
'src/tr1/game/savegame/savegame.c',
|
|
||||||
'src/tr1/game/savegame/savegame_bson.c',
|
|
||||||
'src/tr1/game/savegame/savegame_legacy.c',
|
|
||||||
'src/tr1/game/screen.c',
|
|
||||||
'src/tr1/game/shell.c',
|
|
||||||
'src/tr1/game/sound.c',
|
|
||||||
'src/tr1/game/stats.c',
|
|
||||||
'src/tr1/game/text.c',
|
|
||||||
'src/tr1/game/viewport.c',
|
|
||||||
'src/tr1/global/enum_map.c',
|
|
||||||
'src/tr1/global/vars.c',
|
|
||||||
'src/tr1/math/math.c',
|
|
||||||
'src/tr1/math/math_misc.c',
|
|
||||||
'src/tr1/math/matrix.c',
|
|
||||||
'src/tr1/specific/s_clock.c',
|
|
||||||
'src/tr1/specific/s_fmv.c',
|
|
||||||
'src/tr1/specific/s_input.c',
|
|
||||||
'src/tr1/specific/s_output.c',
|
|
||||||
'src/tr1/specific/s_shell.c',
|
|
||||||
resources,
|
|
||||||
]
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
dep_trx,
|
|
||||||
dep_avcodec,
|
|
||||||
dep_avformat,
|
|
||||||
dep_avutil,
|
|
||||||
dep_mathlibrary,
|
|
||||||
dep_sdl2,
|
|
||||||
dep_swresample,
|
|
||||||
dep_swscale,
|
|
||||||
dep_zlib,
|
|
||||||
]
|
|
||||||
|
|
||||||
executable(
|
|
||||||
'TR1X',
|
|
||||||
sources,
|
|
||||||
include_directories: ['src/tr1/'],
|
|
||||||
dependencies: dependencies,
|
|
||||||
link_args: link_args,
|
|
||||||
gui_app: true,
|
|
||||||
install: true,
|
|
||||||
)
|
|
||||||
|
|
||||||
if host_machine.system() == 'darwin'
|
|
||||||
install_subdir('data/tr1/ship/cfg', install_dir : 'Contents/Resources')
|
|
||||||
install_subdir('data/tr1/ship/data', install_dir : 'Contents/Resources')
|
|
||||||
install_subdir('data/tr1/ship/shaders', install_dir : 'Contents/Resources')
|
|
||||||
install_data('data/tr1/mac/icon.icns', install_dir : 'Contents/Resources')
|
|
||||||
install_data('data/tr1/mac/Info.plist', install_dir : 'Contents')
|
|
||||||
meson.add_install_script('tools/tr1/mac/bundle_dylibs')
|
|
||||||
endif
|
|
166
src/libtrx/meson.build
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
project(
|
||||||
|
'libtrx',
|
||||||
|
'c',
|
||||||
|
default_options: [
|
||||||
|
'c_std=c11',
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
staticdeps = get_option('staticdeps')
|
||||||
|
tr_version = get_option('tr_version')
|
||||||
|
gfx_gl_default_backend = get_option('gfx_gl_default_backend')
|
||||||
|
|
||||||
|
fs = import('fs')
|
||||||
|
c_compiler = meson.get_compiler('c')
|
||||||
|
relative_dir = fs.relative_to(meson.current_source_dir(), meson.global_build_root())
|
||||||
|
build_opts = [
|
||||||
|
'-fmacro-prefix-map=@0@/=libtrx/'.format(relative_dir),
|
||||||
|
'-Wno-unused',
|
||||||
|
'-Wno-address-of-packed-member',
|
||||||
|
'-DMESON_BUILD',
|
||||||
|
'-DDWST_STATIC',
|
||||||
|
'-DPCRE2_STATIC',
|
||||||
|
'-DPCRE2_CODE_UNIT_WIDTH=8',
|
||||||
|
'-DTR_VERSION=' + tr_version.to_string(),
|
||||||
|
'-DGFX_GL_DEFAULT_BACKEND=' + gfx_gl_default_backend,
|
||||||
|
]
|
||||||
|
set_variable('defines', ['-DTR_VERSION=' + tr_version.to_string()])
|
||||||
|
|
||||||
|
add_project_arguments(build_opts, language: 'c')
|
||||||
|
|
||||||
|
# Always dynamically link on macOS
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
staticdeps = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
uthash = subproject('uthash', default_options: ['warning_level=0'])
|
||||||
|
|
||||||
|
null_dep = dependency('', required: false)
|
||||||
|
dep_avcodec = dependency('libavcodec', static: staticdeps)
|
||||||
|
dep_avformat = dependency('libavformat', static: staticdeps)
|
||||||
|
dep_avutil = dependency('libavutil', static: staticdeps)
|
||||||
|
dep_sdl2 = dependency('SDL2', static: staticdeps)
|
||||||
|
dep_pcre2 = dependency('libpcre2-8', static: staticdeps)
|
||||||
|
dep_backtrace = c_compiler.find_library('backtrace', static: true, required: false)
|
||||||
|
dep_swscale = dependency('libswscale', static: staticdeps)
|
||||||
|
dep_swresample = dependency('libswresample', static: staticdeps)
|
||||||
|
|
||||||
|
dep_zlib = null_dep
|
||||||
|
if not staticdeps
|
||||||
|
dep_zlib = dependency('zlib', static: staticdeps)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if host_machine.system() == 'windows'
|
||||||
|
dep_opengl = c_compiler.find_library('opengl32')
|
||||||
|
else
|
||||||
|
dep_opengl = dependency('GL')
|
||||||
|
endif
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'benchmark.c',
|
||||||
|
'config/common.c',
|
||||||
|
'config/file.c',
|
||||||
|
'engine/audio.c',
|
||||||
|
'engine/audio_sample.c',
|
||||||
|
'engine/audio_stream.c',
|
||||||
|
'engine/image.c',
|
||||||
|
'enum_map.c',
|
||||||
|
'event_manager.c',
|
||||||
|
'filesystem.c',
|
||||||
|
'game/backpack.c',
|
||||||
|
'game/console/cmd/config.c',
|
||||||
|
'game/console/cmd/die.c',
|
||||||
|
'game/console/cmd/end_level.c',
|
||||||
|
'game/console/cmd/exit_game.c',
|
||||||
|
'game/console/cmd/exit_to_title.c',
|
||||||
|
'game/console/cmd/flipmap.c',
|
||||||
|
'game/console/cmd/fly.c',
|
||||||
|
'game/console/cmd/give_item.c',
|
||||||
|
'game/console/cmd/heal.c',
|
||||||
|
'game/console/cmd/kill.c',
|
||||||
|
'game/console/cmd/load_game.c',
|
||||||
|
'game/console/cmd/play_demo.c',
|
||||||
|
'game/console/cmd/play_level.c',
|
||||||
|
'game/console/cmd/pos.c',
|
||||||
|
'game/console/cmd/save_game.c',
|
||||||
|
'game/console/cmd/set_health.c',
|
||||||
|
'game/console/cmd/sfx.c',
|
||||||
|
'game/console/cmd/teleport.c',
|
||||||
|
'game/console/common.c',
|
||||||
|
'game/game_string.c',
|
||||||
|
'game/items.c',
|
||||||
|
'game/objects/names.c',
|
||||||
|
'game/ui/common.c',
|
||||||
|
'game/ui/events.c',
|
||||||
|
'game/ui/widgets/console.c',
|
||||||
|
'game/ui/widgets/prompt.c',
|
||||||
|
'game/ui/widgets/spacer.c',
|
||||||
|
'game/ui/widgets/stack.c',
|
||||||
|
'gfx/2d/2d_renderer.c',
|
||||||
|
'gfx/2d/2d_surface.c',
|
||||||
|
'gfx/3d/3d_renderer.c',
|
||||||
|
'gfx/3d/vertex_stream.c',
|
||||||
|
'gfx/context.c',
|
||||||
|
'gfx/gl/buffer.c',
|
||||||
|
'gfx/gl/gl_core_3_3.c',
|
||||||
|
'gfx/gl/program.c',
|
||||||
|
'gfx/gl/sampler.c',
|
||||||
|
'gfx/gl/texture.c',
|
||||||
|
'gfx/gl/utils.c',
|
||||||
|
'gfx/gl/vertex_array.c',
|
||||||
|
'gfx/renderers/fbo_renderer.c',
|
||||||
|
'gfx/renderers/legacy_renderer.c',
|
||||||
|
'gfx/screenshot.c',
|
||||||
|
'json/bson_parse.c',
|
||||||
|
'json/bson_write.c',
|
||||||
|
'json/json_base.c',
|
||||||
|
'json/json_parse.c',
|
||||||
|
'json/json_write.c',
|
||||||
|
'log.c',
|
||||||
|
'memory.c',
|
||||||
|
'strings/common.c',
|
||||||
|
'strings/fuzzy_match.c',
|
||||||
|
'vector.c',
|
||||||
|
'virtual_file.c',
|
||||||
|
]
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
dep_avcodec,
|
||||||
|
dep_avformat,
|
||||||
|
dep_avutil,
|
||||||
|
dep_sdl2,
|
||||||
|
dep_pcre2,
|
||||||
|
dep_backtrace,
|
||||||
|
dep_swresample,
|
||||||
|
dep_swscale,
|
||||||
|
dep_zlib,
|
||||||
|
dep_opengl,
|
||||||
|
uthash.get_variable('uthash_dep'),
|
||||||
|
]
|
||||||
|
|
||||||
|
if dep_backtrace.found() and host_machine.system() == 'linux'
|
||||||
|
sources += ['log_linux.c']
|
||||||
|
elif host_machine.system() == 'windows'
|
||||||
|
sources += ['log_windows.c']
|
||||||
|
dwarfstack = subproject('dwarfstack', default_options: ['warning_level=0'])
|
||||||
|
dep_dwarfstack = dwarfstack.get_variable('dep_dwarfstack')
|
||||||
|
dep_dbghelp = c_compiler.find_library('dbghelp')
|
||||||
|
dependencies += [dep_dbghelp, dep_dwarfstack]
|
||||||
|
else
|
||||||
|
sources += ['log_unknown.c']
|
||||||
|
endif
|
||||||
|
|
||||||
|
libtrx = static_library(
|
||||||
|
'libtrx',
|
||||||
|
sources,
|
||||||
|
dependencies: dependencies,
|
||||||
|
include_directories: ['.', 'include/libtrx/'],
|
||||||
|
)
|
||||||
|
|
||||||
|
dep_trx = declare_dependency(
|
||||||
|
link_whole: libtrx,
|
||||||
|
include_directories: [
|
||||||
|
include_directories('include/', is_system: true)
|
||||||
|
]
|
||||||
|
)
|
20
src/libtrx/meson.options
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
option(
|
||||||
|
'staticdeps',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true,
|
||||||
|
description: 'Try to build against static dependencies. default: true'
|
||||||
|
)
|
||||||
|
|
||||||
|
option(
|
||||||
|
'tr_version',
|
||||||
|
type: 'integer',
|
||||||
|
min: 1,
|
||||||
|
max: 2,
|
||||||
|
description: 'Which engine version to compile for'
|
||||||
|
)
|
||||||
|
|
||||||
|
option(
|
||||||
|
'gfx_gl_default_backend',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Which OpenGL version to target'
|
||||||
|
)
|
320
src/tr1/meson.build
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
project(
|
||||||
|
'TR1X',
|
||||||
|
'c',
|
||||||
|
default_options: [
|
||||||
|
'c_std=c2x',
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
gfx_gl_default_backend = 'GFX_GL_33C'
|
||||||
|
else
|
||||||
|
gfx_gl_default_backend = 'GFX_GL_21'
|
||||||
|
endif
|
||||||
|
|
||||||
|
trx = subproject('libtrx', default_options: {
|
||||||
|
'tr_version': '1',
|
||||||
|
'gfx_gl_default_backend': gfx_gl_default_backend,
|
||||||
|
})
|
||||||
|
c_compiler = meson.get_compiler('c')
|
||||||
|
|
||||||
|
fs = import('fs')
|
||||||
|
relative_dir = fs.relative_to(meson.current_source_dir(), meson.global_build_root())
|
||||||
|
build_opts = [
|
||||||
|
'-Wno-unused',
|
||||||
|
'-DMESON_BUILD',
|
||||||
|
'-DTR_VERSION=1',
|
||||||
|
'-fno-omit-frame-pointer',
|
||||||
|
'-ffile-prefix-map=@0@/='.format(relative_dir),
|
||||||
|
] + trx.get_variable('defines')
|
||||||
|
|
||||||
|
add_project_arguments(build_opts, language: 'c')
|
||||||
|
|
||||||
|
staticdeps = get_option('staticdeps')
|
||||||
|
|
||||||
|
# Always dynamically link on macOS
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
staticdeps = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
null_dep = dependency('', required: false)
|
||||||
|
|
||||||
|
dep_trx = trx.get_variable('dep_trx')
|
||||||
|
dep_avcodec = dependency('libavcodec', static: staticdeps)
|
||||||
|
dep_avformat = dependency('libavformat', static: staticdeps)
|
||||||
|
dep_avutil = dependency('libavutil', static: staticdeps)
|
||||||
|
dep_mathlibrary = c_compiler.find_library('m', static: staticdeps, required : false)
|
||||||
|
dep_swscale = dependency('libswscale', static: staticdeps)
|
||||||
|
dep_swresample = dependency('libswresample', static: staticdeps)
|
||||||
|
dep_sdl2 = dependency('SDL2', static: staticdeps)
|
||||||
|
dep_zlib = null_dep
|
||||||
|
|
||||||
|
if not staticdeps
|
||||||
|
dep_zlib = dependency('zlib', static: staticdeps)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# autogenerated files
|
||||||
|
resources = []
|
||||||
|
python3 = find_program('python3', required: true)
|
||||||
|
git = find_program('git', required: true)
|
||||||
|
|
||||||
|
init = custom_target(
|
||||||
|
'fake_init',
|
||||||
|
output: ['init.c'],
|
||||||
|
command: [python3, meson.source_root() + '/../../tools/tr1/generate_init', '-o', meson.current_build_dir() / '@OUTPUT0@'],
|
||||||
|
build_always_stale: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
version_rc = custom_target(
|
||||||
|
'fake_version',
|
||||||
|
output: ['version.rc'],
|
||||||
|
command: [python3, meson.source_root() + '/../../tools/tr1/generate_rcfile', '-o', '@OUTPUT0@'],
|
||||||
|
build_always_stale: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
icon_rc = custom_target(
|
||||||
|
'fake_icon',
|
||||||
|
output: ['icon.rc'],
|
||||||
|
command: [python3, meson.source_root() + '/../../tools/tr1/generate_rcfile', '-o', '@OUTPUT0@'],
|
||||||
|
)
|
||||||
|
|
||||||
|
link_args = []
|
||||||
|
|
||||||
|
if host_machine.system() == 'windows'
|
||||||
|
windows = import('windows')
|
||||||
|
|
||||||
|
resources = [
|
||||||
|
windows.compile_resources(version_rc),
|
||||||
|
windows.compile_resources(icon_rc),
|
||||||
|
]
|
||||||
|
|
||||||
|
link_args += ['-static']
|
||||||
|
endif
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
init,
|
||||||
|
'config.c',
|
||||||
|
'config_map.c',
|
||||||
|
'game/anim.c',
|
||||||
|
'game/backpack.c',
|
||||||
|
'game/box.c',
|
||||||
|
'game/camera.c',
|
||||||
|
'game/carrier.c',
|
||||||
|
'game/clock.c',
|
||||||
|
'game/collide.c',
|
||||||
|
'game/console/cmd/easy_config.c',
|
||||||
|
'game/console/cmd/speed.c',
|
||||||
|
'game/console/common.c',
|
||||||
|
'game/console/setup.c',
|
||||||
|
'game/creature.c',
|
||||||
|
'game/effect_routines/bubbles.c',
|
||||||
|
'game/effect_routines/chain_block.c',
|
||||||
|
'game/effect_routines/dino_stomp.c',
|
||||||
|
'game/effect_routines/earthquake.c',
|
||||||
|
'game/ui/common.c',
|
||||||
|
'game/ui/widgets/label.c',
|
||||||
|
'game/ui/widgets/prompt.c',
|
||||||
|
'game/ui/widgets/window.c',
|
||||||
|
'game/effect_routines/explosion.c',
|
||||||
|
'game/effect_routines/finish_level.c',
|
||||||
|
'game/effect_routines/flicker.c',
|
||||||
|
'game/effect_routines/flipmap.c',
|
||||||
|
'game/effect_routines/flood.c',
|
||||||
|
'game/effect_routines/lara_effects.c',
|
||||||
|
'game/effect_routines/powerup.c',
|
||||||
|
'game/effect_routines/raising_block.c',
|
||||||
|
'game/effect_routines/sand.c',
|
||||||
|
'game/effect_routines/stairs2slope.c',
|
||||||
|
'game/effect_routines/turn_180.c',
|
||||||
|
'game/effects.c',
|
||||||
|
'game/effects/blood.c',
|
||||||
|
'game/effects/exploding_death.c',
|
||||||
|
'game/effects/gun.c',
|
||||||
|
'game/effects/gunshot.c',
|
||||||
|
'game/fmv.c',
|
||||||
|
'game/game/game.c',
|
||||||
|
'game/game/game_draw.c',
|
||||||
|
'game/game/game_main_menu.c',
|
||||||
|
'game/game_string.c',
|
||||||
|
'game/gamebuf.c',
|
||||||
|
'game/gameflow.c',
|
||||||
|
'game/gun/gun.c',
|
||||||
|
'game/gun/gun_misc.c',
|
||||||
|
'game/gun/gun_pistols.c',
|
||||||
|
'game/gun/gun_rifle.c',
|
||||||
|
'game/inject.c',
|
||||||
|
'game/input.c',
|
||||||
|
'game/interpolation.c',
|
||||||
|
'game/inventory/inventory.c',
|
||||||
|
'game/inventory/inventory_func.c',
|
||||||
|
'game/inventory/inventory_ring.c',
|
||||||
|
'game/inventory/inventory_vars.c',
|
||||||
|
'game/items.c',
|
||||||
|
'game/lara/cheat.c',
|
||||||
|
'game/lara/col.c',
|
||||||
|
'game/lara/common.c',
|
||||||
|
'game/lara/control.c',
|
||||||
|
'game/lara/draw.c',
|
||||||
|
'game/lara/hair.c',
|
||||||
|
'game/lara/look.c',
|
||||||
|
'game/lara/misc.c',
|
||||||
|
'game/lara/state.c',
|
||||||
|
'game/level.c',
|
||||||
|
'game/los.c',
|
||||||
|
'game/lot.c',
|
||||||
|
'game/music.c',
|
||||||
|
'game/objects/common.c',
|
||||||
|
'game/objects/creatures/ape.c',
|
||||||
|
'game/objects/creatures/bacon_lara.c',
|
||||||
|
'game/objects/creatures/baldy.c',
|
||||||
|
'game/objects/creatures/bat.c',
|
||||||
|
'game/objects/creatures/bear.c',
|
||||||
|
'game/objects/creatures/centaur.c',
|
||||||
|
'game/objects/creatures/cowboy.c',
|
||||||
|
'game/objects/creatures/crocodile.c',
|
||||||
|
'game/objects/creatures/cutscene_player.c',
|
||||||
|
'game/objects/creatures/larson.c',
|
||||||
|
'game/objects/creatures/lion.c',
|
||||||
|
'game/objects/creatures/mummy.c',
|
||||||
|
'game/objects/creatures/mutant.c',
|
||||||
|
'game/objects/creatures/natla.c',
|
||||||
|
'game/objects/creatures/pierre.c',
|
||||||
|
'game/objects/creatures/pod.c',
|
||||||
|
'game/objects/creatures/raptor.c',
|
||||||
|
'game/objects/creatures/rat.c',
|
||||||
|
'game/objects/creatures/skate_kid.c',
|
||||||
|
'game/objects/creatures/statue.c',
|
||||||
|
'game/objects/creatures/torso.c',
|
||||||
|
'game/objects/creatures/trex.c',
|
||||||
|
'game/objects/creatures/wolf.c',
|
||||||
|
'game/objects/effects/blood.c',
|
||||||
|
'game/objects/effects/body_part.c',
|
||||||
|
'game/objects/effects/bubble.c',
|
||||||
|
'game/objects/effects/dart_effect.c',
|
||||||
|
'game/objects/effects/ember.c',
|
||||||
|
'game/objects/effects/explosion.c',
|
||||||
|
'game/objects/effects/flame.c',
|
||||||
|
'game/objects/effects/gunshot.c',
|
||||||
|
'game/objects/effects/missile.c',
|
||||||
|
'game/objects/effects/natla_gun.c',
|
||||||
|
'game/objects/effects/ricochet.c',
|
||||||
|
'game/objects/effects/splash.c',
|
||||||
|
'game/objects/effects/twinkle.c',
|
||||||
|
'game/objects/general/boat.c',
|
||||||
|
'game/objects/general/bridge_common.c',
|
||||||
|
'game/objects/general/bridge_flat.c',
|
||||||
|
'game/objects/general/bridge_tilt1.c',
|
||||||
|
'game/objects/general/bridge_tilt2.c',
|
||||||
|
'game/objects/general/cabin.c',
|
||||||
|
'game/objects/general/camera_target.c',
|
||||||
|
'game/objects/general/cog.c',
|
||||||
|
'game/objects/general/door.c',
|
||||||
|
'game/objects/general/drawbridge.c',
|
||||||
|
'game/objects/general/earthquake.c',
|
||||||
|
'game/objects/general/keyhole.c',
|
||||||
|
'game/objects/general/moving_bar.c',
|
||||||
|
'game/objects/general/pickup.c',
|
||||||
|
'game/objects/general/puzzle_hole.c',
|
||||||
|
'game/objects/general/save_crystal.c',
|
||||||
|
'game/objects/general/scion1.c',
|
||||||
|
'game/objects/general/scion2.c',
|
||||||
|
'game/objects/general/scion3.c',
|
||||||
|
'game/objects/general/scion4.c',
|
||||||
|
'game/objects/general/scion_holder.c',
|
||||||
|
'game/objects/general/switch.c',
|
||||||
|
'game/objects/general/trapdoor.c',
|
||||||
|
'game/objects/general/waterfall.c',
|
||||||
|
'game/objects/setup.c',
|
||||||
|
'game/objects/traps/damocles_sword.c',
|
||||||
|
'game/objects/traps/dart.c',
|
||||||
|
'game/objects/traps/dart_emitter.c',
|
||||||
|
'game/objects/traps/ember_emitter.c',
|
||||||
|
'game/objects/traps/falling_block.c',
|
||||||
|
'game/objects/traps/falling_ceiling.c',
|
||||||
|
'game/objects/traps/flame_emitter.c',
|
||||||
|
'game/objects/traps/lava_wedge.c',
|
||||||
|
'game/objects/traps/lightning_emitter.c',
|
||||||
|
'game/objects/traps/midas_touch.c',
|
||||||
|
'game/objects/traps/movable_block.c',
|
||||||
|
'game/objects/traps/pendulum.c',
|
||||||
|
'game/objects/traps/rolling_ball.c',
|
||||||
|
'game/objects/traps/sliding_pillar.c',
|
||||||
|
'game/objects/traps/spikes.c',
|
||||||
|
'game/objects/traps/teeth_trap.c',
|
||||||
|
'game/objects/traps/thors_hammer_handle.c',
|
||||||
|
'game/objects/traps/thors_hammer_head.c',
|
||||||
|
'game/objects/vars.c',
|
||||||
|
'game/option/option.c',
|
||||||
|
'game/option/option_compass.c',
|
||||||
|
'game/option/option_control.c',
|
||||||
|
'game/option/option_control_pick.c',
|
||||||
|
'game/option/option_graphics.c',
|
||||||
|
'game/option/option_passport.c',
|
||||||
|
'game/option/option_sound.c',
|
||||||
|
'game/output.c',
|
||||||
|
'game/overlay.c',
|
||||||
|
'game/packer.c',
|
||||||
|
'game/phase/phase.c',
|
||||||
|
'game/phase/phase_cutscene.c',
|
||||||
|
'game/phase/phase_demo.c',
|
||||||
|
'game/phase/phase_game.c',
|
||||||
|
'game/phase/phase_inventory.c',
|
||||||
|
'game/phase/phase_pause.c',
|
||||||
|
'game/phase/phase_picture.c',
|
||||||
|
'game/phase/phase_stats.c',
|
||||||
|
'game/random.c',
|
||||||
|
'game/requester.c',
|
||||||
|
'game/room.c',
|
||||||
|
'game/room_draw.c',
|
||||||
|
'game/savegame/savegame.c',
|
||||||
|
'game/savegame/savegame_bson.c',
|
||||||
|
'game/savegame/savegame_legacy.c',
|
||||||
|
'game/screen.c',
|
||||||
|
'game/shell.c',
|
||||||
|
'game/sound.c',
|
||||||
|
'game/stats.c',
|
||||||
|
'game/text.c',
|
||||||
|
'game/viewport.c',
|
||||||
|
'global/enum_map.c',
|
||||||
|
'global/vars.c',
|
||||||
|
'math/math.c',
|
||||||
|
'math/math_misc.c',
|
||||||
|
'math/matrix.c',
|
||||||
|
'specific/s_clock.c',
|
||||||
|
'specific/s_fmv.c',
|
||||||
|
'specific/s_input.c',
|
||||||
|
'specific/s_output.c',
|
||||||
|
'specific/s_shell.c',
|
||||||
|
resources,
|
||||||
|
]
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
dep_trx,
|
||||||
|
dep_avcodec,
|
||||||
|
dep_avformat,
|
||||||
|
dep_avutil,
|
||||||
|
dep_mathlibrary,
|
||||||
|
dep_sdl2,
|
||||||
|
dep_swresample,
|
||||||
|
dep_swscale,
|
||||||
|
dep_zlib,
|
||||||
|
]
|
||||||
|
|
||||||
|
executable(
|
||||||
|
'TR1X',
|
||||||
|
sources,
|
||||||
|
dependencies: dependencies,
|
||||||
|
link_args: link_args,
|
||||||
|
gui_app: true,
|
||||||
|
install: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
install_subdir('../../data/ship/cfg', install_dir : 'Contents/Resources')
|
||||||
|
install_subdir('../../data/ship/data', install_dir : 'Contents/Resources')
|
||||||
|
install_subdir('../../data/ship/shaders', install_dir : 'Contents/Resources')
|
||||||
|
install_data('../../data/tr1/mac/icon.icns', install_dir : 'Contents/Resources')
|
||||||
|
install_data('../../data/tr1/mac/Info.plist', install_dir : 'Contents')
|
||||||
|
meson.add_install_script('../../tools/tr1/mac/bundle_dylibs')
|
||||||
|
endif
|
203
src/tr2/meson.build
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
project('TR2X', ['c'],
|
||||||
|
default_options: [
|
||||||
|
'c_std=c17',
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
if host_machine.system() == 'darwin'
|
||||||
|
gfx_gl_default_backend = 'GFX_GL_33C'
|
||||||
|
else
|
||||||
|
gfx_gl_default_backend = 'GFX_GL_21'
|
||||||
|
endif
|
||||||
|
|
||||||
|
trx = subproject('libtrx', default_options: {
|
||||||
|
'tr_version': '2',
|
||||||
|
'gfx_gl_default_backend': gfx_gl_default_backend,
|
||||||
|
})
|
||||||
|
c_compiler = meson.get_compiler('c')
|
||||||
|
|
||||||
|
fs = import('fs')
|
||||||
|
relative_dir = fs.relative_to(meson.current_source_dir(), meson.global_build_root())
|
||||||
|
build_opts = [
|
||||||
|
'-Wno-unused',
|
||||||
|
'-Wno-address-of-packed-member',
|
||||||
|
'-DMESON_BUILD',
|
||||||
|
'-fno-omit-frame-pointer',
|
||||||
|
'-ffile-prefix-map=@0@/='.format(relative_dir),
|
||||||
|
] + trx.get_variable('defines')
|
||||||
|
|
||||||
|
add_project_arguments(build_opts, language: 'c')
|
||||||
|
|
||||||
|
staticdeps = get_option('staticdeps')
|
||||||
|
|
||||||
|
null_dep = dependency('', required: false)
|
||||||
|
dep_trx = trx.get_variable('dep_trx')
|
||||||
|
dep_sdl2 = dependency('SDL2', static: staticdeps)
|
||||||
|
dep_mathlibrary = c_compiler.find_library('m', static: staticdeps, required : false)
|
||||||
|
|
||||||
|
# autogenerated files
|
||||||
|
exe_resources = []
|
||||||
|
dll_resources = []
|
||||||
|
python3 = find_program('python3', required: true)
|
||||||
|
git = find_program('git', required: true)
|
||||||
|
|
||||||
|
init = custom_target(
|
||||||
|
'fake_init',
|
||||||
|
output: ['init.c'],
|
||||||
|
command: [python3, meson.source_root() + '/../../tools/tr2/generate_init', '-o', meson.current_build_dir() / '@OUTPUT0@'],
|
||||||
|
build_always_stale: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
version_rc = custom_target(
|
||||||
|
'fake_version',
|
||||||
|
output: ['version.rc'],
|
||||||
|
command: [python3, meson.source_root() + '/../../tools/tr2/generate_rcfile', '-o', '@OUTPUT0@'],
|
||||||
|
build_always_stale: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
icon_rc = custom_target(
|
||||||
|
'fake_icon',
|
||||||
|
output: ['icon.rc'],
|
||||||
|
command: [python3, meson.source_root() + '/../../tools/tr2/generate_rcfile', '-o', '@OUTPUT0@'],
|
||||||
|
)
|
||||||
|
|
||||||
|
link_args = []
|
||||||
|
|
||||||
|
if host_machine.system() == 'windows'
|
||||||
|
windows = import('windows')
|
||||||
|
|
||||||
|
version_resource = windows.compile_resources(version_rc)
|
||||||
|
icon_resource = windows.compile_resources(icon_rc)
|
||||||
|
exe_resources = [version_resource, icon_resource]
|
||||||
|
dll_resources = [version_resource]
|
||||||
|
|
||||||
|
link_args += ['-static']
|
||||||
|
endif
|
||||||
|
|
||||||
|
exe_sources = [
|
||||||
|
'main_exe.c',
|
||||||
|
exe_resources,
|
||||||
|
]
|
||||||
|
|
||||||
|
dll_sources = [
|
||||||
|
init,
|
||||||
|
'config.c',
|
||||||
|
'config_map.c',
|
||||||
|
'decomp/decomp.c',
|
||||||
|
'decomp/effects.c',
|
||||||
|
'decomp/stats.c',
|
||||||
|
'game/background.c',
|
||||||
|
'game/backpack.c',
|
||||||
|
'game/box.c',
|
||||||
|
'game/camera.c',
|
||||||
|
'game/clock.c',
|
||||||
|
'game/collide.c',
|
||||||
|
'game/console/common.c',
|
||||||
|
'game/console/setup.c',
|
||||||
|
'game/creature.c',
|
||||||
|
'game/demo.c',
|
||||||
|
'game/effects.c',
|
||||||
|
'game/game.c',
|
||||||
|
'game/game_string.c',
|
||||||
|
'game/gameflow.c',
|
||||||
|
'game/gameflow/gameflow_new.c',
|
||||||
|
'game/gameflow/reader.c',
|
||||||
|
'game/gun/gun.c',
|
||||||
|
'game/gun/gun_misc.c',
|
||||||
|
'game/gun/gun_pistols.c',
|
||||||
|
'game/gun/gun_rifle.c',
|
||||||
|
'game/hwr.c',
|
||||||
|
'game/input.c',
|
||||||
|
'game/inventory/backpack.c',
|
||||||
|
'game/inventory/common.c',
|
||||||
|
'game/inventory/ring.c',
|
||||||
|
'game/inventory/vars.c',
|
||||||
|
'game/items.c',
|
||||||
|
'game/lara/cheat.c',
|
||||||
|
'game/lara/col.c',
|
||||||
|
'game/lara/common.c',
|
||||||
|
'game/lara/control.c',
|
||||||
|
'game/lara/draw.c',
|
||||||
|
'game/lara/look.c',
|
||||||
|
'game/lara/misc.c',
|
||||||
|
'game/lara/state.c',
|
||||||
|
'game/level.c',
|
||||||
|
'game/los.c',
|
||||||
|
'game/lot.c',
|
||||||
|
'game/math.c',
|
||||||
|
'game/math_misc.c',
|
||||||
|
'game/matrix.c',
|
||||||
|
'game/music/music_backend_cdaudio.c',
|
||||||
|
'game/music/music_backend_files.c',
|
||||||
|
'game/music/music_main.c',
|
||||||
|
'game/objects/common.c',
|
||||||
|
'game/objects/creatures/bird.c',
|
||||||
|
'game/objects/creatures/diver.c',
|
||||||
|
'game/objects/effects/ember.c',
|
||||||
|
'game/objects/effects/flame.c',
|
||||||
|
'game/objects/general/body_part.c',
|
||||||
|
'game/objects/general/door.c',
|
||||||
|
'game/objects/general/final_level_counter.c',
|
||||||
|
'game/objects/traps/ember_emitter.c',
|
||||||
|
'game/objects/traps/flame_emitter.c',
|
||||||
|
'game/objects/vars.c',
|
||||||
|
'game/objects/vehicles/boat.c',
|
||||||
|
'game/option/option.c',
|
||||||
|
'game/option/option_compass.c',
|
||||||
|
'game/option/option_controls.c',
|
||||||
|
'game/option/option_detail.c',
|
||||||
|
'game/option/option_passport.c',
|
||||||
|
'game/option/option_sound.c',
|
||||||
|
'game/output.c',
|
||||||
|
'game/overlay.c',
|
||||||
|
'game/random.c',
|
||||||
|
'game/requester.c',
|
||||||
|
'game/room.c',
|
||||||
|
'game/room_draw.c',
|
||||||
|
'game/savegame/common.c',
|
||||||
|
'game/shell.c',
|
||||||
|
'game/sound.c',
|
||||||
|
'game/text.c',
|
||||||
|
'game/ui/common.c',
|
||||||
|
'game/ui/controllers/controls.c',
|
||||||
|
'game/ui/widgets/controls_column.c',
|
||||||
|
'game/ui/widgets/controls_dialog.c',
|
||||||
|
'game/ui/widgets/controls_input_selector.c',
|
||||||
|
'game/ui/widgets/controls_layout_selector.c',
|
||||||
|
'game/ui/widgets/label.c',
|
||||||
|
'game/ui/widgets/prompt.c',
|
||||||
|
'game/ui/widgets/window.c',
|
||||||
|
'global/enum_map.c',
|
||||||
|
'global/vars.c',
|
||||||
|
'inject_exec.c',
|
||||||
|
'inject_util.c',
|
||||||
|
'lib/winmm.c',
|
||||||
|
'main_dll.c',
|
||||||
|
'specific/s_audio_sample.c',
|
||||||
|
'specific/s_flagged_string.c',
|
||||||
|
'specific/s_input.c',
|
||||||
|
dll_resources,
|
||||||
|
]
|
||||||
|
|
||||||
|
dll_dependencies = [
|
||||||
|
dep_trx,
|
||||||
|
dep_sdl2,
|
||||||
|
dep_mathlibrary,
|
||||||
|
]
|
||||||
|
|
||||||
|
executable(
|
||||||
|
'TR2X',
|
||||||
|
exe_sources,
|
||||||
|
name_prefix: '',
|
||||||
|
link_args: link_args,
|
||||||
|
gui_app: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
library(
|
||||||
|
'TR2X',
|
||||||
|
dll_sources,
|
||||||
|
name_prefix: '',
|
||||||
|
dependencies: dll_dependencies,
|
||||||
|
link_args: link_args,
|
||||||
|
)
|
1
src/tr2/subprojects/libtrx
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../libtrx
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit ee2f6107f96c31607d2347e24f6813792c39707f
|
|
|
@ -1,5 +1,73 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from libtrx.cli.additional_lint import run_script
|
import argparse
|
||||||
from tr1x.paths import TR1X_REPO_DIR
|
import sys
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from fnmatch import fnmatch
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
run_script(root_dir=TR1X_REPO_DIR, ignored_patterns=["*.patch", "*.bin"])
|
from shared.files import find_versioned_files, is_binary_file
|
||||||
|
from shared.linting import LintContext, lint_bulk_files, lint_file
|
||||||
|
from shared.paths import SRC_DIR
|
||||||
|
|
||||||
|
IGNORED_PATTERNS = ["*.patch", "*.bin", "gl_core_3_3.h"]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("path", type=Path, nargs="*")
|
||||||
|
parser.add_argument("-D", "--debug", action="store_true")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def filter_files(
|
||||||
|
files: Iterable[Path], ignored_patterns: list[str] | None, debug: bool
|
||||||
|
) -> Iterable[Path]:
|
||||||
|
for path in files:
|
||||||
|
if is_binary_file(path):
|
||||||
|
if debug:
|
||||||
|
print(f"{path} is a binary file, ignoring", file=sys.stderr)
|
||||||
|
continue
|
||||||
|
if ignored_patterns and any(
|
||||||
|
fnmatch(path.name, pattern) for pattern in ignored_patterns
|
||||||
|
):
|
||||||
|
if debug:
|
||||||
|
print(
|
||||||
|
f"{path} has a prohibited extension, ignoring",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
def main(root_dir: Path, ignored_patterns: list[str] | None = None) -> None:
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
context = LintContext(
|
||||||
|
root_dir=SRC_DIR,
|
||||||
|
versioned_files=find_versioned_files(root_dir=SRC_DIR),
|
||||||
|
)
|
||||||
|
if args.path:
|
||||||
|
files = args.path
|
||||||
|
else:
|
||||||
|
files = context.versioned_files
|
||||||
|
files = list(
|
||||||
|
filter_files(
|
||||||
|
files, ignored_patterns=IGNORED_PATTERNS, debug=args.debug
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
exit_code = 0
|
||||||
|
for file in files:
|
||||||
|
if args.debug:
|
||||||
|
print(f"Checking {file}...", file=sys.stderr)
|
||||||
|
for lint_warning in lint_file(context, file):
|
||||||
|
print(str(lint_warning), file=sys.stderr)
|
||||||
|
exit_code = 1
|
||||||
|
|
||||||
|
if args.debug:
|
||||||
|
print(f"Checking files in bulk {file}...", file=sys.stderr)
|
||||||
|
for lint_warning in lint_bulk_files(context, files):
|
||||||
|
print(str(lint_warning), file=sys.stderr)
|
||||||
|
exit_code = 1
|
||||||
|
|
||||||
|
exit(exit_code)
|
||||||
|
|
|
@ -3,22 +3,27 @@ import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pyjson5
|
import pyjson5
|
||||||
from tr1x.paths import TR1X_TOOLS_DIR
|
from shared.paths import PROJECT_PATHS
|
||||||
|
|
||||||
CONFIG_TOOL_SPEC_PATH = (
|
|
||||||
TR1X_TOOLS_DIR / "config/TR1X_ConfigTool/Resources/specification.json"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args() -> argparse.Namespace:
|
def parse_args() -> argparse.Namespace:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description=(
|
description=(
|
||||||
"Compares a given TR1X.json5 file with the default specifications "
|
"Compares a given configuration file with the default specifications "
|
||||||
"of the config tool to find changes in the default values"
|
"of the config tool to find changes in the default values"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"path", type=Path, help="path to the freshly written TR1X.json5"
|
"-v",
|
||||||
|
"--version",
|
||||||
|
type=int,
|
||||||
|
help="game version to check the configuration file for",
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"path",
|
||||||
|
type=Path,
|
||||||
|
help="path to the freshly written configuration file",
|
||||||
)
|
)
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
@ -26,7 +31,11 @@ def parse_args() -> argparse.Namespace:
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
game_config = pyjson5.loads(args.path.read_text())
|
game_config = pyjson5.loads(args.path.read_text())
|
||||||
tool_spec = pyjson5.loads(CONFIG_TOOL_SPEC_PATH.read_text())
|
tool_spec_path = (
|
||||||
|
PROJECT_PATHS[args.version].tools_dir
|
||||||
|
/ "config/TR1X_ConfigTool/Resources/specification.json"
|
||||||
|
)
|
||||||
|
tool_spec = pyjson5.loads(tool_spec_path.read_text())
|
||||||
|
|
||||||
spec_map = {
|
spec_map = {
|
||||||
option["Field"]: option["DefaultValue"]
|
option["Field"]: option["DefaultValue"]
|
||||||
|
|
24
tools/generate_icon
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# regenerate the .ICO file from .PSD.
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from shared.icons import generate_icon
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("path", type=Path)
|
||||||
|
parser.add_argument("-o", "--output", type=Path, required=True)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
if args.output.exists():
|
||||||
|
args.output.unlink()
|
||||||
|
generate_icon(args.path, args.output)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -3,10 +3,11 @@ import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from subprocess import check_call
|
from subprocess import check_call
|
||||||
|
|
||||||
from tr1x.paths import TR1X_DATA_DIR
|
from shared.paths import TR1Paths
|
||||||
|
|
||||||
SOURCE_DIR = TR1X_DATA_DIR / "images"
|
SOURCE_DIR = TR1Paths.data_dir / "images"
|
||||||
TARGET_DIR = TR1X_DATA_DIR / "ship/data/images"
|
TARGET_DIR = TR1Paths.shipped_data_dir / "data/images"
|
||||||
|
print(SOURCE_DIR)
|
||||||
|
|
||||||
|
|
||||||
def format_size(size: int) -> str:
|
def format_size(size: int) -> str:
|
||||||
|
|
|
@ -1,4 +1,19 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from libtrx.versioning import generate_version
|
import argparse
|
||||||
|
|
||||||
print(generate_version(), end="")
|
from shared.versioning import generate_version
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("version", choices=[1, 2], type=int)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
print(generate_version(args.version), end="")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../subprojects/libtrx/tools/libtrx
|
|
|
@ -1,5 +1,43 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from libtrx.changelog import get_current_version_changelog
|
import argparse
|
||||||
from tr1x.paths import TR1X_REPO_DIR
|
|
||||||
|
|
||||||
print(get_current_version_changelog(TR1X_REPO_DIR / "CHANGELOG.md"))
|
from shared.git import Git
|
||||||
|
from shared.versioning import generate_version
|
||||||
|
from shared.changelog import get_current_version_changelog
|
||||||
|
from shared.paths import PROJECT_PATHS
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("version", choices=['1', '2', 'all'])
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
commit_hash = Git().get_current_commit_hash()
|
||||||
|
|
||||||
|
if args.version == 'all':
|
||||||
|
print(f"**Commit: {commit_hash}** ")
|
||||||
|
print()
|
||||||
|
for version, project_paths in PROJECT_PATHS.items():
|
||||||
|
commit_tag = generate_version(version)
|
||||||
|
print(f'### TR{version}X changes')
|
||||||
|
print()
|
||||||
|
print(f'**Tag: {commit_tag}**')
|
||||||
|
print()
|
||||||
|
print(get_current_version_changelog(project_paths.changelog_path))
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
project_paths = PROJECT_PATHS.get(int(args.version))
|
||||||
|
commit_tag = generate_version(int(args.version))
|
||||||
|
print(f"**Commit: {commit_hash}** ")
|
||||||
|
print(f"**Tag: {commit_tag}**")
|
||||||
|
print()
|
||||||
|
print("### Changes")
|
||||||
|
print(get_current_version_changelog(project_paths.changelog_path))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
30
tools/output_release_name
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from shared.versioning import generate_version
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("game_version", choices=["1", "2", "all"])
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def get_release_name(game_version: str) -> str:
|
||||||
|
match str(game_version):
|
||||||
|
case "1":
|
||||||
|
return f"TR1X {generate_version(1)}"
|
||||||
|
case "2":
|
||||||
|
return f"TR2X {generate_version(2)}"
|
||||||
|
case "all":
|
||||||
|
return "Development snapshot"
|
||||||
|
return "Unknown release name"
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
print(get_release_name(args.game_version))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
138
tools/release
Executable file
|
@ -0,0 +1,138 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from shared.changelog import update_changelog_to_new_version
|
||||||
|
from shared.git import Git
|
||||||
|
from shared.paths import PROJECT_PATHS
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Options:
|
||||||
|
stable_branch: str = "stable"
|
||||||
|
develop_branch: str = "develop"
|
||||||
|
|
||||||
|
|
||||||
|
class BaseCommand:
|
||||||
|
name: str = NotImplemented
|
||||||
|
help: str = NotImplemented
|
||||||
|
|
||||||
|
def __init__(self, git: Git) -> None:
|
||||||
|
self.git = git
|
||||||
|
|
||||||
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
||||||
|
parser.add_argument("game_version", choices=[1, 2], type=int)
|
||||||
|
parser.add_argument("version")
|
||||||
|
|
||||||
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
||||||
|
raise NotImplementedError("not implemented")
|
||||||
|
|
||||||
|
|
||||||
|
class CommitCommand(BaseCommand):
|
||||||
|
name = "commit"
|
||||||
|
help = "Create and tag a commit with the release information"
|
||||||
|
|
||||||
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
||||||
|
super().decorate_parser(parser)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--dry-run",
|
||||||
|
action="store_true",
|
||||||
|
help="only output the changelog to stdout, do not commit anything",
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
||||||
|
# self.git.checkout_branch("develop")
|
||||||
|
old_tag = self.git.get_branch_version("origin/stable")
|
||||||
|
new_tag = f"tr{args.game_version}-{args.version}"
|
||||||
|
|
||||||
|
changelog_path = PROJECT_PATHS[args.game_version].changelog_path
|
||||||
|
old_changelog = changelog_path.read_text()
|
||||||
|
new_changelog = update_changelog_to_new_version(
|
||||||
|
old_changelog,
|
||||||
|
old_tag=old_tag,
|
||||||
|
new_tag=new_tag,
|
||||||
|
new_version_name=args.version,
|
||||||
|
stable_branch=options.stable_branch,
|
||||||
|
develop_branch=options.develop_branch,
|
||||||
|
)
|
||||||
|
if old_changelog == new_changelog:
|
||||||
|
return
|
||||||
|
|
||||||
|
if args.dry_run:
|
||||||
|
print(new_changelog, end="")
|
||||||
|
return
|
||||||
|
|
||||||
|
changelog_path.write_text(new_changelog)
|
||||||
|
self.git.add(changelog_path)
|
||||||
|
self.git.commit(f"docs/tr{args.game_version}: release {args.version}")
|
||||||
|
self.git.delete_tag(new_tag)
|
||||||
|
self.git.create_tag(new_tag)
|
||||||
|
|
||||||
|
|
||||||
|
class BranchCommand(BaseCommand):
|
||||||
|
name = "branch"
|
||||||
|
help = "Merge branch to the specified tag"
|
||||||
|
|
||||||
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
||||||
|
new_tag = f"tr{args.game_version}-{args.version}"
|
||||||
|
self.git.checkout_branch("stable")
|
||||||
|
self.git.reset(new_tag, hard=True)
|
||||||
|
self.git.checkout_branch("develop")
|
||||||
|
|
||||||
|
|
||||||
|
class PushCommand(BaseCommand):
|
||||||
|
name = "push"
|
||||||
|
help = (
|
||||||
|
"Push the develop and stable branches, and the version tag to GitHub"
|
||||||
|
)
|
||||||
|
|
||||||
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
||||||
|
super().decorate_parser(parser)
|
||||||
|
parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--force",
|
||||||
|
action="store_true",
|
||||||
|
help="force push all targets",
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
||||||
|
new_tag = f"tr{args.game_version}-{args.version}"
|
||||||
|
self.git.push(
|
||||||
|
"origin",
|
||||||
|
["develop", "stable", new_tag],
|
||||||
|
force=args.force,
|
||||||
|
force_with_lease=not args.force,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args(commands: list[BaseCommand]) -> None:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Argument parser with subcommands"
|
||||||
|
)
|
||||||
|
subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
|
||||||
|
for command in commands:
|
||||||
|
subparser = subparsers.add_parser(command.name, help=command.help)
|
||||||
|
command.decorate_parser(subparser)
|
||||||
|
subparser.set_defaults(command=command)
|
||||||
|
|
||||||
|
result = parser.parse_args()
|
||||||
|
if not hasattr(result, "command"):
|
||||||
|
parser.error("missing command")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
git = Git()
|
||||||
|
commands = [
|
||||||
|
command_cls(git=git) for command_cls in BaseCommand.__subclasses__()
|
||||||
|
]
|
||||||
|
options = Options()
|
||||||
|
args = parse_args(commands)
|
||||||
|
args.command.run(args, options)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
39
tools/shared/changelog.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import re
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_version_changelog(changelog_path: Path) -> str:
|
||||||
|
sections = [
|
||||||
|
section
|
||||||
|
for section in changelog_path.read_text().split("\n\n")
|
||||||
|
if re.search(r"- \w", section)
|
||||||
|
]
|
||||||
|
if sections:
|
||||||
|
section = sections[0]
|
||||||
|
return "\n".join(
|
||||||
|
line for line in section.splitlines() if not line.startswith("#")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def update_changelog_to_new_version(
|
||||||
|
changelog: str,
|
||||||
|
old_tag: str,
|
||||||
|
new_tag: str,
|
||||||
|
new_version_name: str,
|
||||||
|
stable_branch: str | None = "stable",
|
||||||
|
develop_branch: str = "develop",
|
||||||
|
) -> str:
|
||||||
|
if f"[{new_version_name}]" in changelog:
|
||||||
|
return changelog
|
||||||
|
changelog = re.sub("Unreleased", new_version_name, changelog, count=1)
|
||||||
|
changelog = re.sub(stable_branch, old_tag, changelog, count=1)
|
||||||
|
changelog = re.sub(develop_branch, new_tag, changelog, count=1)
|
||||||
|
changelog = re.sub(
|
||||||
|
"××××-××-××", datetime.now().strftime("%Y-%m-%d"), changelog
|
||||||
|
)
|
||||||
|
changelog = (
|
||||||
|
f"## [Unreleased](https://github.com/LostArtefacts/TRX/compare/{stable_branch or new_tag}...{develop_branch}) - ××××-××-××\n\n"
|
||||||
|
+ changelog
|
||||||
|
)
|
||||||
|
return changelog
|
139
tools/shared/cli/game_docker_entrypoint.py
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import check_call, run
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from shared.packaging import create_zip
|
||||||
|
from shared.versioning import generate_version
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Options:
|
||||||
|
version: int
|
||||||
|
platform: str
|
||||||
|
compile_args: list[str]
|
||||||
|
release_zip_files: list[tuple[Path, str]]
|
||||||
|
strip_tool = "strip"
|
||||||
|
upx_tool = "upx"
|
||||||
|
target = os.environ.get("TARGET", "debug")
|
||||||
|
compressable_exes: list[Path] | None = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ship_dir(self) -> Path:
|
||||||
|
return Path(f"/app/data/tr{self.version}/ship/")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def build_root(self) -> Path:
|
||||||
|
return Path(f"/app/build/tr{self.version}/{self.platform}/")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def build_target(self) -> str:
|
||||||
|
return f"src/tr{self.version}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def release_zip_filename_fmt(self) -> str:
|
||||||
|
platform = self.platform
|
||||||
|
if platform == "win":
|
||||||
|
platform = "windows"
|
||||||
|
return f"TR{self.version}X-{{version}}-{platform.title()}.zip"
|
||||||
|
|
||||||
|
|
||||||
|
def compress_exe(options: Options, path: Path) -> None:
|
||||||
|
if run([options.upx_tool, "-t", str(path)]).returncode != 0:
|
||||||
|
check_call([options.strip_tool, str(path)])
|
||||||
|
check_call([options.upx_tool, str(path)])
|
||||||
|
|
||||||
|
|
||||||
|
class BaseCommand:
|
||||||
|
name: str = NotImplemented
|
||||||
|
help: str = NotImplemented
|
||||||
|
|
||||||
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self, args: argparse.Namespace) -> None:
|
||||||
|
raise NotImplementedError("not implemented")
|
||||||
|
|
||||||
|
|
||||||
|
class CompileCommand(BaseCommand):
|
||||||
|
name = "compile"
|
||||||
|
|
||||||
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
||||||
|
pkg_config_path = os.environ.get("PKG_CONFIG_PATH")
|
||||||
|
|
||||||
|
if not (options.build_root / "build.ninja").exists():
|
||||||
|
command = [
|
||||||
|
"meson",
|
||||||
|
"setup",
|
||||||
|
"--buildtype",
|
||||||
|
options.target,
|
||||||
|
*options.compile_args,
|
||||||
|
options.build_root,
|
||||||
|
options.build_target,
|
||||||
|
]
|
||||||
|
if pkg_config_path:
|
||||||
|
command.extend(["--pkg-config-path", pkg_config_path])
|
||||||
|
check_call(command)
|
||||||
|
|
||||||
|
check_call(["meson", "compile"], cwd=options.build_root)
|
||||||
|
|
||||||
|
if options.target == "release":
|
||||||
|
for exe_path in options.compressable_exes:
|
||||||
|
compress_exe(options, exe_path)
|
||||||
|
|
||||||
|
|
||||||
|
class PackageCommand(BaseCommand):
|
||||||
|
name = "package"
|
||||||
|
|
||||||
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
||||||
|
parser.add_argument("-o", "--output", type=Path)
|
||||||
|
|
||||||
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
||||||
|
if args.output:
|
||||||
|
zip_path = args.output
|
||||||
|
else:
|
||||||
|
zip_path = Path(
|
||||||
|
options.release_zip_filename_fmt.format(
|
||||||
|
version=generate_version(options.version)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
source_files = [
|
||||||
|
*[
|
||||||
|
(path, path.relative_to(options.ship_dir))
|
||||||
|
for path in options.ship_dir.rglob("*")
|
||||||
|
if path.is_file()
|
||||||
|
],
|
||||||
|
*options.release_zip_files,
|
||||||
|
]
|
||||||
|
|
||||||
|
create_zip(zip_path, source_files)
|
||||||
|
print(f"Created {zip_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args(commands: dict[str, BaseCommand]) -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="Docker entrypoint")
|
||||||
|
subparsers = parser.add_subparsers(dest="action", help="Subcommands")
|
||||||
|
parser.set_defaults(action="compile", command=commands["compile"])
|
||||||
|
|
||||||
|
for command in commands.values():
|
||||||
|
subparser = subparsers.add_parser(command.name, help=command.help)
|
||||||
|
command.decorate_parser(subparser)
|
||||||
|
subparser.set_defaults(command=command)
|
||||||
|
result = parser.parse_args()
|
||||||
|
# if not hasattr(result, "command"):
|
||||||
|
# args.action = "compile"
|
||||||
|
# args.command = CompileCommand
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def run_script(**kwargs: Any) -> None:
|
||||||
|
commands = {
|
||||||
|
command_cls.name: command_cls()
|
||||||
|
for command_cls in BaseCommand.__subclasses__()
|
||||||
|
}
|
||||||
|
args = parse_args(commands)
|
||||||
|
options = Options(**kwargs)
|
||||||
|
args.command.run(args, options)
|
53
tools/shared/files.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import re
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import check_output
|
||||||
|
|
||||||
|
|
||||||
|
def find_files(
|
||||||
|
root_dir: Path,
|
||||||
|
extensions: list[str] | None = None,
|
||||||
|
exception_patterns: list[re.Pattern[str]] | None = None,
|
||||||
|
) -> Iterable[Path]:
|
||||||
|
stack: list[Path] = [root_dir]
|
||||||
|
|
||||||
|
while stack:
|
||||||
|
parent_dir = stack.pop()
|
||||||
|
for path in parent_dir.iterdir():
|
||||||
|
rel_path = path.relative_to(root_dir)
|
||||||
|
if exception_patterns and any(
|
||||||
|
pattern.match(str(rel_path)) for pattern in exception_patterns
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if path.is_dir():
|
||||||
|
stack.append(path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not path.is_file():
|
||||||
|
continue
|
||||||
|
|
||||||
|
if extensions and path.suffix not in extensions:
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
def find_versioned_files(root_dir: Path | None = None) -> Iterable[Path]:
|
||||||
|
for line in check_output(
|
||||||
|
["git", "ls-files"], cwd=root_dir, text=True
|
||||||
|
).splitlines():
|
||||||
|
path = Path(line)
|
||||||
|
if not path.is_dir():
|
||||||
|
if root_dir:
|
||||||
|
yield root_dir / path
|
||||||
|
else:
|
||||||
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
def is_binary_file(path: Path) -> bool:
|
||||||
|
try:
|
||||||
|
path.read_text(encoding="utf-8")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return True
|
||||||
|
return False
|
77
tools/shared/git.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import check_output, run
|
||||||
|
|
||||||
|
|
||||||
|
class Git:
|
||||||
|
def __init__(self, repo_dir: Path | None = None) -> None:
|
||||||
|
self.repo_dir = repo_dir
|
||||||
|
|
||||||
|
def checkout_branch(self, branch_name: str) -> None:
|
||||||
|
if self.check_output(["git", "diff", "--cached", "--name-only"]):
|
||||||
|
raise RuntimeError("Staged files")
|
||||||
|
self.check_output(["git", "checkout", branch_name])
|
||||||
|
|
||||||
|
def reset(self, target: str, hard: bool = False) -> None:
|
||||||
|
self.check_output(
|
||||||
|
["git", "reset", "develop", *(["--hard"] if hard else [])]
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete_tag(self, tag_name: str) -> None:
|
||||||
|
self.grab_output(["git", "tag", "-d", tag_name])
|
||||||
|
|
||||||
|
def create_tag(self, tag_name: str) -> None:
|
||||||
|
self.check_output(["git", "tag", tag_name])
|
||||||
|
|
||||||
|
def add(self, target: str) -> None:
|
||||||
|
self.check_output(["git", "add", target])
|
||||||
|
|
||||||
|
def commit(self, message: str) -> None:
|
||||||
|
self.check_output(["git", "commit", "-m", message])
|
||||||
|
|
||||||
|
def push(
|
||||||
|
self,
|
||||||
|
upstream: str,
|
||||||
|
targets: list[str],
|
||||||
|
force_with_lease: bool = False,
|
||||||
|
force: bool = False,
|
||||||
|
) -> None:
|
||||||
|
self.check_output(
|
||||||
|
[
|
||||||
|
"git",
|
||||||
|
"push",
|
||||||
|
upstream,
|
||||||
|
*targets,
|
||||||
|
*(["--force-with-lease"] if force else []),
|
||||||
|
*(["--force"] if force else []),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_current_commit_hash(self) -> str:
|
||||||
|
return self.grab_output(
|
||||||
|
["git", "log", "-1", "--pretty=format:%H"]
|
||||||
|
).stdout.strip()
|
||||||
|
|
||||||
|
def get_branch_version(
|
||||||
|
self, pattern: str | None = None, branch: str | None = None
|
||||||
|
) -> str:
|
||||||
|
return self.grab_output(
|
||||||
|
[
|
||||||
|
"git",
|
||||||
|
"describe",
|
||||||
|
*([branch] if branch else ["--dirty"]),
|
||||||
|
"--always",
|
||||||
|
"--abbrev=7",
|
||||||
|
"--tags",
|
||||||
|
"--exclude",
|
||||||
|
"latest",
|
||||||
|
*(["--match", pattern] if pattern else []),
|
||||||
|
]
|
||||||
|
).stdout.strip()
|
||||||
|
|
||||||
|
def grab_output(self, *args, **kwargs):
|
||||||
|
return run(
|
||||||
|
*args, **kwargs, capture_output=True, text=True, cwd=self.repo_dir
|
||||||
|
)
|
||||||
|
|
||||||
|
def check_output(self, *args, **kwargs):
|
||||||
|
return check_output(*args, **kwargs, cwd=self.repo_dir)
|
78
tools/shared/icons.py
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import tempfile
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import check_call
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class IconSpec:
|
||||||
|
size: int
|
||||||
|
type: str
|
||||||
|
|
||||||
|
|
||||||
|
SPECS = [
|
||||||
|
IconSpec(size=32, type="bmp"),
|
||||||
|
IconSpec(size=16, type="bmp"),
|
||||||
|
IconSpec(size=256, type="png"),
|
||||||
|
IconSpec(size=128, type="png"),
|
||||||
|
IconSpec(size=64, type="png"),
|
||||||
|
IconSpec(size=48, type="png"),
|
||||||
|
IconSpec(size=32, type="png"),
|
||||||
|
IconSpec(size=16, type="png"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def resize_transformer(path: Path, spec: IconSpec) -> None:
|
||||||
|
check_call(
|
||||||
|
[
|
||||||
|
"convert",
|
||||||
|
f"{path}[0]",
|
||||||
|
"-filter",
|
||||||
|
"lanczos",
|
||||||
|
"-resize",
|
||||||
|
f"{spec.size}x{spec.size}",
|
||||||
|
f"PNG:{path}",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def quantize_transformer(path: Path, spec: IconSpec) -> None:
|
||||||
|
quantized_path = path.with_stem(f"{path.stem}-quantized")
|
||||||
|
check_call(["pngquant", path, "--output", quantized_path])
|
||||||
|
path.write_bytes(quantized_path.read_bytes())
|
||||||
|
quantized_path.unlink()
|
||||||
|
|
||||||
|
|
||||||
|
def optimize_transformer(path: Path, spec: IconSpec) -> None:
|
||||||
|
check_call(["zopflipng", "-y", path, path])
|
||||||
|
|
||||||
|
|
||||||
|
def convert_transformer(path: Path, spec: IconSpec) -> None:
|
||||||
|
if spec.type != "png":
|
||||||
|
check_call(["convert", path, f"{spec.type.upper()}:{path}"])
|
||||||
|
|
||||||
|
|
||||||
|
TRANSFORMERS = [
|
||||||
|
resize_transformer,
|
||||||
|
quantize_transformer,
|
||||||
|
optimize_transformer,
|
||||||
|
convert_transformer,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def generate_icon(source_path: Path, target_path: Path) -> None:
|
||||||
|
aux_paths = []
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
tmp_path = Path(tmpdir)
|
||||||
|
for spec in SPECS:
|
||||||
|
aux_path = tmp_path / f"{spec.size}-{spec.type}.tmp"
|
||||||
|
aux_path.write_bytes(source_path.read_bytes())
|
||||||
|
for transform in TRANSFORMERS:
|
||||||
|
transform(aux_path, spec)
|
||||||
|
|
||||||
|
aux_paths.append(aux_path)
|
||||||
|
|
||||||
|
# NOTE: image order is important for certain software.
|
||||||
|
check_call(["identify", *aux_paths])
|
||||||
|
check_call(["convert", *aux_paths, target_path])
|
96
tools/shared/import_sorter.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import functools
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from shutil import which
|
||||||
|
from subprocess import run
|
||||||
|
|
||||||
|
from shared.files import find_versioned_files
|
||||||
|
|
||||||
|
|
||||||
|
def custom_sort(source: list[str], forced_order: list[str]) -> list[str]:
|
||||||
|
def key_func(item: str) -> tuple[int, int, str]:
|
||||||
|
if item in forced_order:
|
||||||
|
return (forced_order[0], forced_order.index(item))
|
||||||
|
return (item, 0)
|
||||||
|
|
||||||
|
return sorted(source, key=key_func)
|
||||||
|
|
||||||
|
|
||||||
|
def sort_imports(
|
||||||
|
path: Path,
|
||||||
|
root_dir: Path,
|
||||||
|
own_include_map: dict[str, str],
|
||||||
|
fix_map: dict[str, str],
|
||||||
|
forced_order: list[str],
|
||||||
|
) -> None:
|
||||||
|
source = path.read_text()
|
||||||
|
try:
|
||||||
|
rel_path = path.relative_to(root_dir)
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
|
||||||
|
own_include = str(rel_path.with_suffix(".h"))
|
||||||
|
own_include = own_include_map.get(str(rel_path), own_include)
|
||||||
|
|
||||||
|
for key, value in fix_map.items():
|
||||||
|
source = re.sub(
|
||||||
|
r'(#include ["<])' + re.escape(key) + '([">])',
|
||||||
|
r"\1" + value + r"\2",
|
||||||
|
source,
|
||||||
|
)
|
||||||
|
|
||||||
|
def cb(match):
|
||||||
|
includes = re.findall(r'#include (["<][^"<>]+[">])', match.group(0))
|
||||||
|
groups = {
|
||||||
|
"self": set(),
|
||||||
|
"local": set(),
|
||||||
|
"shared": set(),
|
||||||
|
"external": set(),
|
||||||
|
}
|
||||||
|
for include in includes:
|
||||||
|
if include.strip('"') == own_include:
|
||||||
|
groups["self"].add(include)
|
||||||
|
elif include.startswith("<libtrx"):
|
||||||
|
groups["shared"].add(include)
|
||||||
|
elif include.startswith("<"):
|
||||||
|
groups["external"].add(include)
|
||||||
|
elif include.startswith('"'):
|
||||||
|
groups["local"].add(include)
|
||||||
|
|
||||||
|
groups = {key: value for key, value in groups.items() if value}
|
||||||
|
|
||||||
|
ret = "\n\n".join(
|
||||||
|
"\n".join(
|
||||||
|
f"#include {include}"
|
||||||
|
for include in custom_sort(group, forced_order)
|
||||||
|
)
|
||||||
|
for group in groups.values()
|
||||||
|
).strip()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
source = re.sub(
|
||||||
|
"^#include [^\n]+(\n*#include [^\n]+)*",
|
||||||
|
cb,
|
||||||
|
source,
|
||||||
|
flags=re.M,
|
||||||
|
)
|
||||||
|
if source != path.read_text():
|
||||||
|
path.write_text(source)
|
||||||
|
|
||||||
|
|
||||||
|
def sort_imports(
|
||||||
|
root_dir: Path,
|
||||||
|
system_include_dirs: list[Path],
|
||||||
|
paths: list[Path],
|
||||||
|
own_include_map: dict[str, str],
|
||||||
|
fix_map: dict[str, str],
|
||||||
|
forced_order: list[str],
|
||||||
|
) -> None:
|
||||||
|
for path in paths:
|
||||||
|
sort_imports(
|
||||||
|
path,
|
||||||
|
root_dir=root_dir,
|
||||||
|
own_include_map=own_include_map,
|
||||||
|
fix_map=fix_map,
|
||||||
|
forced_order=forced_order,
|
||||||
|
)
|
129
tools/shared/linting.py
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
from collections.abc import Callable, Iterable
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LintContext:
|
||||||
|
root_dir: Path
|
||||||
|
versioned_files: list[Path]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LintWarning:
|
||||||
|
path: Path
|
||||||
|
message: str
|
||||||
|
line: int | None = None
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
prefix = str(self.path)
|
||||||
|
if self.line is not None:
|
||||||
|
prefix += f":{self.line}"
|
||||||
|
return f"{prefix}: {self.message}"
|
||||||
|
|
||||||
|
|
||||||
|
def lint_json_validity(
|
||||||
|
context: LintContext, path: Path
|
||||||
|
) -> Iterable[LintWarning]:
|
||||||
|
if path.suffix != ".json":
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
json.loads(path.read_text())
|
||||||
|
except json.JSONDecodeError as ex:
|
||||||
|
yield LintWarning(path, f"malformed JSON: {ex!s}")
|
||||||
|
|
||||||
|
|
||||||
|
def lint_newlines(context: LintContext, path: Path) -> Iterable[LintWarning]:
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
if not text:
|
||||||
|
return
|
||||||
|
if not text.endswith("\n"):
|
||||||
|
yield LintWarning(path, "missing newline character at end of file")
|
||||||
|
if text.endswith("\n\n"):
|
||||||
|
yield LintWarning(path, "extra newline character at end of file")
|
||||||
|
|
||||||
|
|
||||||
|
def lint_trailing_whitespace(
|
||||||
|
context: LintContext, path: Path
|
||||||
|
) -> Iterable[LintWarning]:
|
||||||
|
if path.suffix == ".md":
|
||||||
|
return
|
||||||
|
for i, line in enumerate(path.open("r"), 1):
|
||||||
|
if line.rstrip("\n").endswith(" "):
|
||||||
|
yield LintWarning(path, "trailing whitespace", line=i)
|
||||||
|
|
||||||
|
|
||||||
|
def lint_const_primitives(
|
||||||
|
context: LintContext, path: Path
|
||||||
|
) -> Iterable[LintWarning]:
|
||||||
|
if path.suffix != ".h":
|
||||||
|
return
|
||||||
|
for i, line in enumerate(path.open("r"), 1):
|
||||||
|
if re.search(r"const (int[a-z0-9_]*|bool)\b\s*[a-z]", line):
|
||||||
|
yield LintWarning(path, "useless const", line=i)
|
||||||
|
if re.search(r"\*\s*const", line):
|
||||||
|
yield LintWarning(path, "useless const", line=i)
|
||||||
|
|
||||||
|
|
||||||
|
def lint_game_strings(
|
||||||
|
context: LintContext, paths: list[Path]
|
||||||
|
) -> Iterable[LintWarning]:
|
||||||
|
def_paths = list(context.root_dir.rglob("**/game_string.def"))
|
||||||
|
defs = [
|
||||||
|
match.group(1)
|
||||||
|
for path in def_paths
|
||||||
|
for match in re.finditer(
|
||||||
|
r"GS_DEFINE\(([A-Z_]+),.*\)", path.read_text()
|
||||||
|
)
|
||||||
|
]
|
||||||
|
if not defs:
|
||||||
|
return
|
||||||
|
|
||||||
|
path_hints = " or ".join(
|
||||||
|
str(path.relative_to(context.root_dir)) for path in def_paths
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
if path.suffix != ".c":
|
||||||
|
continue
|
||||||
|
for i, line in enumerate(path.open("r"), 1):
|
||||||
|
for match in re.finditer(r"GS\(([A-Z_]+)\)", line):
|
||||||
|
def_ = match.group(1)
|
||||||
|
if def_ in defs:
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield LintWarning(
|
||||||
|
path,
|
||||||
|
f"undefined game string: {def_}. "
|
||||||
|
f"Make sure it's defined in {path_hints}.",
|
||||||
|
i,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ALL_LINTERS: list[Callable[[LintContext, Path], Iterable[LintWarning]]] = [
|
||||||
|
lint_json_validity,
|
||||||
|
lint_newlines,
|
||||||
|
lint_trailing_whitespace,
|
||||||
|
lint_const_primitives,
|
||||||
|
]
|
||||||
|
|
||||||
|
ALL_BULK_LINTERS: list[
|
||||||
|
Callable[[LintContext, list[Path]], Iterable[LintWarning]]
|
||||||
|
] = [
|
||||||
|
lint_game_strings,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def lint_file(context: LintContext, file: Path) -> Iterable[LintWarning]:
|
||||||
|
for linter_func in ALL_LINTERS:
|
||||||
|
yield from linter_func(context, file)
|
||||||
|
|
||||||
|
|
||||||
|
def lint_bulk_files(
|
||||||
|
context: LintContext, files: list[Path]
|
||||||
|
) -> Iterable[LintWarning]:
|
||||||
|
for linter_func in ALL_BULK_LINTERS:
|
||||||
|
yield from linter_func(context, files)
|
17
tools/shared/packaging.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import sys
|
||||||
|
import zipfile
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def create_zip(
|
||||||
|
output_path: Path, source_files: Iterable[tuple[Path, str]]
|
||||||
|
) -> None:
|
||||||
|
with zipfile.ZipFile(output_path, "w") as handle:
|
||||||
|
for source_path, archive_name in source_files:
|
||||||
|
if not source_path.exists():
|
||||||
|
print(
|
||||||
|
f"WARNING: {source_path} does not exist", file=sys.stderr
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
handle.write(source_path, archive_name)
|
34
tools/shared/paths.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO_DIR = Path(__file__).parent
|
||||||
|
while REPO_DIR.parent != REPO_DIR and not (REPO_DIR / ".git").exists():
|
||||||
|
REPO_DIR = REPO_DIR.parent
|
||||||
|
|
||||||
|
TOOLS_DIR = REPO_DIR / "tools"
|
||||||
|
SRC_DIR = REPO_DIR / "src"
|
||||||
|
DATA_DIR = REPO_DIR / "data"
|
||||||
|
DOCS_DIR = REPO_DIR / "docs"
|
||||||
|
|
||||||
|
SHARED_INCLUDE_DIR = SRC_DIR / "libtrx/include/libtrx"
|
||||||
|
SHARED_SRC_DIR = SRC_DIR / "libtrx"
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectPaths:
|
||||||
|
def __init__(self, folder_name: str) -> None:
|
||||||
|
self.folder_name = folder_name
|
||||||
|
|
||||||
|
self.data_dir = DATA_DIR / folder_name
|
||||||
|
self.shipped_data_dir = self.data_dir / "ship"
|
||||||
|
self.src_dir = SRC_DIR / folder_name
|
||||||
|
self.tools_dir = TOOLS_DIR / folder_name
|
||||||
|
self.docs_dir = DOCS_DIR / folder_name
|
||||||
|
self.changelog_path = self.docs_dir / "CHANGELOG.md"
|
||||||
|
|
||||||
|
|
||||||
|
TR1Paths = ProjectPaths(folder_name="tr1")
|
||||||
|
|
||||||
|
TR2Paths = ProjectPaths(folder_name="tr2")
|
||||||
|
TR2Paths.progress_file = TR2Paths.docs_dir / "progress.txt"
|
||||||
|
TR2Paths.progress_svg = TR2Paths.docs_dir / "progress.svg"
|
||||||
|
|
||||||
|
PROJECT_PATHS = {1: TR1Paths, 2: TR2Paths}
|
22
tools/shared/versioning.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from shared.git import Git
|
||||||
|
|
||||||
|
PATTERN_MAP = {
|
||||||
|
1: "tr1-*",
|
||||||
|
2: "tr2-*",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def generate_version(version: int, repo_dir: Path | None = None) -> str:
|
||||||
|
git = Git(repo_dir=repo_dir)
|
||||||
|
pattern = PATTERN_MAP[version]
|
||||||
|
return (
|
||||||
|
re.sub(
|
||||||
|
"^tr[0-9]-",
|
||||||
|
"",
|
||||||
|
git.get_branch_version(pattern=pattern, branch=None),
|
||||||
|
)
|
||||||
|
or "?"
|
||||||
|
)
|
81
tools/sort_imports
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from shared.import_sorter import sort_imports
|
||||||
|
from shared.paths import SHARED_SRC_DIR, SRC_DIR, TR1Paths, TR2Paths
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("path", type=Path, nargs="*")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
if args.path:
|
||||||
|
paths = [path.absolute() for path in args.path]
|
||||||
|
else:
|
||||||
|
paths = [
|
||||||
|
path
|
||||||
|
for path in find_versioned_files(root_dir)
|
||||||
|
if path.suffix in [".c", ".h"]
|
||||||
|
]
|
||||||
|
|
||||||
|
sort_imports(
|
||||||
|
paths=[path for path in paths if path.is_relative_to(TR1Paths.src_dir)],
|
||||||
|
root_dir=TR1Paths.src_dir,
|
||||||
|
system_include_dirs=[SRC_DIR],
|
||||||
|
own_include_map={
|
||||||
|
"game/game/game.c": "game/game.h",
|
||||||
|
"game/game/game_cutscene.c": "game/game.h",
|
||||||
|
"game/game/game_demo.c": "game/game.h",
|
||||||
|
"game/game/game_draw.c": "game/game.h",
|
||||||
|
"game/game/game_pause.c": "game/game.h",
|
||||||
|
"game/gun/gun.c": "game/gun.h",
|
||||||
|
"game/inventry.c": "game/inv.h",
|
||||||
|
"game/invfunc.c": "game/inv.h",
|
||||||
|
"game/invvars.c": "game/inv.h",
|
||||||
|
"game/lara/lara.c": "game/lara.h",
|
||||||
|
"game/option/option.c": "game/option.h",
|
||||||
|
"game/savegame/savegame.c": "game/savegame.h",
|
||||||
|
},
|
||||||
|
fix_map={"libavcodec/version_major.h": "libavcodec/version.h"},
|
||||||
|
forced_order=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
sort_imports(
|
||||||
|
paths=[path for path in paths if path.is_relative_to(TR2Paths.src_dir)],
|
||||||
|
root_dir=TR2Paths.src_dir,
|
||||||
|
system_include_dirs=[SRC_DIR],
|
||||||
|
own_include_map={
|
||||||
|
"game/music/music_main.c": "game/music.h",
|
||||||
|
},
|
||||||
|
fix_map={},
|
||||||
|
forced_order=["<ddrawi.h>", "<d3dhal.h>"],
|
||||||
|
)
|
||||||
|
|
||||||
|
sort_imports(
|
||||||
|
paths=[path for path in paths if path.is_relative_to(SHARED_SRC_DIR)],
|
||||||
|
root_dir=SHARED_SRC_DIR,
|
||||||
|
system_include_dirs=[],
|
||||||
|
own_include_map={
|
||||||
|
"json/bson_write.c": "bson.h",
|
||||||
|
"json/bson_parse.c": "bson.h",
|
||||||
|
"json/json_base.c": "json.h",
|
||||||
|
"json/json_write.c": "json.h",
|
||||||
|
"json/json_parse.c": "json.h",
|
||||||
|
"log_unknown.c": "log.h",
|
||||||
|
"log_linux.c": "log.h",
|
||||||
|
"log_windows.c": "log.h",
|
||||||
|
"engine/audio.c": "audio.h",
|
||||||
|
"engine/audio_sample.c": "audio.h",
|
||||||
|
"engine/audio_stream.c": "audio.h",
|
||||||
|
},
|
||||||
|
fix_map={},
|
||||||
|
forced_order=[
|
||||||
|
"<windows.h>",
|
||||||
|
"<dbghelp.h>",
|
||||||
|
"<tlhelp32.h>",
|
||||||
|
],
|
||||||
|
)
|
0
tools/tr1/__init__.py
Normal file
|
@ -67,7 +67,7 @@
|
||||||
<EmbeddedResource Include="Resources\specification.json" />
|
<EmbeddedResource Include="Resources\specification.json" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<Reference Include="TRX_ConfigToolLib">
|
<Reference Include="TRX_ConfigToolLib">
|
||||||
<HintPath>..\..\..\..\subprojects\libtrx\tools\config\TRX_ConfigToolLib\bin\Release\publish\TRX_ConfigToolLib.dll</HintPath>
|
<HintPath>..\..\..\config\TRX_ConfigToolLib\bin\Release\publish\TRX_ConfigToolLib.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -7,7 +7,7 @@ echo $HOME
|
||||||
shopt -s globstar
|
shopt -s globstar
|
||||||
|
|
||||||
# Build the common lib DLL
|
# Build the common lib DLL
|
||||||
cd /app/subprojects/libtrx/tools/config/
|
cd /app/tools/config/
|
||||||
rm -rf **/bin **/obj
|
rm -rf **/bin **/obj
|
||||||
dotnet restore -p:EnableWindowsTargeting=true
|
dotnet restore -p:EnableWindowsTargeting=true
|
||||||
dotnet publish -c Release -p:EnableWindowsTargeting=true
|
dotnet publish -c Release -p:EnableWindowsTargeting=true
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libtrx.cli.game_docker_entrypoint import run_script
|
from shared.cli.game_docker_entrypoint import run_script
|
||||||
|
|
||||||
run_script(
|
run_script(
|
||||||
ship_dir=Path("/app/data/tr1/ship/"),
|
version=1,
|
||||||
build_root=Path("/app/build/linux/"),
|
platform="linux",
|
||||||
compile_args=[],
|
compile_args=[],
|
||||||
release_zip_filename="TR1X-{version}-Linux.zip",
|
|
||||||
release_zip_files=[
|
release_zip_files=[
|
||||||
(Path("/app/build/linux/TR1X"), "TR1X"),
|
(Path("/app/build/tr1/linux/TR1X"), "TR1X"),
|
||||||
],
|
],
|
||||||
compressable_exes=[
|
compressable_exes=[
|
||||||
Path("/app/build/linux/TR1X"),
|
Path("/app/build/tr1/linux/TR1X"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libtrx.cli.game_docker_entrypoint import run_script
|
from shared.cli.game_docker_entrypoint import run_script
|
||||||
|
|
||||||
run_script(
|
run_script(
|
||||||
ship_dir=Path("/app/data/tr1/ship/"),
|
version=1,
|
||||||
build_root=Path("/app/build/win/"),
|
platform="win",
|
||||||
compile_args=[
|
compile_args=[
|
||||||
"--cross",
|
"--cross",
|
||||||
"/app/tools/tr1/docker/game-win/meson_linux_mingw32.txt",
|
"/app/tools/tr1/docker/game-win/meson_linux_mingw32.txt",
|
||||||
],
|
],
|
||||||
release_zip_filename="TR1X-{version}-Windows.zip",
|
|
||||||
release_zip_files=[
|
release_zip_files=[
|
||||||
(Path("/app/build/win/TR1X.exe"), "TR1X.exe"),
|
(Path("/app/build/tr1/win/TR1X.exe"), "TR1X.exe"),
|
||||||
(
|
(
|
||||||
Path("/app/tools/tr1/config/out/TR1X_ConfigTool.exe"),
|
Path("/app/tools/tr1/config/out/TR1X_ConfigTool.exe"),
|
||||||
"TR1X_ConfigTool.exe",
|
"TR1X_ConfigTool.exe",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
compressable_exes=[
|
compressable_exes=[
|
||||||
Path("/app/build/win/TR1X.exe"),
|
Path("/app/build/tr1/win/TR1X.exe"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libtrx.versioning import generate_version
|
from shared.versioning import generate_version
|
||||||
|
|
||||||
TEMPLATE = """
|
TEMPLATE = """
|
||||||
const char *g_TR1XVersion = "TR1X {version}";
|
const char *g_TR1XVersion = "TR1X {version}";
|
||||||
|
@ -16,7 +16,7 @@ def parse_args() -> argparse.Namespace:
|
||||||
|
|
||||||
|
|
||||||
def get_init_c() -> str:
|
def get_init_c() -> str:
|
||||||
return TEMPLATE.format(version=generate_version())
|
return TEMPLATE.format(version=generate_version(1))
|
||||||
|
|
||||||
|
|
||||||
def update_init_c(output_path: Path) -> None:
|
def update_init_c(output_path: Path) -> None:
|
||||||
|
@ -30,7 +30,7 @@ def main() -> None:
|
||||||
if args.output:
|
if args.output:
|
||||||
update_init_c(output_path=args.output)
|
update_init_c(output_path=args.output)
|
||||||
else:
|
else:
|
||||||
print(args.outptu)
|
print(get_init_c(), end="")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
14
tools/generate_rcfile → tools/tr1/generate_rcfile
Normal file → Executable file
|
@ -2,8 +2,8 @@
|
||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libtrx.versioning import generate_version
|
from shared.paths import TR1Paths
|
||||||
from tr1x.paths import TR1X_DATA_DIR
|
from shared.versioning import generate_version
|
||||||
|
|
||||||
|
|
||||||
def parse_args() -> argparse.Namespace:
|
def parse_args() -> argparse.Namespace:
|
||||||
|
@ -17,17 +17,19 @@ def write_rc_template(
|
||||||
) -> None:
|
) -> None:
|
||||||
template = input_path.read_text()
|
template = input_path.read_text()
|
||||||
template = template.replace("{version}", version)
|
template = template.replace("{version}", version)
|
||||||
template = template.replace("{icon_path}", str(TR1X_DATA_DIR / "icon.ico"))
|
template = template.replace(
|
||||||
|
"{icon_path}", str(TR1Paths.data_dir / "icon.ico")
|
||||||
|
)
|
||||||
output_path.write_text(template)
|
output_path.write_text(template)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
version = generate_version()
|
version = generate_version(1)
|
||||||
|
|
||||||
for output_path in args.output:
|
for output_path in args.output or []:
|
||||||
write_rc_template(
|
write_rc_template(
|
||||||
input_path=TR1X_DATA_DIR / output_path.name,
|
input_path=TR1Paths.data_dir / output_path.name,
|
||||||
output_path=output_path,
|
output_path=output_path,
|
||||||
version=version,
|
version=version,
|
||||||
)
|
)
|
29
tools/tr1/inspect_save
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import struct
|
||||||
|
import zlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import bson
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("path", type=Path)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
with args.path.open("rb") as handle:
|
||||||
|
magic = handle.read(4)
|
||||||
|
version, compressed_size, uncompressed_size = struct.unpack(
|
||||||
|
"III", handle.read(12)
|
||||||
|
)
|
||||||
|
data = bson.loads(zlib.decompress(handle.read(uncompressed_size)))
|
||||||
|
print(json.dumps(data, indent=4))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -1,8 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from libtrx.cli.release import run_script
|
|
||||||
from tr1x.paths import TR1X_REPO_DIR
|
|
||||||
|
|
||||||
run_script(
|
|
||||||
project_name="TR1X",
|
|
||||||
changelog_path=TR1X_REPO_DIR / "CHANGELOG.md",
|
|
||||||
)
|
|
1
tools/tr1/shared
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../shared
|
|
@ -1,29 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from libtrx.cli.sort_imports import run_script
|
|
||||||
from tr1x.paths import TR1X_REPO_DIR, TR1X_SRC_DIR
|
|
||||||
|
|
||||||
run_script(
|
|
||||||
root_dir=TR1X_SRC_DIR,
|
|
||||||
include_dirs=[
|
|
||||||
TR1X_SRC_DIR,
|
|
||||||
TR1X_REPO_DIR / "build/linux",
|
|
||||||
TR1X_REPO_DIR / "build/windows",
|
|
||||||
],
|
|
||||||
system_include_dirs=[TR1X_REPO_DIR / "subprojects/libtrx/include"],
|
|
||||||
own_include_map={
|
|
||||||
"game/game/game.c": "game/game.h",
|
|
||||||
"game/game/game_cutscene.c": "game/game.h",
|
|
||||||
"game/game/game_demo.c": "game/game.h",
|
|
||||||
"game/game/game_draw.c": "game/game.h",
|
|
||||||
"game/game/game_pause.c": "game/game.h",
|
|
||||||
"game/gun/gun.c": "game/gun.h",
|
|
||||||
"game/inventry.c": "game/inv.h",
|
|
||||||
"game/invfunc.c": "game/inv.h",
|
|
||||||
"game/invvars.c": "game/inv.h",
|
|
||||||
"game/lara/lara.c": "game/lara.h",
|
|
||||||
"game/option/option.c": "game/option.h",
|
|
||||||
"game/savegame/savegame.c": "game/savegame.h",
|
|
||||||
},
|
|
||||||
fix_map={"libavcodec/version_major.h": "libavcodec/version.h"},
|
|
||||||
forced_order=[],
|
|
||||||
)
|
|
|
@ -1,53 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from tr1x.paths import LIBTRX_INCLUDE_DIR, TR1X_DATA_DIR, TR1X_SRC_DIR
|
|
||||||
|
|
||||||
SHIP_DIR = TR1X_DATA_DIR / "ship"
|
|
||||||
GAME_STRING_DEF_PATHS = [
|
|
||||||
TR1X_SRC_DIR / "game/game_string.def",
|
|
||||||
LIBTRX_INCLUDE_DIR / "game/game_string.def",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_strings_map(paths: list[Path]) -> dict[str, str]:
|
|
||||||
result: dict[str, str] = {}
|
|
||||||
for path in paths:
|
|
||||||
for line in path.read_text().splitlines():
|
|
||||||
if match := re.match(
|
|
||||||
r'^GS_DEFINE\((\w+),\s*"([^"]+)"\)$', line.strip()
|
|
||||||
):
|
|
||||||
result[match.group(1)] = match.group(2)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def postprocess_gameflow(gameflow: str, strings_map: dict[str, str]) -> str:
|
|
||||||
gameflow = re.sub(
|
|
||||||
r'^( "strings": {)[^}]*(})',
|
|
||||||
' "strings": {\n'
|
|
||||||
+ "\n".join(
|
|
||||||
f" {json.dumps(key)}: {json.dumps(value)},"
|
|
||||||
for key, value in sorted(strings_map.items(), key=lambda kv: kv[0])
|
|
||||||
)
|
|
||||||
+ "\n }",
|
|
||||||
gameflow,
|
|
||||||
flags=re.M | re.DOTALL,
|
|
||||||
)
|
|
||||||
return gameflow
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
strings_map = get_default_strings_map(GAME_STRING_DEF_PATHS)
|
|
||||||
assert strings_map
|
|
||||||
|
|
||||||
for gameflow_path in SHIP_DIR.rglob("*gameflow*.json*"):
|
|
||||||
old_gameflow = gameflow_path.read_text()
|
|
||||||
new_gameflow = postprocess_gameflow(old_gameflow, strings_map)
|
|
||||||
if new_gameflow != old_gameflow:
|
|
||||||
gameflow_path.write_text(new_gameflow)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -1,10 +0,0 @@
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
TR1X_TOOLS_DIR = Path(__file__).parent.parent / "tr1"
|
|
||||||
TR1X_REPO_DIR = TR1X_TOOLS_DIR.parent
|
|
||||||
TR1X_DATA_DIR = TR1X_REPO_DIR / "data/tr1"
|
|
||||||
TR1X_SRC_DIR = TR1X_REPO_DIR / "src/tr1"
|
|
||||||
|
|
||||||
LIBTRX_REPO_DIR = TR1X_REPO_DIR / "subprojects/libtrx"
|
|
||||||
LIBTRX_SRC_DIR = LIBTRX_REPO_DIR / "src"
|
|
||||||
LIBTRX_INCLUDE_DIR = LIBTRX_REPO_DIR / "include/libtrx"
|
|
0
tools/tr2/__init__.py
Normal file
|
@ -59,7 +59,7 @@
|
||||||
<EmbeddedResource Include="Resources\specification.json" />
|
<EmbeddedResource Include="Resources\specification.json" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<Reference Include="TRX_ConfigToolLib">
|
<Reference Include="TRX_ConfigToolLib">
|
||||||
<HintPath>..\..\..\subprojects\libtrx\tools\config\TRX_ConfigToolLib\bin\Release\publish\TRX_ConfigToolLib.dll</HintPath>
|
<HintPath>..\..\..\config\TRX_ConfigToolLib\bin\Release\publish\TRX_ConfigToolLib.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -2,4 +2,4 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
||||||
|
|
||||||
ENV HOME /app
|
ENV HOME /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENTRYPOINT ["/app/tools/docker/config/entrypoint.sh"]
|
ENTRYPOINT ["/app/tools/tr2/docker/config/entrypoint.sh"]
|
||||||
|
|
|
@ -7,13 +7,13 @@ echo $HOME
|
||||||
shopt -s globstar
|
shopt -s globstar
|
||||||
|
|
||||||
# Build the common lib DLL
|
# Build the common lib DLL
|
||||||
cd /app/subprojects/libtrx/tools/config/
|
cd /app/tools/config/
|
||||||
rm -rf **/bin **/obj
|
rm -rf **/bin **/obj
|
||||||
dotnet restore -p:EnableWindowsTargeting=true
|
dotnet restore -p:EnableWindowsTargeting=true
|
||||||
dotnet publish -c Release -p:EnableWindowsTargeting=true
|
dotnet publish -c Release -p:EnableWindowsTargeting=true
|
||||||
|
|
||||||
# Build the main executable
|
# Build the main executable
|
||||||
cd /app/tools/config/
|
cd /app/tools/tr2/config/
|
||||||
rm -rf **/bin **/obj **/out/*
|
rm -rf **/bin **/obj **/out/*
|
||||||
dotnet restore
|
dotnet restore
|
||||||
dotnet publish -c Release -o out
|
dotnet publish -c Release -o out
|
||||||
|
|
|
@ -125,4 +125,4 @@ RUN apt-get install -y \
|
||||||
ninja
|
ninja
|
||||||
|
|
||||||
ENV PYTHONPATH=/app/tools/
|
ENV PYTHONPATH=/app/tools/
|
||||||
ENTRYPOINT ["/app/tools/docker/game-win/entrypoint.sh"]
|
ENTRYPOINT ["/app/tools/tr2/docker/game-win/entrypoint.sh"]
|
||||||
|
|
|
@ -1,26 +1,25 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libtrx.cli.game_docker_entrypoint import run_script
|
from shared.cli.game_docker_entrypoint import run_script
|
||||||
|
|
||||||
run_script(
|
run_script(
|
||||||
ship_dir=Path("/app/data/ship/"),
|
version=2,
|
||||||
build_root=Path("/app/build/win/"),
|
platform="win",
|
||||||
compile_args=[
|
compile_args=[
|
||||||
"--cross",
|
"--cross",
|
||||||
"/app/tools/docker/game-win/meson_linux_mingw32.txt",
|
"/app/tools/tr2/docker/game-win/meson_linux_mingw32.txt",
|
||||||
],
|
],
|
||||||
release_zip_filename="TR2X-{version}-Windows.zip",
|
|
||||||
release_zip_files=[
|
release_zip_files=[
|
||||||
(Path("/app/build/win/TR2X.exe"), "TR2X.exe"),
|
(Path("/app/build/tr2/win/TR2X.exe"), "TR2X.exe"),
|
||||||
(Path("/app/build/win/TR2X.dll"), "TR2X.dll"),
|
(Path("/app/build/tr2/win/TR2X.dll"), "TR2X.dll"),
|
||||||
(
|
(
|
||||||
Path("/app/tools/config/out/TR2X_ConfigTool.exe"),
|
Path("/app/tools/tr2/config/out/TR2X_ConfigTool.exe"),
|
||||||
"TR2X_ConfigTool.exe",
|
"TR2X_ConfigTool.exe",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
compressable_exes=[
|
compressable_exes=[
|
||||||
Path("/app/build/win/TR2X.exe"),
|
Path("/app/build/tr2/win/TR2X.exe"),
|
||||||
Path("/app/build/win/TR2X.dll"),
|
Path("/app/build/tr2/win/TR2X.dll"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../subprojects/libtrx/tools/ffmpeg_flags.txt
|
|
|
@ -1,13 +1,18 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from pathlib import Path
|
|
||||||
import re
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from tr2x.ida_progress import FUNC_PTR_RE, VAR_RE, Symbol, parse_progress_file
|
from shared.ida_progress import (
|
||||||
from tr2x.paths import TR2X_PROGRESS_FILE, TR2X_SRC_DIR
|
FUNC_PTR_RE,
|
||||||
|
VAR_RE,
|
||||||
|
Symbol,
|
||||||
|
parse_progress_file,
|
||||||
|
)
|
||||||
|
from shared.paths import TR2Paths
|
||||||
|
|
||||||
FUNCS_H_FILE = TR2X_SRC_DIR / "global/funcs.h"
|
FUNCS_H_FILE = TR2Paths.src_dir / "global/funcs.h"
|
||||||
VARS_H_FILE = TR2X_SRC_DIR / "global/vars_decomp.h"
|
VARS_H_FILE = TR2Paths.src_dir / "global/vars_decomp.h"
|
||||||
TYPES_H_FILE = TR2X_SRC_DIR / "global/types.h"
|
TYPES_H_FILE = TR2Paths.src_dir / "global/types.h"
|
||||||
|
|
||||||
|
|
||||||
COMMON_HEADER = [
|
COMMON_HEADER = [
|
||||||
|
@ -145,7 +150,13 @@ def make_types_h(types: list[str]) -> None:
|
||||||
"\n".join(
|
"\n".join(
|
||||||
[
|
[
|
||||||
*header,
|
*header,
|
||||||
"\n\n".join([definition.strip() for definition in types if '// decompiled' not in definition.strip()]),
|
"\n\n".join(
|
||||||
|
[
|
||||||
|
definition.strip()
|
||||||
|
for definition in types
|
||||||
|
if "// decompiled" not in definition.strip()
|
||||||
|
]
|
||||||
|
),
|
||||||
*footer,
|
*footer,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -154,7 +165,7 @@ def make_types_h(types: list[str]) -> None:
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
progress_file = parse_progress_file(TR2X_PROGRESS_FILE)
|
progress_file = parse_progress_file(TR2Paths.progress_file)
|
||||||
|
|
||||||
make_funcs_h(progress_file.functions)
|
make_funcs_h(progress_file.functions)
|
||||||
make_vars_h(progress_file.variables)
|
make_vars_h(progress_file.variables)
|
||||||
|
|
|
@ -10,14 +10,15 @@ import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import regex
|
import regex
|
||||||
from tr2x.ida_progress import (
|
|
||||||
|
from shared.ida_progress import (
|
||||||
FUNC_PTR_RE,
|
FUNC_PTR_RE,
|
||||||
FUNC_RE,
|
FUNC_RE,
|
||||||
VAR_RE,
|
VAR_RE,
|
||||||
Symbol,
|
Symbol,
|
||||||
parse_progress_file,
|
parse_progress_file,
|
||||||
)
|
)
|
||||||
from tr2x.paths import TR2X_PROGRESS_FILE
|
from shared.paths import TR2Paths
|
||||||
|
|
||||||
|
|
||||||
def generate_types(types: list[str], file) -> None:
|
def generate_types(types: list[str], file) -> None:
|
||||||
|
@ -109,7 +110,7 @@ def parse_args() -> argparse.Namespace:
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
progress_file = parse_progress_file(TR2X_PROGRESS_FILE)
|
progress_file = parse_progress_file(TR2Paths.progress_file)
|
||||||
|
|
||||||
output = Path(args.output)
|
output = Path(args.output)
|
||||||
with output.open("w") as file:
|
with output.open("w") as file:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libtrx.versioning import generate_version
|
from shared.versioning import generate_version
|
||||||
|
|
||||||
TEMPLATE = """
|
TEMPLATE = """
|
||||||
const char *g_TR2XVersion = "TR2X {version}";
|
const char *g_TR2XVersion = "TR2X {version}";
|
||||||
|
@ -16,7 +16,7 @@ def parse_args() -> argparse.Namespace:
|
||||||
|
|
||||||
|
|
||||||
def get_init_c() -> str:
|
def get_init_c() -> str:
|
||||||
return TEMPLATE.format(version=generate_version())
|
return TEMPLATE.format(version=generate_version(2))
|
||||||
|
|
||||||
|
|
||||||
def update_init_c(output_path: Path) -> None:
|
def update_init_c(output_path: Path) -> None:
|
||||||
|
@ -30,7 +30,7 @@ def main() -> None:
|
||||||
if args.output:
|
if args.output:
|
||||||
update_init_c(output_path=args.output)
|
update_init_c(output_path=args.output)
|
||||||
else:
|
else:
|
||||||
print(args.output)
|
print(get_init_c(), end="")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libtrx.versioning import generate_version
|
from shared.paths import TR2Paths
|
||||||
from tr2x.paths import TR2X_DATA_DIR
|
from shared.versioning import generate_version
|
||||||
|
|
||||||
|
|
||||||
def parse_args() -> argparse.Namespace:
|
def parse_args() -> argparse.Namespace:
|
||||||
|
@ -17,17 +17,19 @@ def write_rc_template(
|
||||||
) -> None:
|
) -> None:
|
||||||
template = input_path.read_text()
|
template = input_path.read_text()
|
||||||
template = template.replace("{version}", version)
|
template = template.replace("{version}", version)
|
||||||
template = template.replace("{icon_path}", str(TR2X_DATA_DIR / "icon.ico"))
|
template = template.replace(
|
||||||
|
"{icon_path}", str(TR2Paths.data_dir / "icon.ico")
|
||||||
|
)
|
||||||
output_path.write_text(template)
|
output_path.write_text(template)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
version = generate_version()
|
version = generate_version(2)
|
||||||
|
|
||||||
for output_path in args.output:
|
for output_path in args.output or []:
|
||||||
write_rc_template(
|
write_rc_template(
|
||||||
input_path=TR2X_DATA_DIR / output_path.name,
|
input_path=TR2Paths.data_dir / output_path.name,
|
||||||
output_path=output_path,
|
output_path=output_path,
|
||||||
version=version,
|
version=version,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../subprojects/libtrx/tools/libtrx
|
|
|
@ -8,8 +8,8 @@ from itertools import groupby
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from tr2x.ida_progress import Symbol, SymbolStatus, parse_progress_file
|
from shared.ida_progress import Symbol, SymbolStatus, parse_progress_file
|
||||||
from tr2x.paths import TR2X_PROGRESS_FILE
|
from shared.paths import TR2Paths
|
||||||
|
|
||||||
DOCUMENT_MARGIN = Decimal(2)
|
DOCUMENT_MARGIN = Decimal(2)
|
||||||
GRID_MAX_SQUARES = 50
|
GRID_MAX_SQUARES = 50
|
||||||
|
@ -23,9 +23,6 @@ LEGEND_MARGIN = Decimal(15)
|
||||||
TEXT_SIZE = Decimal(15)
|
TEXT_SIZE = Decimal(15)
|
||||||
TEXT_MARGIN = Decimal(5)
|
TEXT_MARGIN = Decimal(5)
|
||||||
SECTION_MARGIN = GRID_SQUARE_SIZE + LEGEND_MARGIN
|
SECTION_MARGIN = GRID_SQUARE_SIZE + LEGEND_MARGIN
|
||||||
DOCS_DIR = Path(__file__).parent.parent / "docs"
|
|
||||||
PROGRESS_TXT_FILE = DOCS_DIR / "progress.txt"
|
|
||||||
PROGRESS_SVG_FILE = DOCS_DIR / "progress.svg"
|
|
||||||
GRID_WIDTH = (
|
GRID_WIDTH = (
|
||||||
GRID_MAX_SQUARES * (GRID_SQUARE_SIZE + GRID_SQUARE_MARGIN)
|
GRID_MAX_SQUARES * (GRID_SQUARE_SIZE + GRID_SQUARE_MARGIN)
|
||||||
- GRID_SQUARE_MARGIN
|
- GRID_SQUARE_MARGIN
|
||||||
|
@ -204,7 +201,7 @@ def squarify(
|
||||||
|
|
||||||
def collect_functions() -> Iterable[Symbol]:
|
def collect_functions() -> Iterable[Symbol]:
|
||||||
in_functions = False
|
in_functions = False
|
||||||
for line in PROGRESS_TXT_FILE.open():
|
for line in TR2Paths.progress_file.open():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if line == "# FUNCTIONS":
|
if line == "# FUNCTIONS":
|
||||||
in_functions = True
|
in_functions = True
|
||||||
|
@ -698,9 +695,9 @@ class ProgressSVG(Container):
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
progress_file = parse_progress_file(TR2X_PROGRESS_FILE)
|
progress_file = parse_progress_file(TR2Paths.progress_file)
|
||||||
|
|
||||||
with PROGRESS_SVG_FILE.open("w") as handle:
|
with TR2Paths.progress_svg.open("w") as handle:
|
||||||
svg = ProgressSVG(progress_file.functions)
|
svg = ProgressSVG(progress_file.functions)
|
||||||
print(svg.render(), file=handle)
|
print(svg.render(), file=handle)
|
||||||
|
|
||||||
|
|
1
tools/tr2/shared
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../shared
|
|
@ -1,13 +0,0 @@
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
TR2X_TOOLS_DIR = Path(__file__).parent.parent
|
|
||||||
TR2X_REPO_DIR = TR2X_TOOLS_DIR.parent
|
|
||||||
TR2X_DOCS_DIR = TR2X_REPO_DIR / "docs"
|
|
||||||
TR2X_DATA_DIR = TR2X_REPO_DIR / "data"
|
|
||||||
TR2X_SRC_DIR = TR2X_REPO_DIR / "src"
|
|
||||||
|
|
||||||
LIBTRX_REPO_DIR = TR2X_REPO_DIR / "subprojects/libtrx"
|
|
||||||
LIBTRX_SRC_DIR = LIBTRX_REPO_DIR / "src"
|
|
||||||
LIBTRX_INCLUDE_DIR = LIBTRX_REPO_DIR / "include/libtrx"
|
|
||||||
|
|
||||||
TR2X_PROGRESS_FILE = TR2X_DOCS_DIR / "progress.txt"
|
|
|
@ -1,76 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from tr2x.paths import LIBTRX_INCLUDE_DIR, TR2X_DATA_DIR, TR2X_SRC_DIR
|
|
||||||
|
|
||||||
SHIP_DIR = TR2X_DATA_DIR / "ship"
|
|
||||||
GAME_STRING_DEF_PATHS = [
|
|
||||||
TR2X_SRC_DIR / "game/game_string.def",
|
|
||||||
LIBTRX_INCLUDE_DIR / "game/game_string.def",
|
|
||||||
]
|
|
||||||
OBJECT_STRINGS_DEF_PATH = LIBTRX_INCLUDE_DIR / "game/objects/names_tr2.def"
|
|
||||||
|
|
||||||
|
|
||||||
def get_strings_map(paths: list[Path]) -> dict[str, str]:
|
|
||||||
result: dict[str, str] = {}
|
|
||||||
for path in paths:
|
|
||||||
for line in path.read_text().splitlines():
|
|
||||||
if match := re.match(
|
|
||||||
r'^\w+DEFINE\((\w+),\s*"([^"]+)"\)$', line.strip()
|
|
||||||
):
|
|
||||||
result[match.group(1)] = match.group(2)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def postprocess_gameflow(
|
|
||||||
gameflow: str,
|
|
||||||
object_strings_map: dict[str, str],
|
|
||||||
game_strings_map: dict[str, str],
|
|
||||||
) -> str:
|
|
||||||
gameflow = re.sub(
|
|
||||||
r'^( "object_strings": {)[^}]*(})',
|
|
||||||
' "object_strings": {\n'
|
|
||||||
+ "\n".join(
|
|
||||||
f" {json.dumps(key)}: {json.dumps(value)},"
|
|
||||||
for key, value in object_strings_map.items()
|
|
||||||
)
|
|
||||||
+ "\n }",
|
|
||||||
gameflow,
|
|
||||||
flags=re.M | re.DOTALL,
|
|
||||||
)
|
|
||||||
|
|
||||||
gameflow = re.sub(
|
|
||||||
r'^( "game_strings": {)[^}]*(})',
|
|
||||||
' "game_strings": {\n'
|
|
||||||
+ "\n".join(
|
|
||||||
f" {json.dumps(key)}: {json.dumps(value)},"
|
|
||||||
for key, value in sorted(
|
|
||||||
game_strings_map.items(), key=lambda kv: kv[0]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
+ "\n }",
|
|
||||||
gameflow,
|
|
||||||
flags=re.M | re.DOTALL,
|
|
||||||
)
|
|
||||||
return gameflow
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
object_strings_map = get_strings_map([OBJECT_STRINGS_DEF_PATH])
|
|
||||||
game_strings_map = get_strings_map(GAME_STRING_DEF_PATHS)
|
|
||||||
assert object_strings_map
|
|
||||||
assert game_strings_map
|
|
||||||
|
|
||||||
for gameflow_path in SHIP_DIR.rglob("*gameflow*.json*"):
|
|
||||||
old_gameflow = gameflow_path.read_text()
|
|
||||||
new_gameflow = postprocess_gameflow(
|
|
||||||
old_gameflow, object_strings_map, game_strings_map
|
|
||||||
)
|
|
||||||
if new_gameflow != old_gameflow:
|
|
||||||
gameflow_path.write_text(new_gameflow)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
113
tools/update_gameflow
Executable file
|
@ -0,0 +1,113 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from shared.paths import SHARED_INCLUDE_DIR, TR1Paths, TR2Paths
|
||||||
|
|
||||||
|
GAME_STRING_DEF_PATHS = [
|
||||||
|
TR1Paths.src_dir / "game/game_string.def",
|
||||||
|
SHARED_INCLUDE_DIR / "game/game_string.def",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_strings_map(paths: list[Path]) -> dict[str, str]:
|
||||||
|
result: dict[str, str] = {}
|
||||||
|
for path in paths:
|
||||||
|
for line in path.read_text().splitlines():
|
||||||
|
if match := re.match(
|
||||||
|
r'^\w+DEFINE\((\w+),\s*"([^"]+)"\)$', line.strip()
|
||||||
|
):
|
||||||
|
result[match.group(1)] = match.group(2)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def process_tr1() -> None:
|
||||||
|
strings_map = get_strings_map(GAME_STRING_DEF_PATHS)
|
||||||
|
assert strings_map
|
||||||
|
|
||||||
|
def postprocess_gameflow(
|
||||||
|
gameflow: str, strings_map: dict[str, str]
|
||||||
|
) -> str:
|
||||||
|
gameflow = re.sub(
|
||||||
|
r'^( "strings": {)[^}]*(})',
|
||||||
|
' "strings": {\n'
|
||||||
|
+ "\n".join(
|
||||||
|
f" {json.dumps(key)}: {json.dumps(value)},"
|
||||||
|
for key, value in sorted(
|
||||||
|
strings_map.items(), key=lambda kv: kv[0]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
+ "\n }",
|
||||||
|
gameflow,
|
||||||
|
flags=re.M | re.DOTALL,
|
||||||
|
)
|
||||||
|
return gameflow
|
||||||
|
|
||||||
|
for gameflow_path in TR1Paths.shipped_data_dir.rglob("*gameflow*.json*"):
|
||||||
|
old_gameflow = gameflow_path.read_text()
|
||||||
|
new_gameflow = postprocess_gameflow(old_gameflow, strings_map)
|
||||||
|
if new_gameflow != old_gameflow:
|
||||||
|
gameflow_path.write_text(new_gameflow)
|
||||||
|
|
||||||
|
|
||||||
|
def process_tr2() -> None:
|
||||||
|
GAME_STRING_DEF_PATHS = [
|
||||||
|
TR2Paths.src_dir / "game/game_string.def",
|
||||||
|
SHARED_INCLUDE_DIR / "game/game_string.def",
|
||||||
|
]
|
||||||
|
OBJECT_STRINGS_DEF_PATH = SHARED_INCLUDE_DIR / "game/objects/names_tr2.def"
|
||||||
|
|
||||||
|
def postprocess_gameflow(
|
||||||
|
gameflow: str,
|
||||||
|
object_strings_map: dict[str, str],
|
||||||
|
game_strings_map: dict[str, str],
|
||||||
|
) -> str:
|
||||||
|
gameflow = re.sub(
|
||||||
|
r'^( "object_strings": {)[^}]*(})',
|
||||||
|
' "object_strings": {\n'
|
||||||
|
+ "\n".join(
|
||||||
|
f" {json.dumps(key)}: {json.dumps(value)},"
|
||||||
|
for key, value in object_strings_map.items()
|
||||||
|
)
|
||||||
|
+ "\n }",
|
||||||
|
gameflow,
|
||||||
|
flags=re.M | re.DOTALL,
|
||||||
|
)
|
||||||
|
|
||||||
|
gameflow = re.sub(
|
||||||
|
r'^( "game_strings": {)[^}]*(})',
|
||||||
|
' "game_strings": {\n'
|
||||||
|
+ "\n".join(
|
||||||
|
f" {json.dumps(key)}: {json.dumps(value)},"
|
||||||
|
for key, value in sorted(
|
||||||
|
game_strings_map.items(), key=lambda kv: kv[0]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
+ "\n }",
|
||||||
|
gameflow,
|
||||||
|
flags=re.M | re.DOTALL,
|
||||||
|
)
|
||||||
|
return gameflow
|
||||||
|
|
||||||
|
object_strings_map = get_strings_map([OBJECT_STRINGS_DEF_PATH])
|
||||||
|
game_strings_map = get_strings_map(GAME_STRING_DEF_PATHS)
|
||||||
|
assert object_strings_map
|
||||||
|
assert game_strings_map
|
||||||
|
|
||||||
|
for gameflow_path in TR2Paths.shipped_data_dir.rglob("*gameflow*.json*"):
|
||||||
|
old_gameflow = gameflow_path.read_text()
|
||||||
|
new_gameflow = postprocess_gameflow(
|
||||||
|
old_gameflow, object_strings_map, game_strings_map
|
||||||
|
)
|
||||||
|
if new_gameflow != old_gameflow:
|
||||||
|
gameflow_path.write_text(new_gameflow)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
process_tr1()
|
||||||
|
process_tr2()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|