Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 71 additions & 85 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
@@ -1,99 +1,85 @@
name: Bug report
description: Create a report to help us understand and diagnose your issue. Your contribution is welcomed and valued! It is highly recommended that you are using the latest version before submitting a bug report.
title: "[ bug Report ]"
labels: Awaiting Triage
description: Create a report to help us understand and triage your issue.
labels:
- Awaiting Triage

body:
- type: markdown
attributes:
value: |
## Bug Report

- type: markdown
attributes:
value: |
Please follow this document in order to report a bug. It is highly recommended that you are using the latest version before submitting a bug report.
Please follow this document carefully to report a bug.

- type: dropdown
attributes:
label: TombEngine version
description: |
Please select the TombEngine Version from the dropdown list.
options:
- Development Build
- v1.8.0 (latest version)
- v1.7.1
- v1.7.0
- v1.5
validations:
required: true
> **Important**: It is highly recommended that you use the latest version before submitting a bug report.

- type: dropdown
attributes:
label: Tomb Editor version
description: |
Please select the Tomb Editor version used from the dropdown list.
options:
- Development Build
- v1.8.0 (latest version)
- v1.7.2
- v1.7.1
- v1.7.0
validations:
required: true
- type: dropdown
attributes:
label: Tomb Engine Version
description: |
Please select the TombEngine version you are using.
options:
- Development build
- v1.11 (latest public release)
- v1.10.1
validations:
required: true

- type: textarea
attributes:
label: Describe the bug
description: |
Please provide A clear and concise description of what the bug is.
placeholder: |
Your bug report here.
validations:
required: true
- type: checkboxes
attributes:
label: Development Version
description: Are you submitting this report from a development build that has not been officially released?
options:
- label: "I am using an unofficial development version."
- label: "I am using an official release."
- label: "I am using an official pre-release."
validations:
required: true

- type: textarea
attributes:
label: To Reproduce
description: |
To reproduce the behaviour, please provide detailed steps for the development team to follow. This can be done through screenshots or a written guide
- type: textarea
attributes:
label: Describe the Bug
description: |
Please provide a clear and concise description of what the issue is.
placeholder: |
Your bug report here.
validations:
required: true

**If the bug cannot be reproduced, and if the issue is not adequately explained, it will be closed without further investigation**
placeholder: |
Provide detailed reproducible steps here.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: |
Please provide detailed steps to reproduce the issue.

**Note**: If the bug cannot be reproduced or the issue is not clearly explained, it may be closed without further investigation.
placeholder: |
Step-by-step reproduction instructions here.
validations:
required: true

- type: textarea
attributes:
label: Expected Behaviour
description: |
A clear and concise description of what you expected to happen.
placeholder: |
A description of what should happen here.
validations:
required: true
- type: textarea
attributes:
label: Expected Behaviour
description: |
What did you expect to happen?

- type: textarea
attributes:
label: Additional Content
description: |
Add any other context about the problem here.
**Note**: If the bug cannot be reproduced or the issue is not clearly explained, it may be closed without further investigation.
placeholder: |
A description of what should happen here.
validations:
required: true

* Are you testing an build of a TombEngine that has not yet been released? If so please give some context.
* Did you get any asset from the TombEngine website that has presented a bug?
placeholder: |
A description of any additional content here.
validations:
required: false

- type: textarea
attributes:
label: Minimal reproduction project
description: |
**Please upload a .zip file containing your level and all assets needed to compile the level and a cut-down version of your level where the bug presents itself**
The project can be uploaded as a zip file (10 mb max) or provide a link from google drive, dropbox etc.
**Note** if you do not provide this, your issue may be rejected
placeholder: |
Download link to your project
validations:
required: true

- type: textarea
attributes:
label: Minimal Reproduction Project
description: |
Please upload a .zip file (10 MB max) containing your level and all assets needed to compile the level, including a minimal version where the bug occurs.

Alternatively, provide a download link from a cloud storage service (e.g., Google Drive, Dropbox).

> **Important**: If you do not provide a minimal reproduction project, your issue may be rejected.
placeholder: |
Download link to your project or attach a .zip file.
validations:
required: true
87 changes: 87 additions & 0 deletions .github/workflows/cross-repo-dependency.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Cross repo dependency

on:
pull_request:
types: [opened, edited, synchronize, reopened]
pull_request_review:
types: [submitted]

jobs:
check-linked-pr:
runs-on: ubuntu-latest
steps:
- name: Check for dependency
id: parse
uses: actions/github-script@v7
with:
script: |
const body = context.payload.pull_request.body || "";
const match = body.match(/Depends on:\s+([\w-]+)\/([\w-]+)#(\d+)/);

if (!match) {
// No dependency → do NOT create a status check
core.setOutput("skip", "true");
return;
}

core.setOutput("skip", "false");
core.setOutput("depOwner", match[1]);
core.setOutput("depRepo", match[2]);
core.setOutput("depNumber", match[3]);

- name: Exit early if no dependency
if: steps.parse.outputs.skip == 'true'
run: echo "No dependency found — skipping."

- name: Check linked PR status
if: steps.parse.outputs.skip == 'false'
id: check
uses: actions/github-script@v7
with:
script: |
const owner = steps.parse.outputs.depOwner;
const repo = steps.parse.outputs.depRepo;
const number = Number(steps.parse.outputs.depNumber);

const linked = await github.rest.pulls.get({
owner,
repo,
pull_number: number
});

const reviews = await github.rest.pulls.listReviews({
owner,
repo,
pull_number: number
});

const approved = reviews.data.some(r => r.state === "APPROVED");
const mergeable = linked.data.mergeable === true;

core.setOutput("approved", approved);
core.setOutput("mergeable", mergeable);

- name: Set dependency status
if: steps.parse.outputs.skip == 'false'
uses: actions/github-script@v7
with:
script: |
const approved = steps.check.outputs.approved === 'true';
const mergeable = steps.check.outputs.mergeable === 'true';

let state = "pending";
let description = "Waiting for linked PR to be approved and mergeable";

if (approved && mergeable) {
state = "success";
description = "Linked PR is approved and mergeable";
}

await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.payload.pull_request.head.sha,
state,
context: "cross-repo-dependency",
description
});
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- *Lua* as the native scripting language.
- Many objects from the original series (1-5).
- Support for high framerate, antialiasing, mipmapping, and SSAO.
- Full skinning support for all objects.
- Full diagonal geometry support.
- Uncapped map size.
- A streamlined player control scheme.
Expand Down Expand Up @@ -38,4 +39,4 @@ Once done, you should be able to build a level with *Tomb Editor* and run it in
Contributions are welcome. If you would like to participate in development to any degree, whether that be through suggestions, bug reports, or code, join our [Discord server](https://discord.gg/h5tUYFmres).

# Disclaimer
Tomb Engine uses modified MIT license for non-commercial use only. For more information, see [license](https://github.com/TombEngine/TombEngine?tab=License-1-ov-file#readme). Tomb Engine is unaffiliated with the Crystal Dynamics group of companies or Embracer Group AB. *Tomb Raider* is a trademark of the Crystal Dynamics group of companies. Tomb Engine team is not responsible for illegal use of this source code and built binaries alone or in combination with third-party assets or components. This source code is released as-is and continues to be maintained by non-paid contributors in their free time.
Tomb Engine uses modified MIT license for non-commercial use only. For more information, see [license](https://github.com/TombEngine/TombEngine?tab=License-1-ov-file#readme). Tomb Engine is unaffiliated with the Crystal Dynamics group of companies or Embracer Group AB. *Tomb Raider* is a trademark of the Crystal Dynamics group of companies. Tomb Engine team is not responsible for illegal use of this source code and built binaries alone or in combination with third-party assets or components. This source code is released as-is and continues to be maintained by non-paid contributors in their free time.
47 changes: 45 additions & 2 deletions TombEngine/Game/control/box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,15 @@ bool CreaturePathfind(ItemInfo* item, Vector3i prevPos, short angle, short tilt)
else
item->Pose.Orientation.y += BIFF_AVOID_TURN;

// Update floor height to prevent sinking through geometry when nudged by another creature.
if (LOT->Fly == NO_FLYING)
{
floor = GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &roomNumber);
item->Floor = GetFloorHeight(floor, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z);
if (item->Pose.Position.y > item->Floor)
item->Pose.Position.y = item->Floor;
}

return true;
}

Expand Down Expand Up @@ -1086,8 +1095,11 @@ bool CreaturePathfind(ItemInfo* item, Vector3i prevPos, short angle, short tilt)
floor = GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &roomNumber);
item->Floor = GetFloorHeight(floor, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z);

// Snap to floor or smoothly descend.
if (item->Pose.Position.y > item->Floor)
// Snap to floor or smoothly ascend/descend.
int heightDiff = item->Pose.Position.y - item->Floor;
if (heightDiff > CLICK(0.25f) && heightDiff <= CLICK(1))
item->Pose.Position.y -= CLICK(0.25f);
else if (item->Pose.Position.y > item->Floor)
item->Pose.Position.y = item->Floor;
else if (item->Floor - item->Pose.Position.y > CLICK(0.25f))
item->Pose.Position.y += CLICK(0.25f);
Expand Down Expand Up @@ -2144,6 +2156,31 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
auto* item = &g_Level.Items[itemNumber];
auto* creature = GetCreatureInfo(item);

// Apply a forward pivot offset when stepping up so the vault triggers when the
// creature's front half enters the next sector rather than its body centre.
int pivotOffsetX = 0;
int pivotOffsetZ = 0;
if (item->BoxNumber != NO_VALUE)
{
int nextBox = creature->LOT.Node[item->BoxNumber].exitBox;
if (nextBox != NO_VALUE &&
g_Level.PathfindingBoxes[nextBox].height < g_Level.PathfindingBoxes[item->BoxNumber].height)
{
int stepHeight = g_Level.PathfindingBoxes[item->BoxNumber].height - g_Level.PathfindingBoxes[nextBox].height;
if (stepHeight <= CLICK(1))
{
int forwardExtent = GameBoundingBox(item->ObjectNumber, item->Animation.AnimNumber, item->Animation.FrameNumber).Z2 / 2;
if (forwardExtent > 0)
{
pivotOffsetX = (int)(phd_sin(item->Pose.Orientation.y) * forwardExtent);
pivotOffsetZ = (int)(phd_cos(item->Pose.Orientation.y) * forwardExtent);
item->Pose.Position.x += pivotOffsetX;
item->Pose.Position.z += pivotOffsetZ;
}
}
}
}

int xBlock = item->Pose.Position.x / BLOCK(1);
int zBlock = item->Pose.Position.z / BLOCK(1);
int y = item->Pose.Position.y;
Expand All @@ -2169,6 +2206,8 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
}
else if (item->Pose.Position.y > (y - CLICK(1.5f)))
{
item->Pose.Position.x -= pivotOffsetX;
item->Pose.Position.z -= pivotOffsetZ;
return 0;
}
else if (item->Pose.Position.y > (y - CLICK(2.5f)))
Expand All @@ -2191,7 +2230,11 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
if (zBlock == newZblock)
{
if (xBlock == newXblock)
{
item->Pose.Position.x -= pivotOffsetX;
item->Pose.Position.z -= pivotOffsetZ;
return 0;
}

if (xBlock < newXblock)
{
Expand Down
Loading