mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
Merge branch 'develop' into sezz_fx_info_branch_port
This commit is contained in:
commit
1f32ff025d
342 changed files with 7417 additions and 11663 deletions
109
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
109
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
title: "[ bug Report ]"
|
||||
labels: Awaiting Triage
|
||||
|
||||
body:
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please follow this document in order to report a bug
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: TombEngine version
|
||||
description: |
|
||||
Please select the TombEngine Version from the dropdown list.
|
||||
options:
|
||||
- v1.4
|
||||
- v1.3
|
||||
- v1.2
|
||||
- v1.1
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Tomb Editor version
|
||||
description: |
|
||||
Please select the Tomb Editor version used from the dropdown list.
|
||||
options:
|
||||
- v1.7.1
|
||||
- v1.7.0
|
||||
- v1.6.9
|
||||
- v1.6.8
|
||||
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: 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
|
||||
|
||||
**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: 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: Screenshots
|
||||
description: |
|
||||
Please check this box if you have provided screenshots or any other media for this issue
|
||||
**note** If you do not provide screenshots or anything else, it may be hard for devs to investigate
|
||||
provide a link to your screenshot here or simply drag and drop your screenshot into this textbox
|
||||
placeholder: |
|
||||
A description of any additional content here.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Content
|
||||
description: |
|
||||
Add any other context about the problem here.
|
||||
|
||||
* 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
|
||||
|
||||
|
||||
|
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
blank_issues_enabled: false
|
||||
|
||||
# Disable blank issue
|
||||
|
||||
blank_issues_enabled: false
|
||||
|
||||
# Bug Report Form
|
||||
name: Bug Report
|
||||
description: File a bug report.
|
||||
title: "[Bug]: "
|
||||
labels: [ "Awaiting Triage" ]
|
||||
|
||||
# Initial Message
|
||||
body:
|
||||
type: markdown
|
||||
attributes:
|
||||
value: Thanks for taking the time to fill out this bug report! Please use the steps below to log the report for the development team.
|
34
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
Normal file
34
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
name: Feature Request
|
||||
description: Suggest an idea for TombEngine
|
||||
title: "[ Feature Request ] "
|
||||
labels: Awaiting Triage
|
||||
|
||||
body:
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
placeholder: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
placeholder: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
placeholder: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
placeholder: Add any other context or screenshots about the feature request here. (as a link to screenshot or drop the screenshot into this textbox)
|
||||
validations:
|
||||
required: false
|
52
AUTHORS.md
Normal file
52
AUTHORS.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
# Credit List
|
||||
|
||||
This is the credit list of **all** the people who contributed to TombEngine in any shape or form.
|
||||
|
||||
## Developers
|
||||
|
||||
- MontyTRC (Project Leader)
|
||||
|
||||
- Gancian (general coding)
|
||||
- Krystian (general coding)
|
||||
- Kubsy (Some cleanups and fixes)
|
||||
- l.m. (general coding, Lua enhancements, bug fixing)
|
||||
- Lwmte (sound refactoring, general coding, code cleanups, bug fixing)
|
||||
- Moooonyeah (Jumanji) (entity decompilation)
|
||||
- Raildex (renderer refactoring, particle coding, general coding)
|
||||
- RicardoLuis0 (general coding)
|
||||
- Sezz (player state refactoring, general coding, code cleanups, bug fixing, assets)
|
||||
- Squidshire (Hispidence) (Lua implementation, bug fixing)
|
||||
- Stranger1992 (sound asset refactoring and organisation, assets)
|
||||
- TokyoSU (entity and vehicle decompilation)
|
||||
- Tomo (general coding, bug fixing)
|
||||
- Troye (general coding, refactoring)
|
||||
- WolfCheese (general coding)
|
||||
|
||||
## Testers
|
||||
- Adngel
|
||||
- Caesum
|
||||
- Dustie
|
||||
- GeckoKid
|
||||
- JoeyQuint
|
||||
- Kamillos
|
||||
- Kubsy
|
||||
- LGG_PRODUCTION
|
||||
- Lore
|
||||
- RemRem
|
||||
- Stranger1992
|
||||
- WolfCheese
|
||||
|
||||
## Assets and Miscellaneous
|
||||
|
||||
- Geckokid (Sprites and test level creator).
|
||||
|
||||
### Animations
|
||||
- SrDanielPonces (Diagonal shimmy transitions, backwards monkey swinging)
|
||||
- Krystian (Flexibility crawlspace, slope climbing animations)
|
||||
- Sezz (Additional Animations for player state refactoring)
|
||||
- Naotheia (Underwater puzzle placement, crouch 180° turn, crawl 180° turn, water surface 180° turn)
|
||||
- JoeyQuint (Standing 180° turn, monkey swing 180° turn)
|
||||
|
||||
### TombEngine Marketing
|
||||
- Kubsy (Twitter and forum posts)
|
||||
- Stranger1992 (This website, Facebook, Instagram, Youtube and Twitch.
|
|
@ -1,16 +1,70 @@
|
|||
Version 1.4
|
||||
===========
|
||||
# Changelog
|
||||
|
||||
Here you will find the full changelog of TEN's releases from Version 1.0 and up
|
||||
|
||||
The dates are in European standard format where date is presented as **YYYY-MM-DD**
|
||||
|
||||
TombEngine releases are located in this repository (alongside with Tomb Editor): https://github.com/TombEngine/TombEditorReleases
|
||||
|
||||
## Version 1.5 - xxxx-xx-xx
|
||||
|
||||
### Bug fixes
|
||||
* Fixed original issue with classic switch off trigger incorrectly activating some trigger actions.
|
||||
* Fixed incorrect diving animation when swandiving from a high place.
|
||||
* Fixed camera rotating with the player's hips when climbing out of water.
|
||||
* Fixed AI for TR2 skidoo driver and worker with shotgun.
|
||||
* Fixed ember emitter crashing when ocb is between -1 and -10.
|
||||
* Fixed electric cleaner and squishy block not detecting collision with certain block heights.
|
||||
* Fixed squishy blocks crashing the level.
|
||||
* Fixed Larson and Pierre pathfinding.
|
||||
* Fixed torch flame delay when the player throws or drops a torch.
|
||||
* Fixed dart emitters failing with antitrigger.
|
||||
* Fixed homing dart emitter spawning darts continously when player is on its trigger.
|
||||
* Fixed four blade trap floor and ceiling collision.
|
||||
* Fixed Joby spikes collision and deformation.
|
||||
* Fixed sentry gun joint rotation.
|
||||
* Fixed teeth spikes not triggering the player impale animation.
|
||||
* Fixed TR4 mine crash with OCB 1 when triggered.
|
||||
|
||||
### Features/Amendments
|
||||
* Changed Rome Hammer to not hurt player whilst deactivated.
|
||||
* Changed Statue with blade damage, from 20 to 200.
|
||||
* Enhaced Rolling Spindle detection to avoid them going down through pits.
|
||||
* Enhaced Sentry Guns, with a new ItemFlags[3], to contain the ID of the inventory item that deactivates the sentry guns ( by default PUZZLE_ITEM5 )
|
||||
* Enhaced Dart Emitter, with a new ItemFlags[0], to contain the number of frames between shots ( by default 32 in dart emitter, and 24 in homing dar emitter ).
|
||||
* Add new sound conditions: quicksand and Underwater.
|
||||
- Quicksand - sound effect plays when a moveable is in quicksand.
|
||||
- Underwater - sound plays when the camera is submerged.
|
||||
* Changed Water sound condition to ShallowWater.
|
||||
|
||||
### Lua API changes
|
||||
* Added Inventory.GetUsedItem(), Inventory.SetUsedItem() and Inventory.ClearUsedItem() functions.
|
||||
* Added Input.KeyClearAll()
|
||||
* Removed anims.monkeyAutoJump. It is now a player menu configuration.
|
||||
|
||||
## [Version 1.4](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.7.1) - 2024-04-21
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed drawing of display sprites in title level.
|
||||
* Fixed drawing of smoke sprites and various other sprites.
|
||||
* Fixed drawing of transparent surfaces when debris are present in scene.
|
||||
* Fixed player holster state and current vehicle not preserved correctly on level jump.
|
||||
* Fixed diving when swimming over sinks.
|
||||
* Fixed fire item effect not extinguishing in water.
|
||||
* Fixed fade-in and fade-out effects not canceling correctly when next level is loaded.
|
||||
* Fixed shadows still being visible after shattering a moveable.
|
||||
* Fixed FOV interpolation at the end of the flyby sequence.
|
||||
* Fixed sounds resuming in pause mode while switching between apps.
|
||||
* Fixed slide directions.
|
||||
* Fixed occasional collision warnings in a log when teeth spikes object was activated.
|
||||
* Fixed climbable pushables collision during continuous pulling action.
|
||||
* Fixed collision for solid static meshes with zero collision box.
|
||||
* Fixed bottom collision for solid static meshes.
|
||||
* Fixed T-Rex's head rotation.
|
||||
|
||||
### Features/Amendments
|
||||
* Auto-switch to a crawl state if player start position is in a crawlspace.
|
||||
* Allow directional flame emitter (negative OCBs) to be rotated at any angle.
|
||||
* Revise wall spikes:
|
||||
- Wall spikes now stop when they touch a pushable, another spike wall or a normal wall.
|
||||
- Wall spikes will shatter any shatter in its path.
|
||||
|
@ -23,16 +77,17 @@ Version 1.4
|
|||
* Added TR3 Winston (requires updated TEN .wad2 on TombEngine.com).
|
||||
* Added TR4 squishy blocks (requires updated TEN .wad2 on TombEngine.com).
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Added resetHub flag to Flow.Level, which allows to reset hub data.
|
||||
* Added Flow.GetFlipMapStatus() function to get current flipmap status.
|
||||
* Added Moveable:GetMeshCount() function to get number of moveable meshes.
|
||||
* Added timeout parameter for Moveable:Enable() function.
|
||||
* Added Static:GetHP() and Static:SetHP() functions to change shatterable static mesh hit points.
|
||||
* Fixed Moveable:SetOnCollidedWithObject() callback.
|
||||
|
||||
Version 1.3
|
||||
===========
|
||||
## [Version 1.3](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.7) - 2024-01-06
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed crash if title logo is removed from Textures folder.
|
||||
* Fixed crash if unknown player state ID is encountered.
|
||||
* Fixed bug with OCB 2 on pushables, and some other pushable bugs.
|
||||
|
@ -52,7 +107,9 @@ Version 1.3
|
|||
* Fixed big static objects affected wrongly by dynamic lights.
|
||||
* Fixed legacy trigger leveljumps ignoring provided level index.
|
||||
* Fixed incorrect light collection in some cases.
|
||||
* Fixed normal mapping for rooms, items, and statics.
|
||||
* Fixed normal mapping for rooms, items, and statics.'
|
||||
|
||||
### Features/Amendments
|
||||
* Added ambient occlusion (SSAO).
|
||||
* Added new post-process workflow (monochrome, negative, exclusion) with tinting.
|
||||
* Added SMAA antialiasing instead of MSAA.
|
||||
|
@ -76,7 +133,7 @@ Version 1.3
|
|||
- OCB 0: Wolf starts in walking animation, ready to chase Lara.
|
||||
- OCB 1: Wolf starts in sleeping animation.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Added Lara:GetInteractedMoveable() which returns currently interacted moveable by Lara.
|
||||
* Added Moveable:SetStatus() to set the current status of the moveable.
|
||||
* Added Room:GetColor() to get room's ambient light color.
|
||||
|
@ -84,9 +141,9 @@ Lua API changes:
|
|||
* Added View.GetCameraPosition(), View.GetCameraTarget() and View.GetCameraRoom() functions.
|
||||
* Added View.SetPostProcessMode(), View.SetPostProcessStrength() and View.SetPostProcessTint() functions.
|
||||
|
||||
Version 1.2
|
||||
===========
|
||||
## [Version 1.2](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.9) - 2023-11-11
|
||||
|
||||
### Bug Fixes
|
||||
* Fix burning torch not working properly if there are more than 256 objects in a level.
|
||||
* Fix grenade and rocket projectiles smoke offset in certain directions.
|
||||
* Fix projectiles flying through animating objects.
|
||||
|
@ -110,30 +167,32 @@ Version 1.2
|
|||
* Fix non-elevated combat camera.
|
||||
* Fix camera snap when disengaging the look-around mode.
|
||||
* Fix TR4 mapper not being visible.
|
||||
|
||||
### Features/Amendments
|
||||
* Improve head-on wall collision.
|
||||
* Overhaul pushables:
|
||||
- Separate climbable and non-climbable pushable object slots.
|
||||
- Add new pushable OCB to manipulate pushable properties.
|
||||
- Add new animations for pushing pushables off edgees (TR1-3 and TR4-5 versions).
|
||||
- Fix pushables not working with raising blocks.
|
||||
- Fix miscellaneous pushable bugs.
|
||||
- Separate climbable and non-climbable pushable object slots.
|
||||
- Add new pushable OCB to manipulate pushable properties.
|
||||
- Add new animations for pushing pushables off edgees (TR1-3 and TR4-5 versions).
|
||||
- Fix pushables not working with raising blocks.
|
||||
- Fix miscellaneous pushable bugs.
|
||||
* Overhaul look-around feature:
|
||||
- Allow for more consistent and wider viewing angles while crawling, crouching, and hanging.
|
||||
- Improve look camera movement and control.
|
||||
- Re-enable looking while performing up jump, backward jump, or backward crawl.
|
||||
- Add functionality to rotate slowly when holding Walk while using binoculars or lasersight.
|
||||
- Allow for more consistent and wider viewing angles while crawling, crouching, and hanging.
|
||||
- Improve look camera movement and control.
|
||||
- Re-enable looking while performing up jump, backward jump, or backward crawl.
|
||||
- Add functionality to rotate slowly when holding Walk while using binoculars or lasersight.
|
||||
* Add target highlighter system with toggle in Sound and Gameplay settings.
|
||||
* Add sprint slide state 191.
|
||||
* Add swinging blade.
|
||||
* Add crumbling platform and add new OCBs for behaviour:
|
||||
- OCB 0: Default behaviour. When the player steps on the platform, it will shake and crumble after 1.2 seconds.
|
||||
- OCB > 0: When the player steps on the platform, it will crumble after the number of frames set in the OCB.
|
||||
- A positive value results in activation via player collision.
|
||||
- A negative value requires a trigger to activate.
|
||||
- OCB 0: Default behaviour. When the player steps on the platform, it will shake and crumble after 1.2 seconds.
|
||||
- OCB > 0: When the player steps on the platform, it will crumble after the number of frames set in the OCB.
|
||||
- A positive value results in activation via player collision.
|
||||
- A negative value requires a trigger to activate.
|
||||
* Add basic mouse input handling. Allows for binding of mouse inputs in control settings.
|
||||
* Add settings for Mouse Sensitivity and Mouse Smoothing (not used in-game yet).
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Split and organize functions in `Misc` namespace to appropriate new namespaces.
|
||||
* Make Vec2 and Vec3 objects float-based instead of integer-based.
|
||||
* Add DisplaySprite object.
|
||||
|
@ -159,9 +218,9 @@ Lua API changes:
|
|||
* Add DisplayString::SetScale() function to resize text.
|
||||
* Add DisplayString::GetScale() function to get text scale.
|
||||
|
||||
Version 1.1.0
|
||||
==============
|
||||
## [Version 1.1.0](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.8) - 2023-07-29
|
||||
|
||||
### Bug Fixes
|
||||
* Fix enemies shooting Lara through static meshes and moveables.
|
||||
* Fix skeletons and mummies not being affected by explosive weapons.
|
||||
* Fix crash on loading if static meshes with IDs above maximum are present.
|
||||
|
@ -191,6 +250,8 @@ Version 1.1.0
|
|||
* Fix room collector freezing game on some occasions.
|
||||
* Fix incorrect culling for scaled static meshes.
|
||||
* Fix normal mapping.
|
||||
|
||||
### Features/Amendments
|
||||
* Add ability to save screenshot in the "Screenshots" subfolder by pressing the "Print screen" key.
|
||||
* Implement separate audio track channel for playing voiceovers with subtitles in .srt format.
|
||||
* Don't stop ambience when Lara dies.
|
||||
|
@ -208,15 +269,15 @@ Version 1.1.0
|
|||
* Add TR1 skateboard kid.
|
||||
* Add TR1 Kold.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Add soundtrack functions:
|
||||
- Misc::GetAudioTrackLoudness() for getting current loudness of a given track type.
|
||||
- Misc::IsAudioTrackPlaying() for checking if a given track type is playing.
|
||||
- Misc::GetCurrentSubtitle() for getting current subtitle string for the voice track.
|
||||
|
||||
Version 1.0.9
|
||||
=============
|
||||
## [Version 1.0.9](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.7) - 2023-06-03
|
||||
|
||||
### Bug fixes
|
||||
* Fix cold bar triggered in non-water rooms.
|
||||
* Fix spiky wall speed value and change it via OCB number or Lua (Moveable::SetItemFlags[0]).
|
||||
* Fix bats emitter crashing the game if little beetle object does not exist in wad.
|
||||
|
@ -237,6 +298,8 @@ Version 1.0.9
|
|||
* Fix grenade firing angle.
|
||||
* Fix rendering for static meshes with custom blending modes and alpha transparency.
|
||||
* Fix inconsistent multiline string spacing on different display modes.
|
||||
|
||||
### Features/Amendments
|
||||
* Remove search object 4 hardcoded meshswap activated with a flipmap.
|
||||
* Add TR1 cowboy.
|
||||
* Add TR3 wall mounted blade.
|
||||
|
@ -262,7 +325,7 @@ Version 1.0.9
|
|||
* Add "Reset to defaults" entry to controls menu and automatically bind XBOX gamepad profile if connected.
|
||||
* Add 64-bit executable and place both 32-bit and 64-bit versions into /Bin subdirectory.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Add Vec2 class.
|
||||
* Add function String::SetTranslated().
|
||||
* Add function Misc::IsStringDisplaying().
|
||||
|
@ -272,9 +335,9 @@ Lua API changes:
|
|||
- PRESAVE, POSTSAVE
|
||||
- PRELOAD, POSTLOAD
|
||||
|
||||
Version 1.0.8
|
||||
=============
|
||||
## [Version 1.0.8](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.6) - 2023-04-10
|
||||
|
||||
### Bug fixes
|
||||
* Fix bubbles phasing through ceilings.
|
||||
* Fix object camera not clearing at level end.
|
||||
* Fix double breath sound effect when coming up for air.
|
||||
|
@ -293,6 +356,8 @@ Version 1.0.8
|
|||
- Imp is also scared of of the player if holding a lit torch.
|
||||
- Please note you must use the patched version found here: https://github.com/TombEngine/Resources/blob/main/Wad2%20Objects/tr5_Imp.wad2
|
||||
* Fix and improve wraith tails.
|
||||
|
||||
### Features/Amedments
|
||||
* Add dedicated WRAITH_TRAP object with enhanced effects.
|
||||
- OCB 0: Effect disabled.
|
||||
- OCB 1: Effect enabled.
|
||||
|
@ -313,13 +378,13 @@ Version 1.0.8
|
|||
* Restored inventory compass.
|
||||
* Allow dynamic segment count for hair object.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Add function Misc::IsSoundPlaying()
|
||||
* Add function DisplayString::SetFlags()
|
||||
|
||||
Version 1.0.7
|
||||
=============
|
||||
## [Version 1.0.7](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.5) - 2023-02-26
|
||||
|
||||
### Bug fixes
|
||||
* Fix spark particles not being cleared on level reload.
|
||||
* Fix visible but inactive enemies (e.g. Shiva or Xian guardians) taking damage.
|
||||
* Fix blockable LOT type enemies (e.g. T-Rex and Shiva) not being able to step up 1 click or drop 2 clicks.
|
||||
|
@ -340,6 +405,8 @@ Version 1.0.7
|
|||
- Killing move for spear used wrong value.
|
||||
* Fix TR3 big gun spawning rocket with 0 life which caused an immediate explosion.
|
||||
* Fix TR3 Tony and add boss effect for him.
|
||||
|
||||
### Features/Amendments
|
||||
* Add TR3 civvy.
|
||||
* Add TR3 electric cleaner.
|
||||
* Add TR3 Sophia Leigh with following OCBs:
|
||||
|
@ -357,14 +424,14 @@ Version 1.0.7
|
|||
* Prevent Lara from drawing weapons during parallel bar swinging.
|
||||
* Further renderer performance optimizations and bugfixes.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Fix Camera:SetPosition not updating camera position when it is played simultaneously.
|
||||
* Add Moveable:GetAirborne and Moveable:SetAirborne.
|
||||
* Add Moveable:GetLocationAI and Moveable:SetLocationAI.
|
||||
|
||||
Version 1.0.6
|
||||
=============
|
||||
## [Version 1.0.6](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.4) - 2023-01-29
|
||||
|
||||
### Bug FIxes
|
||||
* Fix major pathfinding bug which could have caused lots of issues with enemy behaviour.
|
||||
* Fix potential random crashes due to incorrect rendering behaviour.
|
||||
* Fix savegame crash for disabled enemies with partially set activation mask.
|
||||
|
@ -390,6 +457,8 @@ Version 1.0.6
|
|||
* Fix grenade launcher super ammo emitting too many fragments.
|
||||
* Fix grenade and rocket launcher lighting.
|
||||
* Fix ceiling trapdoor and floor trapdoor that Lara couldn't open manually.
|
||||
|
||||
### Features/Amendments
|
||||
* Make enemies drop pickups at first available bounding box corner point, not centerpoint.
|
||||
* Restore original volumetric explosion effects.
|
||||
* Add TR3 lizard and Puna.
|
||||
|
@ -401,7 +470,7 @@ Version 1.0.6
|
|||
* Lua Moveable functions Enable and Disable now correctly trigger and antitrigger the moveable.
|
||||
* Improve level loading speed a lot.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Moveable:SetVisible has been added. MakeInvisible is now an alias for SetVisible(false).
|
||||
* Moveable:MeshIsVisible is now GetMeshVisible.
|
||||
* Moveable:SetMeshVisible has been added to replace ShowMesh/HideMesh.
|
||||
|
@ -413,9 +482,9 @@ Lua API changes:
|
|||
* Add new function Misc::GetCameraType()
|
||||
* Add new functions Moveable:GetAirborne() and Moveable:SetAirborne(bool input)
|
||||
|
||||
Version 1.0.5
|
||||
=============
|
||||
## [Version 1.0.5](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.3) - 2022-12-30
|
||||
|
||||
### Bug fixes
|
||||
* Fix combined items not existing in inventory upon game reload.
|
||||
* Fix classic rollingball not behaving properly in rooms beyond the distance of 32 blocks.
|
||||
* Fix rollingball not killing Lara under certain movement angles.
|
||||
|
@ -440,6 +509,8 @@ Version 1.0.5
|
|||
* Fix rare crash when smash item is inside a wall and add warning log for the scenario.
|
||||
* Fix bone rotations of some entities.
|
||||
* Fix Lara's animation for cog switch release.
|
||||
|
||||
### Features/Amendments
|
||||
* Added new OCB to cog switch object:
|
||||
- Use OCB 0 to have the traditional behaviour.
|
||||
- Use any other OCB to can use the Cog Switch without need of any door linked.
|
||||
|
@ -448,12 +519,12 @@ Version 1.0.5
|
|||
* Draw real mesh for darts.
|
||||
* Added warning log when one slot requires another slot which is missing.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Add new Room class and several methods for it.
|
||||
|
||||
Version 1.0.4
|
||||
=============
|
||||
## [Version 1.0.4](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.2) - 2022-12-16
|
||||
|
||||
### Features/Amendments
|
||||
* Add generic assignable effects for moveables - fire, sparks, smoke and laser / electric ignite.
|
||||
* Add ability to burn enemies with FLAME_EMITTER_1 and death blocks.
|
||||
* Add wireframe mode and other visual debug information (switch by F10/F11 debug page scroll hotkeys).
|
||||
|
@ -475,6 +546,8 @@ Version 1.0.4
|
|||
* SAS enhancements:
|
||||
- Fix grenade shooting.
|
||||
- Fix AI_MODIFY and AI_GUARD behaviour.
|
||||
|
||||
### Bug fixes
|
||||
* Fix choppy camera movement in several cases.
|
||||
* Fix Lara's vertical position when shimmying around steep slope corners.
|
||||
* Fix legacy pickup triggers not working in certain cases.
|
||||
|
@ -503,7 +576,7 @@ Version 1.0.4
|
|||
* Fix current soundtrack fading into silence if incoming one doesn't exist.
|
||||
* Fix crash if there is an attempt to display a string with missing characters.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Add new Volume class and several methods for it.
|
||||
* Add new Moveable functions: GetEffect, SetEffect and SetCustomEffect (for colored fire).
|
||||
* Add new Lara functions: GetTarget, GetVehicle and TorchIsLit.
|
||||
|
@ -521,9 +594,9 @@ Lua API changes:
|
|||
* Fix Rotation class using integers under the hood which prevented using fractional rotation values.
|
||||
* Fix distance tests failing on a very high distances.
|
||||
|
||||
Version 1.0.3
|
||||
=============
|
||||
## [Version 1.0.3](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6.1) - 2022-11-18
|
||||
|
||||
### Features/Amendments
|
||||
* Add ledge jumps (Lara object must be updated with new animations to make it work).
|
||||
* Allow any object slot to be used as a meshswap.
|
||||
* Add OCB 1 for rollingball to make it silent.
|
||||
|
@ -536,6 +609,8 @@ Version 1.0.3
|
|||
* Improve game and inventory input handling.
|
||||
* Adjust sprint jump timing.
|
||||
* Backport DAMOCLES_SWORD from TR1.
|
||||
|
||||
### Bug fixes
|
||||
* Fix going into inventory and load/save dialogs during fade-ins and fade-outs.
|
||||
* Fix savegames not preserving save number and game timer.
|
||||
* Fix dodgy weapon lock angle constraints.
|
||||
|
@ -567,7 +642,7 @@ Version 1.0.3
|
|||
* Fix SAS_DRAG_BLOKE object interaction.
|
||||
* Fix KILLER_STATUE not triggering.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* A new class has been added, LaraObject, for Lara-specific functions. The built-in "Lara" variable now uses this class.
|
||||
* Add functions for Lara object:
|
||||
- GetPoison / SetPoison
|
||||
|
@ -587,9 +662,9 @@ Lua API changes:
|
|||
* Add SetTotalSecretCount option to gameflow script to set overall amount of secrets.
|
||||
* Raised the maximum value on Moveable.SetHP to 32767 (its internal numeric maximum).
|
||||
|
||||
Version 1.0.2
|
||||
=============
|
||||
## [Version 1.0.2](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.6) - 2022-09-16
|
||||
|
||||
### Features/Amendments
|
||||
* Fix removing Pistols with TakeItem and SetItemCount.
|
||||
* Allow saving and loading of Vec3s in LevelVars and GameVars.
|
||||
* Support volume triggers made with node editor.
|
||||
|
@ -613,7 +688,8 @@ Version 1.0.2
|
|||
- 5 for valve turn
|
||||
- 6 for hole switch
|
||||
- any other OCBs play corresponding switch on anim or OCB+1 switch off anim.
|
||||
|
||||
|
||||
### Bug fixes
|
||||
* Fix incorrect pole mounting.
|
||||
* Fix zeroed forward velocity upon landing.
|
||||
* Fix incorrect behaviour when falling on statics from the top after monkeyswing.
|
||||
|
@ -627,7 +703,7 @@ Version 1.0.2
|
|||
* Fix stargate blades needlessly pushing the player around while hardly doing any damage.
|
||||
* Fix weapon hotkeys and add missing crossbow hotkey.
|
||||
|
||||
Lua API changes:
|
||||
### Lua API changes
|
||||
* Util.ShortenTENCalls no longer needs to be called; it is now automatic for both level scripts and Gameflow.lua.
|
||||
* Flow.InvID has been removed; any function taking a pickup (e.g. GiveItem) now takes an Objects.ObjID instead.
|
||||
* Add Enable, Disable, GetActive, Get/SetSolid functions for static meshes.
|
||||
|
@ -641,12 +717,14 @@ Lua API changes:
|
|||
* Rework GiveItem, TakeItem, and SetItemCount (e.g. SetItemCount with a value of -1 can give infinite ammo/consumables).
|
||||
|
||||
|
||||
Version 1.0.1
|
||||
=============
|
||||
## [Version 1.0.1](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.5.2) - 2022-08-16
|
||||
|
||||
### Features
|
||||
* Added antialiasing support.
|
||||
* Added static mesh scaling support.
|
||||
* Added free rotation for teeth spikes instead of using OCB codes.
|
||||
|
||||
### Bug fixes
|
||||
* Fix some issues with shimmying between diagonal ledges and walls.
|
||||
* Fix rope transparency.
|
||||
* Fix objects disappearing under certain angles at the edges of the screen.
|
||||
|
@ -664,6 +742,8 @@ Version 1.0.1
|
|||
* Fix falling through twoblock platform on room number change.
|
||||
* Fix falling block breaking too early if placed on a vertical portal.
|
||||
* Fix crashes when loading image files are missing.
|
||||
|
||||
### Amendments
|
||||
* Disable trigger check for puzzle holes.
|
||||
* Clear locusts and other swarm enemies on level reload.
|
||||
* Enhance cobra AI and fix targeting.
|
||||
|
@ -679,7 +759,6 @@ Version 1.0.1
|
|||
* EventSequence.lua has been added and documented.
|
||||
|
||||
|
||||
Version 1.0
|
||||
===========
|
||||
## [Version 1.0](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.5.1) - 2022-08-06
|
||||
|
||||
First beta release.
|
82
CODE_OF_CONDUCT.md
Normal file
82
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
TombEngine Discord Server.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
377
CONTRIBUTING.md
Normal file
377
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,377 @@
|
|||
What you will read under has been agreed by the current active team in order to keep a good flow of work and proper management. You are welcome to put suggestions in the comments in order to discuss it with the TEN team.
|
||||
|
||||
# Contributor General rules
|
||||
|
||||
**1. Developer**
|
||||
|
||||
- If you wish to contribute to the TEN project, you must read and follow the coding convention used by the team, available here: https://github.com/MontyTRC89/TombEngine/blob/master/CONTRIBUTING.md#coding-conventions
|
||||
- Do not work directly on master nor any branch which may be developed by several members. Create your branch, and name it with a clear description of the feature/set of features you are working on. You may regularly merge/rebase master or the active development branch with yours.
|
||||
- Be respectful to other developers. Disagreements may occur on code style, changes, and should be discussed directly with the person who pushed or merged the commit/branch. If you are unsure of what some parts of the code means, or why a decision was made, contact the team as a whole so they can be explained to you.
|
||||
- Do not make a pull request until your branch and features are extensively tested by the QA team. You are invited to test your feature set as much as you can too.
|
||||
- If you are allowed to merge PRs, do not do such until code has been properly reviewed, preferably by more than one person.
|
||||
- Merge PRs using **squash and merge** mode to preserve main branch history in original state. For squash merge commit, leave list of commits in commit description (GitHub does it automatically in both desktop client and web interface).
|
||||
- Do not revert active development branch to a previous commit unless you are absolutely sure there will be no regressions. Do not revert parts of code to a previous state for the same reasons. In both of those cases, the entire team needs to be aware of it and agree on the decision.
|
||||
- There are **two key branches**: `master` and `develop`. `master` is to be used for releases, and nothing else. `develop` is based on `master` and is used for active development, **Every PR should use it as its base**. To keep in sync, for release period they are to be merged in the following order: `develop` -> `master`.
|
||||
|
||||
**2. Tester**
|
||||
|
||||
- Be respectful with the developer you are testing the feature of.
|
||||
- New features or bug fixes should be tested with several use cases, if not all possible use cases you can think of, of this feature. This avoids going back to it in the future because of missed test cases.
|
||||
- Pay attention to any regressions. Developer may have touched part of the code that could break other linked or unlinked features. Features or bug fixes can't be considered done if there are any regression elsewhere.
|
||||
|
||||
## Issues handling
|
||||
|
||||
**1. General**
|
||||
|
||||
- Preferably, write one issue for one specific bug. List of bugs should stay rare, unless they are closely related to each other.
|
||||
- Follow the progress of features/fixes on the project board.
|
||||
- Do not assign a dev to an issue. They will do so themselves
|
||||
- Carefully choose the labels you add to the issue
|
||||
|
||||
**2. Developer**
|
||||
|
||||
- Assign yourself to an issue you want to work on available in the To do column of the project board. Add this feature to the "In progress" column. Make the team know you are working on it both by adding a comment to it and via Discord, on the strategy channel of Tomb Engine.
|
||||
- Regularly update the status of the task by adding comments. If you are stuck, let other people know if they can help.
|
||||
- Do not pass an issue as done unless fixes or features are fully tested and merged with active dev branch
|
||||
|
||||
**3. Tester**
|
||||
|
||||
- Give the Developer as much detail as you can about the bug you're writing for, and an easy way to reproduce it.
|
||||
- Update and comment the issue with the tests you've done and your findings after fixes.
|
||||
|
||||
# Coding Conventions
|
||||
|
||||
## General Rules
|
||||
|
||||
* **Do not silently comment out any lines or change operators or conditional statements**, even for testing purposes. Should you comment out certain code, also leave a comment beginning with `TODO` prefix, and date-author signature, like this:
|
||||
|
||||
``` c
|
||||
// TODO: This code caused NPCs to run into walls, so it is disabled for now. -- Lwmte, 21.08.19
|
||||
// GetBoundsAccurate(blah);
|
||||
```
|
||||
|
||||
* **Do not modify existing code without a clear understanding of what it does.** Even if you think you are fixing bugs or restoring original behavior by reverting the code, consult the TombEngine discord before committing any changes. It is possible you may ruin the work of other people since the original Core Design codebase is very fragile and it is very easy to falsely identify code as bugged.
|
||||
|
||||
* **Do not introduce quick hacks to fix issues**. Hacks like `if (room == 314)` or `if (direction == WEST)` should be left in the history of bad Core Design coding practices.
|
||||
|
||||
* If code remains unimplemented or you need to visit another part of the code for a considerable amount of time to implement missing functionality for that first part of code, **leave a comment** prefixed `FIXME` and with a date-author signature, describing missing functionality that you are about to add:
|
||||
|
||||
``` c
|
||||
// FIXME: I need to precisely calculate floor height, but for now let's keep original. -- Lwmte, 21.08.19
|
||||
foo = GetFloor(blah);
|
||||
```
|
||||
|
||||
* Make sure that **any new code is warning-free** before committing. Exceptions to this guideline include cases where fixing warnings would require you to make many changes outside of the new code, where the warning originates from a 3rd-party library, or where fixing the warning would make the code significantly less readable or performant.
|
||||
|
||||
* Avoid using magic numbers. Use constants or enums instead.
|
||||
|
||||
* Use **American English**.
|
||||
|
||||
## Parenthesis and new lines
|
||||
|
||||
Please do not write like this:
|
||||
|
||||
``` c
|
||||
if (blah) {
|
||||
foo;
|
||||
foo_foo;
|
||||
} else {
|
||||
bar;
|
||||
bar_bar; }
|
||||
```
|
||||
|
||||
Write like this instead:
|
||||
|
||||
``` c
|
||||
if (blah)
|
||||
{
|
||||
foo;
|
||||
foo_foo;
|
||||
}
|
||||
else
|
||||
{
|
||||
bar;
|
||||
bar_bar;
|
||||
}
|
||||
```
|
||||
|
||||
However, if you have only one line enclosed (i. e. only `foo`), and there are no following `else` or `else if` conditions, you may omit brackets and do it like this:
|
||||
|
||||
``` c
|
||||
if (blah)
|
||||
foo;
|
||||
```
|
||||
|
||||
For one-line if statements, if the condition itself is multi-line, brackets should be added anyway to maintain readability:
|
||||
|
||||
```
|
||||
if (item.RoomNumber == 123 || IsHeld(In::Action) &&
|
||||
LaraHasEatenSandwich == SANDWICH_BACON)
|
||||
{
|
||||
CurrentLevel = 4;
|
||||
}
|
||||
```
|
||||
|
||||
Same rule applies to loops.
|
||||
|
||||
Avoid multiple nested conditional statements. Where possible, do an early exit from the code using the opposite statement instead of enclosing the statement body in an extra set of brackets. For example, instead of this:
|
||||
|
||||
``` c
|
||||
if (blah)
|
||||
{
|
||||
if (foo)
|
||||
bar;
|
||||
}
|
||||
```
|
||||
|
||||
Write this:
|
||||
|
||||
``` c
|
||||
if (!blah || !foo)
|
||||
return;
|
||||
|
||||
bar;
|
||||
```
|
||||
|
||||
## Spacing
|
||||
|
||||
Don't condense arguments, loop statements, or any other code which requires splitting with commas/semicolons or operators like this:
|
||||
|
||||
``` c
|
||||
void SomeLoop(int blah,int blah2)
|
||||
{
|
||||
for(int i=0;i<4;i++)
|
||||
{
|
||||
bar =blah;
|
||||
foo= blah2;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Instead, separate everything with spaces **on the both sides** of operator, and **after** the comma or semicolon, like this:
|
||||
|
||||
``` c
|
||||
void SomeLoop(int blah, int blah2)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
bar = blah;
|
||||
foo = blah2;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The same rule applies to any code body, not only function declarations or loop statements.
|
||||
|
||||
## Tabulation and indents
|
||||
|
||||
When you have numerous assignment operations in a row, and/or their names are somewhat of equal length, and their data types are similar, align "left" and "right" parts of the assignment using tabs most of the way and spaces the rest of the way, like this:
|
||||
|
||||
``` c
|
||||
float foo = 1.0;
|
||||
float bar_bar = 1.0;
|
||||
float foo_o_o = 1.0;
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
``` c
|
||||
bar = foo-foo-foo;
|
||||
foo_o = bar;
|
||||
bar_r_r = foo;
|
||||
```
|
||||
|
||||
In case you have pointers defined along with "normal" variables, the asterisk symbol must be placed instead of the last tab's space symbol (this also applies for class declarations and/or implementations), like this:
|
||||
|
||||
``` c
|
||||
bar = foo_foo;
|
||||
*foo = &bar_bar;
|
||||
```
|
||||
|
||||
Of course, if one's left part is way longer than another one's left part, there's no need for such alignment, so you can leave it like this:
|
||||
|
||||
``` c
|
||||
*foo_foo = &bar_foo;
|
||||
bar->foo_foo_foo.blah_blah_bar_foo = 1.0;
|
||||
foo_bar = 1.0;
|
||||
```
|
||||
In a switch case, each case body must be one tab further case's own label. Like this:
|
||||
|
||||
``` c
|
||||
switch (blah)
|
||||
{
|
||||
case foo:
|
||||
foo - foo - foo;
|
||||
foo - foo - foo - foo;
|
||||
break;
|
||||
|
||||
case bar:
|
||||
bar - bar;
|
||||
bar - bar - bar;
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
If you need to enclose a particular case into a bracket block, put the body one tab further:
|
||||
|
||||
``` c
|
||||
switch (blah)
|
||||
{
|
||||
case foo:
|
||||
{
|
||||
float bar;
|
||||
bar = foo - foo - foo;
|
||||
foo - foo - foo - foo = bar;
|
||||
break;
|
||||
}
|
||||
|
||||
case bar:
|
||||
bar - bar;
|
||||
bar - bar - bar;
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
## Code splitting
|
||||
|
||||
If a code block becomes too large, it is recommended to split it into several "sub-blocks" with empty lines, taking each sub-block's meaning into account, like this:
|
||||
|
||||
``` c
|
||||
foo = foo_foo + foo_foo_foo;
|
||||
if (foo)
|
||||
foo - foo - foo - foo - foo;
|
||||
foo - foo = foo;
|
||||
|
||||
bar = (bar - bar > bar) ? (bar - bar) : 0;
|
||||
bar - bar - bar = bar - bar - bar;
|
||||
```
|
||||
|
||||
Conditional statements, if there are many, should be grouped according to their meaning. That is, if you are doing early exit from the function because of different conditions, group them as such:
|
||||
|
||||
``` c
|
||||
if (coll.Floor > CLICK(1) && coll.Ceiling < CLICK(3) && bounds.Y1 > WALL_SIZE)
|
||||
return false;
|
||||
|
||||
if (enemy.health <= 0 || lara.health <= 0 || collidedItems[0] == nullptr)
|
||||
return false;
|
||||
```
|
||||
|
||||
However, if there are few conditional statements, you can group them together. The rule of thumb is if there are more than three conditional statements and two of them are of a different kind, split them. This variant is allowed:
|
||||
|
||||
``` c
|
||||
if (coll.Floor > CLICK(2) && coll.Ceiling < CLICK(4) || lara.health <= 0)
|
||||
return false;
|
||||
```
|
||||
|
||||
Sometimes IDA decompiled output generates "pascal-styled" or "basic-styled" variable declarations at the beginning of the function or code block. Like this:
|
||||
|
||||
``` c
|
||||
int foo, bar = 0;
|
||||
float blah;
|
||||
...
|
||||
blah = foo;
|
||||
foo = bar;
|
||||
...
|
||||
```
|
||||
|
||||
**Please**, get rid of this style everywhere you see it and declare variables in the place narrowest to its actual usage, like this:
|
||||
|
||||
``` c
|
||||
int foo = foo;
|
||||
float blah = bar;
|
||||
...
|
||||
```
|
||||
|
||||
Let's cite [Google Style Guide](https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Local_Variables) here:
|
||||
|
||||
> Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.
|
||||
|
||||
## Naming
|
||||
|
||||
* Use `auto` where possible and if the original type name is longer than `auto`. E.g. there is no point in changing `bool enabled = true` to `auto enabled = true`. Remember that C++ `auto` **is not similar to C#** `var`, and for referencing existing value with `auto`, you should add `&` to it in the end, e.g. `auto& item = g_Level.Items[itemIndex];` Also, for underlying pointer types, please write `auto*` instead of `auto`, even if it seems redundant.
|
||||
|
||||
* Avoid using Hungarian notation for function names. Currently, inconsistent notation indicates an unrefactored coding style, because the original code used inconsistent naming, like `SOUND_Stop()`, `have_i_got_object()` or `gar_SuperpackYXZ()`. These should eventually be eradicated along the course of code restyling. For new function names, `PascalCase` should be used.
|
||||
|
||||
* For global struct or class members or methods, `PascalCase` should be used. For local variable names, `camelCase` should be used. For global variables, which are temporary until full refactoring occurs, an exclusive case of Hungarian notation with the `g_` prefix (e.g. `g_Foo`) is permitted.
|
||||
|
||||
* Functions designed to take an enum argument should take the enum type itself instead of an int or short. `PassInfo(InfoEnum type)` is more readable and error-proof than `PassInfo(int type)`.
|
||||
|
||||
* Functions designed to return boolean value (0 or 1) should define return type as bool. Please don't use `int` return type and don't write `return 0` or `return 1` in bool return functions, use `return false` or `return true`.
|
||||
|
||||
* Use the following convention for Pointers and References: `Type* somePointer` / `Type& someReference`. Do not write this: `Type * somePointer` / `Type & someReference` or `Type *somePointer` / `Type &someReference`. Pointers and references are distinct types, hence why the notation for them should have the token on the side of the type.
|
||||
|
||||
* Avoid unscoped enum types. For scoped `enum class` types, use `PascalCase` without including enum prefix:
|
||||
|
||||
``` c
|
||||
enum class WeatherType
|
||||
{
|
||||
None,
|
||||
Rain,
|
||||
Snow,
|
||||
Cats,
|
||||
Dogs
|
||||
};
|
||||
```
|
||||
|
||||
`ENUM_ALL_CAPS` primarily indicates old C-styled Core notation. For C-styled (unscoped) enum values themselves, `ALL_CAPS` may be used for now, along with enum prefix:
|
||||
|
||||
``` c
|
||||
enum LaraWeaponType
|
||||
{
|
||||
WEAPON_NONE,
|
||||
WEAPON_PISTOLS,
|
||||
WEAPON_REVOLVER
|
||||
};
|
||||
```
|
||||
|
||||
## Data types
|
||||
|
||||
Avoid using `_t` data types, such as `uint8_t`, `int8_t`, `int16_t` etc. Use `unsigned char`, `signed char`, `short` etc. instead. If new variables or fields are introduced, prefer longer and more contemporary data types over deprecated ones. That is, if integer value is used, use `int` instead of `char` or `short`. If potentially fractional value is used (such as coordinates which are eventually multiplied or divided or transformed otherwise), prefer `float` over `int`.
|
||||
|
||||
For legacy functions and code paths, preserving original data types may be necessary. Special case are angle values - original games used weird `signed short` angle convention. So extra caution must be taken when writing code which operates on native TR angles, and it should always be kept in variables of `signed short` data type.
|
||||
|
||||
Prefer using references over pointers, both in function body and as arguments. When using references or pointers, prefix with `const` for read-only safety if the variable is not being written to.
|
||||
|
||||
## Casting
|
||||
|
||||
Prefer using C-styled casting instead of C++-styled casting where it is safe. While using it, avoid separating casting operator and variable with space:
|
||||
|
||||
`bar = (int)foo;`
|
||||
|
||||
For expressions, you can enclose expression into brackets to cast it:
|
||||
|
||||
`bar = int(foo + blah * 4);`
|
||||
|
||||
Using C++-styled casting is allowed when C-styled casting provides undefined or unacceptable behaviour.
|
||||
|
||||
## Includes
|
||||
|
||||
For header files from project itself, always use includes with quotes, not with brackets. Also avoid using Windows-specific `\` backslash symbols to specify subpaths, only use normal `/` slashes. Also please include full path to a header file and order includes alphabetically:
|
||||
|
||||
```c
|
||||
#include "Game/effects/lightning.h"
|
||||
#include "Specific/phd_math.h"
|
||||
```
|
||||
|
||||
Includes with brackets are only allowed when using external libraries:
|
||||
|
||||
```c
|
||||
#include <algorithm>
|
||||
#include "Game/collision/collide.h"
|
||||
```
|
||||
|
||||
## Namespaces
|
||||
|
||||
Don't shorten `std` namespace types and methods by using `using` directive. This is bad: `auto x = vector<int>();`
|
||||
Leave them as is. This is good: `auto x = std::vector<int>();`
|
||||
|
||||
## Comments
|
||||
|
||||
Use `//`-styled comments where possible.
|
||||
Only use `/* */` style in case you are about to temporarily comment certain block for testing purposes or when writing a comment that will serve as the source for generated documentation.
|
||||
|
||||
## Branches and pull requests
|
||||
|
||||
Make sure that epic branches (tens or hundreds of files changed due to renames, namespace wrappings, etc) **are focused on a single feature or task**. Don't jump in to others epic branches with another round of your epic changes. It masks bugs and makes review process very cumbersome.
|
||||
|
||||
Avoid making new branches based on unapproved epic PRs which are in the process of review. It may render your work useless if parent epic branch is unapproved and scrapped.
|
|
@ -4,4 +4,5 @@ set LDOC_DIR=.\compiler\ldoc
|
|||
set LUA_PATH=.\compiler\?.lua
|
||||
set LUA_CPATH=.\compiler\?.dll
|
||||
.\compiler\lua.exe %LDOC_DIR%\\ldoc.lua %*
|
||||
del output.xml
|
||||
exit /b %ERRORLEVEL%
|
||||
|
|
|
@ -12,7 +12,7 @@ new_type("luautil", "5 Lua utility modules", true)
|
|||
|
||||
not_luadoc = true
|
||||
|
||||
local version = "1.3"
|
||||
local version = "1.4"
|
||||
project = "TombEngine"
|
||||
title = "TombEngine " .. version .. " Lua API"
|
||||
description = "TombEngine " .. version .. " scripting interface"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -129,6 +129,10 @@
|
|||
<td class="summary">Clear an action key.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#KeyClearAll">KeyClearAll()</a></td>
|
||||
<td class="summary">Clear all action keys.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#GetMouseDisplayPosition">GetMouseDisplayPosition()</a></td>
|
||||
<td class="summary">Get the display position of the cursor in percent.</td>
|
||||
</tr>
|
||||
|
@ -254,6 +258,21 @@
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "KeyClearAll"></a>
|
||||
<strong>KeyClearAll()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Clear all action keys.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "GetMouseDisplayPosition"></a>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -124,6 +124,18 @@
|
|||
<td class="name" ><a href="#SetItemCount">SetItemCount(objectID, count)</a></td>
|
||||
<td class="summary">Set the amount of an item in the player's inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#GetUsedItem">GetUsedItem()</a></td>
|
||||
<td class="summary">Get last item used in the player's inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#SetUsedItem">SetUsedItem(objectID)</a></td>
|
||||
<td class="summary">Set last item used in the player's inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#ClearUsedItem">ClearUsedItem()</a></td>
|
||||
<td class="summary">Clear last item used in the player's inventory.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
@ -245,6 +257,70 @@
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "GetUsedItem"></a>
|
||||
<strong>GetUsedItem()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get last item used in the player's inventory.
|
||||
This value will be valid only for a single frame after exiting inventory, after which Lara says "No".
|
||||
Therefore, this function must be preferably used either in OnLoop or OnUseItem events.
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
|
||||
Last item used in the inventory.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "SetUsedItem"></a>
|
||||
<strong>SetUsedItem(objectID)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set last item used in the player's inventory.
|
||||
You will be able to specify only objects which already exist in the inventory.
|
||||
Will only be valid for the next frame. If not processed by the game, Lara will say "No".
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">objectID</span>
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
|
||||
Object ID of the item to select from inventory.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "ClearUsedItem"></a>
|
||||
<strong>ClearUsedItem()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Clear last item used in the player's inventory.
|
||||
When this function is used in OnUseItem level function, it allows to override existing item functionality.
|
||||
For items without existing functionality, this function is needed to avoid Lara saying "No" after using it.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -263,7 +263,8 @@ LOAD
|
|||
SAVE
|
||||
START
|
||||
END
|
||||
LOOP</pre>
|
||||
LOOP
|
||||
USEITEM</pre>
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -109,7 +109,7 @@
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#ShowString">ShowString(str, time)</a></td>
|
||||
<td class="name" ><a href="#ShowString">ShowString(str, time, autoDelete)</a></td>
|
||||
<td class="summary">Show some text on-screen.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -131,7 +131,7 @@
|
|||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "ShowString"></a>
|
||||
<strong>ShowString(str, time)</strong>
|
||||
<strong>ShowString(str, time, autoDelete)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Show some text on-screen.
|
||||
|
@ -151,6 +151,13 @@ If not given, the string will have an "infinite" life, and will show
|
|||
until <a href="../1 modules/Strings.html#HideString">HideString</a> is called or until the level is finished.
|
||||
Default: nil (i.e. infinite)
|
||||
</li>
|
||||
<li><span class="parameter">autoDelete</span>
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
should be string automatically deleted after timeout is reached.
|
||||
If not given, the string will remain allocated even after timeout is reached, and can be
|
||||
shown again without re-initialization.
|
||||
Default: false
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -364,7 +364,7 @@ pickups, and Lara herself (see also <a href="../2 classes/Objects.LaraObject.htm
|
|||
Use this to bring back original unswapped mesh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:Enable">Moveable:Enable()</a></td>
|
||||
<td class="name" ><a href="#Moveable:Enable">Moveable:Enable(timeout)</a></td>
|
||||
<td class="summary">Enable the item, as if a trigger for it had been stepped on.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -1861,13 +1861,20 @@ sas:SetPosition(newPos, <span class="keyword">false</span>)</pre>
|
|||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:Enable"></a>
|
||||
<strong>Moveable:Enable()</strong>
|
||||
<strong>Moveable:Enable(timeout)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Enable the item, as if a trigger for it had been stepped on.
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">timeout</span>
|
||||
<span class="types"><span class="type">float</span></span>
|
||||
time (in seconds) after which moveable automatically disables (optional).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -100,27 +100,27 @@
|
|||
<div id="content">
|
||||
|
||||
<h1>Primitive Class <code>Color</code></h1>
|
||||
<p>An RGBA or RGB color.</p>
|
||||
<p>Components are specified in bytes; all values are clamped to [0, 255].</p>
|
||||
<p>Represents an RGBA or RGB color.</p>
|
||||
<p> Components are specified in bytes. All values are clamped to the range [0, 255].</p>
|
||||
|
||||
|
||||
<h2><a href="#Members">Members</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#r">r</a></td>
|
||||
<td class="summary">(int) red component</td>
|
||||
<td class="summary">(int) Red component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#g">g</a></td>
|
||||
<td class="summary">(int) green component</td>
|
||||
<td class="summary">(int) Green component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#b">b</a></td>
|
||||
<td class="summary">(int) blue component</td>
|
||||
<td class="summary">(int) Blue component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#a">a</a></td>
|
||||
<td class="summary">(int) alpha component (255 = opaque, 0 = invisible)</td>
|
||||
<td class="summary">(int) Alpha component (0 = invisible, 255 = opaque).</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
|
@ -129,12 +129,6 @@
|
|||
<td class="name" ><a href="#Color">Color(R, G, B)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Color">Color(R, G, B, A)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -157,7 +151,7 @@
|
|||
<strong>r</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
(int) red component
|
||||
(int) Red component.
|
||||
|
||||
|
||||
|
||||
|
@ -172,7 +166,7 @@
|
|||
<strong>g</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
(int) green component
|
||||
(int) Green component.
|
||||
|
||||
|
||||
|
||||
|
@ -187,7 +181,7 @@
|
|||
<strong>b</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
(int) blue component
|
||||
(int) Blue component.
|
||||
|
||||
|
||||
|
||||
|
@ -202,7 +196,7 @@
|
|||
<strong>a</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
(int) alpha component (255 = opaque, 0 = invisible)
|
||||
(int) Alpha component (0 = invisible, 255 = opaque).
|
||||
|
||||
|
||||
|
||||
|
@ -253,48 +247,6 @@
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Color"></a>
|
||||
<strong>Color(R, G, B, A)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">R</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
red component
|
||||
</li>
|
||||
<li><span class="parameter">G</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
green component
|
||||
</li>
|
||||
<li><span class="parameter">B</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
blue component
|
||||
</li>
|
||||
<li><span class="parameter">A</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
alpha component (255 is opaque, 0 is invisible)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
|
||||
A new Color object.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "__tostring"></a>
|
||||
|
@ -311,7 +263,7 @@
|
|||
<ul>
|
||||
<li><span class="parameter">color</span>
|
||||
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
|
||||
this color
|
||||
This color.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -319,7 +271,7 @@
|
|||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
|
||||
A string showing the r, g, b, and a values of the color
|
||||
A string representing the r, g, b, and a values of the color.
|
||||
</ol>
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.3 Lua API</title>
|
||||
<title>TombEngine 1.4 Lua API</title>
|
||||
<link rel="stylesheet" href="ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -100,7 +100,7 @@
|
|||
<div id="content">
|
||||
|
||||
|
||||
<h2>TombEngine 1.3 scripting interface</h2>
|
||||
<h2>TombEngine 1.4 scripting interface</h2>
|
||||
<p>Welcome to the TombEngine scripting API. This is a work in progress and some information might be wrong or outdated. Please also note that this is primarily a reference document, not a tutorial, so expect descriptions to be fairly sparse.</p>
|
||||
|
||||
<p>At the time of writing, there is a tutorial describing the basics of Lua, as well as a number of example scripts, on <a href="https://www.tombengine.com">the TombEngine website</a>.</p>
|
||||
|
@ -244,7 +244,7 @@ local door = GetMoveableByName("door_type4_14")
|
|||
<table class="module_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="3 primitive classes/Color.html">Color</a></td>
|
||||
<td class="summary">An RGBA or RGB color.</td>
|
||||
<td class="summary">Represents an RGBA or RGB color.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="3 primitive classes/Rotation.html">Rotation</a></td>
|
||||
|
|
File diff suppressed because it is too large
Load diff
10
IMPORTANT_LINKS.md
Normal file
10
IMPORTANT_LINKS.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Important Links
|
||||
|
||||
Here you will find other essential sources that TombEngine has.
|
||||
|
||||
- TombEngine website: https://tombengine.com/
|
||||
- TombEngine Organization repository: https://github.com/TombEngine
|
||||
- TombEngine LUA API webpage source: https://github.com/TombEngine/TombEngine.github.io
|
||||
- TombEngine Assets used on the tombEngine website: https://github.com/TombEngine/Resources
|
||||
- TombEngine releases: https://github.com/TombEngine/TombEditorReleases
|
||||
- TombEditor repository: https://github.com/MontyTRC89/Tomb-Editor (A Tomb Raider Level Editor to build custom levels. Tomb Editor should be used to develop levels for TombEngine)
|
59
README.md
59
README.md
|
@ -1,10 +1,8 @@
|
|||
# TombEngine
|
||||
|
||||
In the year 2000, Core Design granted us a great gift: their TR4-based Level Editor, which allowed people to create custom levels. It was, unfortunately, quite limited, hence why over the decades it was upgraded massively with fan projects such as Tomb Raider Engine Patcher (TREP) and Tomb Raider Next Generation (TRNG).
|
||||
- TREP was a tool which allowed modification of the executable to expand certain limits and implement new features.
|
||||
- TRNG built upon TREP and provided many new tools, including a scripting language, expanding even more limits with its own .DLL.
|
||||

|
||||
|
||||
Unfortunately, TRNG's toolset is poorly documented and not user-friendly; the program remains closed-source to this day and is in all practicality an abandonware. As a direct consequence, no one is able to fix the countless well-known bugs and issues extant in TRNG, rendering implementation of new features is impossible without an in-depth knowledge of C++ plugin creation and a solid understanding of the classic Tomb Raider engine's many idiosyncrasies.
|
||||
In the year 2000, Core Design granted us a great gift: their TR4-based Level Editor, which allowed people to create custom levels. It was, unfortunately, quite limited, hence why over the decades it was upgraded massively with fan patcher projects such as Tomb Raider Engine Patcher (TREP) and Tomb Raider Next Generation (TRNG).
|
||||
|
||||
TombEngine (TEN) is a new, open-source engine which aims to abolish all limits, fix bugs from the original games, introduce new features while refining old ones, and provide for a refined, user-friendly level creation process. Current support includes:
|
||||
- Lua (as the native scripting language)
|
||||
|
@ -20,7 +18,7 @@ Tomb Engine should be used in conjuction with Tomb Editor. Tomb Editor is also o
|
|||
# Compiling TombEngine
|
||||
To compile TEN, ensure you have installed:
|
||||
- Microsoft Visual Studio
|
||||
- TombEditor (if you would like to create and test levels)
|
||||
- Tomb Editor (if you would like to create and test levels)
|
||||
|
||||
Steps:
|
||||
1) Clone the repository to your GitHub Desktop
|
||||
|
@ -40,54 +38,3 @@ Visual Studio may also warn about NuGet packages. To fix:
|
|||
# Disclaimer
|
||||
We do not and have never worked for Core Design, Eidos Interactive, or Square Enix. This is a hobby project. Tomb Raider is a registered trademark of Square Enix; TombEngine is not be sold. The code is open-source to encourage contributions and to be used for study purposes. We are not responsible for illegal uses of this source code. This source code is released as-is and continues to be maintained by non-paid contributors in their free time.
|
||||
|
||||
# Credit List
|
||||
|
||||
## Developers
|
||||
|
||||
- MontyTRC (Project Leader)
|
||||
|
||||
- Gancian (general coding)
|
||||
- Krystian (general coding)
|
||||
- Kubsy (Some cleanups and fixes)
|
||||
- l.m. (general coding, Lua enhancements, bug fixing)
|
||||
- Lwmte (sound refactoring, general coding, code cleanups, bug fixing)
|
||||
- Moooonyeah (Jumanji) (entity decompilation)
|
||||
- Raildex (renderer refactoring, particle coding, general coding)
|
||||
- RicardoLuis0 (general coding)
|
||||
- Sezz (player state refactoring, general coding, code cleanups, bug fixing, assets)
|
||||
- Squidshire (Hispidence) (Lua implementation, bug fixing)
|
||||
- Stranger1992 (sound asset refactoring and organisation, assets)
|
||||
- TokyoSU (entity and vehicle decompilation)
|
||||
- Tomo (general coding, bug fixing)
|
||||
- Troye (general coding, refactoring)
|
||||
- WolfCheese (general coding)
|
||||
|
||||
## Testers
|
||||
- Adngel
|
||||
- Caesum
|
||||
- Dustie
|
||||
- GeckoKid
|
||||
- JoeyQuint
|
||||
- Kamillos
|
||||
- Kubsy
|
||||
- LGG_PRODUCTION
|
||||
- Lore
|
||||
- RemRem
|
||||
- Stranger1992
|
||||
- WolfCheese
|
||||
|
||||
## Assets and Miscellaneous
|
||||
|
||||
- Geckokid (Sprites and test level creator).
|
||||
|
||||
### Animations
|
||||
- SrDanielPonces (Diagonal shimmy transitions, backwards monkey swinging)
|
||||
- Krystian (Flexibility crawlspace, slope climbing animations)
|
||||
- Sezz (Additional Animations for player state refactoring)
|
||||
- Naotheia (Underwater puzzle placement, crouch 180° turn, crawl 180° turn, water surface 180° turn)
|
||||
- JoeyQuint (Standing 180° turn, monkey swing 180° turn)
|
||||
|
||||
### TombEngine Marketing
|
||||
- Kubsy (Twitter and forum posts)
|
||||
- Stranger1992 (This website, Facebook, Instagram, Youtube and Twitch.
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ local anims = Flow.Animations.new()
|
|||
anims.crawlExtended = true
|
||||
anims.crouchRoll = true
|
||||
anims.crawlspaceSwandive = true
|
||||
anims.monkeyAutoJump = false
|
||||
anims.overhangClimb = false
|
||||
anims.slideExtended = false
|
||||
anims.sprintJump = false
|
||||
|
|
|
@ -51,7 +51,8 @@ local strings =
|
|||
ammo_used = { "Ammo Used" },
|
||||
antialiasing = { "Antialiasing" },
|
||||
apply = { "Apply" },
|
||||
automatic_targeting = { "Automatic Targeting" },
|
||||
auto_monkey_swing_jump = { "Auto Monkey Jump" },
|
||||
auto_targeting = { "Auto Targeting" },
|
||||
back = { "Back" },
|
||||
cancel = { "Cancel" },
|
||||
caustics = { "Underwater Caustics" },
|
||||
|
|
BIN
TEN logo.png
Normal file
BIN
TEN logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
|
@ -196,7 +196,7 @@ namespace TEN::Hud
|
|||
|
||||
DisplayPickup& PickupSummaryController::GetNewDisplayPickup()
|
||||
{
|
||||
assertion(_displayPickups.size() <= DISPLAY_PICKUP_COUNT_MAX, "Display pickup overflow.");
|
||||
TENAssert(_displayPickups.size() <= DISPLAY_PICKUP_COUNT_MAX, "Display pickup overflow.");
|
||||
|
||||
// Add and return new display pickup.
|
||||
if (_displayPickups.size() < DISPLAY_PICKUP_COUNT_MAX)
|
||||
|
@ -213,12 +213,15 @@ namespace TEN::Hud
|
|||
_displayPickups.erase(
|
||||
std::remove_if(
|
||||
_displayPickups.begin(), _displayPickups.end(),
|
||||
[](const DisplayPickup& pickup) { return ((pickup.Life <= 0.0f) && pickup.IsOffscreen()); }),
|
||||
[](const DisplayPickup& pickup)
|
||||
{
|
||||
return ((pickup.Life <= 0.0f) && pickup.IsOffscreen());
|
||||
}),
|
||||
_displayPickups.end());
|
||||
}
|
||||
|
||||
void PickupSummaryController::DrawDebug() const
|
||||
{
|
||||
g_Renderer.PrintDebugMessage("Display pickups in summary: %d", _displayPickups.size());
|
||||
PrintDebugMessage("Display pickups in summary: %d", _displayPickups.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,14 +33,17 @@ namespace TEN::Hud
|
|||
{
|
||||
private:
|
||||
// Constants
|
||||
|
||||
static constexpr auto DISPLAY_PICKUP_COUNT_MAX = 64;
|
||||
static constexpr auto DISPLAY_PICKUP_COUNT_ARG_DEFAULT = 1;
|
||||
|
||||
// Members
|
||||
|
||||
std::vector<DisplayPickup> _displayPickups = {};
|
||||
|
||||
public:
|
||||
// Utilities
|
||||
|
||||
void AddDisplayPickup(GAME_OBJECT_ID objectID, const Vector2& origin, unsigned int count = DISPLAY_PICKUP_COUNT_ARG_DEFAULT);
|
||||
void AddDisplayPickup(GAME_OBJECT_ID objectID, const Vector3& pos, unsigned int count = DISPLAY_PICKUP_COUNT_ARG_DEFAULT);
|
||||
|
||||
|
@ -50,6 +53,7 @@ namespace TEN::Hud
|
|||
|
||||
private:
|
||||
// Helpers
|
||||
|
||||
std::vector<Vector2> GetStackPositions() const;
|
||||
DisplayPickup& GetNewDisplayPickup();
|
||||
void ClearInactiveDisplayPickups();
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
|
||||
#include "Game/effects/DisplaySprite.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Renderer/Renderer.h"
|
||||
#include "Specific/clock.h"
|
||||
|
||||
using namespace TEN::Effects::DisplaySprite;
|
||||
using namespace TEN::Math;
|
||||
using TEN::Renderer::g_Renderer;
|
||||
|
||||
namespace TEN::Hud
|
||||
{
|
||||
|
@ -80,10 +78,10 @@ namespace TEN::Hud
|
|||
|
||||
void SpeedometerController::DrawDebug() const
|
||||
{
|
||||
g_Renderer.PrintDebugMessage("SPEEDOMETER DEBUG");
|
||||
g_Renderer.PrintDebugMessage("Value: %.3f", _value);
|
||||
g_Renderer.PrintDebugMessage("Pointer angle: %.3f", _pointerAngle);
|
||||
g_Renderer.PrintDebugMessage("Opacity: %.3f", _opacity);
|
||||
g_Renderer.PrintDebugMessage("Life: %.3f", _life / FPS);
|
||||
PrintDebugMessage("SPEEDOMETER DEBUG");
|
||||
PrintDebugMessage("Value: %.3f", _value);
|
||||
PrintDebugMessage("Pointer angle: %.3f", _pointerAngle);
|
||||
PrintDebugMessage("Opacity: %.3f", _opacity);
|
||||
PrintDebugMessage("Life: %.3f", _life / FPS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@ namespace TEN::Hud
|
|||
{
|
||||
private:
|
||||
// Constants
|
||||
|
||||
static constexpr auto LIFE_MAX = 0.75f;
|
||||
|
||||
// Members
|
||||
|
||||
bool _hasValueUpdated = false;
|
||||
|
||||
float _value = 0.0f;
|
||||
|
@ -18,6 +20,7 @@ namespace TEN::Hud
|
|||
|
||||
public:
|
||||
// Utilities
|
||||
|
||||
void UpdateValue(float value);
|
||||
|
||||
void Update();
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace TEN::Hud
|
|||
{
|
||||
private:
|
||||
// Members
|
||||
|
||||
StatusBar _airBar = {};
|
||||
StatusBar _exposureBar = {};
|
||||
StatusBar _healthBar = {};
|
||||
|
@ -35,6 +36,7 @@ namespace TEN::Hud
|
|||
|
||||
public:
|
||||
// Utilities
|
||||
|
||||
void Initialize(const ItemInfo& item);
|
||||
void Update(const ItemInfo& item);
|
||||
void Draw(const ItemInfo& item) const;
|
||||
|
@ -42,12 +44,14 @@ namespace TEN::Hud
|
|||
|
||||
private:
|
||||
// Update helpers
|
||||
|
||||
void UpdateAirBar(const ItemInfo& item);
|
||||
void UpdateExposureBar(const ItemInfo& item);
|
||||
void UpdateHealthBar(const ItemInfo& item);
|
||||
void UpdateStaminaBar(const ItemInfo& item);
|
||||
|
||||
// Draw helpers
|
||||
|
||||
void DrawStatusBar(float value, float criticalValue, const RendererHudBar& rHudBar, GAME_OBJECT_ID textureID, int frame, bool isPoisoned) const;
|
||||
void DrawAirBar() const;
|
||||
void DrawExposureBar() const;
|
||||
|
|
|
@ -350,9 +350,9 @@ namespace TEN::Hud
|
|||
for (const auto& [itemNumber, crosshair] : _crosshairs)
|
||||
crosshair.IsPrimary ? primaryCount++ : peripheralCount++;
|
||||
|
||||
g_Renderer.PrintDebugMessage("TARGET HIGHLIGHTER DEBUG");
|
||||
g_Renderer.PrintDebugMessage(g_Configuration.EnableTargetHighlighter ? "Enabled" : "Disabled");
|
||||
g_Renderer.PrintDebugMessage("Primary crosshairs: %d", primaryCount);
|
||||
g_Renderer.PrintDebugMessage("Peripheral crosshairs: %d", peripheralCount);
|
||||
PrintDebugMessage("TARGET HIGHLIGHTER DEBUG");
|
||||
PrintDebugMessage(g_Configuration.EnableTargetHighlighter ? "Enabled" : "Disabled");
|
||||
PrintDebugMessage("Primary crosshairs: %d", primaryCount);
|
||||
PrintDebugMessage("Peripheral crosshairs: %d", peripheralCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,13 @@ namespace TEN::Hud
|
|||
|
||||
public:
|
||||
// Constants
|
||||
|
||||
static constexpr auto COLOR_RED = Color(1.0f, 0.2f, 0.2f);
|
||||
static constexpr auto COLOR_GRAY = Color(0.7f, 0.7f, 0.7f, 0.7f);
|
||||
static constexpr auto SEGMENT_COUNT = 4;
|
||||
|
||||
// Members
|
||||
|
||||
bool IsActive = false;
|
||||
bool IsPrimary = false;
|
||||
|
||||
|
@ -35,15 +37,18 @@ namespace TEN::Hud
|
|||
std::array<SegmentData, SEGMENT_COUNT> Segments = {};
|
||||
|
||||
// Getters
|
||||
|
||||
float GetScale(float cameraDist) const;
|
||||
float GetRadius() const;
|
||||
Vector2 GetPositionOffset(short orientOffset) const;
|
||||
|
||||
// Setters
|
||||
|
||||
void SetPrimary();
|
||||
void SetPeripheral();
|
||||
|
||||
// Utilities
|
||||
|
||||
void Update(const Vector3& targetPos, bool isActive, bool doPulse);
|
||||
void Draw() const;
|
||||
};
|
||||
|
@ -52,19 +57,23 @@ namespace TEN::Hud
|
|||
{
|
||||
private:
|
||||
// Members
|
||||
|
||||
std::unordered_map<int, CrosshairData> _crosshairs = {}; // Key = item number.
|
||||
|
||||
public:
|
||||
// Utilities
|
||||
|
||||
void Update(const ItemInfo& playerItem);
|
||||
void Draw() const;
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
// Update helpers
|
||||
|
||||
void Update(const std::vector<int>& itemNumbers);
|
||||
|
||||
// Object helpers
|
||||
|
||||
CrosshairData& GetNewCrosshair(int itemNumber);
|
||||
void AddCrosshair(int itemNumber, const Vector3& targetPos);
|
||||
void ClearInactiveCrosshairs();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/control/los.h"
|
||||
#include "Game/items.h"
|
||||
|
@ -14,6 +15,7 @@
|
|||
#include "Specific/Input/Input.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Input;
|
||||
|
||||
namespace TEN::Entities::Player
|
||||
|
@ -35,8 +37,8 @@ namespace TEN::Entities::Player
|
|||
const auto& player = GetLaraInfo(item);
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, 0, 0, -coll.Setup.Height / 2); // NOTE: Height offset required for correct bridge collision.
|
||||
int relFloorHeight = pointColl.Position.Floor - item.Pose.Position.y;
|
||||
auto pointColl = GetPointCollision(item, 0, 0, -coll.Setup.Height / 2); // NOTE: Height offset required for correct bridge collision.
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - item.Pose.Position.y;
|
||||
|
||||
// 1) Test if player is already aligned with floor.
|
||||
if (relFloorHeight == 0)
|
||||
|
@ -61,8 +63,8 @@ namespace TEN::Entities::Player
|
|||
constexpr auto UPPER_FLOOR_BOUND_DOWN = CLICK(0.75f);
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, 0, 0, -coll.Setup.Height / 2); // NOTE: Height offset required for correct bridge collision.
|
||||
int relFloorHeight = pointColl.Position.Floor - item.Pose.Position.y;
|
||||
auto pointColl = GetPointCollision(item, 0, 0, -coll.Setup.Height / 2); // NOTE: Height offset required for correct bridge collision.
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - item.Pose.Position.y;
|
||||
|
||||
// Determine appropriate floor bounds.
|
||||
int lowerFloorBound = isGoingUp ? LOWER_FLOOR_BOUND_UP : LOWER_FLOOR_BOUND_DOWN;
|
||||
|
@ -167,30 +169,30 @@ namespace TEN::Entities::Player
|
|||
int playerHeight = isCrawling ? LARA_HEIGHT_CRAWL : coll.Setup.Height;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, setup.HeadingAngle, OFFSET_RADIUS(playerRadius), -playerHeight);
|
||||
auto pointColl = GetPointCollision(item, setup.HeadingAngle, OFFSET_RADIUS(playerRadius), -playerHeight);
|
||||
int vPos = item.Pose.Position.y;
|
||||
int vPosTop = vPos - playerHeight;
|
||||
|
||||
// Calculate slope aspect delta angle.
|
||||
short aspectAngle = Geometry::GetSurfaceAspectAngle(pointColl.FloorNormal);
|
||||
short aspectAngle = Geometry::GetSurfaceAspectAngle(pointColl.GetFloorNormal());
|
||||
short aspectAngleDelta = Geometry::GetShortestAngle(setup.HeadingAngle, aspectAngle);
|
||||
|
||||
// 1) Check for slippery slope below floor (if applicable).
|
||||
if (setup.TestSlipperySlopeBelow &&
|
||||
(pointColl.Position.FloorSlope && abs(aspectAngleDelta) <= SLOPE_ASPECT_ANGLE_DELTA_MAX))
|
||||
// 1) Check for illegal slope below floor (if applicable).
|
||||
if (setup.TestSteepFloorBelow &&
|
||||
(pointColl.IsSteepFloor() && abs(aspectAngleDelta) <= SLOPE_ASPECT_ANGLE_DELTA_MAX))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1) Check for slippery slope above floor (if applicable).
|
||||
if (setup.TestSlipperySlopeAbove &&
|
||||
(pointColl.Position.FloorSlope && abs(aspectAngleDelta) >= SLOPE_ASPECT_ANGLE_DELTA_MAX))
|
||||
// 1) Check for illegal slope above floor (if applicable).
|
||||
if (setup.TestSteepFloorAbove &&
|
||||
(pointColl.IsSteepFloor() && abs(aspectAngleDelta) >= SLOPE_ASPECT_ANGLE_DELTA_MAX))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3) Check for death floor (if applicable).
|
||||
if (setup.TestDeathFloor && pointColl.Block->Flags.Death)
|
||||
if (setup.TestDeathFloor && pointColl.GetSector().Flags.Death && pointColl.GetFloorBridgeItemNumber() == NO_VALUE)
|
||||
return false;
|
||||
|
||||
// LOS setup at upper floor bound.
|
||||
|
@ -200,9 +202,9 @@ namespace TEN::Entities::Player
|
|||
item.Pose.Position.z,
|
||||
item.RoomNumber);
|
||||
auto target0 = GameVector(
|
||||
pointColl.Coordinates.x,
|
||||
pointColl.GetPosition().x,
|
||||
(vPos + setup.UpperFloorBound) - 1,
|
||||
pointColl.Coordinates.z,
|
||||
pointColl.GetPosition().z,
|
||||
item.RoomNumber);
|
||||
|
||||
// LOS setup at lowest ceiling bound (player height).
|
||||
|
@ -212,9 +214,9 @@ namespace TEN::Entities::Player
|
|||
item.Pose.Position.z,
|
||||
item.RoomNumber);
|
||||
auto target1 = GameVector(
|
||||
pointColl.Coordinates.x,
|
||||
pointColl.GetPosition().x,
|
||||
vPosTop + 1,
|
||||
pointColl.Coordinates.z,
|
||||
pointColl.GetPosition().z,
|
||||
item.RoomNumber);
|
||||
|
||||
// Calculate LOS direction.
|
||||
|
@ -232,9 +234,9 @@ namespace TEN::Entities::Player
|
|||
if (!LOS(&origin0, &target0) || !LOS(&origin1, &target1))
|
||||
return false;
|
||||
|
||||
int relFloorHeight = pointColl.Position.Floor - vPos;
|
||||
int relCeilHeight = pointColl.Position.Ceiling - vPos;
|
||||
int floorToCeilHeight = abs(pointColl.Position.Ceiling - pointColl.Position.Floor);
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - vPos;
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - vPos;
|
||||
int floorToCeilHeight = abs(pointColl.GetCeilingHeight() - pointColl.GetFloorHeight());
|
||||
|
||||
// 6) Assess point collision.
|
||||
if (relFloorHeight <= setup.LowerFloorBound && // Floor height is above lower floor bound.
|
||||
|
@ -400,12 +402,12 @@ namespace TEN::Entities::Player
|
|||
return false;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, 0, 0, -coll.Setup.Height / 2); // NOTE: Offset required for correct bridge collision.
|
||||
int relFloorHeight = pointColl.Position.Floor - item.Pose.Position.y;
|
||||
auto pointColl = GetPointCollision(item, 0, 0, -coll.Setup.Height / 2); // NOTE: Offset required for correct bridge collision.
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - item.Pose.Position.y;
|
||||
|
||||
// 2) Assess point collision.
|
||||
if (abs(relFloorHeight) <= ABS_FLOOR_BOUND && // Floor height is within upper/lower floor bounds.
|
||||
pointColl.Position.FloorSlope) // Floor is a slippery slope.
|
||||
pointColl.IsSteepFloor()) // Floor is a slippery slope.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -432,8 +434,8 @@ namespace TEN::Entities::Player
|
|||
float radius = TestState(item.Animation.ActiveState, CROUCH_STATES) ? LARA_RADIUS_CRAWL : LARA_RADIUS;
|
||||
|
||||
// Get center point collision.
|
||||
auto pointCollCenter = GetCollision(&item, 0, 0.0f, -LARA_HEIGHT / 2);
|
||||
int floorToCeilHeightCenter = abs(pointCollCenter.Position.Ceiling - pointCollCenter.Position.Floor);
|
||||
auto pointCollCenter = GetPointCollision(item, 0, 0.0f, -LARA_HEIGHT / 2);
|
||||
int floorToCeilHeightCenter = abs(pointCollCenter.GetCeilingHeight() - pointCollCenter.GetFloorHeight());
|
||||
|
||||
// Assess center point collision.
|
||||
if (floorToCeilHeightCenter < LARA_HEIGHT || // Floor-to-ceiling height isn't too wide.
|
||||
|
@ -445,9 +447,9 @@ namespace TEN::Entities::Player
|
|||
// TODO: Check whether < or <= and > or >=.
|
||||
|
||||
// Get front point collision.
|
||||
auto pointCollFront = GetCollision(&item, item.Pose.Orientation.y, radius, -coll.Setup.Height);
|
||||
int floorToCeilHeightFront = abs(pointCollFront.Position.Ceiling - pointCollFront.Position.Floor);
|
||||
int relFloorHeightFront = abs(pointCollFront.Position.Floor - pointCollCenter.Position.Floor);
|
||||
auto pointCollFront = GetPointCollision(item, item.Pose.Orientation.y, radius, -coll.Setup.Height);
|
||||
int floorToCeilHeightFront = abs(pointCollFront.GetCeilingHeight() - pointCollFront.GetFloorHeight());
|
||||
int relFloorHeightFront = abs(pointCollFront.GetFloorHeight() - pointCollCenter.GetFloorHeight());
|
||||
|
||||
// Assess front point collision.
|
||||
if (relFloorHeightFront <= CRAWL_STEPUP_HEIGHT && // Floor is within upper/lower floor bounds.
|
||||
|
@ -458,9 +460,9 @@ namespace TEN::Entities::Player
|
|||
}
|
||||
|
||||
// Get back point collision.
|
||||
auto pointCollBack = GetCollision(&item, item.Pose.Orientation.y, -radius, -coll.Setup.Height);
|
||||
int floorToCeilHeightBack = abs(pointCollBack.Position.Ceiling - pointCollBack.Position.Floor);
|
||||
int relFloorHeightBack = abs(pointCollBack.Position.Floor - pointCollCenter.Position.Floor);
|
||||
auto pointCollBack = GetPointCollision(item, item.Pose.Orientation.y, -radius, -coll.Setup.Height);
|
||||
int floorToCeilHeightBack = abs(pointCollBack.GetCeilingHeight() - pointCollBack.GetFloorHeight());
|
||||
int relFloorHeightBack = abs(pointCollBack.GetFloorHeight() - pointCollCenter.GetFloorHeight());
|
||||
|
||||
// Assess back point collision.
|
||||
if (relFloorHeightBack <= CRAWL_STEPUP_HEIGHT && // Floor is within upper/lower floor bounds.
|
||||
|
@ -526,22 +528,22 @@ namespace TEN::Entities::Player
|
|||
|
||||
// TODO: Extend point collision struct to also find water depths.
|
||||
float dist = 0.0f;
|
||||
auto pointColl0 = GetCollision(&item);
|
||||
auto pointColl0 = GetPointCollision(item);
|
||||
|
||||
// 3) Test continuity of path.
|
||||
while (dist < PROBE_DIST_MAX)
|
||||
{
|
||||
// Get point collision.
|
||||
dist += STEP_DIST;
|
||||
auto pointColl1 = GetCollision(&item, item.Pose.Orientation.y, dist, -LARA_HEIGHT_CRAWL);
|
||||
auto pointColl1 = GetPointCollision(item, item.Pose.Orientation.y, dist, -LARA_HEIGHT_CRAWL);
|
||||
|
||||
int floorHeightDelta = abs(pointColl0.Position.Floor - pointColl1.Position.Floor);
|
||||
int floorToCeilHeight = abs(pointColl1.Position.Ceiling - pointColl1.Position.Floor);
|
||||
int floorHeightDelta = abs(pointColl0.GetFloorHeight() - pointColl1.GetFloorHeight());
|
||||
int floorToCeilHeight = abs(pointColl1.GetCeilingHeight() - pointColl1.GetFloorHeight());
|
||||
|
||||
// Assess point collision.
|
||||
if (floorHeightDelta > FLOOR_BOUND || // Avoid floor height delta beyond crawl stepup threshold.
|
||||
floorToCeilHeight <= FLOOR_TO_CEIL_HEIGHT_MAX || // Avoid narrow spaces.
|
||||
pointColl1.Position.FloorSlope) // Avoid slippery floor slopes.
|
||||
pointColl1.IsSteepFloor()) // Avoid slippery floor slopes.
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -580,8 +582,8 @@ namespace TEN::Entities::Player
|
|||
constexpr auto UPPER_CEIL_BOUND = -MONKEY_STEPUP_HEIGHT;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item);
|
||||
int relCeilHeight = pointColl.Position.Ceiling - (item.Pose.Position.y - LARA_HEIGHT_MONKEY);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - (item.Pose.Position.y - LARA_HEIGHT_MONKEY);
|
||||
|
||||
// Assess point collision.
|
||||
if (relCeilHeight <= LOWER_CEIL_BOUND && // Ceiling height is above lower ceiling bound.
|
||||
|
@ -604,14 +606,14 @@ namespace TEN::Entities::Player
|
|||
return true;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
|
||||
// 2) Test for slippery ceiling slope and check if overhang climb is disabled.
|
||||
if (pointColl.Position.CeilingSlope && !g_GameFlow->HasOverhangClimb())
|
||||
if (pointColl.IsSteepCeiling() && !g_GameFlow->HasOverhangClimb())
|
||||
return true;
|
||||
|
||||
// 3) Assess point collision.
|
||||
int relCeilHeight = pointColl.Position.Ceiling - (item.Pose.Position.y - LARA_HEIGHT_MONKEY);
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - (item.Pose.Position.y - LARA_HEIGHT_MONKEY);
|
||||
if (abs(relCeilHeight) > ABS_CEIL_BOUND) // Ceiling height is within lower/upper ceiling bound.
|
||||
return true;
|
||||
|
||||
|
@ -630,9 +632,9 @@ namespace TEN::Entities::Player
|
|||
return false;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item);
|
||||
int relCeilHeight = pointColl.Position.Ceiling - (item.Pose.Position.y - LARA_HEIGHT_MONKEY);
|
||||
int floorToCeilHeight = abs(pointColl.Position.Ceiling - pointColl.Position.Floor);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - (item.Pose.Position.y - LARA_HEIGHT_MONKEY);
|
||||
int floorToCeilHeight = abs(pointColl.GetCeilingHeight() - pointColl.GetFloorHeight());
|
||||
|
||||
// 2) Assess collision with ceiling.
|
||||
if (relCeilHeight < 0 &&
|
||||
|
@ -658,14 +660,14 @@ namespace TEN::Entities::Player
|
|||
constexpr auto PLAYER_HEIGHT = LARA_HEIGHT_MONKEY;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, setup.HeadingAngle, OFFSET_RADIUS(coll.Setup.Radius));
|
||||
auto pointColl = GetPointCollision(item, setup.HeadingAngle, OFFSET_RADIUS(coll.Setup.Radius));
|
||||
|
||||
// 1) Test if ceiling is monkey swing.
|
||||
if (!pointColl.BottomBlock->Flags.Monkeyswing)
|
||||
if (!pointColl.GetBottomSector().Flags.Monkeyswing)
|
||||
return false;
|
||||
|
||||
// 2) Test for ceiling slippery slope.
|
||||
if (pointColl.Position.CeilingSlope)
|
||||
// 2) Test for illegal ceiling.
|
||||
if (pointColl.IsSteepCeiling())
|
||||
return false;
|
||||
|
||||
int vPos = item.Pose.Position.y;
|
||||
|
@ -678,9 +680,9 @@ namespace TEN::Entities::Player
|
|||
item.Pose.Position.z,
|
||||
item.RoomNumber);
|
||||
auto target0 = GameVector(
|
||||
pointColl.Coordinates.x,
|
||||
pointColl.GetPosition().x,
|
||||
vPos - 1,
|
||||
pointColl.Coordinates.z,
|
||||
pointColl.GetPosition().z,
|
||||
item.RoomNumber);
|
||||
|
||||
// Raycast setup at lower ceiling bound.
|
||||
|
@ -690,9 +692,9 @@ namespace TEN::Entities::Player
|
|||
item.Pose.Position.z,
|
||||
item.RoomNumber);
|
||||
auto target1 = GameVector(
|
||||
pointColl.Coordinates.x,
|
||||
pointColl.GetPosition().x,
|
||||
(vPosTop + setup.LowerCeilingBound) + 1,
|
||||
pointColl.Coordinates.z,
|
||||
pointColl.GetPosition().z,
|
||||
item.RoomNumber);
|
||||
|
||||
// Prepare data for static object LOS.
|
||||
|
@ -712,9 +714,9 @@ namespace TEN::Entities::Player
|
|||
|
||||
// TODO: Assess static object geometry ray collision.
|
||||
|
||||
int relFloorHeight = pointColl.Position.Floor - vPos;
|
||||
int relCeilHeight = pointColl.Position.Ceiling - vPosTop;
|
||||
int floorToCeilHeight = abs(pointColl.Position.Ceiling - pointColl.Position.Floor);
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - vPos;
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - vPosTop;
|
||||
int floorToCeilHeight = abs(pointColl.GetCeilingHeight() - pointColl.GetFloorHeight());
|
||||
|
||||
// 4) Assess point collision.
|
||||
if (relFloorHeight > 0 && // Floor is within highest floor bound (player base).
|
||||
|
@ -782,8 +784,8 @@ namespace TEN::Entities::Player
|
|||
return false;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, 0, 0, -coll.Setup.Height / 2);
|
||||
int relFloorHeight = pointColl.Position.Floor - item.Pose.Position.y;
|
||||
auto pointColl = GetPointCollision(item, 0, 0, -coll.Setup.Height / 2);
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - item.Pose.Position.y;
|
||||
|
||||
// 2) Assess point collision.
|
||||
if (relFloorHeight > UPPER_FLOOR_BOUND) // Floor height is below upper floor bound.
|
||||
|
@ -805,11 +807,11 @@ namespace TEN::Entities::Player
|
|||
return true;
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
int vPos = item.Pose.Position.y;
|
||||
|
||||
// 3) Assess point collision.
|
||||
if ((pointColl.Position.Floor - vPos) <= projVerticalVel) // Floor height is above projected vertical position.
|
||||
if ((pointColl.GetFloorHeight() - vPos) <= projVerticalVel) // Floor height is above projected vertical position.
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -848,9 +850,9 @@ namespace TEN::Entities::Player
|
|||
return false;*/
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, setup.HeadingAngle, setup.Distance, -coll.Setup.Height);
|
||||
int relFloorHeight = pointColl.Position.Floor - item.Pose.Position.y;
|
||||
int relCeilHeight = pointColl.Position.Ceiling - item.Pose.Position.y;
|
||||
auto pointColl = GetPointCollision(item, setup.HeadingAngle, setup.Distance, -coll.Setup.Height);
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - item.Pose.Position.y;
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - item.Pose.Position.y;
|
||||
|
||||
// 4) Assess point collision.
|
||||
if (relFloorHeight >= -STEPUP_HEIGHT && // Floor is within highest floor bound.
|
||||
|
@ -923,11 +925,11 @@ namespace TEN::Entities::Player
|
|||
return IsRunJumpQueueableState(item.Animation.TargetState);
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item, item.Pose.Orientation.y, BLOCK(1), -coll.Setup.Height);
|
||||
auto pointColl = GetPointCollision(item, item.Pose.Orientation.y, BLOCK(1), -coll.Setup.Height);
|
||||
|
||||
int lowerCeilingBound = (LOWER_CEIL_BOUND_BASE - coll.Setup.Height);
|
||||
int relFloorHeight = pointColl.Position.Floor - item.Pose.Position.y;
|
||||
int relCeilHeight = pointColl.Position.Ceiling - item.Pose.Position.y;
|
||||
int relFloorHeight = pointColl.GetFloorHeight() - item.Pose.Position.y;
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - item.Pose.Position.y;
|
||||
|
||||
// 2) Assess point collision for possible running jump ahead.
|
||||
if (relCeilHeight < lowerCeilingBound || // Ceiling height is above lower ceiling bound.
|
||||
|
@ -993,7 +995,7 @@ namespace TEN::Entities::Player
|
|||
|
||||
// TODO: Broken on diagonal slides?
|
||||
|
||||
auto pointColl = GetCollision(&item);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
|
||||
//short aspectAngle = GetLaraSlideHeadingAngle(item, coll);
|
||||
//short slopeAngle = Geometry::GetSurfaceSlopeAngle(GetSurfaceNormal(pointColl.FloorTilt, true));
|
||||
|
@ -1002,8 +1004,8 @@ namespace TEN::Entities::Player
|
|||
|
||||
bool CanCrawlspaceDive(const ItemInfo& item, const CollisionInfo& coll)
|
||||
{
|
||||
auto pointColl = GetCollision(&item, coll.Setup.ForwardAngle, coll.Setup.Radius, -coll.Setup.Height);
|
||||
return (abs(pointColl.Position.Ceiling - pointColl.Position.Floor) < LARA_HEIGHT || IsInLowSpace(item, coll));
|
||||
auto pointColl = GetPointCollision(item, coll.Setup.ForwardAngle, coll.Setup.Radius, -coll.Setup.Height);
|
||||
return (abs(pointColl.GetCeilingHeight() - pointColl.GetFloorHeight()) < LARA_HEIGHT || IsInLowSpace(item, coll));
|
||||
}
|
||||
|
||||
bool CanPerformLedgeJump(const ItemInfo& item, const CollisionInfo& coll)
|
||||
|
@ -1031,8 +1033,8 @@ namespace TEN::Entities::Player
|
|||
// TODO: Assess static object geometry ray collision.
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(&item);
|
||||
int relCeilHeight = pointColl.Position.Ceiling - (item.Pose.Position.y - LARA_HEIGHT_STRETCH);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
int relCeilHeight = pointColl.GetCeilingHeight() - (item.Pose.Position.y - LARA_HEIGHT_STRETCH);
|
||||
|
||||
// 3) Assess point collision.
|
||||
if (relCeilHeight >= -coll.Setup.Height) // Ceiling height is below upper ceiling bound.
|
||||
|
@ -1045,10 +1047,10 @@ namespace TEN::Entities::Player
|
|||
{
|
||||
const auto& player = GetLaraInfo(item);
|
||||
|
||||
auto pointColl = GetCollision(&item);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
|
||||
if (player.Control.Tightrope.CanDismount && // Dismount is allowed.
|
||||
pointColl.Position.Floor == item.Pose.Position.y) // Floor is level with player.
|
||||
pointColl.GetFloorHeight() == item.Pose.Position.y) // Floor is level with player.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ namespace TEN::Entities::Player
|
|||
int LowerFloorBound = 0;
|
||||
int UpperFloorBound = 0;
|
||||
|
||||
bool TestSlipperySlopeBelow = true;
|
||||
bool TestSlipperySlopeAbove = true;
|
||||
bool TestDeathFloor = true;
|
||||
bool TestSteepFloorBelow = true;
|
||||
bool TestSteepFloorAbove = true;
|
||||
bool TestDeathFloor = true;
|
||||
};
|
||||
|
||||
struct MonkeySwingMovementSetupData
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "Game/camera.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/flipeffect.h"
|
||||
#include "Game/control/volume.h"
|
||||
#include "Game/effects/Hair.h"
|
||||
|
@ -47,6 +48,7 @@
|
|||
#include "Specific/winmain.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Control::Volumes;
|
||||
using namespace TEN::Effects::Hair;
|
||||
using namespace TEN::Effects::Items;
|
||||
|
@ -152,7 +154,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
|||
}
|
||||
else if (item->Animation.ActiveState == LS_FREEFALL_DIVE)
|
||||
{
|
||||
SetAnimation(item, LA_SWANDIVE_DIVE);
|
||||
SetAnimation(item, LA_SWANDIVE_FREEFALL_DIVE);
|
||||
item->Animation.Velocity.y /= 2;
|
||||
item->Pose.Orientation.x = ANGLE(-85.0f);
|
||||
player.Control.HandStatus = HandStatus::Free;
|
||||
|
@ -207,7 +209,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
|||
// pre-TR5 bug where player would keep submerged until root mesh was above water level.
|
||||
isWaterOnHeadspace = TestEnvironment(
|
||||
ENV_FLAG_WATER, item->Pose.Position.x, item->Pose.Position.y - CLICK(1), item->Pose.Position.z,
|
||||
GetCollision(item->Pose.Position.x, item->Pose.Position.y - CLICK(1), item->Pose.Position.z, item->RoomNumber).RoomNumber);
|
||||
GetPointCollision(*item, 0, 0, -CLICK(1)).GetRoomNumber());
|
||||
|
||||
if (water.WaterDepth == NO_HEIGHT || abs(water.HeightFromWater) >= CLICK(1) || isWaterOnHeadspace ||
|
||||
item->Animation.AnimNumber == LA_UNDERWATER_RESURFACE || item->Animation.AnimNumber == LA_ONWATER_DIVE)
|
||||
|
@ -333,7 +335,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (DebugMode)
|
||||
{
|
||||
DrawNearbyPathfinding(GetCollision(item).BottomBlock->Box);
|
||||
DrawNearbyPathfinding(GetPointCollision(*item).GetBottomSector().PathfindingBoxID);
|
||||
DrawNearbySectorFlags(*item);
|
||||
}
|
||||
}
|
||||
|
@ -634,12 +636,6 @@ void UpdateLara(ItemInfo* item, bool isTitle)
|
|||
if (isTitle)
|
||||
ActionMap = actionMap;
|
||||
|
||||
if (g_Gui.GetInventoryItemChosen() != NO_VALUE)
|
||||
{
|
||||
g_Gui.SetInventoryItemChosen(NO_VALUE);
|
||||
SayNo();
|
||||
}
|
||||
|
||||
// Update player animations.
|
||||
g_Renderer.UpdateLaraAnimations(true);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Game/animation.h"
|
||||
#include "Game/camera.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/collision/sphere.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/items.h"
|
||||
|
@ -14,6 +15,7 @@
|
|||
#include "Specific/Input/Input.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Input;
|
||||
|
||||
constexpr auto LADDER_TEST_MARGIN = 8;
|
||||
|
@ -327,8 +329,8 @@ void lara_col_climb_idle(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
// HACK: Prevent climbing inside sloped ceilings. Breaks overhang even more, but that shouldn't matter since we'll be doing it over. -- Sezz 2022.05.13
|
||||
int y = item->Pose.Position.y - (coll->Setup.Height + CLICK(0.5f));
|
||||
auto probe = GetCollision(item, 0, 0, -(coll->Setup.Height + CLICK(0.5f)));
|
||||
if ((probe.Position.Ceiling - y) < 0)
|
||||
auto probe = GetPointCollision(*item, 0, 0, -(coll->Setup.Height + CLICK(0.5f)));
|
||||
if ((probe.GetCeilingHeight() - y) < 0)
|
||||
{
|
||||
item->Animation.TargetState = LS_LADDER_UP;
|
||||
item->Pose.Position.y += yShift;
|
||||
|
@ -416,7 +418,7 @@ void lara_as_climb_stepoff_right(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
short GetClimbFlags(int x, int y, int z, short roomNumber)
|
||||
{
|
||||
return GetClimbFlags(GetCollision(x, y, z, roomNumber).BottomBlock);
|
||||
return GetClimbFlags(&GetPointCollision(Vector3i(x, y, z), roomNumber).GetBottomSector());
|
||||
}
|
||||
|
||||
short GetClimbFlags(FloorInfo* floor)
|
||||
|
@ -787,13 +789,13 @@ int LaraTestClimb(ItemInfo* item, int xOffset, int yOffset, int zOffset, int xFr
|
|||
int y = item->Pose.Position.y + yOffset;
|
||||
int z = item->Pose.Position.z + zOffset;
|
||||
|
||||
auto probeUp = GetCollision(x, y - CLICK(0.5f), z, item->RoomNumber);
|
||||
auto probeDown = GetCollision(x, y, z, item->RoomNumber);
|
||||
auto probeUp = GetPointCollision(Vector3i(x, y - CLICK(0.5f), z), item->RoomNumber);
|
||||
auto probeDown = GetPointCollision(Vector3i(x, y, z), item->RoomNumber);
|
||||
|
||||
if (!lara->Control.CanClimbLadder && !TestLaraNearClimbableWall(item, probeDown.BottomBlock))
|
||||
if (!lara->Control.CanClimbLadder && !TestLaraNearClimbableWall(item, &probeDown.GetBottomSector()))
|
||||
return 0;
|
||||
|
||||
int height = probeUp.Position.Floor;
|
||||
int height = probeUp.GetFloorHeight();
|
||||
|
||||
if (height == NO_HEIGHT)
|
||||
return 0;
|
||||
|
@ -805,7 +807,7 @@ int LaraTestClimb(ItemInfo* item, int xOffset, int yOffset, int zOffset, int xFr
|
|||
if (height < 0)
|
||||
*shift = height;
|
||||
|
||||
int ceiling = probeDown.Position.Ceiling - y;
|
||||
int ceiling = probeDown.GetCeilingHeight() - y;
|
||||
if (ceiling > LADDER_CLIMB_SHIFT)
|
||||
return 0;
|
||||
|
||||
|
@ -822,8 +824,8 @@ int LaraTestClimb(ItemInfo* item, int xOffset, int yOffset, int zOffset, int xFr
|
|||
int dz = zFront + z;
|
||||
int dx = xFront + x;
|
||||
|
||||
auto probeFront = GetCollision(dx, y, dz, item->RoomNumber);
|
||||
height = probeFront.Position.Floor;
|
||||
auto probeFront = GetPointCollision(Vector3i(dx, y, dz), item->RoomNumber);
|
||||
height = probeFront.GetFloorHeight();
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
height -= y;
|
||||
|
@ -839,9 +841,9 @@ int LaraTestClimb(ItemInfo* item, int xOffset, int yOffset, int zOffset, int xFr
|
|||
*shift = height;
|
||||
}
|
||||
|
||||
auto probeTop = GetCollision(x, y + itemHeight, z, item->RoomNumber);
|
||||
auto probeTopFront = GetCollision(dx, y + itemHeight, dz, probeTop.RoomNumber);
|
||||
ceiling = probeTopFront.Position.Ceiling;
|
||||
auto probeTop = GetPointCollision(Vector3i(x, y + itemHeight, z), item->RoomNumber);
|
||||
auto probeTopFront = GetPointCollision(Vector3i(dx, y + itemHeight, dz), probeTop.GetRoomNumber());
|
||||
ceiling = probeTopFront.GetCeilingHeight();
|
||||
|
||||
if (ceiling == NO_HEIGHT)
|
||||
return 1;
|
||||
|
@ -862,7 +864,7 @@ int LaraTestClimb(ItemInfo* item, int xOffset, int yOffset, int zOffset, int xFr
|
|||
return 1;
|
||||
}
|
||||
|
||||
ceiling = probeFront.Position.Ceiling - y;
|
||||
ceiling = probeFront.GetCeilingHeight() - y;
|
||||
if (ceiling >= CLICK(2))
|
||||
return 1;
|
||||
|
||||
|
@ -895,16 +897,16 @@ int LaraTestClimbUpPos(ItemInfo* item, int front, int right, int* shift, int* le
|
|||
*shift = 0;
|
||||
|
||||
// Test center.
|
||||
auto pointColl = GetCollision(item);
|
||||
auto pointColl = GetPointCollision(*item);
|
||||
int vPos = item->Pose.Position.y - CLICK(4);
|
||||
if ((pointColl.Position.Ceiling - vPos) > LADDER_CLIMB_SHIFT)
|
||||
if ((pointColl.GetCeilingHeight() - vPos) > LADDER_CLIMB_SHIFT)
|
||||
return 0;
|
||||
|
||||
pointColl = GetCollision(probePos.x, probePos.y, probePos.z, item->RoomNumber);
|
||||
int ceiling = (CLICK(1) - probePos.y) + pointColl.Position.Ceiling;
|
||||
pointColl = GetPointCollision(probePos, item->RoomNumber);
|
||||
int ceiling = (CLICK(1) - probePos.y) + pointColl.GetCeilingHeight();
|
||||
|
||||
pointColl = GetCollision(probePos.x + probeOffset.x, probePos.y, probePos.z + probeOffset.z, pointColl.RoomNumber);
|
||||
int height = pointColl.Position.Floor;
|
||||
pointColl = GetPointCollision(Vector3i(probePos.x + probeOffset.x, probePos.y, probePos.z + probeOffset.z), pointColl.GetRoomNumber());
|
||||
int height = pointColl.GetFloorHeight();
|
||||
|
||||
if (height == NO_HEIGHT)
|
||||
{
|
||||
|
@ -933,10 +935,10 @@ int LaraTestClimbUpPos(ItemInfo* item, int front, int right, int* shift, int* le
|
|||
if (height > 0 && height > *shift)
|
||||
*shift = height;
|
||||
|
||||
pointColl = GetCollision(probePos.x, probePos.y + CLICK(2), probePos.z, item->RoomNumber);
|
||||
pointColl = GetCollision(probePos.x + probeOffset.x, probePos.y + CLICK(2), probePos.z + probeOffset.z, pointColl.RoomNumber);
|
||||
pointColl = GetPointCollision(Vector3i(probePos.x, probePos.y + CLICK(2), probePos.z), item->RoomNumber);
|
||||
pointColl = GetPointCollision(Vector3i(probePos.x + probeOffset.x, probePos.y + CLICK(2), probePos.z + probeOffset.z), pointColl.GetRoomNumber());
|
||||
|
||||
ceiling = pointColl.Position.Ceiling - probePos.y;
|
||||
ceiling = pointColl.GetCeilingHeight() - probePos.y;
|
||||
if (ceiling <= height)
|
||||
return 1;
|
||||
|
||||
|
@ -947,7 +949,7 @@ int LaraTestClimbUpPos(ItemInfo* item, int front, int right, int* shift, int* le
|
|||
}
|
||||
else
|
||||
{
|
||||
ceiling = GetCollision(probePos.x + probeOffset.x, probePos.y, probePos.z + probeOffset.z, pointColl.RoomNumber).Position.Ceiling - probePos.y;
|
||||
ceiling = GetPointCollision(Vector3i(probePos.x + probeOffset.x, probePos.y, probePos.z + probeOffset.z), pointColl.GetRoomNumber()).GetCeilingHeight() - probePos.y;
|
||||
if (ceiling < CLICK(2))
|
||||
{
|
||||
if ((height - ceiling) <= LARA_HEIGHT)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Game/animation.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/items.h"
|
||||
|
@ -19,9 +20,15 @@
|
|||
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
|
||||
#include "Scripting/Include/ScriptInterfaceLevel.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Entities::Player;
|
||||
using namespace TEN::Input;
|
||||
|
||||
constexpr auto DEFLECT_STRAIGHT_ANGLE = ANGLE(5.0f);
|
||||
constexpr auto DEFLECT_DIAGONAL_ANGLE = ANGLE(12.0f);
|
||||
constexpr auto DEFLECT_STRAIGHT_ANGLE_CRAWL = ANGLE(2.0f);
|
||||
constexpr auto DEFLECT_DIAGONAL_ANGLE_CRAWL = ANGLE(5.0f);
|
||||
|
||||
// -----------------------------
|
||||
// COLLISION TEST FUNCTIONS
|
||||
// For State Control & Collision
|
||||
|
@ -43,12 +50,12 @@ bool LaraDeflectEdge(ItemInfo* item, CollisionInfo* coll)
|
|||
if (coll->CollisionType == CollisionType::Left)
|
||||
{
|
||||
ShiftItem(item, coll);
|
||||
item->Pose.Orientation.y += ANGLE(coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y += coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE;
|
||||
}
|
||||
else if (coll->CollisionType == CollisionType::Right)
|
||||
{
|
||||
ShiftItem(item, coll);
|
||||
item->Pose.Orientation.y -= ANGLE(coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y -= coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE;
|
||||
}
|
||||
else if (coll->LastBridgeItemNumber != NO_VALUE)
|
||||
{
|
||||
|
@ -118,11 +125,11 @@ bool LaraDeflectEdgeJump(ItemInfo* item, CollisionInfo* coll)
|
|||
switch (coll->CollisionType)
|
||||
{
|
||||
case CollisionType::Left:
|
||||
item->Pose.Orientation.y += ANGLE(DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y += DEFLECT_STRAIGHT_ANGLE;
|
||||
break;
|
||||
|
||||
case CollisionType::Right:
|
||||
item->Pose.Orientation.y -= ANGLE(DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y -= DEFLECT_STRAIGHT_ANGLE;
|
||||
break;
|
||||
|
||||
case CollisionType::Top:
|
||||
|
@ -154,11 +161,11 @@ void LaraSlideEdgeJump(ItemInfo* item, CollisionInfo* coll)
|
|||
switch (coll->CollisionType)
|
||||
{
|
||||
case CollisionType::Left:
|
||||
item->Pose.Orientation.y += ANGLE(DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y += DEFLECT_STRAIGHT_ANGLE;
|
||||
break;
|
||||
|
||||
case CollisionType::Right:
|
||||
item->Pose.Orientation.y -= ANGLE(DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y -= DEFLECT_STRAIGHT_ANGLE;
|
||||
break;
|
||||
|
||||
case CollisionType::Top:
|
||||
|
@ -196,12 +203,12 @@ bool LaraDeflectEdgeCrawl(ItemInfo* item, CollisionInfo* coll)
|
|||
if (coll->CollisionType == CollisionType::Left)
|
||||
{
|
||||
ShiftItem(item, coll);
|
||||
item->Pose.Orientation.y += ANGLE(coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE_CRAWL : DEFLECT_STRAIGHT_ANGLE_CRAWL);
|
||||
item->Pose.Orientation.y += coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE_CRAWL : DEFLECT_STRAIGHT_ANGLE_CRAWL;
|
||||
}
|
||||
else if (coll->CollisionType == CollisionType::Right)
|
||||
{
|
||||
ShiftItem(item, coll);
|
||||
item->Pose.Orientation.y -= ANGLE(coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE_CRAWL : DEFLECT_STRAIGHT_ANGLE_CRAWL);
|
||||
item->Pose.Orientation.y -= coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE_CRAWL : DEFLECT_STRAIGHT_ANGLE_CRAWL;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -227,12 +234,12 @@ bool LaraDeflectEdgeMonkey(ItemInfo* item, CollisionInfo* coll)
|
|||
if (coll->CollisionType == CollisionType::Left)
|
||||
{
|
||||
ShiftItem(item, coll);
|
||||
item->Pose.Orientation.y += ANGLE(coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y += coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE;
|
||||
}
|
||||
else if (coll->CollisionType == CollisionType::Right)
|
||||
{
|
||||
ShiftItem(item, coll);
|
||||
item->Pose.Orientation.y -= ANGLE(coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
|
||||
item->Pose.Orientation.y -= coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -489,11 +496,17 @@ void LaraSurfaceCollision(ItemInfo* item, CollisionInfo* coll)
|
|||
item->Pose.Orientation.y -= ANGLE(5.0f);
|
||||
}
|
||||
|
||||
auto pointColl = GetCollision(item);
|
||||
auto pointColl = GetPointCollision(*item);
|
||||
int waterHeight = GetWaterHeight(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber);
|
||||
|
||||
if ((pointColl.Position.Floor - item->Pose.Position.y) < SWIM_WATER_DEPTH)
|
||||
if ((pointColl.GetFloorHeight() - item->Pose.Position.y) < SWIM_WATER_DEPTH)
|
||||
{
|
||||
TestPlayerWaterStepOut(item, coll);
|
||||
}
|
||||
else if ((waterHeight - item->Pose.Position.y) <= -LARA_HEADROOM)
|
||||
{
|
||||
SetLaraSwimDiveAnimation(item);
|
||||
}
|
||||
}
|
||||
|
||||
void LaraSwimCollision(ItemInfo* item, CollisionInfo* coll)
|
||||
|
|
|
@ -3,11 +3,6 @@
|
|||
struct ItemInfo;
|
||||
struct CollisionInfo;
|
||||
|
||||
constexpr auto DEFLECT_STRAIGHT_ANGLE = 5.0f;
|
||||
constexpr auto DEFLECT_DIAGONAL_ANGLE = 12.0f;
|
||||
constexpr auto DEFLECT_STRAIGHT_ANGLE_CRAWL = 2.0f;
|
||||
constexpr auto DEFLECT_DIAGONAL_ANGLE_CRAWL = 5.0f;
|
||||
|
||||
// -----------------------------
|
||||
// COLLISION TEST FUNCTIONS
|
||||
// For State Control & Collision
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Game/animation.h"
|
||||
#include "Game/camera.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/effects/chaffFX.h"
|
||||
|
@ -18,6 +19,7 @@
|
|||
#include "Specific/clock.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Math;
|
||||
|
||||
constexpr auto FLARE_LIFE_MAX = 60.0f * FPS;
|
||||
|
@ -258,7 +260,7 @@ void DrawFlare(ItemInfo& laraItem)
|
|||
SoundEffect(
|
||||
SFX_TR4_FLARE_IGNITE_DRY,
|
||||
&laraItem.Pose,
|
||||
TestEnvironment(ENV_FLAG_WATER, &laraItem) ? SoundEnvironment::Water : SoundEnvironment::Land);
|
||||
TestEnvironment(ENV_FLAG_WATER, &laraItem) ? SoundEnvironment::ShallowWater : SoundEnvironment::Land);
|
||||
}
|
||||
|
||||
DoFlareInHand(laraItem, player.Flare.Life);
|
||||
|
@ -323,7 +325,7 @@ void CreateFlare(ItemInfo& laraItem, GAME_OBJECT_ID objectID, bool isThrown)
|
|||
|
||||
flareItem.Pose.Position = pos;
|
||||
|
||||
int floorHeight = GetCollision(pos.x, pos.y, pos.z, laraItem.RoomNumber).Position.Floor;
|
||||
int floorHeight = GetPointCollision(pos, laraItem.RoomNumber).GetFloorHeight();
|
||||
auto isCollided = !GetCollidedObjects(flareItem, true, true).IsEmpty();
|
||||
bool hasLanded = false;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "Game/camera.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/control/volume.h"
|
||||
#include "Game/items.h"
|
||||
|
@ -21,7 +22,6 @@
|
|||
#include "Game/savegame.h"
|
||||
#include "Game/Setup.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Renderer/Renderer.h"
|
||||
#include "Scripting/Include/ScriptInterfaceLevel.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/Input/Input.h"
|
||||
|
@ -37,6 +37,7 @@
|
|||
#include "Objects/TR4/Vehicles/motorbike.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Control::Volumes;
|
||||
using namespace TEN::Effects::Bubble;
|
||||
using namespace TEN::Effects::Drip;
|
||||
|
@ -44,7 +45,6 @@ using namespace TEN::Entities::Player;
|
|||
using namespace TEN::Gui;
|
||||
using namespace TEN::Input;
|
||||
using namespace TEN::Math;
|
||||
using namespace TEN::Renderer;
|
||||
|
||||
// -----------------------------
|
||||
// HELPER FUNCTIONS
|
||||
|
@ -160,9 +160,9 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa
|
|||
const auto& vehicleItem = g_Level.Items[player.Context.Vehicle];
|
||||
if (vehicleItem.ObjectNumber == ID_UPV)
|
||||
{
|
||||
auto pointColl = GetCollision(&item, 0, 0, CLICK(1));
|
||||
auto pointColl = GetPointCollision(item, 0, 0, CLICK(1));
|
||||
|
||||
water.IsCold = (water.IsCold || TestEnvironment(ENV_FLAG_COLD, pointColl.RoomNumber));
|
||||
water.IsCold = (water.IsCold || TestEnvironment(ENV_FLAG_COLD, pointColl.GetRoomNumber()));
|
||||
if (water.IsCold)
|
||||
{
|
||||
player.Status.Exposure--;
|
||||
|
@ -276,50 +276,7 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa
|
|||
}
|
||||
}
|
||||
|
||||
static void UsePlayerMedipack(ItemInfo& item)
|
||||
{
|
||||
auto& player = GetLaraInfo(item);
|
||||
|
||||
// Can't use medipack; return early.
|
||||
if (item.HitPoints <= 0 ||
|
||||
(item.HitPoints >= LARA_HEALTH_MAX && player.Status.Poison == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasUsedMedipack = false;
|
||||
|
||||
if (IsClicked(In::SmallMedipack) &&
|
||||
player.Inventory.TotalSmallMedipacks != 0)
|
||||
{
|
||||
hasUsedMedipack = true;
|
||||
|
||||
item.HitPoints += LARA_HEALTH_MAX / 2;
|
||||
if (item.HitPoints > LARA_HEALTH_MAX)
|
||||
item.HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
if (player.Inventory.TotalSmallMedipacks != -1)
|
||||
player.Inventory.TotalSmallMedipacks--;
|
||||
}
|
||||
else if (IsClicked(In::LargeMedipack) &&
|
||||
player.Inventory.TotalLargeMedipacks != 0)
|
||||
{
|
||||
hasUsedMedipack = true;
|
||||
item.HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
if (player.Inventory.TotalLargeMedipacks != -1)
|
||||
player.Inventory.TotalLargeMedipacks--;
|
||||
}
|
||||
|
||||
if (hasUsedMedipack)
|
||||
{
|
||||
player.Status.Poison = 0;
|
||||
SaveGame::Statistics.Game.HealthUsed++;
|
||||
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
||||
}
|
||||
}
|
||||
|
||||
static std::optional<LaraWeaponType> GetPlayerScrolledWeaponType(const ItemInfo& item, LaraWeaponType currentWeaponType, bool getPrev)
|
||||
static LaraWeaponType GetPlayerScrolledWeaponType(const ItemInfo& item, LaraWeaponType currentWeaponType, bool getPrev)
|
||||
{
|
||||
static const auto SCROLL_WEAPON_TYPES = std::vector<LaraWeaponType>
|
||||
{
|
||||
|
@ -334,15 +291,15 @@ static std::optional<LaraWeaponType> GetPlayerScrolledWeaponType(const ItemInfo&
|
|||
LaraWeaponType::RocketLauncher
|
||||
};
|
||||
|
||||
auto getNextIndex = [getPrev](unsigned int index)
|
||||
auto getNextIndex = [getPrev](int index)
|
||||
{
|
||||
return (index + (getPrev ? ((unsigned int)SCROLL_WEAPON_TYPES.size() - 1) : 1)) % (unsigned int)SCROLL_WEAPON_TYPES.size();
|
||||
return (index + (getPrev ? ((int)SCROLL_WEAPON_TYPES.size() - 1) : 1)) % (int)SCROLL_WEAPON_TYPES.size();
|
||||
};
|
||||
|
||||
auto& player = GetLaraInfo(item);
|
||||
|
||||
// Get vector index for current weapon type.
|
||||
auto currentIndex = std::optional<unsigned int>(std::nullopt);
|
||||
auto currentIndex = NO_VALUE;
|
||||
for (int i = 0; i < SCROLL_WEAPON_TYPES.size(); i++)
|
||||
{
|
||||
if (SCROLL_WEAPON_TYPES[i] == currentWeaponType)
|
||||
|
@ -352,13 +309,13 @@ static std::optional<LaraWeaponType> GetPlayerScrolledWeaponType(const ItemInfo&
|
|||
}
|
||||
}
|
||||
|
||||
// Invalid current weapon type; return nullopt.
|
||||
if (!currentIndex.has_value())
|
||||
return std::nullopt;
|
||||
// Invalid current weapon type; return None type.
|
||||
if (currentIndex == NO_VALUE)
|
||||
return LaraWeaponType::None;
|
||||
|
||||
// Get next valid weapon type in sequence.
|
||||
unsigned int nextIndex = getNextIndex(*currentIndex);
|
||||
while (nextIndex != *currentIndex)
|
||||
int nextIndex = getNextIndex(currentIndex);
|
||||
while (nextIndex != currentIndex)
|
||||
{
|
||||
auto nextWeaponType = SCROLL_WEAPON_TYPES[nextIndex];
|
||||
if (player.Weapons[(int)nextWeaponType].Present)
|
||||
|
@ -367,8 +324,8 @@ static std::optional<LaraWeaponType> GetPlayerScrolledWeaponType(const ItemInfo&
|
|||
nextIndex = getNextIndex(nextIndex);
|
||||
}
|
||||
|
||||
// No valid weapon type; return nullopt.
|
||||
return std::nullopt;
|
||||
// No valid weapon type; return None type.
|
||||
return LaraWeaponType::None;
|
||||
}
|
||||
|
||||
void HandlePlayerQuickActions(ItemInfo& item)
|
||||
|
@ -376,17 +333,21 @@ void HandlePlayerQuickActions(ItemInfo& item)
|
|||
auto& player = GetLaraInfo(item);
|
||||
|
||||
// Handle medipacks.
|
||||
if (IsClicked(In::SmallMedipack) || IsClicked(In::LargeMedipack))
|
||||
UsePlayerMedipack(item);
|
||||
if (IsClicked(In::SmallMedipack))
|
||||
{
|
||||
g_Gui.UseItem(item, GAME_OBJECT_ID::ID_SMALLMEDI_ITEM);
|
||||
}
|
||||
else if (IsClicked(In::LargeMedipack))
|
||||
{
|
||||
g_Gui.UseItem(item, GAME_OBJECT_ID::ID_BIGMEDI_ITEM);
|
||||
}
|
||||
|
||||
// Handle weapon scroll request.
|
||||
if (IsClicked(In::PreviousWeapon) || IsClicked(In::NextWeapon))
|
||||
{
|
||||
bool getPrev = IsClicked(In::PreviousWeapon);
|
||||
auto weaponType = GetPlayerScrolledWeaponType(item, player.Control.Weapon.GunType, getPrev);
|
||||
|
||||
if (weaponType.has_value())
|
||||
player.Control.Weapon.RequestGunType = *weaponType;
|
||||
auto weaponType = GetPlayerScrolledWeaponType(item, player.Control.Weapon.GunType, IsClicked(In::PreviousWeapon));
|
||||
if (weaponType != LaraWeaponType::None)
|
||||
player.Control.Weapon.RequestGunType = weaponType;
|
||||
}
|
||||
|
||||
// Handle weapon requests.
|
||||
|
@ -419,7 +380,7 @@ void HandlePlayerQuickActions(ItemInfo& item)
|
|||
|
||||
// TODO: 10th possible weapon, probably grapple gun.
|
||||
/*if (IsClicked(In::Weapon10) && player.Weapons[(int)LaraWeaponType::].Present)
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::;*/
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::;*/
|
||||
}
|
||||
|
||||
bool CanPlayerLookAround(const ItemInfo& item)
|
||||
|
@ -1029,7 +990,7 @@ void HandlePlayerAirBubbles(ItemInfo* item)
|
|||
{
|
||||
constexpr auto BUBBLE_COUNT_MAX = 3;
|
||||
|
||||
SoundEffect(SFX_TR4_LARA_BUBBLES, &item->Pose, SoundEnvironment::Water);
|
||||
SoundEffect(SFX_TR4_LARA_BUBBLES, &item->Pose, SoundEnvironment::ShallowWater);
|
||||
|
||||
const auto& level = *g_GameFlow->GetLevel(CurrentLevel);
|
||||
|
||||
|
@ -1250,20 +1211,14 @@ LaraInfo*& GetLaraInfo(ItemInfo* item)
|
|||
|
||||
PlayerWaterData GetPlayerWaterData(ItemInfo& item)
|
||||
{
|
||||
bool isWater = TestEnvironment(ENV_FLAG_WATER, &item);
|
||||
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, &item);
|
||||
bool isCold = TestEnvironment(ENV_FLAG_COLD, &item);
|
||||
|
||||
int waterDepth = GetWaterDepth(&item);
|
||||
int waterHeight = GetWaterHeight(&item);
|
||||
|
||||
auto pointColl = GetCollision(item);
|
||||
int heightFromWater = (waterHeight == NO_HEIGHT) ? NO_HEIGHT : (std::min(item.Pose.Position.y, pointColl.Position.Floor) - waterHeight);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
int heightFromWater = (pointColl.GetWaterTopHeight() == NO_HEIGHT) ?
|
||||
NO_HEIGHT : (std::min(item.Pose.Position.y, pointColl.GetFloorHeight()) - pointColl.GetWaterTopHeight());
|
||||
|
||||
return PlayerWaterData
|
||||
{
|
||||
isWater, isSwamp, isCold,
|
||||
waterDepth, waterHeight, heightFromWater
|
||||
TestEnvironment(ENV_FLAG_WATER, &item), TestEnvironment(ENV_FLAG_SWAMP, &item), TestEnvironment(ENV_FLAG_COLD, &item),
|
||||
pointColl.GetWaterBottomHeight(), pointColl.GetWaterTopHeight(), heightFromWater
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1322,20 +1277,20 @@ static short GetLegacySlideHeadingAngle(const Vector3& floorNormal)
|
|||
short GetPlayerSlideHeadingAngle(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
short headingAngle = coll->Setup.ForwardAngle;
|
||||
auto pointColl = GetCollision(item);
|
||||
auto pointColl = GetPointCollision(*item);
|
||||
|
||||
// Ground is flat.
|
||||
if (pointColl.FloorTilt == Vector2::Zero)
|
||||
if (pointColl.GetFloorNormal() == -Vector3::UnitY)
|
||||
return coll->Setup.ForwardAngle;
|
||||
|
||||
// Return slide heading angle.
|
||||
if (g_GameFlow->HasSlideExtended())
|
||||
{
|
||||
return Geometry::GetSurfaceAspectAngle(pointColl.FloorNormal);
|
||||
return Geometry::GetSurfaceAspectAngle(pointColl.GetFloorNormal());
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetLegacySlideHeadingAngle(pointColl.FloorNormal);
|
||||
return GetLegacySlideHeadingAngle(pointColl.GetFloorNormal());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1510,7 +1465,7 @@ void UpdateLaraSubsuitAngles(ItemInfo* item)
|
|||
auto mul1 = (float)abs(lara->Control.Subsuit.Velocity[0]) / BLOCK(8);
|
||||
auto mul2 = (float)abs(lara->Control.Subsuit.Velocity[1]) / BLOCK(8);
|
||||
auto vol = ((mul1 + mul2) * 5.0f) + 0.5f;
|
||||
SoundEffect(SFX_TR5_VEHICLE_DIVESUIT_ENGINE, &item->Pose, SoundEnvironment::Water, 1.0f + (mul1 + mul2), vol);
|
||||
SoundEffect(SFX_TR5_VEHICLE_DIVESUIT_ENGINE, &item->Pose, SoundEnvironment::ShallowWater, 1.0f + (mul1 + mul2), vol);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1524,7 +1479,7 @@ void ModulateLaraSlideVelocity(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (g_GameFlow->HasSlideExtended())
|
||||
{
|
||||
auto probe = GetCollision(item);
|
||||
auto probe = GetPointCollision(*item);
|
||||
short minSlideAngle = ANGLE(33.75f);
|
||||
//short steepness = Geometry::GetSurfaceSlopeAngle(probe.FloorTilt);
|
||||
//short direction = Geometry::GetSurfaceAspectAngle(probe.FloorTilt);
|
||||
|
@ -1533,7 +1488,7 @@ void ModulateLaraSlideVelocity(ItemInfo* item, CollisionInfo* coll)
|
|||
//int slideVelocity = std::min<int>(minVelocity + 10 * (steepness * velocityMultiplier), LARA_TERMINAL_VELOCITY);
|
||||
//short deltaAngle = abs((short)(direction - item->Pose.Orientation.y));
|
||||
|
||||
//g_Renderer.PrintDebugMessage("%d", slideVelocity);
|
||||
//PrintDebugMessage("%d", slideVelocity);
|
||||
|
||||
//lara->ExtraVelocity.x += slideVelocity;
|
||||
//lara->ExtraVelocity.y += slideVelocity * phd_sin(steepness);
|
||||
|
@ -1545,7 +1500,7 @@ void ModulateLaraSlideVelocity(ItemInfo* item, CollisionInfo* coll)
|
|||
void AlignLaraToSurface(ItemInfo* item, float alpha)
|
||||
{
|
||||
// Determine relative orientation adhering to floor normal.
|
||||
auto floorNormal = GetCollision(item).FloorNormal;
|
||||
auto floorNormal = GetPointCollision(*item).GetFloorNormal();
|
||||
auto orient = Geometry::GetRelOrientToNormal(item->Pose.Orientation.y, floorNormal);
|
||||
|
||||
// Apply extra rotation according to alpha.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "framework.h"
|
||||
#include "Game/Lara/lara_initialise.h"
|
||||
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/Hud/Hud.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
|
@ -18,6 +19,7 @@
|
|||
#include "Objects/TR4/Vehicles/motorbike.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Entities::Player;
|
||||
using namespace TEN::Hud;
|
||||
|
||||
|
@ -131,8 +133,8 @@ void InitializeLaraAnims(ItemInfo* item)
|
|||
player.Control.WaterStatus = WaterStatus::Dry;
|
||||
|
||||
// Allow player to start in crawl idle anim if start position is too low.
|
||||
auto pointColl = GetCollision(item);
|
||||
if (abs(pointColl.Position.Ceiling - pointColl.Position.Floor) < LARA_HEIGHT)
|
||||
auto pointColl = GetPointCollision(*item);
|
||||
if (abs(pointColl.GetCeilingHeight() - pointColl.GetFloorHeight()) < LARA_HEIGHT)
|
||||
{
|
||||
SetAnimation(item, LA_CRAWL_IDLE);
|
||||
player.Control.IsLow =
|
||||
|
|
|
@ -64,7 +64,7 @@ void lara_as_jump_forward(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
DoLaraFallDamage(item);
|
||||
|
||||
if (item->HitPoints <= 0) USE_FEATURE_IF_CPP20([[unlikely]])
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else if (IsHeld(In::Forward) && !IsHeld(In::Walk) &&
|
||||
player.Control.WaterStatus != WaterStatus::Wade)
|
||||
|
@ -146,7 +146,7 @@ void lara_as_freefall(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -202,7 +202,7 @@ void lara_as_reach(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -414,7 +414,7 @@ void lara_as_jump_back(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -468,7 +468,7 @@ void lara_as_jump_right(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -523,7 +523,7 @@ void lara_as_jump_left(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -576,7 +576,7 @@ void lara_as_jump_up(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -673,7 +673,7 @@ void lara_as_fall_back(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (item->HitPoints <= 0)
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -749,7 +749,7 @@ void lara_as_swan_dive(ItemInfo* item, CollisionInfo* coll)
|
|||
item->Animation.TargetState = LS_CROUCH_IDLE;
|
||||
TranslateItem(item, coll->Setup.ForwardAngle, CLICK(0.5f)); // HACK: Move forward to avoid standing up or falling out on an edge.
|
||||
}
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
@ -823,7 +823,7 @@ void lara_as_freefall_dive(ItemInfo* item, CollisionInfo* coll)
|
|||
item->Animation.TargetState = LS_DEATH;
|
||||
Rumble(0.5f, 0.2f);
|
||||
}
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
|
||||
SetLaraLand(item, coll);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Game/animation.h"
|
||||
#include "Game/camera.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/box.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/control/los.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "Specific/Input/Input.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Effects::Bubble;
|
||||
using namespace TEN::Effects::Drip;
|
||||
using namespace TEN::Effects::Environment;
|
||||
|
@ -426,7 +428,7 @@ void FireShotgun(ItemInfo& laraItem)
|
|||
|
||||
player.RightArm.GunFlash = Weapons[(int)LaraWeaponType::Shotgun].FlashTime;
|
||||
|
||||
SoundEffect(SFX_TR4_EXPLOSION1, &laraItem.Pose, TestEnvironment(ENV_FLAG_WATER, &laraItem) ? SoundEnvironment::Water : SoundEnvironment::Land);
|
||||
SoundEffect(SFX_TR4_EXPLOSION1, &laraItem.Pose, TestEnvironment(ENV_FLAG_WATER, &laraItem) ? SoundEnvironment::ShallowWater : SoundEnvironment::Land);
|
||||
SoundEffect(Weapons[(int)LaraWeaponType::Shotgun].SampleNum, &laraItem.Pose);
|
||||
|
||||
Rumble(0.5f, 0.2f);
|
||||
|
@ -600,7 +602,7 @@ bool FireHarpoon(ItemInfo& laraItem, const std::optional<Pose>& pose)
|
|||
auto jointPos = GetJointPosition(&laraItem, LM_RHAND, Vector3i(-2, 373, 77));
|
||||
harpoonItem.RoomNumber = laraItem.RoomNumber;
|
||||
|
||||
int floorHeight = GetCollision(jointPos.x, jointPos.y, jointPos.z, harpoonItem.RoomNumber).Position.Floor;
|
||||
int floorHeight = GetPointCollision(jointPos, harpoonItem.RoomNumber).GetFloorHeight();
|
||||
if (floorHeight >= jointPos.y)
|
||||
{
|
||||
harpoonItem.Pose.Position = jointPos;
|
||||
|
@ -693,7 +695,7 @@ void FireGrenade(ItemInfo& laraItem)
|
|||
grenadeItem.Pose.Position = jointPos;
|
||||
auto smokePos = jointPos;
|
||||
|
||||
int floorHeight = GetCollision(jointPos.x, jointPos.y, jointPos.z, grenadeItem.RoomNumber).Position.Floor;
|
||||
int floorHeight = GetPointCollision(jointPos, grenadeItem.RoomNumber).GetFloorHeight();
|
||||
if (floorHeight < jointPos.y)
|
||||
{
|
||||
grenadeItem.Pose.Position.x = laraItem.Pose.Position.x;
|
||||
|
@ -1027,9 +1029,11 @@ void FireCrossbow(ItemInfo& laraItem, const std::optional<Pose>& pose)
|
|||
|
||||
boltItem.RoomNumber = laraItem.RoomNumber;
|
||||
|
||||
int floorHeight = GetCollision(jointPos.x, jointPos.y, jointPos.z, boltItem.RoomNumber).Position.Floor;
|
||||
int floorHeight = GetPointCollision(jointPos, boltItem.RoomNumber).GetFloorHeight();
|
||||
if (floorHeight >= jointPos.y)
|
||||
{
|
||||
boltItem.Pose.Position = jointPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
boltItem.Pose.Position = Vector3i(laraItem.Pose.Position.x, jointPos.y, laraItem.Pose.Position.z);
|
||||
|
@ -1418,20 +1422,20 @@ bool EmitFromProjectile(ItemInfo& projectile, ProjectileType type)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TestProjectileNewRoom(ItemInfo& item, const CollisionResult& coll)
|
||||
bool TestProjectileNewRoom(ItemInfo& item, PointCollisionData& pointColl)
|
||||
{
|
||||
// Check if projectile changed room.
|
||||
if (item.RoomNumber == coll.RoomNumber)
|
||||
if (item.RoomNumber == pointColl.GetRoomNumber())
|
||||
return false;
|
||||
|
||||
// If currently in water and previously on land, spawn ripple.
|
||||
if (TestEnvironment(ENV_FLAG_WATER, item.RoomNumber) != TestEnvironment(ENV_FLAG_WATER, coll.RoomNumber))
|
||||
if (TestEnvironment(ENV_FLAG_WATER, item.RoomNumber) != TestEnvironment(ENV_FLAG_WATER, pointColl.GetRoomNumber()))
|
||||
{
|
||||
const auto& player = GetLaraInfo(item);
|
||||
|
||||
int floorDiff = abs(coll.Position.Floor - item.Pose.Position.y);
|
||||
int ceilingDiff = abs(coll.Position.Ceiling - item.Pose.Position.y);
|
||||
int yPoint = (floorDiff > ceilingDiff) ? coll.Position.Ceiling : coll.Position.Floor;
|
||||
int floorDiff = abs(pointColl.GetFloorHeight() - item.Pose.Position.y);
|
||||
int ceilingDiff = abs(pointColl.GetCeilingHeight() - item.Pose.Position.y);
|
||||
int yPoint = (floorDiff > ceilingDiff) ? pointColl.GetCeilingHeight() : pointColl.GetFloorHeight();
|
||||
|
||||
if (player.Control.Weapon.GunType != LaraWeaponType::GrenadeLauncher && player.Control.Weapon.GunType != LaraWeaponType::RocketLauncher)
|
||||
{
|
||||
|
@ -1447,7 +1451,7 @@ bool TestProjectileNewRoom(ItemInfo& item, const CollisionResult& coll)
|
|||
}
|
||||
}
|
||||
|
||||
ItemNewRoom(item.Index, coll.RoomNumber);
|
||||
ItemNewRoom(item.Index, pointColl.GetRoomNumber());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1475,7 +1479,7 @@ void ExplodeProjectile(ItemInfo& item, const Vector3i& prevPos)
|
|||
|
||||
void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& prevPos, ProjectileType type, int damage)
|
||||
{
|
||||
auto pointColl = GetCollision(&projectile);
|
||||
auto pointColl = GetPointCollision(projectile);
|
||||
|
||||
bool hasHit = false;
|
||||
bool hasHitNotByEmitter = false;
|
||||
|
@ -1485,8 +1489,8 @@ void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& p
|
|||
// For non-grenade projectiles, check for room collision.
|
||||
if (type < ProjectileType::Grenade)
|
||||
{
|
||||
if (pointColl.Position.Floor < projectile.Pose.Position.y ||
|
||||
pointColl.Position.Ceiling > projectile.Pose.Position.y)
|
||||
if (pointColl.GetFloorHeight() < projectile.Pose.Position.y ||
|
||||
pointColl.GetCeilingHeight() > projectile.Pose.Position.y)
|
||||
{
|
||||
hasHit = hasHitNotByEmitter = true;
|
||||
}
|
||||
|
@ -1559,7 +1563,7 @@ void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& p
|
|||
break;
|
||||
|
||||
// Run through statics.
|
||||
for (auto* staticPtr : collObjects.StaticPtrs)
|
||||
for (auto* staticPtr : collObjects.Statics)
|
||||
{
|
||||
hasHit = hasHitNotByEmitter = doShatter = true;
|
||||
doExplosion = isExplosive;
|
||||
|
@ -1580,7 +1584,7 @@ void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& p
|
|||
}
|
||||
|
||||
// Run through items.
|
||||
for (auto* itemPtr : collObjects.ItemPtrs)
|
||||
for (auto* itemPtr : collObjects.Items)
|
||||
{
|
||||
// Object was already affected by collision, skip it.
|
||||
if (std::find(affectedObjects.begin(), affectedObjects.end(), itemPtr->Index) != affectedObjects.end())
|
||||
|
|
|
@ -39,6 +39,7 @@ void HarpoonBoltControl(short itemNumber);
|
|||
void FireGrenade(ItemInfo& laraItem);
|
||||
void GrenadeControl(short itemNumber);
|
||||
void FireRocket(ItemInfo& laraItem);
|
||||
void FireRocket(ItemInfo& laraItem);
|
||||
void RocketControl(short itemNumber);
|
||||
void FireCrossbow(ItemInfo& laraItem, const std::optional<Pose>& pose = std::nullopt);
|
||||
void FireCrossBowFromLaserSight(ItemInfo& laraItem, GameVector* origin, GameVector* target);
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
#include "Game/Lara/lara_overhang.h"
|
||||
|
||||
#include "Game/camera.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/Lara/lara_climb.h"
|
||||
|
@ -16,6 +17,8 @@
|
|||
#include "Specific/Input/Input.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Entities::Generic;
|
||||
using namespace TEN::Input;
|
||||
|
||||
|
@ -324,14 +327,14 @@ void lara_col_slopeclimb(ItemInfo* item, CollisionInfo* coll)
|
|||
auto up = Vector3i(item->Pose.Position.x - slopeData.Offset.x, item->Pose.Position.y - CLICK(1), item->Pose.Position.z - slopeData.Offset.z);
|
||||
auto down = Vector3i(item->Pose.Position.x + slopeData.Offset.x, item->Pose.Position.y + CLICK(1), item->Pose.Position.z + slopeData.Offset.z);
|
||||
|
||||
auto probeNow = GetCollision(now.x, now.y, now.z, item->RoomNumber);
|
||||
auto probeUp = GetCollision(up.x, up.y, up.z, item->RoomNumber);
|
||||
auto probeDown = GetCollision(down.x, down.y, down.z, item->RoomNumber);
|
||||
auto probeNow = GetPointCollision(now, item->RoomNumber);
|
||||
auto probeUp = GetPointCollision(up, item->RoomNumber);
|
||||
auto probeDown = GetPointCollision(down, item->RoomNumber);
|
||||
|
||||
if (item->Animation.AnimNumber == LA_OVERHANG_LADDER_SLOPE_CONCAVE)
|
||||
return;
|
||||
|
||||
item->Pose.Position.y = probeNow.Position.Ceiling + HEIGHT_ADJUST;
|
||||
item->Pose.Position.y = probeNow.GetCeilingHeight() + HEIGHT_ADJUST;
|
||||
|
||||
// Drop down if action not pressed.
|
||||
if (!IsHeld(In::Action))
|
||||
|
@ -351,13 +354,13 @@ void lara_col_slopeclimb(ItemInfo* item, CollisionInfo* coll)
|
|||
if (IsHeld(In::Forward))
|
||||
{
|
||||
// Test for ledge over slope.
|
||||
short tempRoom = probeUp.Block->GetNextRoomNumber(up.x, up.z, false).value_or(NO_VALUE);
|
||||
short tempRoom = probeUp.GetSector().GetNextRoomNumber(up.x, up.z, false).value_or(NO_VALUE);
|
||||
if (tempRoom != NO_VALUE)
|
||||
{
|
||||
auto probeLedge = GetCollision(now.x, now.y - CLICK(3), now.z, tempRoom);
|
||||
auto probeLedge = GetPointCollision(Vector3i(now.x, now.y - CLICK(3), now.z), tempRoom);
|
||||
|
||||
if ((probeLedge.Position.Floor - probeLedge.Position.Ceiling) >= CLICK(3) &&
|
||||
abs((item->Pose.Position.y - (CLICK(2.5f) + 48)) - probeLedge.Position.Floor) < 64)
|
||||
if ((probeLedge.GetFloorHeight() - probeLedge.GetCeilingHeight()) >= CLICK(3) &&
|
||||
abs((item->Pose.Position.y - (CLICK(2.5f) + 48)) - probeLedge.GetFloorHeight()) < 64)
|
||||
{
|
||||
AlignToEdge(item, FORWARD_ALIGNMENT);
|
||||
SetAnimation(item, LA_OVERHANG_LEDGE_VAULT_START); // Ledge climb-up from slope.
|
||||
|
@ -365,32 +368,32 @@ void lara_col_slopeclimb(ItemInfo* item, CollisionInfo* coll)
|
|||
}
|
||||
|
||||
// Test for slope to overhead ladder transition (convex).
|
||||
if (GetClimbFlags(probeUp.BottomBlock) & slopeData.ClimbOrient &&
|
||||
if (GetClimbFlags(&probeUp.GetBottomSector()) & slopeData.ClimbOrient &&
|
||||
InStrip(item->Pose.Position.x, item->Pose.Position.z, item->Pose.Orientation.y, CLICK(3), CLICK(4)))
|
||||
{
|
||||
if (GetCollision(probeUp.Block, up.x, up.y, up.z).Position.Ceiling - item->Pose.Position.y <= (BLOCK(1.5f) - 80)) // Check if a wall is actually there.
|
||||
{
|
||||
AlignToEdge(item, FORWARD_ALIGNMENT);
|
||||
SetAnimation(item, LA_OVERHANG_SLOPE_LADDER_CONVEX_START);
|
||||
}
|
||||
//if (GetPointCollision(probeUp.Block, up.x, up.y, up.z).GetCeilingHeight() - item->Pose.Position.y <= (BLOCK(1.5f) - 80)) // Check if a wall is actually there.
|
||||
//{
|
||||
// AlignToEdge(item, FORWARD_ALIGNMENT);
|
||||
// SetAnimation(item, LA_OVERHANG_SLOPE_LADDER_CONVEX_START);
|
||||
//}
|
||||
}
|
||||
|
||||
// Test for monkey at next position.
|
||||
if (probeUp.BottomBlock->Flags.Monkeyswing)
|
||||
if (probeUp.GetBottomSector().Flags.Monkeyswing)
|
||||
{
|
||||
int yDelta = probeUp.Position.Ceiling - probeNow.Position.Ceiling;
|
||||
int yDelta = probeUp.GetCeilingHeight() - probeNow.GetCeilingHeight();
|
||||
|
||||
int height; // Height variable for bridge ceiling functions.
|
||||
|
||||
// Test for upwards slope to climb.
|
||||
short bridge = FindBridge(4, item->Pose.Orientation.y, up, &height, -CLICK(2.5f), -CLICK(1.5f));
|
||||
if (yDelta >= -CLICK(1.25f) && yDelta <= -CLICK(0.75f) && (SlopeCheck(probeUp.CeilingTilt, slopeData.Goal) || bridge >= 0))
|
||||
if (yDelta >= -CLICK(1.25f) && yDelta <= -CLICK(0.75f) && (SlopeCheck(GetSurfaceTilt(probeUp.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) || bridge >= 0))
|
||||
{
|
||||
// Do one more check for wall/ceiling step 2 * offX / Z further to avoid lara sinking her head in wall/step.
|
||||
auto probeWall = GetCollision((up.x - slopeData.Offset.x), (up.y - CLICK(1)), (up.z - slopeData.Offset.z), item->RoomNumber);
|
||||
auto probeWall = GetPointCollision(Vector3i((up.x - slopeData.Offset.x), (up.y - CLICK(1)), (up.z - slopeData.Offset.z)), item->RoomNumber);
|
||||
|
||||
if (!probeWall.Block->IsWall((up.x - slopeData.Offset.x), (up.z - slopeData.Offset.z)) &&
|
||||
(probeNow.Position.Ceiling - probeWall.Position.Ceiling) > CLICK(0.5f)) // No wall or downward ceiling step.
|
||||
if (!probeWall.GetSector().IsWall((up.x - slopeData.Offset.x), (up.z - slopeData.Offset.z)) &&
|
||||
(probeNow.GetCeilingHeight() - probeWall.GetCeilingHeight()) > CLICK(0.5f)) // No wall or downward ceiling step.
|
||||
{
|
||||
TranslateItem(item, 0, -CLICK(1), -CLICK(1));
|
||||
SetAnimation(item, item->Animation.AnimNumber == LA_OVERHANG_IDLE_LEFT ? LA_OVERHANG_CLIMB_UP_LEFT : LA_OVERHANG_CLIMB_UP_RIGHT);
|
||||
|
@ -405,7 +408,7 @@ void lara_col_slopeclimb(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
// HACK: because of the different calculations of bridge height in TR4 and TEN, we need to lower yDiff tolerance to 0.9f.
|
||||
if (yDelta > -CLICK(0.9f) && yDelta <= -CLICK(0.5f) &&
|
||||
((abs(probeUp.CeilingTilt.x) <= 2 && abs(probeUp.CeilingTilt.y) <= 2) || bridge >= 0))
|
||||
((abs(GetSurfaceTilt(probeUp.GetCeilingNormal(), false).ToVector2().x) <= 2 && abs(GetSurfaceTilt(probeUp.GetCeilingNormal(), false).ToVector2().y) <= 2) || bridge >= 0))
|
||||
{
|
||||
SetAnimation(item, LA_OVERHANG_SLOPE_MONKEY_CONCAVE); // Slope to overhead monkey transition (concave).
|
||||
}
|
||||
|
@ -413,30 +416,30 @@ void lara_col_slopeclimb(ItemInfo* item, CollisionInfo* coll)
|
|||
}
|
||||
else if (IsHeld(In::Back))
|
||||
{
|
||||
if ((GetClimbFlags(GetCollision(probeNow.Block, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z).BottomBlock) & slopeData.ClimbOrient) &&
|
||||
InStrip(item->Pose.Position.x, item->Pose.Position.z, item->Pose.Orientation.y, 0, CLICK(1)))
|
||||
{
|
||||
AlignToEdge(item, BACKWARD_ALIGNMENT);
|
||||
SetAnimation(item, LA_OVERHANG_SLOPE_LADDER_CONCAVE); // Slope to underlying ladder transition (concave).
|
||||
return;
|
||||
}
|
||||
//if ((GetClimbFlags(GetPointCollision(probeNow.Block, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z).BottomBlock) & slopeData.ClimbOrient) &&
|
||||
// InStrip(item->Pose.Position.x, item->Pose.Position.z, item->Pose.Orientation.y, 0, CLICK(1)))
|
||||
//{
|
||||
// AlignToEdge(item, BACKWARD_ALIGNMENT);
|
||||
// SetAnimation(item, LA_OVERHANG_SLOPE_LADDER_CONCAVE); // Slope to underlying ladder transition (concave).
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (probeDown.BottomBlock->Flags.Monkeyswing)
|
||||
if (probeDown.GetBottomSector().Flags.Monkeyswing)
|
||||
{
|
||||
int height;
|
||||
int yDiff = probeDown.Position.Ceiling - probeNow.Position.Ceiling;
|
||||
int yDiff = probeDown.GetCeilingHeight() - probeNow.GetCeilingHeight();
|
||||
|
||||
// Test for flat monkey (abs(slope) < 2).
|
||||
short bridge = FindBridge(0, slopeData.GoalOrient, down, &height, -CLICK(3), -CLICK(2));
|
||||
if (bridge < 0)
|
||||
bridge = FindBridge(1, slopeData.GoalOrient, down, &height, -CLICK(3), -CLICK(2));
|
||||
|
||||
if ((abs(yDiff) < CLICK(1) && abs(probeDown.CeilingTilt.x) <= 2 && abs(probeDown.CeilingTilt.y) <= 2) || bridge >= 0)
|
||||
if ((abs(yDiff) < CLICK(1) && abs(GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2().x) <= 2 && abs(GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2().y) <= 2) || bridge >= 0)
|
||||
SetAnimation(item, LA_OVERHANG_SLOPE_MONKEY_CONVEX); // Force slope to underlying monkey transition (convex)
|
||||
|
||||
// Test for downward slope to climb.
|
||||
bridge = FindBridge(4, slopeData.GoalOrient, down, &height, -CLICK(2.5f), -CLICK(1.5f));
|
||||
if (yDiff >= CLICK(0.75f) && yDiff <= CLICK(1.25f) && (SlopeCheck(probeDown.CeilingTilt, slopeData.Goal) || bridge >= 0))
|
||||
if (yDiff >= CLICK(0.75f) && yDiff <= CLICK(1.25f) && (SlopeCheck(GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) || bridge >= 0))
|
||||
{
|
||||
SetAnimation(item, item->Animation.AnimNumber == LA_OVERHANG_IDLE_LEFT ? LA_OVERHANG_CLIMB_DOWN_LEFT : LA_OVERHANG_CLIMB_DOWN_RIGHT);
|
||||
return;
|
||||
|
@ -491,9 +494,9 @@ void lara_col_slopehang(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
auto now = item->Pose.Position;
|
||||
|
||||
auto probeNow = GetCollision(now.x, now.y, now.z, item->RoomNumber);
|
||||
auto probeNow = GetPointCollision(now, item->RoomNumber);
|
||||
|
||||
item->Pose.Position.y = probeNow.Position.Ceiling + HEIGHT_ADJUST;
|
||||
item->Pose.Position.y = probeNow.GetCeilingHeight() + HEIGHT_ADJUST;
|
||||
|
||||
// Drop down if action not pressed.
|
||||
if (!IsHeld(In::Action))
|
||||
|
@ -528,16 +531,16 @@ void lara_col_slopehang(ItemInfo* item, CollisionInfo* coll)
|
|||
direction = ANGLE(90.0f);
|
||||
}
|
||||
|
||||
auto probeShimmy = GetCollision(shimmy.x, shimmy.y, shimmy.z, item->RoomNumber);
|
||||
auto probeShimmy = GetPointCollision(shimmy, item->RoomNumber);
|
||||
|
||||
if (probeShimmy.BottomBlock->Flags.Monkeyswing)
|
||||
if (probeShimmy.GetBottomSector().Flags.Monkeyswing)
|
||||
{
|
||||
int yDiff = probeShimmy.Position.Ceiling - probeNow.Position.Ceiling;
|
||||
int yDiff = probeShimmy.GetCeilingHeight() - probeNow.GetCeilingHeight();
|
||||
|
||||
int height;
|
||||
short bridge = FindBridge(4, slopeData.GoalOrient, shimmy, &height, -CLICK(2.5f), -CLICK(1.5f));
|
||||
|
||||
if ((SlopeCheck(probeShimmy.CeilingTilt, slopeData.Goal) && abs(yDiff) < 64) || bridge >= 0)
|
||||
if ((SlopeCheck(GetSurfaceTilt(probeShimmy.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) && abs(yDiff) < 64) || bridge >= 0)
|
||||
SetAnimation(item, direction < 0 ? LA_OVERHANG_SHIMMY_LEFT : LA_OVERHANG_SHIMMY_RIGHT);
|
||||
}
|
||||
}
|
||||
|
@ -567,9 +570,9 @@ void lara_col_slopeshimmy(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
auto now = item->Pose.Position;
|
||||
|
||||
auto probeNow = GetCollision(now.x, now.y, now.z, item->RoomNumber);
|
||||
auto probeNow = GetPointCollision(now, item->RoomNumber);
|
||||
|
||||
item->Pose.Position.y = probeNow.Position.Ceiling + HEIGHT_ADJUST;
|
||||
item->Pose.Position.y = probeNow.GetCeilingHeight() + HEIGHT_ADJUST;
|
||||
|
||||
auto shimmy = item->Pose.Position;
|
||||
if (item->Animation.AnimNumber == LA_OVERHANG_SHIMMY_LEFT)
|
||||
|
@ -583,17 +586,17 @@ void lara_col_slopeshimmy(ItemInfo* item, CollisionInfo* coll)
|
|||
shimmy.z -= slopeData.Offset.x / 2;
|
||||
}
|
||||
|
||||
auto probeShimmy = GetCollision(shimmy.x, shimmy.y, shimmy.z, item->RoomNumber);
|
||||
auto probeShimmy = GetPointCollision(shimmy, item->RoomNumber);
|
||||
|
||||
bool cancelShimmy = true;
|
||||
if (probeShimmy.BottomBlock->Flags.Monkeyswing)
|
||||
if (probeShimmy.GetBottomSector().Flags.Monkeyswing)
|
||||
{
|
||||
int yDiff = probeShimmy.Position.Ceiling - probeNow.Position.Ceiling;
|
||||
int yDiff = probeShimmy.GetCeilingHeight() - probeNow.GetCeilingHeight();
|
||||
|
||||
int height;
|
||||
short bridge = FindBridge(4, slopeData.GoalOrient, shimmy, &height, -CLICK(2.5f), -CLICK(1.5f));
|
||||
|
||||
if ((SlopeCheck(probeShimmy.CeilingTilt, slopeData.Goal) && abs(yDiff) < 64) || bridge >= 0)
|
||||
if ((SlopeCheck(GetSurfaceTilt(probeShimmy.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) && abs(yDiff) < 64) || bridge >= 0)
|
||||
cancelShimmy = false;
|
||||
}
|
||||
|
||||
|
@ -836,16 +839,16 @@ void SlopeHangExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
auto down = Vector3i(item->Pose.Position.x + slopeData.Offset.x, item->Pose.Position.y + CLICK(1), item->Pose.Position.z + slopeData.Offset.z);
|
||||
|
||||
auto probeDown = GetCollision(down.x, down.y, down.z, item->RoomNumber);
|
||||
auto probeDown = GetPointCollision(down, item->RoomNumber);
|
||||
|
||||
int ceilDist = item->Pose.Position.y - probeDown.Position.Ceiling;
|
||||
int ceilDist = item->Pose.Position.y - probeDown.GetCeilingHeight();
|
||||
|
||||
if (item->Animation.TargetState == LS_LADDER_IDLE) // Prevent going from hang to climb mode if slope is under ladder.
|
||||
{
|
||||
if (ceilDist >= CLICK(1) && ceilDist < CLICK(2))
|
||||
{
|
||||
if ((probeDown.CeilingTilt.x / 3) == (slopeData.Goal.x / 3) ||
|
||||
(probeDown.CeilingTilt.y / 3) == (slopeData.Goal.y / 3))
|
||||
if ((GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2().x / 3) == (slopeData.Goal.x / 3) ||
|
||||
(GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2().y / 3) == (slopeData.Goal.y / 3))
|
||||
{
|
||||
item->Animation.TargetState = LS_HANG;
|
||||
if (IsHeld(In::Forward))
|
||||
|
@ -861,8 +864,8 @@ void SlopeHangExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
if (ceilDist < CLICK(1))
|
||||
{
|
||||
if ((probeDown.CeilingTilt.x / 3) == (goal.x / 3) ||
|
||||
(probeDown.CeilingTilt.z / 3) == (goal.y / 3))
|
||||
if ((GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2().x / 3) == (goal.x / 3) ||
|
||||
(GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2().z / 3) == (goal.y / 3))
|
||||
{
|
||||
SetAnimation(item, LA_REACH_TO_HANG, 21);
|
||||
}
|
||||
|
@ -881,19 +884,19 @@ void SlopeReachExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
auto now = item->Pose.Position;
|
||||
|
||||
auto probeNow = GetCollision(now.x, now.y, now.z, item->RoomNumber);
|
||||
auto probeNow = GetPointCollision(now, item->RoomNumber);
|
||||
|
||||
int ceilDist = item->Pose.Position.y - probeNow.Position.Ceiling;
|
||||
int ceilDist = item->Pose.Position.y - probeNow.GetCeilingHeight();
|
||||
|
||||
if (probeNow.BottomBlock->Flags.Monkeyswing && ceilDist <= CLICK(3.5f))
|
||||
if (probeNow.GetBottomSector().Flags.Monkeyswing && ceilDist <= CLICK(3.5f))
|
||||
{
|
||||
int height;
|
||||
short bridge = FindBridge(4, slopeData.GoalOrient, now, &height, -CLICK(4), -CLICK(2.5f));
|
||||
|
||||
if (abs(probeNow.CeilingTilt.x) > 2 || abs(probeNow.CeilingTilt.y) > 2 || bridge >= 0)
|
||||
if (abs(GetSurfaceTilt(probeNow.GetCeilingNormal(), false).ToVector2().x) > 2 || abs(GetSurfaceTilt(probeNow.GetCeilingNormal(), false).ToVector2().y) > 2 || bridge >= 0)
|
||||
{
|
||||
bool disableGrab = true;
|
||||
if (SlopeCheck(probeNow.CeilingTilt, slopeData.Goal) || bridge >= 0)
|
||||
if (SlopeCheck(GetSurfaceTilt(probeNow.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) || bridge >= 0)
|
||||
{
|
||||
if (abs(OrientDelta(item->Pose.Orientation.y, slopeData.GoalOrient)) < ANGLE(33.75f))
|
||||
disableGrab = false;
|
||||
|
@ -916,17 +919,17 @@ void SlopeClimbExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
auto now = item->Pose.Position;
|
||||
auto down = Vector3i(item->Pose.Position.x + slopeData.Offset.x, item->Pose.Position.y + CLICK(1), item->Pose.Position.z + slopeData.Offset.z);
|
||||
|
||||
auto probeNow = GetCollision(now.x, now.y, now.z, item->RoomNumber);
|
||||
auto probeDown = GetCollision(down.x, down.y, down.z, item->RoomNumber);
|
||||
auto probeNow = GetPointCollision(now, item->RoomNumber);
|
||||
auto probeDown = GetPointCollision(down, item->RoomNumber);
|
||||
|
||||
// Block for ladder to overhead slope transition.
|
||||
if (item->Animation.AnimNumber == LA_LADDER_IDLE)
|
||||
{
|
||||
if (IsHeld(In::Forward))
|
||||
{
|
||||
int ceilDist = probeNow.Position.Ceiling - item->Pose.Position.y;
|
||||
int ceilDist = probeNow.GetCeilingHeight() - item->Pose.Position.y;
|
||||
|
||||
if (probeNow.BottomBlock->Flags.Monkeyswing && ceilDist >= -CLICK(4) && ceilDist <= -CLICK(3))
|
||||
if (probeNow.GetBottomSector().Flags.Monkeyswing && ceilDist >= -CLICK(4) && ceilDist <= -CLICK(3))
|
||||
{
|
||||
short facing = item->Pose.Orientation.y + ANGLE(45.0f);
|
||||
facing &= ANGLE(270.0f);
|
||||
|
@ -934,9 +937,9 @@ void SlopeClimbExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
int height;
|
||||
short bridge = FindBridge(4, facing, now, &height, -CLICK(4), -CLICK(3));
|
||||
|
||||
if (SlopeCheck(probeNow.CeilingTilt, slopeData.Goal) || bridge >= 0)
|
||||
if (SlopeCheck(GetSurfaceTilt(probeNow.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) || bridge >= 0)
|
||||
{
|
||||
item->Pose.Position.y = probeNow.Position.Ceiling + 900;
|
||||
item->Pose.Position.y = probeNow.GetCeilingHeight() + 900;
|
||||
SetAnimation(item, LA_OVERHANG_LADDER_SLOPE_CONCAVE); // Ladder to overhead slope transition (concave).
|
||||
}
|
||||
}
|
||||
|
@ -944,9 +947,9 @@ void SlopeClimbExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (IsHeld(In::Back))
|
||||
{
|
||||
int ceilDist = probeDown.Position.Ceiling - item->Pose.Position.y;
|
||||
int ceilDist = probeDown.GetCeilingHeight() - item->Pose.Position.y;
|
||||
|
||||
if (probeDown.BottomBlock->Flags.Monkeyswing && ceilDist >= 0 && ceilDist <= CLICK(1))
|
||||
if (probeDown.GetBottomSector().Flags.Monkeyswing && ceilDist >= 0 && ceilDist <= CLICK(1))
|
||||
{
|
||||
short facing = item->Pose.Orientation.y + ANGLE(45.0f);
|
||||
facing &= ANGLE(270.0f);
|
||||
|
@ -954,9 +957,9 @@ void SlopeClimbExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
int height;
|
||||
short bridge = FindBridge(4, facing, down, &height, -CLICK(0.5f), -CLICK(0.25f));
|
||||
|
||||
if (SlopeCheck(probeDown.CeilingTilt, slopeData.Goal) || bridge >= 0)
|
||||
if (SlopeCheck(GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) || bridge >= 0)
|
||||
{
|
||||
item->Pose.Position.y = probeDown.Position.Ceiling - 156;
|
||||
item->Pose.Position.y = probeDown.GetCeilingHeight() - 156;
|
||||
SetAnimation(item, LA_OVERHANG_LADDER_SLOPE_CONVEX); // Ladder to underlying slope transition (convex).
|
||||
}
|
||||
}
|
||||
|
@ -967,12 +970,12 @@ void SlopeClimbExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
// Extends LS_LADDER_IDLE (56)
|
||||
bool LadderMonkeyExtra(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
auto probe = GetCollision(item);
|
||||
auto probe = GetPointCollision(*item);
|
||||
|
||||
if (probe.Position.CeilingSlope)
|
||||
if (probe.IsSteepCeiling())
|
||||
return false;
|
||||
|
||||
if (probe.BottomBlock->Flags.Monkeyswing && (item->Pose.Position.y - coll->Setup.Height - CLICK(0.5f) <= probe.Position.Ceiling))
|
||||
if (probe.GetBottomSector().Flags.Monkeyswing && (item->Pose.Position.y - coll->Setup.Height - CLICK(0.5f) <= probe.GetCeilingHeight()))
|
||||
{
|
||||
item->Animation.TargetState = LS_MONKEY_IDLE;
|
||||
return true;
|
||||
|
@ -991,15 +994,15 @@ void SlopeClimbDownExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
auto down = Vector3i(item->Pose.Position.x + slopeData.Offset.x, item->Pose.Position.y + CLICK(1), item->Pose.Position.z + slopeData.Offset.z);
|
||||
|
||||
auto probeDown = GetCollision(down.x, down.y, down.z, item->RoomNumber);
|
||||
auto probeDown = GetPointCollision(down, item->RoomNumber);
|
||||
|
||||
if (item->Animation.AnimNumber == LA_LADDER_DOWN) // Make Lara stop before underlying slope ceiling at correct height.
|
||||
{
|
||||
if (IsHeld(In::Back))
|
||||
{
|
||||
int ceilDist = probeDown.Position.Ceiling - item->Pose.Position.y;
|
||||
int ceilDist = probeDown.GetCeilingHeight() - item->Pose.Position.y;
|
||||
|
||||
if (probeDown.BottomBlock->Flags.Monkeyswing && ceilDist >= 0 && ceilDist <= CLICK(1))
|
||||
if (probeDown.GetBottomSector().Flags.Monkeyswing && ceilDist >= 0 && ceilDist <= CLICK(1))
|
||||
{
|
||||
short facing = item->Pose.Orientation.y + ANGLE(45.0f);
|
||||
facing &= ANGLE(270.0f);
|
||||
|
@ -1007,9 +1010,9 @@ void SlopeClimbDownExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
int height;
|
||||
short bridge = FindBridge(4, facing, down, &height, -CLICK(0.5f), -CLICK(0.25f));
|
||||
|
||||
if (SlopeCheck(probeDown.CeilingTilt, slopeData.Goal) || bridge >= 0)
|
||||
if (SlopeCheck(GetSurfaceTilt(probeDown.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) || bridge >= 0)
|
||||
{
|
||||
item->Pose.Position.y = probeDown.Position.Ceiling - 156;
|
||||
item->Pose.Position.y = probeDown.GetCeilingHeight() - 156;
|
||||
item->Animation.TargetState = LS_LADDER_IDLE;
|
||||
}
|
||||
}
|
||||
|
@ -1054,14 +1057,14 @@ void SlopeMonkeyExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
auto now = item->Pose.Position;
|
||||
auto down = Vector3i(item->Pose.Position.x + slopeData.Offset.x, item->Pose.Position.y + CLICK(1), item->Pose.Position.z + slopeData.Offset.z);
|
||||
|
||||
auto probeNow = GetCollision(now.x, now.y, now.z, item->RoomNumber);
|
||||
auto probeDown = GetCollision(down.x, down.y, down.z, item->RoomNumber);
|
||||
auto probeNow = GetPointCollision(now, item->RoomNumber);
|
||||
auto probeDown = GetPointCollision(down, item->RoomNumber);
|
||||
|
||||
if (item->Animation.AnimNumber == LA_REACH_TO_MONKEY && !GetFrameIndex(item, 0)) // Manage proper grabbing of monkey slope on forward jump.
|
||||
{
|
||||
int ceilDist = item->Pose.Position.y - probeNow.Position.Ceiling;
|
||||
int ceilDist = item->Pose.Position.y - probeNow.GetCeilingHeight();
|
||||
|
||||
if (probeNow.BottomBlock->Flags.Monkeyswing && ceilDist <= CLICK(3.5f))
|
||||
if (probeNow.GetBottomSector().Flags.Monkeyswing && ceilDist <= CLICK(3.5f))
|
||||
{
|
||||
short facing = item->Pose.Orientation.y + ANGLE(45.0f);
|
||||
facing &= 0xC000;
|
||||
|
@ -1069,12 +1072,12 @@ void SlopeMonkeyExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
int height;
|
||||
short bridge = FindBridge(4, facing, now, &height, -CLICK(3.5f), -CLICK(2.5f));
|
||||
|
||||
if (SlopeCheck(probeNow.CeilingTilt, slopeData.Goal) || bridge >= 0)
|
||||
if (SlopeCheck(GetSurfaceTilt(probeNow.GetCeilingNormal(), false).ToVector2(), slopeData.Goal) || bridge >= 0)
|
||||
{
|
||||
lara->Context.NextCornerPos.Orientation.z = AlignToGrab(item);
|
||||
|
||||
int ceiling = GetCollision(probeNow.Block, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z).Position.Ceiling;
|
||||
item->Pose.Position.y = ceiling + HEIGHT_ADJUST;
|
||||
/*int ceiling = GetPointCollision(probeNow.Block, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z).GetCeilingHeight();
|
||||
item->Pose.Position.y = ceiling + HEIGHT_ADJUST;*/
|
||||
|
||||
SetAnimation(item, LA_OVERHANG_HANG_SWING);
|
||||
}
|
||||
|
@ -1083,16 +1086,16 @@ void SlopeMonkeyExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
if (IsHeld(In::Forward)) // Monkey to slope transitions.
|
||||
{
|
||||
if (probeNow.BottomBlock->Flags.Monkeyswing &&
|
||||
if (probeNow.GetBottomSector().Flags.Monkeyswing &&
|
||||
((item->Animation.AnimNumber == LA_REACH_TO_MONKEY && GetFrameIndex(item, 0) >= 54) || item->Animation.AnimNumber == LA_MONKEY_IDLE))
|
||||
{
|
||||
if (abs(OrientDelta(slopeData.GoalOrient, item->Pose.Orientation.y)) <= ANGLE(30.0f) &&
|
||||
InStrip(item->Pose.Position.x, item->Pose.Position.z, item->Pose.Orientation.y, 0, CLICK(0.5f)))
|
||||
{
|
||||
if (probeDown.BottomBlock->Flags.Monkeyswing)
|
||||
/*if (probeDown.BottomBlock->Flags.Monkeyswing)
|
||||
{
|
||||
int ceiling = GetCollision(probeDown.Block, down.x, now.y, down.z).Position.Ceiling;
|
||||
int yDiff = ceiling - probeNow.Position.Ceiling;
|
||||
int ceiling = GetPointCollision(probeDown.Block, down.x, now.y, down.z).GetCeilingHeight();
|
||||
int yDiff = ceiling - probeNow.GetCeilingHeight();
|
||||
|
||||
int height;
|
||||
short bridge = FindBridge(4, slopeData.GoalOrient, down, &height, -CLICK(7) >> 1, -CLICK(5) >> 1);
|
||||
|
@ -1113,7 +1116,7 @@ void SlopeMonkeyExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
return;
|
||||
//item->Pose.Position.y = ceiling + 914;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1122,19 +1125,19 @@ void SlopeMonkeyExtra(ItemInfo* item, CollisionInfo* coll)
|
|||
// Additional overhang ladder tests.
|
||||
|
||||
int y = item->Pose.Position.y - coll->Setup.Height;
|
||||
auto probe = GetCollision(down.x, item->Pose.Position.y - coll->Setup.Height, down.z, item->RoomNumber);
|
||||
auto probe = GetPointCollision(Vector3i(down.x, item->Pose.Position.y - coll->Setup.Height, down.z), item->RoomNumber);
|
||||
|
||||
if (probe.BottomBlock->Flags.IsWallClimbable(GetClimbDirectionFlags(item->Pose.Orientation.y + ANGLE(180.0f))) &&
|
||||
probe.Position.Floor >= (item->Pose.Position.y - CLICK(1)) &&
|
||||
probe.Position.Ceiling <= (y - CLICK(1)))
|
||||
if (probe.GetBottomSector().Flags.IsWallClimbable(GetClimbDirectionFlags(item->Pose.Orientation.y + ANGLE(180.0f))) &&
|
||||
probe.GetFloorHeight() >= (item->Pose.Position.y - CLICK(1)) &&
|
||||
probe.GetCeilingHeight() <= (y - CLICK(1)))
|
||||
{
|
||||
// Primary checks succeeded, now do C-shaped secondary probing.
|
||||
probe = GetCollision(down.x, y, down.z, probe.RoomNumber);
|
||||
probe = GetCollision(down.x, y - CLICK(2), down.z, probe.RoomNumber);
|
||||
probe = GetCollision(now.x, y - CLICK(2), now.z, probe.RoomNumber);
|
||||
probe = GetPointCollision(Vector3i(down.x, y, down.z), probe.GetRoomNumber());
|
||||
probe = GetPointCollision(Vector3i(down.x, y - CLICK(2), down.z), probe.GetRoomNumber());
|
||||
probe = GetPointCollision(Vector3i(now.x, y - CLICK(2), now.z), probe.GetRoomNumber());
|
||||
|
||||
if (probe.Position.Floor <= (y - CLICK(1)) ||
|
||||
probe.Position.Ceiling >= (y - CLICK(1)))
|
||||
if (probe.GetFloorHeight() <= (y - CLICK(1)) ||
|
||||
probe.GetCeilingHeight() >= (y - CLICK(1)))
|
||||
{
|
||||
if (item->Animation.TargetState != LS_LADDER_IDLE)
|
||||
{
|
||||
|
|
|
@ -1024,7 +1024,7 @@ public:
|
|||
|
||||
Ammo& operator --()
|
||||
{
|
||||
assertion(Count > 0, "Ammo count is already 0.");
|
||||
TENAssert(Count > 0, "Ammo count is already 0.");
|
||||
--Count;
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -273,6 +273,5 @@ void lara_as_surface_climb_out(ItemInfo* item, CollisionInfo* coll)
|
|||
player.Control.Look.Mode = LookMode::None;
|
||||
coll->Setup.EnableObjectPush = false;
|
||||
coll->Setup.EnableSpasm = false;
|
||||
Camera.flags = CF_FOLLOW_CENTER;
|
||||
Camera.laraNode = LM_HIPS; // Forces the camera to follow Lara instead of snapping.
|
||||
Camera.flags = CF_FOLLOW_CENTER; // Forces the camera to follow Lara instead of snapping.
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Game/animation.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/control/los.h"
|
||||
#include "Game/items.h"
|
||||
|
@ -16,16 +17,16 @@
|
|||
#include "Game/Lara/lara_helpers.h"
|
||||
#include "Game/Lara/lara_monkey.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Renderer/Renderer.h"
|
||||
#include "Specific/configuration.h"
|
||||
#include "Specific/Input/Input.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/trutils.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Entities::Player;
|
||||
using namespace TEN::Input;
|
||||
using namespace TEN::Math;
|
||||
using namespace TEN::Renderer;
|
||||
using namespace TEN::Utils;
|
||||
|
||||
// -----------------------------
|
||||
|
@ -46,18 +47,18 @@ bool TestValidLedge(ItemInfo* item, CollisionInfo* coll, bool ignoreHeadroom, bo
|
|||
int y = item->Pose.Position.y - coll->Setup.Height;
|
||||
|
||||
// Get frontal collision data
|
||||
auto frontLeft = GetCollision(item->Pose.Position.x + xl, y, item->Pose.Position.z + zl, GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber);
|
||||
auto frontRight = GetCollision(item->Pose.Position.x + xr, y, item->Pose.Position.z + zr, GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber);
|
||||
auto frontLeft = GetPointCollision(Vector3i(item->Pose.Position.x + xl, y, item->Pose.Position.z + zl), GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber);
|
||||
auto frontRight = GetPointCollision(Vector3i(item->Pose.Position.x + xr, y, item->Pose.Position.z + zr), GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber);
|
||||
|
||||
// If any of the frontal collision results intersects item bounds, return false, because there is material intersection.
|
||||
// This check helps to filter out cases when Lara is formally facing corner but ledge check returns true because probe distance is fixed.
|
||||
if (frontLeft.Position.Floor < (item->Pose.Position.y - CLICK(0.5f)) || frontRight.Position.Floor < (item->Pose.Position.y - CLICK(0.5f)))
|
||||
if (frontLeft.GetFloorHeight() < (item->Pose.Position.y - CLICK(0.5f)) || frontRight.GetFloorHeight() < (item->Pose.Position.y - CLICK(0.5f)))
|
||||
return false;
|
||||
if (frontLeft.Position.Ceiling > (item->Pose.Position.y - coll->Setup.Height) || frontRight.Position.Ceiling > (item->Pose.Position.y - coll->Setup.Height))
|
||||
if (frontLeft.GetCeilingHeight() >(item->Pose.Position.y - coll->Setup.Height) || frontRight.GetCeilingHeight() > (item->Pose.Position.y - coll->Setup.Height))
|
||||
return false;
|
||||
|
||||
//g_Renderer.AddDebugSphere(Vector3(item->pos.Position.x + xl, left, item->pos.Position.z + zl), 64, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
//g_Renderer.AddDebugSphere(Vector3(item->pos.Position.x + xr, right, item->pos.Position.z + zr), 64, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
//DrawDebugSphere(Vector3(item->pos.Position.x + xl, left, item->pos.Position.z + zl), 64, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
//DrawDebugSphere(Vector3(item->pos.Position.x + xr, right, item->pos.Position.z + zr), 64, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
|
||||
// Determine ledge probe embed offset.
|
||||
// We use 0.2f radius extents here for two purposes. First - we can't guarantee that shifts weren't already applied
|
||||
|
@ -66,8 +67,8 @@ bool TestValidLedge(ItemInfo* item, CollisionInfo* coll, bool ignoreHeadroom, bo
|
|||
int zf = phd_cos(coll->NearestLedgeAngle) * (coll->Setup.Radius * 1.2f);
|
||||
|
||||
// Get floor heights at both points
|
||||
auto left = GetCollision(item->Pose.Position.x + xf + xl, y, item->Pose.Position.z + zf + zl, GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber).Position.Floor;
|
||||
auto right = GetCollision(item->Pose.Position.x + xf + xr, y, item->Pose.Position.z + zf + zr, GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber).Position.Floor;
|
||||
auto left = GetPointCollision(Vector3i(item->Pose.Position.x + xf + xl, y, item->Pose.Position.z + zf + zl), GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber).GetFloorHeight();
|
||||
auto right = GetPointCollision(Vector3i(item->Pose.Position.x + xf + xr, y, item->Pose.Position.z + zf + zr), GetRoomVector(item->Location, Vector3i(item->Pose.Position.x, y, item->Pose.Position.z)).RoomNumber).GetFloorHeight();
|
||||
|
||||
// If specified, limit vertical search zone only to nearest height
|
||||
if (heightLimit && (abs(left - y) > CLICK(0.5f) || abs(right - y) > CLICK(0.5f)))
|
||||
|
@ -214,7 +215,7 @@ bool TestLaraHang(ItemInfo* item, CollisionInfo* coll)
|
|||
z += testShift.y;
|
||||
}
|
||||
|
||||
if (TestLaraNearClimbableWall(item, GetCollision(x, item->Pose.Position.y, z, item->RoomNumber).BottomBlock))
|
||||
if (TestLaraNearClimbableWall(item, &GetPointCollision(Vector3i(x, item->Pose.Position.y, z), item->RoomNumber).GetBottomSector()))
|
||||
{
|
||||
if (!TestLaraHangOnClimbableWall(item, coll))
|
||||
verticalShift = 0; // Ignore vertical shift if ladder is encountered next block
|
||||
|
@ -450,7 +451,7 @@ bool TestLaraClimbIdle(ItemInfo* item, CollisionInfo* coll)
|
|||
bool TestLaraNearClimbableWall(ItemInfo* item, FloorInfo* floor)
|
||||
{
|
||||
if (floor == nullptr)
|
||||
floor = GetCollision(item).BottomBlock;
|
||||
floor = &GetPointCollision(*item).GetBottomSector();
|
||||
|
||||
return ((256 << (GetQuadrant(item->Pose.Orientation.y))) & GetClimbFlags(floor));
|
||||
}
|
||||
|
@ -523,7 +524,7 @@ bool TestLaraValidHangPosition(ItemInfo* item, CollisionInfo* coll)
|
|||
// Get incoming ledge height and own Lara's upper bound.
|
||||
// First one will be negative while first one is positive.
|
||||
// Difference between two indicates difference in height between ledges.
|
||||
auto frontFloor = GetCollision(item, lara->Control.MoveAngle, coll->Setup.Radius + CLICK(0.5f), -LARA_HEIGHT).Position.Floor;
|
||||
auto frontFloor = GetPointCollision(*item, lara->Control.MoveAngle, coll->Setup.Radius + CLICK(0.5f), -LARA_HEIGHT).GetFloorHeight();
|
||||
auto laraUpperBound = item->Pose.Position.y - coll->Setup.Height;
|
||||
|
||||
// If difference is above 1/2 click, return false (ledge is out of reach).
|
||||
|
@ -582,7 +583,7 @@ CornerType TestLaraHangCorner(ItemInfo* item, CollisionInfo* coll, float testAng
|
|||
item->Pose = cornerResult.RealPositionResult;
|
||||
lara->Context.NextCornerPos.Position = Vector3i(
|
||||
item->Pose.Position.x,
|
||||
GetCollision(item, item->Pose.Orientation.y, coll->Setup.Radius + 16, -(coll->Setup.Height + CLICK(0.5f))).Position.Floor + abs(bounds.Y1),
|
||||
GetPointCollision(*item, item->Pose.Orientation.y, coll->Setup.Radius + 16, -(coll->Setup.Height + CLICK(0.5f))).GetFloorHeight() + abs(bounds.Y1),
|
||||
item->Pose.Position.z
|
||||
);
|
||||
lara->Context.NextCornerPos.Orientation.y = item->Pose.Orientation.y;
|
||||
|
@ -640,7 +641,7 @@ CornerType TestLaraHangCorner(ItemInfo* item, CollisionInfo* coll, float testAng
|
|||
// Store next position
|
||||
item->Pose = cornerResult.RealPositionResult;
|
||||
lara->Context.NextCornerPos.Position.x = item->Pose.Position.x;
|
||||
lara->Context.NextCornerPos.Position.y = GetCollision(item, item->Pose.Orientation.y, coll->Setup.Radius * 1.25f, -(abs(bounds.Y1) + LARA_HEADROOM)).Position.Floor + abs(bounds.Y1);
|
||||
lara->Context.NextCornerPos.Position.y = GetPointCollision(*item, item->Pose.Orientation.y, coll->Setup.Radius * 1.25f, -(abs(bounds.Y1) + LARA_HEADROOM)).GetFloorHeight() + abs(bounds.Y1);
|
||||
lara->Context.NextCornerPos.Position.z = item->Pose.Position.z;
|
||||
lara->Context.NextCornerPos.Orientation.y = item->Pose.Orientation.y;
|
||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||
|
@ -745,11 +746,11 @@ bool TestHangSwingIn(ItemInfo* item, CollisionInfo* coll)
|
|||
auto* lara = GetLaraInfo(item);
|
||||
|
||||
int y = item->Pose.Position.y;
|
||||
auto probe = GetCollision(item, item->Pose.Orientation.y, OFFSET_RADIUS(coll->Setup.Radius));
|
||||
auto probe = GetPointCollision(*item, item->Pose.Orientation.y, OFFSET_RADIUS(coll->Setup.Radius));
|
||||
|
||||
if ((probe.Position.Floor - y) > 0 &&
|
||||
(probe.Position.Ceiling - y) < -CLICK(1.6f) &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
if ((probe.GetFloorHeight() - y) > 0 &&
|
||||
(probe.GetCeilingHeight() - y) < -CLICK(1.6f) &&
|
||||
probe.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -852,32 +853,22 @@ bool LaraPositionOnLOS(ItemInfo* item, short angle, int distance)
|
|||
|
||||
int LaraFloorFront(ItemInfo* item, short angle, int distance)
|
||||
{
|
||||
return LaraCollisionFront(item, angle, distance).Position.Floor;
|
||||
auto pointColl = GetPointCollision(*item, angle, distance, -LARA_HEIGHT);
|
||||
|
||||
if (pointColl.GetFloorHeight() == NO_HEIGHT)
|
||||
return pointColl.GetFloorHeight();
|
||||
|
||||
return (pointColl.GetFloorHeight() - item->Pose.Position.y);
|
||||
}
|
||||
|
||||
int LaraCeilingFront(ItemInfo* item, short angle, int distance, int height)
|
||||
{
|
||||
return LaraCeilingCollisionFront(item, angle, distance, height).Position.Ceiling;
|
||||
}
|
||||
auto pointColl = GetPointCollision(*item, angle, distance, -height);
|
||||
|
||||
CollisionResult LaraCollisionFront(ItemInfo* item, short angle, int distance)
|
||||
{
|
||||
auto probe = GetCollision(item, angle, distance, -LARA_HEIGHT);
|
||||
if (pointColl.GetCeilingHeight() == NO_HEIGHT)
|
||||
return pointColl.GetCeilingHeight();
|
||||
|
||||
if (probe.Position.Floor != NO_HEIGHT)
|
||||
probe.Position.Floor -= item->Pose.Position.y;
|
||||
|
||||
return probe;
|
||||
}
|
||||
|
||||
CollisionResult LaraCeilingCollisionFront(ItemInfo* item, short angle, int distance, int height)
|
||||
{
|
||||
auto probe = GetCollision(item, angle, distance, -height);
|
||||
|
||||
if (probe.Position.Ceiling != NO_HEIGHT)
|
||||
probe.Position.Ceiling += height - item->Pose.Position.y;
|
||||
|
||||
return probe;
|
||||
return ((pointColl.GetCeilingHeight() + height) - item->Pose.Position.y);
|
||||
}
|
||||
|
||||
bool TestPlayerWaterStepOut(ItemInfo* item, CollisionInfo* coll)
|
||||
|
@ -885,17 +876,17 @@ bool TestPlayerWaterStepOut(ItemInfo* item, CollisionInfo* coll)
|
|||
auto& player = GetLaraInfo(*item);
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(item);
|
||||
auto pointColl = GetPointCollision(*item);
|
||||
int vPos = item->Pose.Position.y;
|
||||
|
||||
if (coll->CollisionType == CollisionType::Front ||
|
||||
pointColl.Position.FloorSlope ||
|
||||
(pointColl.Position.Floor - vPos) <= 0)
|
||||
pointColl.IsSteepFloor() ||
|
||||
(pointColl.GetFloorHeight() - vPos) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((pointColl.Position.Floor - vPos) >= -CLICK(0.5f))
|
||||
if ((pointColl.GetFloorHeight() - vPos) >= -CLICK(0.5f))
|
||||
{
|
||||
SetAnimation(item, LA_STAND_IDLE);
|
||||
}
|
||||
|
@ -905,7 +896,7 @@ bool TestPlayerWaterStepOut(ItemInfo* item, CollisionInfo* coll)
|
|||
item->Animation.TargetState = LS_IDLE;
|
||||
}
|
||||
|
||||
item->Pose.Position.y = pointColl.Position.Floor;
|
||||
item->Pose.Position.y = pointColl.GetFloorHeight();
|
||||
UpdateLaraRoom(item, -(STEPUP_HEIGHT - 3));
|
||||
|
||||
ResetPlayerLean(item);
|
||||
|
@ -961,8 +952,8 @@ bool TestLaraWaterClimbOut(ItemInfo* item, CollisionInfo* coll)
|
|||
if (coll->HitStatic)
|
||||
return false;
|
||||
|
||||
auto probe = GetCollision(item, coll->Setup.ForwardAngle, CLICK(2), -CLICK(1));
|
||||
int headroom = probe.Position.Floor - probe.Position.Ceiling;
|
||||
auto probe = GetPointCollision(*item, coll->Setup.ForwardAngle, CLICK(2), -CLICK(1));
|
||||
int headroom = probe.GetFloorHeight() - probe.GetCeilingHeight();
|
||||
|
||||
if (frontFloor <= -CLICK(1))
|
||||
{
|
||||
|
@ -1095,8 +1086,8 @@ void TestLaraWaterDepth(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
auto& player = GetLaraInfo(*item);
|
||||
|
||||
auto pointColl = GetCollision(item);
|
||||
int waterDepth = GetWaterDepth(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, pointColl.RoomNumber);
|
||||
auto pointColl = GetPointCollision(*item);
|
||||
int waterDepth = GetWaterDepth(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, pointColl.GetRoomNumber());
|
||||
|
||||
if (waterDepth == NO_HEIGHT)
|
||||
{
|
||||
|
@ -1109,7 +1100,7 @@ void TestLaraWaterDepth(ItemInfo* item, CollisionInfo* coll)
|
|||
SetAnimation(item, LA_UNDERWATER_TO_STAND);
|
||||
ResetPlayerLean(item);
|
||||
item->Animation.TargetState = LS_IDLE;
|
||||
item->Pose.Position.y = pointColl.Position.Floor;
|
||||
item->Pose.Position.y = pointColl.GetFloorHeight();
|
||||
item->Animation.IsAirborne = false;
|
||||
item->Animation.Velocity.y = 0.0f;
|
||||
item->Animation.Velocity.z = 0.0f;
|
||||
|
@ -1202,12 +1193,12 @@ std::optional<VaultTestResult> TestLaraVaultTolerance(ItemInfo* item, CollisionI
|
|||
auto* lara = GetLaraInfo(item);
|
||||
|
||||
int distance = OFFSET_RADIUS(coll->Setup.Radius);
|
||||
auto probeFront = GetCollision(item, coll->NearestLedgeAngle, distance, -coll->Setup.Height);
|
||||
auto probeMiddle = GetCollision(item);
|
||||
auto probeFront = GetPointCollision(*item, coll->NearestLedgeAngle, distance, -coll->Setup.Height);
|
||||
auto probeMiddle = GetPointCollision(*item);
|
||||
|
||||
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
||||
bool swampTooDeep = testSetup.CheckSwampDepth ? (isSwamp && lara->Context.WaterSurfaceDist < -CLICK(3)) : isSwamp;
|
||||
int y = isSwamp ? item->Pose.Position.y : probeMiddle.Position.Floor; // HACK: Avoid cheese when in the midst of performing a step. Can be done better. @Sezz 2022.04.08
|
||||
int y = isSwamp ? item->Pose.Position.y : probeMiddle.GetFloorHeight(); // HACK: Avoid cheese when in the midst of performing a step. Can be done better. @Sezz 2022.04.08
|
||||
|
||||
// Check swamp depth (if applicable).
|
||||
if (swampTooDeep)
|
||||
|
@ -1220,27 +1211,27 @@ std::optional<VaultTestResult> TestLaraVaultTolerance(ItemInfo* item, CollisionI
|
|||
|
||||
// Raise y position of point/room probe by increments of CLICK(0.5f) to find potential vault ledge.
|
||||
int yOffset = testSetup.LowerFloorBound;
|
||||
while (((probeFront.Position.Ceiling - y) > -coll->Setup.Height || // Ceiling is below Lara's height...
|
||||
abs(probeFront.Position.Ceiling - probeFront.Position.Floor) <= testSetup.ClampMin || // OR clamp is too small
|
||||
abs(probeFront.Position.Ceiling - probeFront.Position.Floor) > testSetup.ClampMax) && // OR clamp is too large (future-proofing; not possible right now).
|
||||
while (((probeFront.GetCeilingHeight() - y) > -coll->Setup.Height || // Ceiling is below Lara's height...
|
||||
abs(probeFront.GetCeilingHeight() - probeFront.GetFloorHeight()) <= testSetup.ClampMin || // OR clamp is too small
|
||||
abs(probeFront.GetCeilingHeight() - probeFront.GetFloorHeight()) > testSetup.ClampMax) && // OR clamp is too large (future-proofing; not possible right now).
|
||||
yOffset > (testSetup.UpperFloorBound - coll->Setup.Height)) // Offset is not too high.
|
||||
{
|
||||
probeFront = GetCollision(item, coll->NearestLedgeAngle, distance, yOffset);
|
||||
probeFront = GetPointCollision(*item, coll->NearestLedgeAngle, distance, yOffset);
|
||||
yOffset -= std::max<int>(CLICK(0.5f), testSetup.ClampMin);
|
||||
}
|
||||
|
||||
// Discard walls.
|
||||
if (probeFront.Position.Floor == NO_HEIGHT)
|
||||
if (probeFront.GetFloorHeight() == NO_HEIGHT)
|
||||
return std::nullopt;
|
||||
|
||||
// Assess point/room collision.
|
||||
if ((probeFront.Position.Floor - y) < testSetup.LowerFloorBound && // Within lower floor bound.
|
||||
(probeFront.Position.Floor - y) >= testSetup.UpperFloorBound && // Within upper floor bound.
|
||||
abs(probeFront.Position.Ceiling - probeFront.Position.Floor) > testSetup.ClampMin && // Within clamp min.
|
||||
abs(probeFront.Position.Ceiling - probeFront.Position.Floor) <= testSetup.ClampMax && // Within clamp max.
|
||||
abs(probeMiddle.Position.Ceiling - probeFront.Position.Floor) >= testSetup.GapMin) // Gap is optically permissive.
|
||||
if ((probeFront.GetFloorHeight() - y) < testSetup.LowerFloorBound && // Within lower floor bound.
|
||||
(probeFront.GetFloorHeight() - y) >= testSetup.UpperFloorBound && // Within upper floor bound.
|
||||
abs(probeFront.GetCeilingHeight() - probeFront.GetFloorHeight()) > testSetup.ClampMin && // Within clamp min.
|
||||
abs(probeFront.GetCeilingHeight() - probeFront.GetFloorHeight()) <= testSetup.ClampMax && // Within clamp max.
|
||||
abs(probeMiddle.GetCeilingHeight() - probeFront.GetFloorHeight()) >= testSetup.GapMin) // Gap is optically permissive.
|
||||
{
|
||||
return VaultTestResult{ probeFront.Position.Floor };
|
||||
return VaultTestResult{ probeFront.GetFloorHeight() };
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
@ -1390,20 +1381,20 @@ std::optional<VaultTestResult> TestLaraLadderAutoJump(ItemInfo* item, CollisionI
|
|||
|
||||
int y = item->Pose.Position.y;
|
||||
int distance = OFFSET_RADIUS(coll->Setup.Radius);
|
||||
auto probeFront = GetCollision(item, coll->NearestLedgeAngle, distance, -coll->Setup.Height);
|
||||
auto probeMiddle = GetCollision(item);
|
||||
auto probeFront = GetPointCollision(*item, coll->NearestLedgeAngle, distance, -coll->Setup.Height);
|
||||
auto probeMiddle = GetPointCollision(*item);
|
||||
|
||||
// Check ledge angle.
|
||||
if (!TestValidLedgeAngle(item, coll))
|
||||
return std::nullopt;
|
||||
|
||||
if (lara->Control.CanClimbLadder && // Ladder sector flag set.
|
||||
(probeMiddle.Position.Ceiling - y) <= -CLICK(6.5f) && // Within lowest middle ceiling bound. (Synced with TestLaraLadderMount())
|
||||
((probeFront.Position.Floor - y) <= -CLICK(6.5f) || // Floor height is appropriate, OR
|
||||
(probeFront.Position.Ceiling - y) > -CLICK(6.5f)) && // Ceiling height is appropriate. (Synced with TestLaraLadderMount())
|
||||
(probeMiddle.GetCeilingHeight() - y) <= -CLICK(6.5f) && // Within lowest middle ceiling bound. (Synced with TestLaraLadderMount())
|
||||
((probeFront.GetFloorHeight() - y) <= -CLICK(6.5f) || // Floor height is appropriate, OR
|
||||
(probeFront.GetCeilingHeight() - y) > -CLICK(6.5f)) && // Ceiling height is appropriate. (Synced with TestLaraLadderMount())
|
||||
coll->NearestLedgeDistance <= coll->Setup.Radius) // Appropriate distance from wall.
|
||||
{
|
||||
return VaultTestResult{ probeMiddle.Position.Ceiling, false, true, true };
|
||||
return VaultTestResult{ probeMiddle.GetCeilingHeight(), false, true, true };
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
@ -1415,18 +1406,18 @@ std::optional<VaultTestResult> TestLaraLadderMount(ItemInfo* item, CollisionInfo
|
|||
|
||||
int y = item->Pose.Position.y;
|
||||
int distance = OFFSET_RADIUS(coll->Setup.Radius);
|
||||
auto probeFront = GetCollision(item, coll->NearestLedgeAngle, distance, -coll->Setup.Height);
|
||||
auto probeMiddle = GetCollision(item);
|
||||
auto probeFront = GetPointCollision(*item, coll->NearestLedgeAngle, distance, -coll->Setup.Height);
|
||||
auto probeMiddle = GetPointCollision(*item);
|
||||
|
||||
// Check ledge angle.
|
||||
if (!TestValidLedgeAngle(item, coll))
|
||||
return std::nullopt;
|
||||
|
||||
if (lara->Control.CanClimbLadder && // Ladder sector flag set.
|
||||
(probeMiddle.Position.Ceiling - y) <= -CLICK(4.5f) && // Within lower middle ceiling bound.
|
||||
(probeMiddle.Position.Ceiling - y) > -CLICK(6.5f) && // Within upper middle ceiling bound.
|
||||
(probeMiddle.Position.Floor - y) > -CLICK(6.5f) && // Within upper middle floor bound. (Synced with TestLaraAutoJump())
|
||||
(probeFront.Position.Ceiling - y) <= -CLICK(4.5f) && // Within lowest front ceiling bound.
|
||||
(probeMiddle.GetCeilingHeight() - y) <= -CLICK(4.5f) && // Within lower middle ceiling bound.
|
||||
(probeMiddle.GetCeilingHeight() - y) > -CLICK(6.5f) && // Within upper middle ceiling bound.
|
||||
(probeMiddle.GetFloorHeight() - y) > -CLICK(6.5f) && // Within upper middle floor bound. (Synced with TestLaraAutoJump())
|
||||
(probeFront.GetCeilingHeight() - y) <= -CLICK(4.5f) && // Within lowest front ceiling bound.
|
||||
coll->NearestLedgeDistance <= coll->Setup.Radius) // Appropriate distance from wall.
|
||||
{
|
||||
return VaultTestResult{ NO_HEIGHT, true, true, false };
|
||||
|
@ -1435,18 +1426,18 @@ std::optional<VaultTestResult> TestLaraLadderMount(ItemInfo* item, CollisionInfo
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<VaultTestResult> TestLaraMonkeyAutoJump(ItemInfo* item, CollisionInfo* coll)
|
||||
std::optional<VaultTestResult> TestLaraAutoMonkeySwingJump(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
auto* lara = GetLaraInfo(item);
|
||||
|
||||
int y = item->Pose.Position.y;
|
||||
auto probe = GetCollision(item);
|
||||
auto probe = GetPointCollision(*item);
|
||||
|
||||
if (lara->Control.CanMonkeySwing && // Monkey swing sector flag set.
|
||||
(probe.Position.Ceiling - y) < -LARA_HEIGHT_MONKEY && // Within lower ceiling bound.
|
||||
(probe.Position.Ceiling - y) >= -CLICK(7)) // Within upper ceiling bound.
|
||||
(probe.GetCeilingHeight() - y) < -LARA_HEIGHT_MONKEY && // Within lower ceiling bound.
|
||||
(probe.GetCeilingHeight() - y) >= -CLICK(7)) // Within upper ceiling bound.
|
||||
{
|
||||
return VaultTestResult{ probe.Position.Ceiling, false, false, true };
|
||||
return VaultTestResult{ probe.GetCeilingHeight(), false, false, true };
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
@ -1538,8 +1529,8 @@ std::optional<VaultTestResult> TestLaraVault(ItemInfo* item, CollisionInfo* coll
|
|||
// In this case, they fail due to a reliance on ShiftItem(). @Sezz 2021.02.05
|
||||
|
||||
// Auto jump to monkey swing.
|
||||
vaultResult = TestLaraMonkeyAutoJump(item, coll);
|
||||
if (vaultResult.has_value() && g_GameFlow->HasMonkeyAutoJump())
|
||||
vaultResult = TestLaraAutoMonkeySwingJump(item, coll);
|
||||
if (vaultResult.has_value() && g_Configuration.EnableAutoMonkeySwingJump)
|
||||
{
|
||||
vaultResult->TargetState = LS_AUTO_JUMP;
|
||||
if (!HasStateDispatch(item, vaultResult->TargetState))
|
||||
|
@ -1606,15 +1597,15 @@ bool TestAndDoLaraLadderClimb(ItemInfo* item, CollisionInfo* coll)
|
|||
CrawlVaultTestResult TestLaraCrawlVaultTolerance(ItemInfo* item, CollisionInfo* coll, CrawlVaultTestSetup testSetup)
|
||||
{
|
||||
int y = item->Pose.Position.y;
|
||||
auto probeA = GetCollision(item, item->Pose.Orientation.y, testSetup.CrossDist, -LARA_HEIGHT_CRAWL); // Crossing.
|
||||
auto probeB = GetCollision(item, item->Pose.Orientation.y, testSetup.DestDist, -LARA_HEIGHT_CRAWL); // Approximate destination.
|
||||
auto probeMiddle = GetCollision(item);
|
||||
auto probeA = GetPointCollision(*item, item->Pose.Orientation.y, testSetup.CrossDist, -LARA_HEIGHT_CRAWL); // Crossing.
|
||||
auto probeB = GetPointCollision(*item, item->Pose.Orientation.y, testSetup.DestDist, -LARA_HEIGHT_CRAWL); // Approximate destination.
|
||||
auto probeMiddle = GetPointCollision(*item);
|
||||
|
||||
bool isSlope = testSetup.CheckSlope ? probeB.Position.FloorSlope : false;
|
||||
bool isDeath = testSetup.CheckDeath ? probeB.Block->Flags.Death : false;
|
||||
bool isSlope = testSetup.CheckSlope ? probeB.IsSteepFloor() : false;
|
||||
bool isDeath = testSetup.CheckDeath ? probeB.GetSector().Flags.Death : false;
|
||||
|
||||
// Discard walls.
|
||||
if (probeA.Position.Floor == NO_HEIGHT || probeB.Position.Floor == NO_HEIGHT)
|
||||
if (probeA.GetFloorHeight() == NO_HEIGHT || probeB.GetFloorHeight() == NO_HEIGHT)
|
||||
return CrawlVaultTestResult{ false };
|
||||
|
||||
// Check for slope or death sector (if applicable).
|
||||
|
@ -1622,14 +1613,14 @@ CrawlVaultTestResult TestLaraCrawlVaultTolerance(ItemInfo* item, CollisionInfo*
|
|||
return CrawlVaultTestResult{ false };
|
||||
|
||||
// Assess point/room collision.
|
||||
if ((probeA.Position.Floor - y) <= testSetup.LowerFloorBound && // Within lower floor bound.
|
||||
(probeA.Position.Floor - y) >= testSetup.UpperFloorBound && // Within upper floor bound.
|
||||
abs(probeA.Position.Ceiling - probeA.Position.Floor) > testSetup.ClampMin && // Crossing clamp limit.
|
||||
abs(probeB.Position.Ceiling - probeB.Position.Floor) > testSetup.ClampMin && // Destination clamp limit.
|
||||
abs(probeMiddle.Position.Ceiling - probeA.Position.Floor) >= testSetup.GapMin && // Gap is optically permissive (going up).
|
||||
abs(probeA.Position.Ceiling - probeMiddle.Position.Floor) >= testSetup.GapMin && // Gap is optically permissive (going down).
|
||||
abs(probeA.Position.Floor - probeB.Position.Floor) <= testSetup.FloorBound && // Crossing/destination floor height difference suggests continuous crawl surface.
|
||||
(probeA.Position.Ceiling - y) < -testSetup.GapMin) // Ceiling height is permissive.
|
||||
if ((probeA.GetFloorHeight() - y) <= testSetup.LowerFloorBound && // Within lower floor bound.
|
||||
(probeA.GetFloorHeight() - y) >= testSetup.UpperFloorBound && // Within upper floor bound.
|
||||
abs(probeA.GetCeilingHeight() - probeA.GetFloorHeight()) > testSetup.ClampMin && // Crossing clamp limit.
|
||||
abs(probeB.GetCeilingHeight() - probeB.GetFloorHeight()) > testSetup.ClampMin && // Destination clamp limit.
|
||||
abs(probeMiddle.GetCeilingHeight() - probeA.GetFloorHeight()) >= testSetup.GapMin && // Gap is optically permissive (going up).
|
||||
abs(probeA.GetCeilingHeight() - probeMiddle.GetFloorHeight()) >= testSetup.GapMin && // Gap is optically permissive (going down).
|
||||
abs(probeA.GetFloorHeight() - probeB.GetFloorHeight()) <= testSetup.FloorBound && // Crossing/destination floor height difference suggests continuous crawl surface.
|
||||
(probeA.GetCeilingHeight() - y) < -testSetup.GapMin) // Ceiling height is permissive.
|
||||
{
|
||||
return CrawlVaultTestResult{ true };
|
||||
}
|
||||
|
@ -1718,7 +1709,7 @@ CrawlVaultTestResult TestLaraCrawlVault(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
if (IsHeld(In::Crouch) && TestLaraCrawlDownStep(item, coll).Success)
|
||||
crawlVaultResult.TargetState = LS_CRAWL_STEP_DOWN;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
crawlVaultResult.TargetState = LS_CRAWL_EXIT_STEP_DOWN;
|
||||
|
||||
crawlVaultResult.Success = HasStateDispatch(item, crawlVaultResult.TargetState);
|
||||
|
@ -1731,7 +1722,7 @@ CrawlVaultTestResult TestLaraCrawlVault(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
if (IsHeld(In::Walk))
|
||||
crawlVaultResult.TargetState = LS_CRAWL_EXIT_FLIP;
|
||||
else USE_FEATURE_IF_CPP20([[likely]])
|
||||
else
|
||||
crawlVaultResult.TargetState = LS_CRAWL_EXIT_JUMP;
|
||||
|
||||
crawlVaultResult.Success = HasStateDispatch(item, crawlVaultResult.TargetState);
|
||||
|
@ -1763,14 +1754,14 @@ bool TestLaraCrawlToHang(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
int y = item->Pose.Position.y;
|
||||
int distance = CLICK(1.2f);
|
||||
auto probe = GetCollision(item, item->Pose.Orientation.y + ANGLE(180.0f), distance, -LARA_HEIGHT_CRAWL);
|
||||
auto probe = GetPointCollision(*item, item->Pose.Orientation.y + ANGLE(180.0f), distance, -LARA_HEIGHT_CRAWL);
|
||||
|
||||
bool objectCollided = TestLaraObjectCollision(item, item->Pose.Orientation.y + ANGLE(180.0f), CLICK(1.2f), -LARA_HEIGHT_CRAWL);
|
||||
|
||||
if (!objectCollided && // No obstruction.
|
||||
(probe.Position.Floor - y) >= LARA_HEIGHT_STRETCH && // Highest floor bound.
|
||||
(probe.Position.Ceiling - y) <= -CLICK(0.75f) && // Gap is optically permissive.
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
(probe.GetFloorHeight() - y) >= LARA_HEIGHT_STRETCH && // Highest floor bound.
|
||||
(probe.GetCeilingHeight() - y) <= -CLICK(0.75f) && // Gap is optically permissive.
|
||||
probe.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -1801,9 +1792,9 @@ bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, fl
|
|||
auto sphere = BoundingSphere(spherePos, poleProbeCollRadius);
|
||||
auto offsetSphere = BoundingSphere(spherePos + sphereOffset2D, poleProbeCollRadius);
|
||||
|
||||
//g_Renderer.AddDebugSphere(sphere.Center, 16.0f, Vector4(1, 0, 0, 1), RendererDebugPage::CollisionStats);
|
||||
//DrawDebugSphere(sphere.Center, 16.0f, Vector4(1, 0, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
for (const auto* itemPtr : collObjects.ItemPtrs)
|
||||
for (const auto* itemPtr : collObjects.Items)
|
||||
{
|
||||
if (itemPtr->ObjectNumber != ID_POLEROPE)
|
||||
continue;
|
||||
|
@ -1811,7 +1802,7 @@ bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, fl
|
|||
auto poleBox = GameBoundingBox(itemPtr).ToBoundingOrientedBox(itemPtr->Pose);
|
||||
poleBox.Extents = poleBox.Extents + Vector3(coll->Setup.Radius, 0.0f, coll->Setup.Radius);
|
||||
|
||||
//g_Renderer.AddDebugBox(poleBox, Vector4(0, 0, 1, 1), RendererDebugPage::CollisionStats);
|
||||
//DrawDebugBox(poleBox, Vector4(0, 0, 1, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
if (poleBox.Intersects(sphere) || poleBox.Intersects(offsetSphere))
|
||||
{
|
||||
|
|
|
@ -34,8 +34,6 @@ bool TestLaraFacingCorner(const ItemInfo* item, short headingAngle, float dist);
|
|||
bool LaraPositionOnLOS(ItemInfo* item, short angle, int distance);
|
||||
int LaraFloorFront(ItemInfo* item, short angle, int distance);
|
||||
int LaraCeilingFront(ItemInfo* item, short angle, int distance, int height);
|
||||
CollisionResult LaraCollisionFront(ItemInfo* item, short angle, int distance);
|
||||
CollisionResult LaraCeilingCollisionFront(ItemInfo* item, short angle, int distance, int height);
|
||||
|
||||
bool TestPlayerWaterStepOut(ItemInfo* item, CollisionInfo* coll);
|
||||
bool TestLaraWaterClimbOut(ItemInfo* item, CollisionInfo* coll);
|
||||
|
@ -58,7 +56,7 @@ std::optional<VaultTestResult> TestLaraVault3StepsToCrouch(ItemInfo* item, Colli
|
|||
std::optional<VaultTestResult> TestLaraLedgeAutoJump(ItemInfo* item, CollisionInfo* coll);
|
||||
std::optional<VaultTestResult> TestLaraLadderAutoJump(ItemInfo* item, CollisionInfo* coll);
|
||||
std::optional<VaultTestResult> TestLaraLadderMount(ItemInfo* item, CollisionInfo* coll);
|
||||
std::optional<VaultTestResult> TestLaraMonkeyAutoJump(ItemInfo* item, CollisionInfo* coll);
|
||||
std::optional<VaultTestResult> TestLaraAutoMonkeySwingJump(ItemInfo* item, CollisionInfo* coll);
|
||||
std::optional<VaultTestResult> TestLaraVault(ItemInfo* item, CollisionInfo* coll);
|
||||
bool TestAndDoLaraLadderClimb(ItemInfo* item, CollisionInfo* coll);
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ void InitializeGameFlags()
|
|||
ZeroMemory(FlipMap, MAX_FLIPMAP * sizeof(int));
|
||||
ZeroMemory(FlipStats, MAX_FLIPMAP * sizeof(bool));
|
||||
|
||||
FlipEffect = -1;
|
||||
FlipEffect = NO_VALUE;
|
||||
FlipStatus = false;
|
||||
Camera.underwater = false;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Game/camera.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/box.h"
|
||||
#include "Game/control/flipeffect.h"
|
||||
#include "Game/items.h"
|
||||
|
@ -15,6 +16,7 @@
|
|||
#include "Sound/sound.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Entities::Generic;
|
||||
using namespace TEN::Math;
|
||||
using TEN::Renderer::g_Renderer;
|
||||
|
@ -110,49 +112,95 @@ static void PerformAnimCommands(ItemInfo& item, bool isFrameBased)
|
|||
break;
|
||||
|
||||
case AnimCommandType::SoundEffect:
|
||||
if (isFrameBased && item.Animation.FrameNumber == commandDataPtr[0])
|
||||
{
|
||||
int frameNumber = commandDataPtr[0];
|
||||
if (isFrameBased && item.Animation.FrameNumber == frameNumber)
|
||||
{
|
||||
if (!Objects[item.ObjectNumber].waterCreature)
|
||||
{
|
||||
bool playInWater = (commandDataPtr[1] & 0x8000) != 0;
|
||||
bool playOnLand = (commandDataPtr[1] & 0x4000) != 0;
|
||||
bool playAlways = (playInWater && playOnLand) || (!playInWater && !playOnLand);
|
||||
// Get sound ID and sound environment flag from packed data.
|
||||
int soundID = commandDataPtr[1] & 0xFFF; // Exclude last 4 bits for sound ID.
|
||||
int soundEnvFlag = commandDataPtr[1] & 0xF000; // Keep only last 4 bits for sound environment flag.
|
||||
|
||||
if (item.IsLara())
|
||||
{
|
||||
auto& player = GetLaraInfo(item);
|
||||
|
||||
if (playAlways ||
|
||||
(playOnLand && (player.Context.WaterSurfaceDist >= -SHALLOW_WATER_DEPTH || player.Context.WaterSurfaceDist == NO_HEIGHT)) ||
|
||||
(playInWater && player.Context.WaterSurfaceDist < -SHALLOW_WATER_DEPTH && player.Context.WaterSurfaceDist != NO_HEIGHT && !TestEnvironment(ENV_FLAG_SWAMP, &item)))
|
||||
{
|
||||
SoundEffect(commandDataPtr[1] & 0x3FFF, &item.Pose, SoundEnvironment::Always);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.RoomNumber == NO_VALUE)
|
||||
{
|
||||
SoundEffect(commandDataPtr[1] & 0x3FFF, &item.Pose, SoundEnvironment::Always);
|
||||
}
|
||||
else if (TestEnvironment(ENV_FLAG_WATER, &item))
|
||||
{
|
||||
if (playAlways || (playInWater && TestEnvironment(ENV_FLAG_WATER, Camera.pos.RoomNumber)))
|
||||
SoundEffect(commandDataPtr[1] & 0x3FFF, &item.Pose, SoundEnvironment::Always);
|
||||
}
|
||||
else if (playAlways || (playOnLand && !TestEnvironment(ENV_FLAG_WATER, Camera.pos.RoomNumber) && !TestEnvironment(ENV_FLAG_SWAMP, Camera.pos.RoomNumber)))
|
||||
{
|
||||
SoundEffect(commandDataPtr[1] & 0x3FFF, &item.Pose, SoundEnvironment::Always);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// FAILSAFE.
|
||||
if (item.RoomNumber == NO_VALUE)
|
||||
{
|
||||
SoundEffect(commandDataPtr[1] & 0x3FFF, &item.Pose, TestEnvironment(ENV_FLAG_WATER, &item) ? SoundEnvironment::Water : SoundEnvironment::Land);
|
||||
SoundEffect(soundID, &item.Pose, SoundEnvironment::Always);
|
||||
commandDataPtr += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get required sound environment from flag.
|
||||
auto requiredSoundEnv = SoundEnvironment::Always;
|
||||
switch (soundEnvFlag)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
requiredSoundEnv = SoundEnvironment::Always;
|
||||
break;
|
||||
|
||||
case (1 << 14):
|
||||
requiredSoundEnv = SoundEnvironment::Land;
|
||||
break;
|
||||
|
||||
case (1 << 15):
|
||||
requiredSoundEnv = SoundEnvironment::ShallowWater;
|
||||
break;
|
||||
|
||||
case (1 << 12):
|
||||
requiredSoundEnv = SoundEnvironment::Swamp;
|
||||
break;
|
||||
|
||||
case (1 << 13):
|
||||
requiredSoundEnv = SoundEnvironment::Underwater;
|
||||
break;
|
||||
}
|
||||
|
||||
int roomNumberAtPos = GetPointCollision(item).GetRoomNumber();
|
||||
bool isWater = TestEnvironment(ENV_FLAG_WATER, roomNumberAtPos);
|
||||
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, roomNumberAtPos);
|
||||
|
||||
// Get sound environment for sound effect.
|
||||
auto soundEnv = std::optional<SoundEnvironment>();
|
||||
switch (requiredSoundEnv)
|
||||
{
|
||||
case SoundEnvironment::Always:
|
||||
soundEnv = SoundEnvironment::Always;
|
||||
break;
|
||||
|
||||
case SoundEnvironment::Land:
|
||||
if (!isWater && !isSwamp)
|
||||
soundEnv = SoundEnvironment::Land;
|
||||
|
||||
break;
|
||||
|
||||
case SoundEnvironment::ShallowWater:
|
||||
if (isWater)
|
||||
{
|
||||
// HACK: Must update assets before removing this exception for water creatures.
|
||||
const auto& object = Objects[item.ObjectNumber];
|
||||
soundEnv = object.waterCreature ? SoundEnvironment::Underwater : SoundEnvironment::ShallowWater;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SoundEnvironment::Swamp:
|
||||
if (isSwamp)
|
||||
soundEnv = SoundEnvironment::Swamp;
|
||||
|
||||
break;
|
||||
|
||||
case SoundEnvironment::Underwater:
|
||||
if (isWater || isSwamp)
|
||||
soundEnv = SoundEnvironment::Underwater;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (soundEnv.has_value())
|
||||
SoundEffect(soundID, &item.Pose, *soundEnv);
|
||||
}
|
||||
|
||||
commandDataPtr += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case AnimCommandType::Flipeffect:
|
||||
|
@ -506,7 +554,7 @@ const AnimFrame* GetFrame(GAME_OBJECT_ID objectID, int animNumber, int frameNumb
|
|||
const auto& object = Objects[objectID];
|
||||
|
||||
int animIndex = object.animIndex + animNumber;
|
||||
assertion(animIndex < g_Level.Anims.size(), "GetFrame() attempted to access missing animation.");
|
||||
TENAssert(animIndex < g_Level.Anims.size(), "GetFrame() attempted to access missing animation.");
|
||||
|
||||
const auto& anim = GetAnimData(object, animNumber);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Game/animation.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/control/los.h"
|
||||
#include "Game/effects/debris.h"
|
||||
#include "Game/effects/effects.h"
|
||||
|
@ -21,12 +22,13 @@
|
|||
#include "Specific/Input/Input.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using TEN::Renderer::g_Renderer;
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Effects::Environment;
|
||||
using namespace TEN::Entities::Generic;
|
||||
using namespace TEN::Input;
|
||||
using namespace TEN::Math;
|
||||
using TEN::Renderer::g_Renderer;
|
||||
|
||||
constexpr auto PARTICLE_FADE_THRESHOLD = BLOCK(14);
|
||||
constexpr auto COLL_CHECK_THRESHOLD = BLOCK(4);
|
||||
|
@ -132,8 +134,8 @@ static int GetLookCameraVerticalOffset(const ItemInfo& item, const CollisionInfo
|
|||
}
|
||||
|
||||
// Get floor-to-ceiling height.
|
||||
auto pointColl = GetCollision(item);
|
||||
int floorToCeilHeight = abs(pointColl.Position.Ceiling - pointColl.Position.Floor);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
int floorToCeilHeight = abs(pointColl.GetCeilingHeight() - pointColl.GetFloorHeight());
|
||||
|
||||
// Return appropriate vertical offset.
|
||||
return -((verticalOffset < floorToCeilHeight) ? verticalOffset : floorToCeilHeight);
|
||||
|
@ -173,8 +175,8 @@ void LookCamera(ItemInfo& item, const CollisionInfo& coll)
|
|||
auto lookAtPos = Geometry::TranslatePoint(pivotPos, orient, LOOK_AT_DIST);
|
||||
|
||||
// Determine best position.
|
||||
auto origin = GameVector(pivotPos, GetCollision(&item, item.Pose.Orientation.y, pivotOffset.z, pivotOffset.y).RoomNumber);
|
||||
auto target = GameVector(idealPos, GetCollision(origin.ToVector3i(), origin.RoomNumber, orient, idealDist).RoomNumber);
|
||||
auto origin = GameVector(pivotPos, GetPointCollision(item, item.Pose.Orientation.y, pivotOffset.z, pivotOffset.y).GetRoomNumber());
|
||||
auto target = GameVector(idealPos, GetPointCollision(origin.ToVector3i(), origin.RoomNumber, orient.ToDirection(), idealDist).GetRoomNumber());
|
||||
|
||||
// Handle room and object collisions.
|
||||
LOSAndReturnTarget(&origin, &target, 0);
|
||||
|
@ -343,9 +345,9 @@ void MoveCamera(GameVector* ideal, int speed)
|
|||
if (TestEnvironment(ENV_FLAG_SWAMP, Camera.pos.RoomNumber))
|
||||
y = g_Level.Rooms[Camera.pos.RoomNumber].y - CLICK(1);
|
||||
|
||||
auto probe = GetCollision(Camera.pos.x, y, Camera.pos.z, Camera.pos.RoomNumber);
|
||||
if (y < probe.Position.Ceiling ||
|
||||
y > probe.Position.Floor)
|
||||
auto pointColl = GetPointCollision(Vector3i(Camera.pos.x, y, Camera.pos.z), Camera.pos.RoomNumber);
|
||||
if (y < pointColl.GetCeilingHeight() ||
|
||||
y > pointColl.GetFloorHeight())
|
||||
{
|
||||
LOSAndReturnTarget(&Camera.target, &Camera.pos, 0);
|
||||
|
||||
|
@ -364,41 +366,41 @@ void MoveCamera(GameVector* ideal, int speed)
|
|||
}
|
||||
}
|
||||
|
||||
probe = GetCollision(Camera.pos.x, Camera.pos.y, Camera.pos.z, Camera.pos.RoomNumber);
|
||||
pointColl = GetPointCollision(Camera.pos.ToVector3i(), Camera.pos.RoomNumber);
|
||||
|
||||
int buffer = CLICK(1) - 1;
|
||||
if ((Camera.pos.y - buffer) < probe.Position.Ceiling &&
|
||||
(Camera.pos.y + buffer) > probe.Position.Floor &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
if ((Camera.pos.y - buffer) < pointColl.GetCeilingHeight() &&
|
||||
(Camera.pos.y + buffer) > pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
Camera.pos.y = (probe.Position.Floor + probe.Position.Ceiling) / 2;
|
||||
Camera.pos.y = (pointColl.GetFloorHeight() + pointColl.GetCeilingHeight()) / 2;
|
||||
}
|
||||
else if ((Camera.pos.y + buffer) > probe.Position.Floor &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
else if ((Camera.pos.y + buffer) > pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
Camera.pos.y = probe.Position.Floor - buffer;
|
||||
Camera.pos.y = pointColl.GetFloorHeight() - buffer;
|
||||
}
|
||||
else if ((Camera.pos.y - buffer) < probe.Position.Ceiling &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
else if ((Camera.pos.y - buffer) < pointColl.GetCeilingHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
Camera.pos.y = probe.Position.Ceiling + buffer;
|
||||
Camera.pos.y = pointColl.GetCeilingHeight() + buffer;
|
||||
}
|
||||
else if (probe.Position.Ceiling >= probe.Position.Floor ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT)
|
||||
else if (pointColl.GetCeilingHeight() >= pointColl.GetFloorHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT)
|
||||
{
|
||||
Camera.pos = *ideal;
|
||||
}
|
||||
|
||||
ItemsCollideCamera();
|
||||
|
||||
Camera.pos.RoomNumber = GetCollision(Camera.pos.x, Camera.pos.y, Camera.pos.z, Camera.pos.RoomNumber).RoomNumber;
|
||||
Camera.pos.RoomNumber = GetPointCollision(Camera.pos.ToVector3i(), Camera.pos.RoomNumber).GetRoomNumber();
|
||||
LookAt(&Camera, 0);
|
||||
UpdateMikePos(*LaraItem);
|
||||
Camera.oldType = Camera.type;
|
||||
|
@ -465,7 +467,7 @@ void MoveObjCamera(GameVector* ideal, ItemInfo* camSlotId, int camMeshId, ItemIn
|
|||
}
|
||||
|
||||
Camera.pos += (ideal->ToVector3i() - Camera.pos.ToVector3i()) / speed;
|
||||
Camera.pos.RoomNumber = GetCollision(Camera.pos.x, Camera.pos.y, Camera.pos.z, Camera.pos.RoomNumber).RoomNumber;
|
||||
Camera.pos.RoomNumber = GetPointCollision(Camera.pos.ToVector3i(), Camera.pos.RoomNumber).GetRoomNumber();
|
||||
LookAt(&Camera, 0);
|
||||
|
||||
auto angle = Camera.target.ToVector3i() - Camera.pos.ToVector3i();
|
||||
|
@ -529,21 +531,23 @@ void ChaseCamera(ItemInfo* item)
|
|||
|
||||
int distance = Camera.targetDistance * phd_cos(Camera.actualElevation);
|
||||
|
||||
auto probe = GetCollision(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z, Camera.target.RoomNumber);
|
||||
auto pointColl = GetPointCollision(Vector3i(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z), Camera.target.RoomNumber);
|
||||
|
||||
if (TestEnvironment(ENV_FLAG_SWAMP, probe.RoomNumber))
|
||||
Camera.target.y = g_Level.Rooms[probe.RoomNumber].maxceiling - CLICK(1);
|
||||
if (TestEnvironment(ENV_FLAG_SWAMP, pointColl.GetRoomNumber()))
|
||||
Camera.target.y = g_Level.Rooms[pointColl.GetRoomNumber()].maxceiling - CLICK(1);
|
||||
|
||||
int y = Camera.target.y;
|
||||
probe = GetCollision(Camera.target.x, y, Camera.target.z, Camera.target.RoomNumber);
|
||||
if (((y < probe.Position.Ceiling || probe.Position.Floor < y) || probe.Position.Floor <= probe.Position.Ceiling) ||
|
||||
(probe.Position.Floor == NO_HEIGHT || probe.Position.Ceiling == NO_HEIGHT))
|
||||
pointColl = GetPointCollision(Vector3i(Camera.target.x, y, Camera.target.z), Camera.target.RoomNumber);
|
||||
if (((y < pointColl.GetCeilingHeight() || pointColl.GetFloorHeight() < y) || pointColl.GetFloorHeight() <= pointColl.GetCeilingHeight()) ||
|
||||
(pointColl.GetFloorHeight() == NO_HEIGHT || pointColl.GetCeilingHeight() == NO_HEIGHT))
|
||||
{
|
||||
TargetSnaps++;
|
||||
Camera.target = LastTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetSnaps = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxSwivelSteps; i++)
|
||||
Ideals[i].y = Camera.target.y + (Camera.targetDistance * phd_sin(Camera.actualElevation));
|
||||
|
@ -646,43 +650,43 @@ void CombatCamera(ItemInfo* item)
|
|||
Camera.targetElevation = player.ExtraHeadRot.x + player.ExtraTorsoRot.x + item->Pose.Orientation.x - ANGLE(15.0f);
|
||||
}
|
||||
|
||||
auto probe = GetCollision(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z, Camera.target.RoomNumber);
|
||||
if (TestEnvironment(ENV_FLAG_SWAMP, probe.RoomNumber))
|
||||
Camera.target.y = g_Level.Rooms[probe.RoomNumber].y - CLICK(1);
|
||||
auto pointColl = GetPointCollision(Vector3i(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z), Camera.target.RoomNumber);
|
||||
if (TestEnvironment(ENV_FLAG_SWAMP, pointColl.GetRoomNumber()))
|
||||
Camera.target.y = g_Level.Rooms[pointColl.GetRoomNumber()].y - CLICK(1);
|
||||
|
||||
probe = GetCollision(Camera.target.x, Camera.target.y, Camera.target.z, Camera.target.RoomNumber);
|
||||
Camera.target.RoomNumber = probe.RoomNumber;
|
||||
pointColl = GetPointCollision(Camera.target.ToVector3i(), Camera.target.RoomNumber);
|
||||
Camera.target.RoomNumber = pointColl.GetRoomNumber();
|
||||
|
||||
int buffer = CLICK(0.25f);
|
||||
if ((probe.Position.Ceiling + buffer) > (probe.Position.Floor - buffer) &&
|
||||
probe.Position.Floor != NO_HEIGHT &&
|
||||
probe.Position.Ceiling != NO_HEIGHT)
|
||||
if ((pointColl.GetCeilingHeight() + buffer) > (pointColl.GetFloorHeight() - buffer) &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT)
|
||||
{
|
||||
Camera.target.y = (probe.Position.Ceiling + probe.Position.Floor) / 2;
|
||||
Camera.target.y = (pointColl.GetCeilingHeight() + pointColl.GetFloorHeight()) / 2;
|
||||
Camera.targetElevation = 0;
|
||||
}
|
||||
else if (Camera.target.y > (probe.Position.Floor - buffer) &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
else if (Camera.target.y > (pointColl.GetFloorHeight() - buffer) &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
Camera.target.y = probe.Position.Floor - buffer;
|
||||
Camera.target.y = pointColl.GetFloorHeight() - buffer;
|
||||
Camera.targetElevation = 0;
|
||||
}
|
||||
else if (Camera.target.y < (probe.Position.Ceiling + buffer) &&
|
||||
probe.Position.Ceiling != NO_HEIGHT)
|
||||
else if (Camera.target.y < (pointColl.GetCeilingHeight() + buffer) &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT)
|
||||
{
|
||||
Camera.target.y = probe.Position.Ceiling + buffer;
|
||||
Camera.target.y = pointColl.GetCeilingHeight() + buffer;
|
||||
Camera.targetElevation = 0;
|
||||
}
|
||||
|
||||
int y = Camera.target.y;
|
||||
probe = GetCollision(Camera.target.x, y, Camera.target.z, Camera.target.RoomNumber);
|
||||
Camera.target.RoomNumber = probe.RoomNumber;
|
||||
pointColl = GetPointCollision(Vector3i(Camera.target.x, y, Camera.target.z), Camera.target.RoomNumber);
|
||||
Camera.target.RoomNumber = pointColl.GetRoomNumber();
|
||||
|
||||
if (y < probe.Position.Ceiling ||
|
||||
y > probe.Position.Floor ||
|
||||
probe.Position.Ceiling >= probe.Position.Floor ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT)
|
||||
if (y < pointColl.GetCeilingHeight() ||
|
||||
y > pointColl.GetFloorHeight() ||
|
||||
pointColl.GetCeilingHeight() >= pointColl.GetFloorHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT)
|
||||
{
|
||||
TargetSnaps++;
|
||||
Camera.target = LastTarget;
|
||||
|
@ -768,116 +772,114 @@ bool CameraCollisionBounds(GameVector* ideal, int push, bool yFirst)
|
|||
int y = ideal->y;
|
||||
int z = ideal->z;
|
||||
|
||||
CollisionResult probe = {};
|
||||
auto pointColl = GetPointCollision(Vector3i(x, y, z), ideal->RoomNumber);
|
||||
if (yFirst)
|
||||
{
|
||||
probe = GetCollision(x, y, z, ideal->RoomNumber);
|
||||
|
||||
int buffer = CLICK(1) - 1;
|
||||
if ((y - buffer) < probe.Position.Ceiling &&
|
||||
(y + buffer) > probe.Position.Floor &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
if ((y - buffer) < pointColl.GetCeilingHeight() &&
|
||||
(y + buffer) > pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
y = (probe.Position.Floor + probe.Position.Ceiling) / 2;
|
||||
y = (pointColl.GetFloorHeight() + pointColl.GetCeilingHeight()) / 2;
|
||||
}
|
||||
else if ((y + buffer) > probe.Position.Floor &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
else if ((y + buffer) > pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
y = probe.Position.Floor - buffer;
|
||||
y = pointColl.GetFloorHeight() - buffer;
|
||||
}
|
||||
else if ((y - buffer) < probe.Position.Ceiling &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
else if ((y - buffer) < pointColl.GetCeilingHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
y = probe.Position.Ceiling + buffer;
|
||||
y = pointColl.GetCeilingHeight() + buffer;
|
||||
}
|
||||
}
|
||||
|
||||
probe = GetCollision(x - push, y, z, ideal->RoomNumber);
|
||||
if (y > probe.Position.Floor ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT ||
|
||||
probe.Position.Ceiling >= probe.Position.Floor ||
|
||||
y < probe.Position.Ceiling)
|
||||
pointColl = GetPointCollision(Vector3i(x - push, y, z), ideal->RoomNumber);
|
||||
if (y > pointColl.GetFloorHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() >= pointColl.GetFloorHeight() ||
|
||||
y < pointColl.GetCeilingHeight())
|
||||
{
|
||||
x = (x & (~1023)) + push;
|
||||
}
|
||||
|
||||
probe = GetCollision(x, y, z - push, ideal->RoomNumber);
|
||||
if (y > probe.Position.Floor ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT ||
|
||||
probe.Position.Ceiling >= probe.Position.Floor ||
|
||||
y < probe.Position.Ceiling)
|
||||
pointColl = GetPointCollision(Vector3i(x, y, z - push), ideal->RoomNumber);
|
||||
if (y > pointColl.GetFloorHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() >= pointColl.GetFloorHeight() ||
|
||||
y < pointColl.GetCeilingHeight())
|
||||
{
|
||||
z = (z & (~1023)) + push;
|
||||
}
|
||||
|
||||
probe = GetCollision(x + push, y, z, ideal->RoomNumber);
|
||||
if (y > probe.Position.Floor ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT ||
|
||||
probe.Position.Ceiling >= probe.Position.Floor ||
|
||||
y < probe.Position.Ceiling)
|
||||
pointColl = GetPointCollision(Vector3i(x + push, y, z), ideal->RoomNumber);
|
||||
if (y > pointColl.GetFloorHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() >= pointColl.GetFloorHeight() ||
|
||||
y < pointColl.GetCeilingHeight())
|
||||
{
|
||||
x = (x | 1023) - push;
|
||||
}
|
||||
|
||||
probe = GetCollision(x, y, z + push, ideal->RoomNumber);
|
||||
if (y > probe.Position.Floor ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT ||
|
||||
probe.Position.Ceiling >= probe.Position.Floor ||
|
||||
y < probe.Position.Ceiling)
|
||||
pointColl = GetPointCollision(Vector3i(x, y, z + push), ideal->RoomNumber);
|
||||
if (y > pointColl.GetFloorHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() >= pointColl.GetFloorHeight() ||
|
||||
y < pointColl.GetCeilingHeight())
|
||||
{
|
||||
z = (z | 1023) - push;
|
||||
}
|
||||
|
||||
if (!yFirst)
|
||||
{
|
||||
probe = GetCollision(x, y, z, ideal->RoomNumber);
|
||||
pointColl = GetPointCollision(Vector3i(x, y, z), ideal->RoomNumber);
|
||||
|
||||
int buffer = CLICK(1) - 1;
|
||||
if ((y - buffer) < probe.Position.Ceiling &&
|
||||
(y + buffer) > probe.Position.Floor &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
if ((y - buffer) < pointColl.GetCeilingHeight() &&
|
||||
(y + buffer) > pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
y = (probe.Position.Floor + probe.Position.Ceiling) / 2;
|
||||
y = (pointColl.GetFloorHeight() + pointColl.GetCeilingHeight()) / 2;
|
||||
}
|
||||
else if ((y + buffer) > probe.Position.Floor &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
else if ((y + buffer) > pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
y = probe.Position.Floor - buffer;
|
||||
y = pointColl.GetFloorHeight() - buffer;
|
||||
}
|
||||
else if ((y - buffer) < probe.Position.Ceiling &&
|
||||
probe.Position.Ceiling < probe.Position.Floor &&
|
||||
probe.Position.Ceiling != NO_HEIGHT &&
|
||||
probe.Position.Floor != NO_HEIGHT)
|
||||
else if ((y - buffer) < pointColl.GetCeilingHeight() &&
|
||||
pointColl.GetCeilingHeight() < pointColl.GetFloorHeight() &&
|
||||
pointColl.GetCeilingHeight() != NO_HEIGHT &&
|
||||
pointColl.GetFloorHeight() != NO_HEIGHT)
|
||||
{
|
||||
y = probe.Position.Ceiling + buffer;
|
||||
y = pointColl.GetCeilingHeight() + buffer;
|
||||
}
|
||||
}
|
||||
|
||||
probe = GetCollision(x, y, z, ideal->RoomNumber);
|
||||
if (y > probe.Position.Floor ||
|
||||
y < probe.Position.Ceiling ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT ||
|
||||
probe.Position.Ceiling >= probe.Position.Floor)
|
||||
pointColl = GetPointCollision(Vector3i(x, y, z), ideal->RoomNumber);
|
||||
if (y > pointColl.GetFloorHeight() ||
|
||||
y < pointColl.GetCeilingHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() >= pointColl.GetFloorHeight())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ideal->RoomNumber = probe.RoomNumber;
|
||||
ideal->RoomNumber = pointColl.GetRoomNumber();
|
||||
ideal->x = x;
|
||||
ideal->y = y;
|
||||
ideal->z = z;
|
||||
|
@ -961,20 +963,20 @@ void BinocularCamera(ItemInfo* item)
|
|||
int y = item->Pose.Position.y - CLICK(2);
|
||||
int z = item->Pose.Position.z;
|
||||
|
||||
auto probe = GetCollision(x, y, z, item->RoomNumber);
|
||||
if (probe.Position.Ceiling <= (y - CLICK(1)))
|
||||
auto pointColl = GetPointCollision(Vector3i(x, y, z), item->RoomNumber);
|
||||
if (pointColl.GetCeilingHeight() <= (y - CLICK(1)))
|
||||
{
|
||||
y -= CLICK(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
y = probe.Position.Ceiling + CLICK(0.25f);
|
||||
y = pointColl.GetCeilingHeight() + CLICK(0.25f);
|
||||
}
|
||||
|
||||
Camera.pos.x = x;
|
||||
Camera.pos.y = y;
|
||||
Camera.pos.z = z;
|
||||
Camera.pos.RoomNumber = probe.RoomNumber;
|
||||
Camera.pos.RoomNumber = pointColl.GetRoomNumber();
|
||||
|
||||
float l = BLOCK(20.25f) * phd_cos(player.Control.Look.Orientation.x);
|
||||
float tx = x + l * phd_sin(item->Pose.Orientation.y + player.Control.Look.Orientation.y);
|
||||
|
@ -1014,7 +1016,7 @@ void BinocularCamera(ItemInfo* item)
|
|||
}
|
||||
}
|
||||
|
||||
Camera.target.RoomNumber = GetCollision(Camera.pos.x, Camera.pos.y, Camera.pos.z, Camera.target.RoomNumber).RoomNumber;
|
||||
Camera.target.RoomNumber = GetPointCollision(Camera.pos.ToVector3i(), Camera.target.RoomNumber).GetRoomNumber();
|
||||
LookAt(&Camera, 0);
|
||||
UpdateMikePos(*item);
|
||||
Camera.oldType = Camera.type;
|
||||
|
@ -1050,12 +1052,12 @@ void ConfirmCameraTargetPos()
|
|||
}
|
||||
|
||||
int y = Camera.target.y;
|
||||
auto probe = GetCollision(Camera.target.x, y, Camera.target.z, Camera.target.RoomNumber);
|
||||
if (y < probe.Position.Ceiling ||
|
||||
probe.Position.Floor < y ||
|
||||
probe.Position.Floor <= probe.Position.Ceiling ||
|
||||
probe.Position.Floor == NO_HEIGHT ||
|
||||
probe.Position.Ceiling == NO_HEIGHT)
|
||||
auto pointColl = GetPointCollision(Vector3i(Camera.target.x, y, Camera.target.z), Camera.target.RoomNumber);
|
||||
if (y < pointColl.GetCeilingHeight() ||
|
||||
pointColl.GetFloorHeight() < y ||
|
||||
pointColl.GetFloorHeight() <= pointColl.GetCeilingHeight() ||
|
||||
pointColl.GetFloorHeight() == NO_HEIGHT ||
|
||||
pointColl.GetCeilingHeight() == NO_HEIGHT)
|
||||
{
|
||||
Camera.target.x = pos.x;
|
||||
Camera.target.y = pos.y;
|
||||
|
@ -1266,7 +1268,7 @@ void CalculateCamera(const CollisionInfo& coll)
|
|||
Camera.speed = 1;
|
||||
}
|
||||
|
||||
Camera.target.RoomNumber = GetCollision(x, y, z, Camera.target.RoomNumber).RoomNumber;
|
||||
Camera.target.RoomNumber = GetPointCollision(Vector3i(x, y, z), Camera.target.RoomNumber).GetRoomNumber();
|
||||
|
||||
if (abs(LastTarget.x - Camera.target.x) < 4 &&
|
||||
abs(LastTarget.y - Camera.target.y) < 4 &&
|
||||
|
@ -1359,9 +1361,9 @@ void ItemPushCamera(GameBoundingBox* bounds, Pose* pos, short radius)
|
|||
Camera.pos.x = pos->Position.x + ((x * cosY) + (z * sinY));
|
||||
Camera.pos.z = pos->Position.z + ((z * cosY) - (x * sinY));
|
||||
|
||||
auto pointColl = GetCollision(Camera.pos.x, Camera.pos.y, Camera.pos.z, Camera.pos.RoomNumber);
|
||||
if (pointColl.Position.Floor == NO_HEIGHT || Camera.pos.y > pointColl.Position.Floor || Camera.pos.y < pointColl.Position.Ceiling)
|
||||
Camera.pos = GameVector(CamOldPos, pointColl.RoomNumber);
|
||||
auto pointColl = GetPointCollision(Camera.pos.ToVector3i(), Camera.pos.RoomNumber);
|
||||
if (pointColl.GetFloorHeight() == NO_HEIGHT || Camera.pos.y > pointColl.GetFloorHeight() || Camera.pos.y < pointColl.GetCeilingHeight())
|
||||
Camera.pos = GameVector(CamOldPos, pointColl.GetRoomNumber());
|
||||
}
|
||||
|
||||
bool CheckItemCollideCamera(ItemInfo* item)
|
||||
|
@ -1484,7 +1486,7 @@ void ItemsCollideCamera()
|
|||
if (TestBoundsCollideCamera(bounds, item->Pose, CAMERA_RADIUS))
|
||||
ItemPushCamera(&bounds, &item->Pose, RADIUS);
|
||||
|
||||
TEN::Renderer::g_Renderer.AddDebugBox(
|
||||
DrawDebugBox(
|
||||
bounds.ToBoundingOrientedBox(item->Pose),
|
||||
Vector4(1.0f, 0.0f, 0.0f, 1.0f), RendererDebugPage::CollisionStats);
|
||||
}
|
||||
|
@ -1507,7 +1509,7 @@ void ItemsCollideCamera()
|
|||
if (TestBoundsCollideCamera(bounds, mesh->pos, CAMERA_RADIUS))
|
||||
ItemPushCamera(&bounds, &mesh->pos, RADIUS);
|
||||
|
||||
TEN::Renderer::g_Renderer.AddDebugBox(
|
||||
DrawDebugBox(
|
||||
bounds.ToBoundingOrientedBox(mesh->pos),
|
||||
Vector4(1.0f, 0.0f, 0.0f, 1.0f), RendererDebugPage::CollisionStats);
|
||||
}
|
||||
|
|
401
TombEngine/Game/collision/Point.cpp
Normal file
401
TombEngine/Game/collision/Point.cpp
Normal file
|
@ -0,0 +1,401 @@
|
|||
#include "framework.h"
|
||||
#include "Game/collision/Point.h"
|
||||
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/room.h"
|
||||
#include "Game/Setup.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Objects/game_object_ids.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Room;
|
||||
using namespace TEN::Math;
|
||||
|
||||
namespace TEN::Collision::Point
|
||||
{
|
||||
PointCollisionData::PointCollisionData(const Vector3i& pos, int roomNumber)
|
||||
{
|
||||
_position = pos;
|
||||
_roomNumber = roomNumber;
|
||||
}
|
||||
|
||||
Vector3i PointCollisionData::GetPosition() const
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetRoomNumber() const
|
||||
{
|
||||
return _roomNumber;
|
||||
}
|
||||
|
||||
FloorInfo& PointCollisionData::GetSector()
|
||||
{
|
||||
if (_sector != nullptr)
|
||||
return *_sector;
|
||||
|
||||
// Set current sector.
|
||||
short probeRoomNumber = _roomNumber;
|
||||
_sector = GetFloor(_position.x, _position.y, _position.z, &probeRoomNumber);
|
||||
|
||||
return *_sector;
|
||||
}
|
||||
|
||||
FloorInfo& PointCollisionData::GetBottomSector()
|
||||
{
|
||||
if (_bottomSector != nullptr)
|
||||
return *_bottomSector;
|
||||
|
||||
// Set bottom sector.
|
||||
auto* bottomSector = &GetSector();
|
||||
auto roomNumberBelow = bottomSector->GetNextRoomNumber(_position, true);
|
||||
while (roomNumberBelow.has_value())
|
||||
{
|
||||
int roomNumber = roomNumberBelow.value_or(bottomSector->RoomNumber);
|
||||
auto& room = g_Level.Rooms[roomNumber];
|
||||
|
||||
bottomSector = Room::GetSector(&room, _position.x - room.x, _position.z - room.z);
|
||||
roomNumberBelow = bottomSector->GetNextRoomNumber(_position, true);
|
||||
}
|
||||
_bottomSector = bottomSector;
|
||||
|
||||
return *_bottomSector;
|
||||
}
|
||||
|
||||
FloorInfo& PointCollisionData::GetTopSector()
|
||||
{
|
||||
if (_topSector != nullptr)
|
||||
return *_topSector;
|
||||
|
||||
// Set top sector.
|
||||
auto* topSector = &GetSector();
|
||||
auto roomNumberAbove = topSector->GetNextRoomNumber(_position, false);
|
||||
while (roomNumberAbove.has_value())
|
||||
{
|
||||
int roomNumber = roomNumberAbove.value_or(topSector->RoomNumber);
|
||||
auto& room = g_Level.Rooms[roomNumber];
|
||||
|
||||
topSector = Room::GetSector(&room, _position.x - room.x, _position.z - room.z);
|
||||
roomNumberAbove = topSector->GetNextRoomNumber(_position, false);
|
||||
}
|
||||
_topSector = topSector;
|
||||
|
||||
return *_topSector;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetFloorHeight()
|
||||
{
|
||||
if (_floorHeight.has_value())
|
||||
return *_floorHeight;
|
||||
|
||||
// Set floor height.
|
||||
auto location = RoomVector(GetSector().RoomNumber, _position.y);
|
||||
_floorHeight = Floordata::GetSurfaceHeight(location, _position.x, _position.z, true).value_or(NO_HEIGHT);
|
||||
|
||||
return *_floorHeight;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetCeilingHeight()
|
||||
{
|
||||
if (_ceilingHeight.has_value())
|
||||
return *_ceilingHeight;
|
||||
|
||||
// Set ceiling height.
|
||||
auto location = RoomVector(GetSector().RoomNumber, _position.y);
|
||||
_ceilingHeight = Floordata::GetSurfaceHeight(location, _position.x, _position.z, false).value_or(NO_HEIGHT);
|
||||
|
||||
return *_ceilingHeight;
|
||||
}
|
||||
|
||||
Vector3 PointCollisionData::GetFloorNormal()
|
||||
{
|
||||
if (_floorNormal.has_value())
|
||||
return *_floorNormal;
|
||||
|
||||
// Set floor normal.
|
||||
if (GetFloorBridgeItemNumber() != NO_VALUE)
|
||||
{
|
||||
_floorNormal = GetBridgeNormal(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_floorNormal = GetBottomSector().GetSurfaceNormal(_position.x, _position.z, true);
|
||||
}
|
||||
|
||||
return *_floorNormal;
|
||||
}
|
||||
|
||||
Vector3 PointCollisionData::GetCeilingNormal()
|
||||
{
|
||||
if (_ceilingNormal.has_value())
|
||||
return *_ceilingNormal;
|
||||
|
||||
// Set ceiling normal.
|
||||
if (GetCeilingBridgeItemNumber() != NO_VALUE)
|
||||
{
|
||||
_ceilingNormal = GetBridgeNormal(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ceilingNormal = GetTopSector().GetSurfaceNormal(_position.x, _position.z, false);
|
||||
}
|
||||
|
||||
return *_ceilingNormal;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetFloorBridgeItemNumber()
|
||||
{
|
||||
if (_floorBridgeItemNumber.has_value())
|
||||
return *_floorBridgeItemNumber;
|
||||
|
||||
// Set floor bridge item number.
|
||||
int floorHeight = GetFloorHeight();
|
||||
auto pos = Vector3i(_position.x, floorHeight, _position.z);
|
||||
_floorBridgeItemNumber = GetBottomSector().GetInsideBridgeItemNumber(pos, true, false);
|
||||
|
||||
return *_floorBridgeItemNumber;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetCeilingBridgeItemNumber()
|
||||
{
|
||||
if (_ceilingBridgeItemNumber.has_value())
|
||||
return *_ceilingBridgeItemNumber;
|
||||
|
||||
// Set ceiling bridge item number.
|
||||
int ceilingHeight = GetCeilingHeight();
|
||||
auto pos = Vector3i(_position.x, ceilingHeight, _position.z);
|
||||
_ceilingBridgeItemNumber = GetTopSector().GetInsideBridgeItemNumber(pos, false, true);
|
||||
|
||||
return *_ceilingBridgeItemNumber;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetWaterSurfaceHeight()
|
||||
{
|
||||
if (_waterSurfaceHeight.has_value())
|
||||
return *_waterSurfaceHeight;
|
||||
|
||||
// Set water surface height. TODO: Calculate here.
|
||||
_waterSurfaceHeight = GetWaterSurface(_position.x, _position.y, _position.z, _roomNumber);
|
||||
|
||||
return *_waterSurfaceHeight;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetWaterBottomHeight()
|
||||
{
|
||||
if (_waterBottomHeight.has_value())
|
||||
return *_waterBottomHeight;
|
||||
|
||||
// Set water bottom height. TODO: Calculate here.
|
||||
_waterBottomHeight = GetWaterDepth(_position.x, _position.y, _position.z, _roomNumber);
|
||||
|
||||
return *_waterBottomHeight;
|
||||
}
|
||||
|
||||
int PointCollisionData::GetWaterTopHeight()
|
||||
{
|
||||
if (_waterTopHeight.has_value())
|
||||
return *_waterTopHeight;
|
||||
|
||||
// Set water top height. TODO: Calculate here.
|
||||
_waterTopHeight = GetWaterHeight(_position.x, _position.y, _position.z, _roomNumber);
|
||||
|
||||
return *_waterTopHeight;
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsWall()
|
||||
{
|
||||
return (GetFloorHeight() == NO_HEIGHT || GetCeilingHeight() == NO_HEIGHT ||
|
||||
GetFloorHeight() <= GetCeilingHeight());
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsSteepFloor()
|
||||
{
|
||||
short slopeAngle = Geometry::GetSurfaceSlopeAngle(GetFloorNormal());
|
||||
short steepSlopeAngle = (GetFloorBridgeItemNumber() != NO_VALUE) ?
|
||||
DEFAULT_STEEP_FLOOR_SLOPE_ANGLE :
|
||||
GetBottomSector().GetSurfaceIllegalSlopeAngle(_position.x, _position.z, true);
|
||||
|
||||
return (abs(slopeAngle) >= steepSlopeAngle);
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsSteepCeiling()
|
||||
{
|
||||
short slopeAngle = Geometry::GetSurfaceSlopeAngle(GetCeilingNormal(), -Vector3::UnitY);
|
||||
short steepSlopeAngle = (GetCeilingBridgeItemNumber() != NO_VALUE) ?
|
||||
DEFAULT_STEEP_CEILING_SLOPE_ANGLE :
|
||||
GetTopSector().GetSurfaceIllegalSlopeAngle(_position.x, _position.z, false);
|
||||
|
||||
return (abs(slopeAngle) >= steepSlopeAngle);
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsDiagonalFloorStep()
|
||||
{
|
||||
return GetBottomSector().IsSurfaceDiagonalStep(true);
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsDiagonalCeilingStep()
|
||||
{
|
||||
return GetTopSector().IsSurfaceDiagonalStep(false);
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsDiagonalFloorSplit()
|
||||
{
|
||||
float splitAngle = GetBottomSector().FloorSurface.SplitAngle;
|
||||
return (splitAngle == SectorSurfaceData::SPLIT_ANGLE_0 || splitAngle == SectorSurfaceData::SPLIT_ANGLE_1);
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsDiagonalCeilingSplit()
|
||||
{
|
||||
float splitAngle = GetTopSector().CeilingSurface.SplitAngle;
|
||||
return (splitAngle == SectorSurfaceData::SPLIT_ANGLE_0 || splitAngle == SectorSurfaceData::SPLIT_ANGLE_1);
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsFlippedDiagonalFloorSplit()
|
||||
{
|
||||
float splitAngle = GetBottomSector().FloorSurface.SplitAngle;
|
||||
return (IsDiagonalFloorStep() && splitAngle == SectorSurfaceData::SPLIT_ANGLE_1);
|
||||
}
|
||||
|
||||
bool PointCollisionData::IsFlippedDiagonalCeilingSplit()
|
||||
{
|
||||
float splitAngle = GetTopSector().CeilingSurface.SplitAngle;
|
||||
return (IsDiagonalCeilingStep() && splitAngle == SectorSurfaceData::SPLIT_ANGLE_1);
|
||||
}
|
||||
|
||||
bool PointCollisionData::TestEnvironmentFlag(RoomEnvFlags envFlag)
|
||||
{
|
||||
const auto& room = g_Level.Rooms[_roomNumber];
|
||||
return ((room.flags & envFlag) == envFlag);
|
||||
}
|
||||
|
||||
// HACK.
|
||||
Vector3 PointCollisionData::GetBridgeNormal(bool isFloor)
|
||||
{
|
||||
constexpr auto ANGLE_STEP = ANGLE(45.0f / 4);
|
||||
|
||||
int bridgeItemNumber = isFloor ? GetFloorBridgeItemNumber() : GetCeilingBridgeItemNumber();
|
||||
const auto& bridgeItem = g_Level.Items[bridgeItemNumber];
|
||||
|
||||
auto orient = bridgeItem.Pose.Orientation;
|
||||
switch (bridgeItem.ObjectNumber)
|
||||
{
|
||||
default:
|
||||
case ID_BRIDGE_FLAT:
|
||||
break;
|
||||
|
||||
case ID_BRIDGE_TILT1:
|
||||
orient.z -= ANGLE_STEP;
|
||||
break;
|
||||
|
||||
case ID_BRIDGE_TILT2:
|
||||
orient.z -= ANGLE_STEP * 2;
|
||||
break;
|
||||
|
||||
case ID_BRIDGE_TILT3:
|
||||
orient.z -= ANGLE_STEP * 3;
|
||||
break;
|
||||
|
||||
case ID_BRIDGE_TILT4:
|
||||
orient.z -= ANGLE_STEP * 4;
|
||||
break;
|
||||
}
|
||||
|
||||
int sign = isFloor ? -1 : 1;
|
||||
return Vector3::Transform(Vector3::UnitY * sign, orient.ToRotationMatrix());
|
||||
}
|
||||
|
||||
static int GetProbeRoomNumber(const Vector3i& pos, const RoomVector& location, const Vector3i& probePos)
|
||||
{
|
||||
// Conduct L-shaped room traversal.
|
||||
short probeRoomNumber = GetRoomVector(location, Vector3i(pos.x, probePos.y, pos.z)).RoomNumber;
|
||||
GetFloor(probePos.x, probePos.y, probePos.z, &probeRoomNumber);
|
||||
|
||||
return probeRoomNumber;
|
||||
}
|
||||
|
||||
static RoomVector GetLocation(const Vector3i& pos, int roomNumber)
|
||||
{
|
||||
short tempRoomNumber = roomNumber;
|
||||
const auto& sector = *GetFloor(pos.x, pos.y, pos.z, &tempRoomNumber);
|
||||
|
||||
return RoomVector(sector.RoomNumber, pos.y);
|
||||
}
|
||||
|
||||
static RoomVector GetLocation(const ItemInfo& item)
|
||||
{
|
||||
// TODO: Find cleaner solution. Manually constructing a player "location" can result in stumbles when climbing onto thin platforms.
|
||||
// May have to do with player's room number being updated at half-height? -- Sezz 2022.06.14
|
||||
if (item.IsLara())
|
||||
return item.Location;
|
||||
|
||||
short tempRoomNumber = item.RoomNumber;
|
||||
const auto& sector = *GetFloor(item.Pose.Position.x, item.Pose.Position.y, item.Pose.Position.z, &tempRoomNumber);
|
||||
|
||||
return RoomVector(sector.RoomNumber, item.Pose.Position.y);
|
||||
}
|
||||
|
||||
PointCollisionData GetPointCollision(const Vector3i& pos, int roomNumber)
|
||||
{
|
||||
// HACK: Ensure room number is correct if position extends to another room.
|
||||
// Accounts for some calls to this function which directly pass offset position instead of using dedicated probe overloads.
|
||||
GetFloor(pos.x, pos.y, pos.z, (short*)&roomNumber);
|
||||
|
||||
return PointCollisionData(pos, roomNumber);
|
||||
}
|
||||
|
||||
PointCollisionData GetPointCollision(const Vector3i& pos, int roomNumber, const Vector3& dir, float dist)
|
||||
{
|
||||
// Get "location".
|
||||
auto location = GetLocation(pos, roomNumber);
|
||||
|
||||
// Calculate probe position.
|
||||
auto probePos = Geometry::TranslatePoint(pos, dir, dist);
|
||||
short probeRoomNumber = GetProbeRoomNumber(pos, location, probePos);
|
||||
|
||||
return PointCollisionData(probePos, probeRoomNumber);
|
||||
}
|
||||
|
||||
PointCollisionData GetPointCollision(const Vector3i& pos, int roomNumber, short headingAngle, float forward, float down, float right, const Vector3& axis)
|
||||
{
|
||||
// Get "location".
|
||||
auto location = GetLocation(pos, roomNumber);
|
||||
|
||||
// Calculate probe position.
|
||||
auto probePos = Geometry::TranslatePoint(pos, headingAngle, forward, down, right, axis);
|
||||
short probeRoomNumber = GetProbeRoomNumber(pos, location, probePos);
|
||||
|
||||
return PointCollisionData(probePos, probeRoomNumber);
|
||||
}
|
||||
|
||||
PointCollisionData GetPointCollision(const ItemInfo& item)
|
||||
{
|
||||
return GetPointCollision(item.Pose.Position, item.RoomNumber);
|
||||
}
|
||||
|
||||
PointCollisionData GetPointCollision(const ItemInfo& item, const Vector3& dir, float dist)
|
||||
{
|
||||
// Get "location".
|
||||
auto location = GetLocation(item);
|
||||
|
||||
// Calculate probe position.
|
||||
auto probePos = Geometry::TranslatePoint(item.Pose.Position, dir, dist);
|
||||
short probeRoomNumber = GetProbeRoomNumber(item.Pose.Position, location, probePos);
|
||||
|
||||
return PointCollisionData(probePos, probeRoomNumber);
|
||||
}
|
||||
|
||||
PointCollisionData GetPointCollision(const ItemInfo& item, short headingAngle, float forward, float down, float right, const Vector3& axis)
|
||||
{
|
||||
// Get "location".
|
||||
auto location = GetLocation(item);
|
||||
|
||||
// Calculate probe position.
|
||||
auto probePos = Geometry::TranslatePoint(item.Pose.Position, headingAngle, forward, down, right, axis);
|
||||
short probeRoomNumber = GetProbeRoomNumber(item.Pose.Position, location, probePos);
|
||||
|
||||
return PointCollisionData(probePos, probeRoomNumber);
|
||||
}
|
||||
}
|
90
TombEngine/Game/collision/Point.h
Normal file
90
TombEngine/Game/collision/Point.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#pragma once
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Math/Math.h"
|
||||
|
||||
enum RoomEnvFlags;
|
||||
class FloorInfo;
|
||||
struct ItemInfo;
|
||||
|
||||
using namespace TEN::Math;
|
||||
|
||||
namespace TEN::Collision::Point
|
||||
{
|
||||
class PointCollisionData
|
||||
{
|
||||
private:
|
||||
// Members
|
||||
|
||||
Vector3i _position = Vector3i::Zero;
|
||||
int _roomNumber = 0;
|
||||
|
||||
FloorInfo* _sector = nullptr;
|
||||
FloorInfo* _bottomSector = nullptr;
|
||||
FloorInfo* _topSector = nullptr;
|
||||
|
||||
std::optional<int> _floorHeight = std::nullopt;
|
||||
std::optional<int> _ceilingHeight = std::nullopt;
|
||||
std::optional<Vector3> _floorNormal = std::nullopt;
|
||||
std::optional<Vector3> _ceilingNormal = std::nullopt;
|
||||
std::optional<int> _floorBridgeItemNumber = std::nullopt;
|
||||
std::optional<int> _ceilingBridgeItemNumber = std::nullopt;
|
||||
|
||||
std::optional<int> _waterSurfaceHeight = std::nullopt;
|
||||
std::optional<int> _waterBottomHeight = std::nullopt;
|
||||
std::optional<int> _waterTopHeight = std::nullopt;
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
PointCollisionData(const Vector3i& pos, int roomNumber);
|
||||
|
||||
// Getters
|
||||
|
||||
Vector3i GetPosition() const;
|
||||
int GetRoomNumber() const;
|
||||
|
||||
FloorInfo& GetSector();
|
||||
FloorInfo& GetBottomSector();
|
||||
FloorInfo& GetTopSector();
|
||||
|
||||
int GetFloorHeight();
|
||||
int GetCeilingHeight();
|
||||
Vector3 GetFloorNormal();
|
||||
Vector3 GetCeilingNormal();
|
||||
int GetFloorBridgeItemNumber();
|
||||
int GetCeilingBridgeItemNumber();
|
||||
|
||||
int GetWaterSurfaceHeight();
|
||||
int GetWaterBottomHeight();
|
||||
int GetWaterTopHeight();
|
||||
|
||||
// Inquirers
|
||||
|
||||
bool IsWall();
|
||||
bool IsSteepFloor();
|
||||
bool IsSteepCeiling();
|
||||
bool IsDiagonalFloorStep();
|
||||
bool IsDiagonalCeilingStep();
|
||||
bool IsDiagonalFloorSplit();
|
||||
bool IsDiagonalCeilingSplit();
|
||||
bool IsFlippedDiagonalFloorSplit();
|
||||
bool IsFlippedDiagonalCeilingSplit();
|
||||
|
||||
bool TestEnvironmentFlag(RoomEnvFlags envFlag);
|
||||
|
||||
private:
|
||||
// Helpers
|
||||
|
||||
Vector3 GetBridgeNormal(bool isFloor);
|
||||
};
|
||||
|
||||
PointCollisionData GetPointCollision(const Vector3i& pos, int roomNumber);
|
||||
PointCollisionData GetPointCollision(const Vector3i& pos, int roomNumber, const Vector3& dir, float dist);
|
||||
PointCollisionData GetPointCollision(const Vector3i& pos, int roomNumber, short headingAngle, float forward, float down = 0.0f, float right = 0.0f,
|
||||
const Vector3& axis = Vector3::UnitY);
|
||||
|
||||
PointCollisionData GetPointCollision(const ItemInfo& item);
|
||||
PointCollisionData GetPointCollision(const ItemInfo& item, const Vector3& dir, float dist);
|
||||
PointCollisionData GetPointCollision(const ItemInfo& item, short headingAngle, float forward, float down = 0.0f, float right = 0.0f,
|
||||
const Vector3& axis = Vector3::UnitY);
|
||||
}
|
|
@ -4,6 +4,8 @@
|
|||
#include "Game/animation.h"
|
||||
#include "Game/control/los.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/collision/sphere.h"
|
||||
#include "Game/effects/debris.h"
|
||||
#include "Game/effects/effects.h"
|
||||
|
@ -16,12 +18,12 @@
|
|||
#include "Game/room.h"
|
||||
#include "Game/Setup.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Renderer/Renderer.h"
|
||||
#include "Scripting/Include/ScriptInterfaceGame.h"
|
||||
#include "Sound/sound.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Math;
|
||||
using namespace TEN::Renderer;
|
||||
|
||||
constexpr auto ANIMATED_ALIGNMENT_FRAME_COUNT_THRESHOLD = 6;
|
||||
|
||||
|
@ -200,7 +202,7 @@ CollidedObjectData GetCollidedObjects(ItemInfo& collidingItem, bool onlyVisible,
|
|||
|
||||
// Test accurate box intersection.
|
||||
if (box0.Intersects(box1))
|
||||
collObjects.ItemPtrs.push_back(&item);
|
||||
collObjects.Items.push_back(&item);
|
||||
}
|
||||
while (itemNumber != NO_VALUE);
|
||||
}
|
||||
|
@ -249,7 +251,7 @@ CollidedObjectData GetCollidedObjects(ItemInfo& collidingItem, bool onlyVisible,
|
|||
|
||||
// Test accurate box intersection.
|
||||
if (box0.Intersects(box1))
|
||||
collObjects.StaticPtrs.push_back(&staticObj);
|
||||
collObjects.Statics.push_back(&staticObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +305,7 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
auto mxR = Matrix::CreateFromYawPitchRoll(TO_RAD(coll->Setup.ForwardAngle), 0.0f, 0.0f);
|
||||
auto direction = (Matrix::CreateTranslation(Vector3::UnitZ) * mxR).Translation();
|
||||
|
||||
// g_Renderer.AddDebugSphere(origin, 16, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
// DrawDebugSphere(origin, 16, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
|
||||
for (auto i : g_Level.Rooms[item->RoomNumber].neighbors)
|
||||
{
|
||||
|
@ -400,7 +402,7 @@ bool AlignLaraPosition(const Vector3i& offset, ItemInfo* item, ItemInfo* laraIte
|
|||
auto pos = Vector3::Transform(offset.ToVector3(), rotMatrix);
|
||||
auto target = item->Pose.Position.ToVector3() + pos;
|
||||
|
||||
int height = GetCollision(target.x, target.y, target.z, laraItem->RoomNumber).Position.Floor;
|
||||
int height = GetPointCollision(target, laraItem->RoomNumber).GetFloorHeight();
|
||||
if ((laraItem->Pose.Position.y - height) <= CLICK(2))
|
||||
{
|
||||
laraItem->Pose.Position = Vector3i(target);
|
||||
|
@ -429,7 +431,7 @@ bool MoveLaraPosition(const Vector3i& offset, ItemInfo* item, ItemInfo* laraItem
|
|||
else
|
||||
{
|
||||
// Prevent picking up items which can result in so called "flare pickup bug"
|
||||
int height = GetCollision(target.Position.x, target.Position.y, target.Position.z, laraItem->RoomNumber).Position.Floor;
|
||||
int height = GetPointCollision(target.Position, laraItem->RoomNumber).GetFloorHeight();
|
||||
if (abs(height - laraItem->Pose.Position.y) <= CLICK(2))
|
||||
return Move3DPosTo3DPos(laraItem, laraItem->Pose, target, LARA_ALIGN_VELOCITY, ANGLE(2.0f));
|
||||
}
|
||||
|
@ -702,7 +704,7 @@ bool ItemPushItem(ItemInfo* item0, ItemInfo* item1, CollisionInfo* coll, bool en
|
|||
item1->Pose.Position.Lerp(item0->Pose.Position + newDeltaPos, SOFT_PUSH_LERP_ALPHA);
|
||||
}
|
||||
// Snap to new position.
|
||||
else
|
||||
else if (coll->Setup.EnableObjectPush)
|
||||
{
|
||||
item1->Pose.Position = item0->Pose.Position + newDeltaPos;
|
||||
}
|
||||
|
@ -885,22 +887,19 @@ void ItemPushBridge(ItemInfo& item, CollisionInfo& coll)
|
|||
ShiftItem(&item, &coll);
|
||||
}
|
||||
|
||||
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResult& collResult)
|
||||
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, PointCollisionData& pointColl)
|
||||
{
|
||||
// Store an offset for a bridge item into shifts, if exists.
|
||||
if (coll.LastBridgeItemNumber == collResult.Position.Bridge && coll.LastBridgeItemNumber != NO_VALUE)
|
||||
// Store offset for bridge item into shifts if it exists.
|
||||
if (coll.LastBridgeItemNumber == pointColl.GetFloorBridgeItemNumber() && coll.LastBridgeItemNumber != NO_VALUE)
|
||||
{
|
||||
auto& bridgeItem = g_Level.Items[collResult.Position.Bridge];
|
||||
auto& bridgeItem = g_Level.Items[pointColl.GetFloorBridgeItemNumber()];
|
||||
|
||||
auto deltaPos = bridgeItem.Pose.Position - coll.LastBridgeItemPose.Position;
|
||||
auto deltaOrient = bridgeItem.Pose.Orientation - coll.LastBridgeItemPose.Orientation;
|
||||
auto deltaPose = Pose(deltaPos, deltaOrient);
|
||||
|
||||
int absDeltaHeight = item.Pose.Position.y - collResult.Position.Floor;
|
||||
int relDeltaHeight = absDeltaHeight + GameBoundingBox(&item).Y2;
|
||||
|
||||
if (deltaPose != Pose::Zero &&
|
||||
(abs(absDeltaHeight) <= CLICK(1 / 8.0f) || abs(relDeltaHeight) <= CLICK(1 / 8.0f)))
|
||||
// Item is grounded and bridge position changed; set shift.
|
||||
if (deltaPose != Pose::Zero && !item.Animation.IsAirborne)
|
||||
{
|
||||
const auto& bridgePos = bridgeItem.Pose.Position;
|
||||
|
||||
|
@ -910,15 +909,19 @@ void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResu
|
|||
auto offset = bridgePos.ToVector3() + Vector3::Transform(relOffset, rotMatrix);
|
||||
|
||||
deltaPose.Position -= item.Pose.Position - Vector3i(offset);
|
||||
|
||||
// Don't update shifts if difference is too big (possibly bridge was teleported or just entered bridge).
|
||||
if (deltaPose.Position.ToVector3().Length() <= coll.Setup.Radius * 2)
|
||||
|
||||
// Don't update shifts if difference is too big (bridge was possibly teleported or just entered).
|
||||
if (Vector2(deltaPose.Position.x, deltaPose.Position.z).Length() <= (coll.Setup.Radius * 2))
|
||||
{
|
||||
deltaPose.Orientation = EulerAngles(0, deltaPose.Orientation.y, 0);
|
||||
coll.Shift = deltaPose;
|
||||
}
|
||||
}
|
||||
else if (deltaPos.ToVector3().Length() <= coll.Setup.Radius && relDeltaHeight > 0 &&
|
||||
(deltaPos != Vector3i::Zero || deltaOrient != EulerAngles::Identity))
|
||||
// Push item.
|
||||
else if (TestBoundsCollide(&bridgeItem, &item, coll.Setup.Radius) &&
|
||||
Vector2(deltaPose.Position.x, deltaPose.Position.z).Length() <= coll.Setup.Radius &&
|
||||
(deltaPos != Vector3i::Zero || deltaOrient != EulerAngles::Identity))
|
||||
{
|
||||
// Push item away if not directly above bridge, and bridge position was changed.
|
||||
ItemPushItem(&bridgeItem, &item);
|
||||
}
|
||||
|
||||
|
@ -930,7 +933,7 @@ void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResu
|
|||
coll.LastBridgeItemNumber = NO_VALUE;
|
||||
}
|
||||
|
||||
coll.LastBridgeItemNumber = collResult.Position.Bridge;
|
||||
coll.LastBridgeItemNumber = pointColl.GetFloorBridgeItemNumber();
|
||||
}
|
||||
|
||||
void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
|
||||
|
@ -965,6 +968,10 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
// Get DX static bounds in global coordinates.
|
||||
auto staticBounds = box.ToBoundingOrientedBox(pose);
|
||||
|
||||
// Ignore processing null bounds.
|
||||
if (Vector3(staticBounds.Extents) == Vector3::Zero)
|
||||
return false;
|
||||
|
||||
// Get local TR bounds and DX item bounds in global coordinates.
|
||||
auto itemBBox = GameBoundingBox(item);
|
||||
auto itemBounds = itemBBox.ToBoundingOrientedBox(item->Pose);
|
||||
|
@ -980,7 +987,7 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
itemBounds.Extents = itemBounds.Extents - Vector3(BLOCK(1));
|
||||
|
||||
// Draw static bounds.
|
||||
g_Renderer.AddDebugBox(staticBounds, Vector4(1, 0.3f, 0, 1), RendererDebugPage::CollisionStats);
|
||||
DrawDebugBox(staticBounds, Vector4(1, 0.3f, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
// Calculate horizontal item collision bounds according to radius.
|
||||
GameBoundingBox collBox;
|
||||
|
@ -1006,12 +1013,8 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
auto collBounds = collBox.ToBoundingOrientedBox(Pose(item->Pose.Position));
|
||||
bool intersects = staticBounds.Intersects(collBounds);
|
||||
|
||||
// Check if previous item horizontal position intersects bounds.
|
||||
auto prevCollBounds = collBox.ToBoundingOrientedBox(Pose(coll->Setup.PrevPosition));
|
||||
bool prevHorIntersects = staticBounds.Intersects(prevCollBounds);
|
||||
|
||||
// Draw item coll bounds.
|
||||
g_Renderer.AddDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
DrawDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
// Decompose static bounds into top/bottom plane vertices.
|
||||
Vector3 corners[8];
|
||||
|
@ -1068,7 +1071,7 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
auto distanceToVerticalPlane = height / 2 - yPoint;
|
||||
|
||||
// Correct position according to top/bottom bounds, if collided and plane is nearby.
|
||||
if (intersects && prevHorIntersects && minDistance < height)
|
||||
if (intersects && minDistance < height)
|
||||
{
|
||||
if (bottom)
|
||||
{
|
||||
|
@ -1272,39 +1275,42 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
|
||||
auto prevPointProbe = GetCollision(x, y, z, item->RoomNumber);
|
||||
auto pointProbe = GetCollision(item);
|
||||
auto prevPointColl = GetPointCollision(Vector3i(x, y, z), item->RoomNumber);
|
||||
auto pointColl = GetPointCollision(*item);
|
||||
|
||||
// TODO: Use floor normal directly.
|
||||
auto floorTilt = GetSurfaceTilt(pointColl.GetFloorNormal(), true);
|
||||
|
||||
auto bounds = GameBoundingBox(item);
|
||||
int radius = bounds.GetHeight();
|
||||
|
||||
item->Pose.Position.y += radius;
|
||||
|
||||
if (item->Pose.Position.y >= pointProbe.Position.Floor)
|
||||
if (item->Pose.Position.y >= pointColl.GetFloorHeight())
|
||||
{
|
||||
int bs = 0;
|
||||
|
||||
if (pointProbe.Position.FloorSlope && prevPointProbe.Position.Floor < pointProbe.Position.Floor)
|
||||
if (pointColl.IsSteepFloor() && prevPointColl.GetFloorHeight() < pointColl.GetFloorHeight())
|
||||
{
|
||||
int yAngle = (long)((unsigned short)item->Pose.Orientation.y);
|
||||
|
||||
if (pointProbe.FloorTilt.x < 0)
|
||||
if (floorTilt.x < 0)
|
||||
{
|
||||
if (yAngle >= ANGLE(180.0f))
|
||||
bs = 1;
|
||||
}
|
||||
else if (pointProbe.FloorTilt.x > 0)
|
||||
else if (floorTilt.x > 0)
|
||||
{
|
||||
if (yAngle <= ANGLE(180.0f))
|
||||
bs = 1;
|
||||
}
|
||||
|
||||
if (pointProbe.FloorTilt.y < 0)
|
||||
if (floorTilt.y < 0)
|
||||
{
|
||||
if (yAngle >= ANGLE(90.0f) && yAngle <= ANGLE(270.0f))
|
||||
bs = 1;
|
||||
}
|
||||
else if (pointProbe.FloorTilt.y > 0)
|
||||
else if (floorTilt.y > 0)
|
||||
{
|
||||
if (yAngle <= ANGLE(90.0f) || yAngle >= ANGLE(270.0f))
|
||||
bs = 1;
|
||||
|
@ -1313,7 +1319,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
|
||||
// If last position of item was also below this floor height, we've hit a wall, else we've hit a floor.
|
||||
|
||||
if (y > (pointProbe.Position.Floor + 32) && bs == 0 &&
|
||||
if (y > (pointColl.GetFloorHeight() + 32) && bs == 0 &&
|
||||
(((x / BLOCK(1)) != (item->Pose.Position.x / BLOCK(1))) ||
|
||||
((z / BLOCK(1)) != (item->Pose.Position.z / BLOCK(1)))))
|
||||
{
|
||||
|
@ -1353,14 +1359,14 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
item->Pose.Position.z = z;
|
||||
}
|
||||
// Hit a steep slope?
|
||||
else if (pointProbe.Position.FloorSlope)
|
||||
else if (pointColl.IsSteepFloor())
|
||||
{
|
||||
// Need to know which direction the slope is.
|
||||
|
||||
item->Animation.Velocity.z -= (item->Animation.Velocity.z / 4);
|
||||
|
||||
// Hit angle = ANGLE(90.0f)
|
||||
if (pointProbe.FloorTilt.x < 0 && ((abs(pointProbe.FloorTilt.x)) - (abs(pointProbe.FloorTilt.y)) >= 2))
|
||||
if (floorTilt.x < 0 && ((abs(floorTilt.x)) - (abs(floorTilt.y)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1372,7 +1378,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z -= pointProbe.FloorTilt.x * 2;
|
||||
item->Animation.Velocity.z -= floorTilt.x * 2;
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(90.0f) && (unsigned short)item->Pose.Orientation.y < ANGLE(270.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1394,7 +1400,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(270.0f)
|
||||
else if (pointProbe.FloorTilt.x > 0 && ((abs(pointProbe.FloorTilt.x)) - (abs(pointProbe.FloorTilt.y)) >= 2))
|
||||
else if (floorTilt.x > 0 && ((abs(floorTilt.x)) - (abs(floorTilt.y)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) < ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1406,7 +1412,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.x * 2;
|
||||
item->Animation.Velocity.z += floorTilt.x * 2;
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(270.0f) || (unsigned short)item->Pose.Orientation.y < ANGLE(90.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1428,7 +1434,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = 0
|
||||
else if (pointProbe.FloorTilt.y < 0 && ((abs(pointProbe.FloorTilt.y)) - (abs(pointProbe.FloorTilt.x)) >= 2))
|
||||
else if (floorTilt.y < 0 && ((abs(floorTilt.y)) - (abs(floorTilt.x)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(90.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(270.0f))
|
||||
{
|
||||
|
@ -1440,7 +1446,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z -= pointProbe.FloorTilt.y * 2;
|
||||
item->Animation.Velocity.z -= floorTilt.y * 2;
|
||||
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1463,7 +1469,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(180.0f)
|
||||
else if (pointProbe.FloorTilt.y > 0 && ((abs(pointProbe.FloorTilt.y)) - (abs(pointProbe.FloorTilt.x)) >= 2))
|
||||
else if (floorTilt.y > 0 && ((abs(floorTilt.y)) - (abs(floorTilt.x)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(270.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(90.0f))
|
||||
{
|
||||
|
@ -1475,7 +1481,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.y * 2;
|
||||
item->Animation.Velocity.z += floorTilt.y * 2;
|
||||
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1497,7 +1503,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
item->Animation.Velocity.y = 0;
|
||||
}
|
||||
}
|
||||
else if (pointProbe.FloorTilt.x < 0 && pointProbe.FloorTilt.y < 0) // Hit angle = 0x2000
|
||||
else if (floorTilt.x < 0 && floorTilt.y < 0) // Hit angle = 0x2000
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(135.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(315.0f))
|
||||
{
|
||||
|
@ -1509,7 +1515,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += -pointProbe.FloorTilt.x + -pointProbe.FloorTilt.y;
|
||||
item->Animation.Velocity.z += -floorTilt.x + -floorTilt.y;
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(45.0f) && (unsigned short)item->Pose.Orientation.y < ANGLE(225.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1531,7 +1537,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(135.0f)
|
||||
else if (pointProbe.FloorTilt.x < 0 && pointProbe.FloorTilt.y > 0)
|
||||
else if (floorTilt.x < 0 && floorTilt.y > 0)
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(225.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(45.0f))
|
||||
{
|
||||
|
@ -1543,7 +1549,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += (-pointProbe.FloorTilt.x) + pointProbe.FloorTilt.y;
|
||||
item->Animation.Velocity.z += (-floorTilt.x) + floorTilt.y;
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(315.0f) && (unsigned short)item->Pose.Orientation.y > ANGLE(135.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1565,7 +1571,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(225.5f)
|
||||
else if (pointProbe.FloorTilt.x > 0 && pointProbe.FloorTilt.y > 0)
|
||||
else if (floorTilt.x > 0 && floorTilt.y > 0)
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(315.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(135.0f))
|
||||
{
|
||||
|
@ -1577,7 +1583,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.x + pointProbe.FloorTilt.y;
|
||||
item->Animation.Velocity.z += floorTilt.x + floorTilt.y;
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(45.0f) || (unsigned short)item->Pose.Orientation.y > ANGLE(225.5f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1599,7 +1605,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(315.0f)
|
||||
else if (pointProbe.FloorTilt.x > 0 && pointProbe.FloorTilt.y < 0)
|
||||
else if (floorTilt.x > 0 && floorTilt.y < 0)
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(45.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(225.5f))
|
||||
{
|
||||
|
@ -1611,7 +1617,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.x + (-pointProbe.FloorTilt.y);
|
||||
item->Animation.Velocity.z += floorTilt.x + (-floorTilt.y);
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(135.0f) || (unsigned short)item->Pose.Orientation.y > ANGLE(315.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1672,7 +1678,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
item->Pose.Position.y = pointProbe.Position.Floor;
|
||||
item->Pose.Position.y = pointColl.GetFloorHeight();
|
||||
}
|
||||
}
|
||||
// Check for on top of object.
|
||||
|
@ -1680,8 +1686,8 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (yv >= 0)
|
||||
{
|
||||
prevPointProbe = GetCollision(item->Pose.Position.x, y, item->Pose.Position.z, item->RoomNumber);
|
||||
pointProbe = GetCollision(item);
|
||||
prevPointColl = GetPointCollision(Vector3i(item->Pose.Position.x, y, item->Pose.Position.z), item->RoomNumber);
|
||||
pointColl = GetPointCollision(*item);
|
||||
|
||||
// Bounce off floor.
|
||||
|
||||
|
@ -1689,7 +1695,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
// was always set to 0 by GetHeight() function which was called before the check.
|
||||
// Possibly a mistake or unfinished feature by Core? -- Lwmte, 27.08.21
|
||||
|
||||
if (item->Pose.Position.y >= prevPointProbe.Position.Floor)
|
||||
if (item->Pose.Position.y >= prevPointColl.GetFloorHeight())
|
||||
{
|
||||
// Hit the floor; bounce and slow down.
|
||||
if (item->Animation.Velocity.y > 0)
|
||||
|
@ -1723,17 +1729,17 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
item->Pose.Position.y = prevPointProbe.Position.Floor;
|
||||
item->Pose.Position.y = prevPointColl.GetFloorHeight();
|
||||
}
|
||||
}
|
||||
// else
|
||||
{
|
||||
// Bounce off ceiling.
|
||||
pointProbe = GetCollision(item);
|
||||
pointColl = GetPointCollision(*item);
|
||||
|
||||
if (item->Pose.Position.y < pointProbe.Position.Ceiling)
|
||||
if (item->Pose.Position.y < pointColl.GetCeilingHeight())
|
||||
{
|
||||
if (y < pointProbe.Position.Ceiling &&
|
||||
if (y < pointColl.GetCeilingHeight() &&
|
||||
(((x / BLOCK(1)) != (item->Pose.Position.x / BLOCK(1))) ||
|
||||
((z / BLOCK(1)) != (item->Pose.Position.z / BLOCK(1)))))
|
||||
{
|
||||
|
@ -1762,7 +1768,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
item->Pose.Position.z = z;
|
||||
}
|
||||
else
|
||||
item->Pose.Position.y = pointProbe.Position.Ceiling;
|
||||
item->Pose.Position.y = pointColl.GetCeilingHeight();
|
||||
|
||||
if (item->Animation.Velocity.y < 0)
|
||||
item->Animation.Velocity.y = -item->Animation.Velocity.y;
|
||||
|
@ -1770,14 +1776,14 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
pointProbe = GetCollision(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber);
|
||||
pointColl = GetPointCollision(*item);
|
||||
|
||||
if (pointProbe.RoomNumber != item->RoomNumber)
|
||||
if (pointColl.GetRoomNumber() != item->RoomNumber)
|
||||
{
|
||||
if (item->ObjectNumber == ID_GRENADE && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, pointProbe.RoomNumber))
|
||||
if (item->ObjectNumber == ID_GRENADE && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, pointColl.GetRoomNumber()))
|
||||
Splash(item);
|
||||
|
||||
ItemNewRoom(itemNumber, pointProbe.RoomNumber);
|
||||
ItemNewRoom(itemNumber, pointColl.GetRoomNumber());
|
||||
}
|
||||
|
||||
item->Pose.Position.y -= radius;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#pragma once
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Math/Math.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
|
||||
class FloorInfo;
|
||||
struct CollisionInfo;
|
||||
struct CollisionResult;
|
||||
|
@ -27,10 +30,10 @@ struct ObjectCollisionBounds
|
|||
|
||||
struct CollidedObjectData
|
||||
{
|
||||
std::vector<ItemInfo*> ItemPtrs = {};
|
||||
std::vector<MESH_INFO*> StaticPtrs = {};
|
||||
std::vector<ItemInfo*> Items = {};
|
||||
std::vector<MESH_INFO*> Statics = {};
|
||||
|
||||
bool IsEmpty() const { return (ItemPtrs.empty() && StaticPtrs.empty()); };
|
||||
bool IsEmpty() const { return (Items.empty() && Statics.empty()); };
|
||||
};
|
||||
|
||||
void GenericSphereBoxCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
|
@ -56,7 +59,7 @@ void ItemPushBridge(ItemInfo& item, CollisionInfo& coll);
|
|||
|
||||
bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose& pose, CollisionInfo* coll);
|
||||
void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll);
|
||||
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResult& collResult);
|
||||
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, PointCollisionData& pointColl);
|
||||
|
||||
void AIPickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
void ObjectCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
|
|
|
@ -4,17 +4,18 @@
|
|||
#include "Game/control/box.h"
|
||||
#include "Game/control/los.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/animation.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/room.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Renderer/Renderer.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Collision::Room;
|
||||
using namespace TEN::Math;
|
||||
using namespace TEN::Renderer;
|
||||
|
||||
void ShiftItem(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
|
@ -97,12 +98,12 @@ bool TestItemRoomCollisionAABB(ItemInfo* item)
|
|||
|
||||
auto test = [item](short x, short y, short z, bool floor)
|
||||
{
|
||||
auto collPos = GetCollision(x, y, z, item->RoomNumber).Position;
|
||||
auto pointColl = GetPointCollision(Vector3i(x, y, z), item->RoomNumber);
|
||||
|
||||
if (floor)
|
||||
return (y > collPos.Floor);
|
||||
return (y > pointColl.GetFloorHeight());
|
||||
else
|
||||
return (y < collPos.Ceiling);
|
||||
return (y < pointColl.GetCeilingHeight());
|
||||
};
|
||||
|
||||
bool collided =
|
||||
|
@ -118,155 +119,26 @@ bool TestItemRoomCollisionAABB(ItemInfo* item)
|
|||
return collided;
|
||||
}
|
||||
|
||||
// Overload used to quickly get point collision parameters at a given item's position.
|
||||
CollisionResult GetCollision(const ItemInfo& item)
|
||||
static CollisionPositionData GetCollisionPosition(PointCollisionData& pointColl)
|
||||
{
|
||||
short newRoomNumber = item.RoomNumber;
|
||||
auto floor = GetFloor(item.Pose.Position.x, item.Pose.Position.y, item.Pose.Position.z, &newRoomNumber);
|
||||
auto probe = GetCollision(floor, item.Pose.Position.x, item.Pose.Position.y, item.Pose.Position.z);
|
||||
auto collPos = CollisionPositionData{};
|
||||
collPos.Floor = pointColl.GetFloorHeight();
|
||||
collPos.Ceiling = pointColl.GetCeilingHeight();
|
||||
collPos.Bridge = pointColl.GetFloorBridgeItemNumber();
|
||||
collPos.SplitAngle = pointColl.GetBottomSector().FloorSurface.SplitAngle;
|
||||
collPos.FloorSlope = pointColl.IsSteepFloor();
|
||||
collPos.CeilingSlope = pointColl.IsSteepCeiling();
|
||||
collPos.DiagonalStep = pointColl.IsDiagonalFloorStep();
|
||||
|
||||
probe.RoomNumber = newRoomNumber;
|
||||
return probe;
|
||||
return collPos;
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
CollisionResult GetCollision(const ItemInfo* item)
|
||||
{
|
||||
return GetCollision(*item);
|
||||
}
|
||||
|
||||
// Overload used to probe point collision parameters from a given item's position.
|
||||
CollisionResult GetCollision(const ItemInfo* item, short headingAngle, float forward, float down, float right)
|
||||
{
|
||||
short tempRoomNumber = item->RoomNumber;
|
||||
|
||||
// TODO: Find cleaner solution. Constructing a Location for Lara on the spot can result in a stumble when climbing onto thin platforms. -- Sezz 2022.06.14
|
||||
auto location = item->IsLara() ?
|
||||
item->Location :
|
||||
RoomVector(GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &tempRoomNumber)->RoomNumber, item->Pose.Position.y);
|
||||
|
||||
auto point = Geometry::TranslatePoint(item->Pose.Position, headingAngle, forward, down, right);
|
||||
int adjacentRoomNumber = GetRoomVector(location, Vector3i(item->Pose.Position.x, point.y, item->Pose.Position.z)).RoomNumber;
|
||||
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
||||
}
|
||||
|
||||
// Overload used to probe point collision parameters from a given position.
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber, short headingAngle, float forward, float down, float right)
|
||||
{
|
||||
short tempRoomNumber = roomNumber;
|
||||
auto location = RoomVector(GetFloor(pos.x, pos.y, pos.z, &tempRoomNumber)->RoomNumber, pos.y);
|
||||
|
||||
auto point = Geometry::TranslatePoint(pos, headingAngle, forward, down, right);
|
||||
int adjacentRoomNumber = GetRoomVector(location, Vector3i(pos.x, point.y, pos.z)).RoomNumber;
|
||||
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
||||
}
|
||||
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber, const EulerAngles& orient, float dist)
|
||||
{
|
||||
auto point = Geometry::TranslatePoint(pos, orient, dist);
|
||||
|
||||
short tempRoomNumber = roomNumber;
|
||||
auto location = RoomVector(GetFloor(pos.x, pos.y, pos.z, &tempRoomNumber)->RoomNumber, pos.y);
|
||||
int adjacentRoomNumber = GetRoomVector(location, Vector3i(pos.x, point.y, pos.z)).RoomNumber;
|
||||
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
||||
}
|
||||
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber, const Vector3& dir, float dist)
|
||||
{
|
||||
auto point = Geometry::TranslatePoint(pos, dir, dist);
|
||||
|
||||
short tempRoomNumber = roomNumber;
|
||||
auto location = RoomVector(GetFloor(pos.x, pos.y, pos.z, &tempRoomNumber)->RoomNumber, pos.y);
|
||||
int adjacentRoomNumber = GetRoomVector(location, Vector3i(pos.x, point.y, pos.z)).RoomNumber;
|
||||
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
||||
}
|
||||
|
||||
// Overload used as universal wrapper across collisional code replacing
|
||||
// triads of roomNumber-GetFloor()-GetFloorHeight() calls.
|
||||
// Advantage is that it does NOT modify incoming roomNumber argument,
|
||||
// instead storing one modified by GetFloor() within a returned CollisionResult struct.
|
||||
// This way, no external variables are modified as output arguments.
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber)
|
||||
{
|
||||
return GetCollision(pos.x, pos.y, pos.z, roomNumber);
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
CollisionResult GetCollision(int x, int y, int z, short roomNumber)
|
||||
{
|
||||
auto room = roomNumber;
|
||||
auto floor = GetFloor(x, y, z, &room);
|
||||
auto result = GetCollision(floor, x, y, z);
|
||||
|
||||
result.RoomNumber = room;
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: To be used only when absolutely necessary.
|
||||
CollisionResult GetCollision(const GameVector& pos)
|
||||
{
|
||||
return GetCollision(pos.x, pos.y, pos.z, pos.RoomNumber);
|
||||
}
|
||||
|
||||
// A reworked legacy GetFloorHeight() function which writes data
|
||||
// into a special CollisionResult struct instead of global variables.
|
||||
// It writes for both floor and ceiling heights at the same coordinates, meaning it should be used
|
||||
// in place of successive GetFloorHeight() and GetCeilingHeight() calls to increase readability.
|
||||
CollisionResult GetCollision(FloorInfo* floor, int x, int y, int z)
|
||||
{
|
||||
auto result = CollisionResult{};
|
||||
|
||||
// Record coordinates.
|
||||
result.Coordinates = Vector3i(x, y, z);
|
||||
|
||||
// Return provided collision block into result as itself.
|
||||
result.Block = floor;
|
||||
|
||||
// Floor and ceiling heights are borrowed directly from floordata.
|
||||
result.Position.Floor = GetSurfaceHeight(RoomVector(floor->RoomNumber, y), x, z, true).value_or(NO_HEIGHT);
|
||||
result.Position.Ceiling = GetSurfaceHeight(RoomVector(floor->RoomNumber, y), x, z, false).value_or(NO_HEIGHT);
|
||||
|
||||
// Probe bottom collision block through portals.
|
||||
while (floor->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
{
|
||||
auto* room = &g_Level.Rooms[floor->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(floor->RoomNumber)];
|
||||
floor = GetSector(room, x - room->x, z - room->z);
|
||||
}
|
||||
|
||||
// Return probed bottom collision block into result.
|
||||
result.BottomBlock = floor;
|
||||
|
||||
// Get surface noramls.
|
||||
result.FloorNormal = floor->GetSurfaceNormal(x, z, true);
|
||||
result.CeilingNormal = floor->GetSurfaceNormal(x, z, false);
|
||||
|
||||
// Backport surface normals to tilts.
|
||||
result.FloorTilt = GetSurfaceTilt(result.FloorNormal, true).ToVector2();
|
||||
result.CeilingTilt = GetSurfaceTilt(result.CeilingNormal, false).ToVector2();
|
||||
|
||||
// Split, bridge and slope data.
|
||||
result.Position.DiagonalStep = floor->IsSurfaceDiagonalStep(true);
|
||||
result.Position.SplitAngle = TO_RAD(floor->FloorSurface.SplitAngle);
|
||||
result.Position.Bridge = result.BottomBlock->GetInsideBridgeItemNumber(Vector3i(x, result.Position.Floor, z), true, false);
|
||||
result.Position.FloorSlope = result.Position.Bridge < 0 && Geometry::GetSurfaceSlopeAngle(result.FloorNormal) >=
|
||||
result.BottomBlock->GetSurfaceIllegalSlopeAngle(x, z, true);
|
||||
result.Position.CeilingSlope = Geometry::GetSurfaceSlopeAngle(result.CeilingNormal, -Vector3::UnitY) >=
|
||||
result.BottomBlock->GetSurfaceIllegalSlopeAngle(x, z, false); // TODO: Fix on bridges placed beneath ceiling slopes. @Sezz 2022.01.29
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, bool resetRoom)
|
||||
{
|
||||
GetCollisionInfo(coll, item, Vector3i::Zero, resetRoom);
|
||||
}
|
||||
|
||||
static void SetSectorAttribs(CollisionPosition& sectorAttribs, const CollisionSetup& collSetup, const CollisionResult& pointColl,
|
||||
static void SetSectorAttribs(CollisionPositionData& sectorAttribs, const CollisionSetupData& collSetup, PointCollisionData& pointColl,
|
||||
const Vector3i& probePos, int realRoomNumber)
|
||||
{
|
||||
constexpr auto ASPECT_ANGLE_DELTA_MAX = ANGLE(90.0f);
|
||||
|
||||
auto floorNormal = pointColl.FloorNormal;
|
||||
auto floorNormal = pointColl.GetFloorNormal();
|
||||
short aspectAngle = Geometry::GetSurfaceAspectAngle(floorNormal);
|
||||
short aspectAngleDelta = Geometry::GetShortestAngle(collSetup.ForwardAngle, aspectAngle);
|
||||
|
||||
|
@ -293,14 +165,14 @@ static void SetSectorAttribs(CollisionPosition& sectorAttribs, const CollisionSe
|
|||
}
|
||||
else if (collSetup.BlockDeathFloorDown &&
|
||||
sectorAttribs.Floor >= CLICK(0.5f) &&
|
||||
pointColl.BottomBlock->Flags.Death)
|
||||
pointColl.GetBottomSector().Flags.Death)
|
||||
{
|
||||
sectorAttribs.Floor = MAX_HEIGHT;
|
||||
}
|
||||
else if (collSetup.BlockMonkeySwingEdge)
|
||||
{
|
||||
auto pointColl = GetCollision(probePos.x, probePos.y + collSetup.Height, probePos.z, realRoomNumber);
|
||||
if (!pointColl.BottomBlock->Flags.Monkeyswing)
|
||||
auto pointColl = GetPointCollision(probePos, realRoomNumber, Vector3::UnitY, collSetup.Height);
|
||||
if (!pointColl.GetBottomSector().Flags.Monkeyswing)
|
||||
sectorAttribs.Floor = MAX_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
@ -407,8 +279,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
|
||||
// HACK: when using SetPosition animcommand, item->RoomNumber does not immediately
|
||||
// update, but only at the end of control loop. This may cause bugs when Lara is
|
||||
// climbing or vaulting ledges under slopes. Using Location->roomNumber solves
|
||||
// these bugs, as it is updated immediately. But since Location->roomNumber is ONLY
|
||||
// climbing or vaulting ledges under slopes. Using Location->RoomNumber solves
|
||||
// these bugs, as it is updated immediately. But since Location->RoomNumber is ONLY
|
||||
// updated for Lara, we can't use it for all objects for now. In future, we should
|
||||
// either update Location field for all objects or use this value as it is now.
|
||||
|
||||
|
@ -416,22 +288,22 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
|
||||
// TEST 1: TILT AND NEAREST LEDGE CALCULATION
|
||||
|
||||
auto collResult = GetCollision(probePos.x, item->Pose.Position.y, probePos.z, realRoomNumber);
|
||||
auto pointColl = GetPointCollision(Vector3i(probePos.x, item->Pose.Position.y, probePos.z), realRoomNumber);
|
||||
|
||||
coll->FloorNormal = collResult.FloorNormal;
|
||||
coll->CeilingNormal = collResult.CeilingNormal;
|
||||
coll->FloorTilt = collResult.FloorTilt;
|
||||
coll->CeilingTilt = collResult.CeilingTilt;
|
||||
coll->FloorNormal = pointColl.GetFloorNormal();
|
||||
coll->CeilingNormal = pointColl.GetCeilingNormal();
|
||||
coll->FloorTilt = GetSurfaceTilt(pointColl.GetFloorNormal(), true).ToVector2();
|
||||
coll->CeilingTilt = GetSurfaceTilt(pointColl.GetCeilingNormal(), false).ToVector2();
|
||||
coll->NearestLedgeAngle = GetNearestLedgeAngle(item, coll, coll->NearestLedgeDistance);
|
||||
|
||||
// Debug angle and distance
|
||||
// g_Renderer.PrintDebugMessage("Nearest angle: %d", coll->NearestLedgeAngle);
|
||||
// g_Renderer.PrintDebugMessage("Nearest dist: %f", coll->NearestLedgeDistance);
|
||||
// PrintDebugMessage("Nearest angle: %d", coll->NearestLedgeAngle);
|
||||
// PrintDebugMessage("Nearest dist: %f", coll->NearestLedgeDistance);
|
||||
|
||||
// TEST 2: CENTERPOINT PROBE
|
||||
|
||||
collResult = GetCollision(probePos.x, probePos.y, probePos.z, realRoomNumber);
|
||||
int topRoomNumber = collResult.RoomNumber; // Keep top room number as we need it to re-probe from origin room.
|
||||
pointColl = GetPointCollision(probePos, realRoomNumber);
|
||||
int topRoomNumber = pointColl.GetRoomNumber(); // Keep top room number as we need it to re-probe from origin room.
|
||||
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
|
@ -443,8 +315,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
else
|
||||
{
|
||||
height = collResult.Position.Floor;
|
||||
ceiling = GetCeiling(collResult.Block, probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
height = pointColl.GetFloorHeight();
|
||||
ceiling = GetCeiling(&pointColl.GetSector(), probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
}
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
|
@ -453,21 +325,21 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
if (ceiling != NO_HEIGHT)
|
||||
ceiling -= probePos.y;
|
||||
|
||||
coll->Middle = collResult.Position;
|
||||
coll->Middle = GetCollisionPosition(pointColl);
|
||||
coll->Middle.Floor = height;
|
||||
coll->Middle.Ceiling = ceiling;
|
||||
|
||||
// Additionally calculate bridge shifts, if present.
|
||||
CollideBridgeItems(*item, *coll, collResult);
|
||||
// Additionally calculate bridge shifts if present.
|
||||
CollideBridgeItems(*item, *coll, pointColl);
|
||||
|
||||
// TEST 3: FRONTAL PROBE
|
||||
|
||||
probePos.x = entityPos.x + xFront;
|
||||
probePos.z = entityPos.z + zFront;
|
||||
|
||||
g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(1, 0, 0, 1), RendererDebugPage::CollisionStats);
|
||||
DrawDebugSphere(probePos.ToVector3(), 32, Vector4(1, 0, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
collResult = GetCollision(probePos.x, probePos.y, probePos.z, topRoomNumber);
|
||||
pointColl = GetPointCollision(probePos, topRoomNumber);
|
||||
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
|
@ -486,8 +358,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
else
|
||||
{
|
||||
height = collResult.Position.Floor;
|
||||
ceiling = GetCeiling(collResult.Block, probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
height = pointColl.GetFloorHeight();
|
||||
ceiling = GetCeiling(&pointColl.GetSector(), probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
}
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
|
@ -496,7 +368,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
if (ceiling != NO_HEIGHT)
|
||||
ceiling -= probePos.y;
|
||||
|
||||
coll->Front = collResult.Position;
|
||||
coll->Front = GetCollisionPosition(pointColl);
|
||||
coll->Front.Floor = height;
|
||||
coll->Front.Ceiling = ceiling;
|
||||
|
||||
|
@ -507,22 +379,22 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
else
|
||||
{
|
||||
height = GetCollision(probePos.x + xFront, probePos.y, probePos.z + zFront, topRoomNumber).Position.Floor;
|
||||
height = GetPointCollision(Vector3i(probePos.x + xFront, probePos.y, probePos.z + zFront), topRoomNumber).GetFloorHeight();
|
||||
}
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
height -= (doPlayerCollision ? entityPos.y : probePos.y);
|
||||
|
||||
SetSectorAttribs(coll->Front, coll->Setup, collResult, probePos, realRoomNumber);
|
||||
SetSectorAttribs(coll->Front, coll->Setup, pointColl, probePos, realRoomNumber);
|
||||
|
||||
// TEST 4: MIDDLE-LEFT PROBE
|
||||
|
||||
probePos.x = entityPos.x + xLeft;
|
||||
probePos.z = entityPos.z + zLeft;
|
||||
|
||||
g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(0, 0, 1, 1), RendererDebugPage::CollisionStats);
|
||||
DrawDebugSphere(probePos.ToVector3(), 32, Vector4(0, 0, 1, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
collResult = GetCollision(probePos.x, probePos.y, probePos.z, item->RoomNumber);
|
||||
pointColl = GetPointCollision(probePos, item->RoomNumber);
|
||||
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
|
@ -534,8 +406,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
else
|
||||
{
|
||||
height = collResult.Position.Floor;
|
||||
ceiling = GetCeiling(collResult.Block, probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
height = pointColl.GetFloorHeight();
|
||||
ceiling = GetCeiling(&pointColl.GetSector(), probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
}
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
|
@ -544,15 +416,16 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
if (ceiling != NO_HEIGHT)
|
||||
ceiling -= probePos.y;
|
||||
|
||||
coll->MiddleLeft = collResult.Position;
|
||||
coll->MiddleLeft = GetCollisionPosition(pointColl);
|
||||
coll->MiddleLeft.Floor = height;
|
||||
coll->MiddleLeft.Ceiling = ceiling;
|
||||
|
||||
SetSectorAttribs(coll->MiddleLeft, coll->Setup, collResult, probePos, realRoomNumber);
|
||||
SetSectorAttribs(coll->MiddleLeft, coll->Setup, pointColl, probePos, realRoomNumber);
|
||||
|
||||
// TEST 5: FRONT-LEFT PROBE
|
||||
|
||||
collResult = GetCollision(probePos.x, probePos.y, probePos.z, topRoomNumber); // Use plain X/Z values here as proposed by Choco.
|
||||
// Use plain X/Z values.
|
||||
pointColl = GetPointCollision(probePos, topRoomNumber);
|
||||
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
|
@ -564,8 +437,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
else
|
||||
{
|
||||
height = collResult.Position.Floor;
|
||||
ceiling = GetCeiling(collResult.Block, probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
height = pointColl.GetFloorHeight();
|
||||
ceiling = GetCeiling(&pointColl.GetSector(), probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
}
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
|
@ -574,20 +447,20 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
if (ceiling != NO_HEIGHT)
|
||||
ceiling -= probePos.y;
|
||||
|
||||
coll->FrontLeft = collResult.Position;
|
||||
coll->FrontLeft = GetCollisionPosition(pointColl);
|
||||
coll->FrontLeft.Floor = height;
|
||||
coll->FrontLeft.Ceiling = ceiling;
|
||||
|
||||
SetSectorAttribs(coll->FrontLeft, coll->Setup, collResult, probePos, realRoomNumber);
|
||||
SetSectorAttribs(coll->FrontLeft, coll->Setup, pointColl, probePos, realRoomNumber);
|
||||
|
||||
// TEST 6: MIDDLE-RIGHT PROBE
|
||||
|
||||
probePos.x = entityPos.x + xRight;
|
||||
probePos.z = entityPos.z + zRight;
|
||||
|
||||
g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
DrawDebugSphere(probePos.ToVector3(), 32, Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
collResult = GetCollision(probePos.x, probePos.y, probePos.z, item->RoomNumber);
|
||||
pointColl = GetPointCollision(probePos, item->RoomNumber);
|
||||
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
|
@ -599,8 +472,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
else
|
||||
{
|
||||
height = collResult.Position.Floor;
|
||||
ceiling = GetCeiling(collResult.Block, probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
height = pointColl.GetFloorHeight();
|
||||
ceiling = GetCeiling(&pointColl.GetSector(), probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
}
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
|
@ -609,15 +482,15 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
if (ceiling != NO_HEIGHT)
|
||||
ceiling -= probePos.y;
|
||||
|
||||
coll->MiddleRight = collResult.Position;
|
||||
coll->MiddleRight = GetCollisionPosition(pointColl);
|
||||
coll->MiddleRight.Floor = height;
|
||||
coll->MiddleRight.Ceiling = ceiling;
|
||||
|
||||
SetSectorAttribs(coll->MiddleRight, coll->Setup, collResult, probePos, realRoomNumber);
|
||||
SetSectorAttribs(coll->MiddleRight, coll->Setup, pointColl, probePos, realRoomNumber);
|
||||
|
||||
// TEST 7: FRONT-RIGHT PROBE
|
||||
|
||||
collResult = GetCollision(probePos.x, probePos.y, probePos.z, topRoomNumber);
|
||||
pointColl = GetPointCollision(probePos, topRoomNumber);
|
||||
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
|
@ -629,8 +502,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
else
|
||||
{
|
||||
height = collResult.Position.Floor;
|
||||
ceiling = GetCeiling(collResult.Block, probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
height = pointColl.GetFloorHeight();
|
||||
ceiling = GetCeiling(&pointColl.GetSector(), probePos.x, probePos.y - item->Animation.Velocity.y, probePos.z);
|
||||
}
|
||||
|
||||
if (height != NO_HEIGHT)
|
||||
|
@ -639,11 +512,11 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
if (ceiling != NO_HEIGHT)
|
||||
ceiling -= probePos.y;
|
||||
|
||||
coll->FrontRight = collResult.Position;
|
||||
coll->FrontRight = GetCollisionPosition(pointColl);
|
||||
coll->FrontRight.Floor = height;
|
||||
coll->FrontRight.Ceiling = ceiling;
|
||||
|
||||
SetSectorAttribs(coll->FrontRight, coll->Setup, collResult, probePos, realRoomNumber);
|
||||
SetSectorAttribs(coll->FrontRight, coll->Setup, pointColl, probePos, realRoomNumber);
|
||||
|
||||
// TEST 8: SOLID STATIC MESHES
|
||||
|
||||
|
@ -818,16 +691,21 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
}
|
||||
}
|
||||
|
||||
void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, bool resetRoom)
|
||||
{
|
||||
GetCollisionInfo(coll, item, Vector3i::Zero, resetRoom);
|
||||
}
|
||||
|
||||
void AlignEntityToSurface(ItemInfo* item, const Vector2& ellipse, float alpha, short constraintAngle)
|
||||
{
|
||||
// Reduce ellipse axis lengths for stability.
|
||||
auto reducedEllipse = ellipse * 0.75f;
|
||||
|
||||
// Probe heights at points around entity.
|
||||
int frontHeight = GetCollision(item, item->Pose.Orientation.y, reducedEllipse.y).Position.Floor;
|
||||
int backHeight = GetCollision(item, item->Pose.Orientation.y + ANGLE(180.0f), reducedEllipse.y).Position.Floor;
|
||||
int leftHeight = GetCollision(item, item->Pose.Orientation.y - ANGLE(90.0f), reducedEllipse.x).Position.Floor;
|
||||
int rightHeight = GetCollision(item, item->Pose.Orientation.y + ANGLE(90.0f), reducedEllipse.x).Position.Floor;
|
||||
int frontHeight = GetPointCollision(*item, item->Pose.Orientation.y, reducedEllipse.y).GetFloorHeight();
|
||||
int backHeight = GetPointCollision(*item, item->Pose.Orientation.y + ANGLE(180.0f), reducedEllipse.y).GetFloorHeight();
|
||||
int leftHeight = GetPointCollision(*item, item->Pose.Orientation.y - ANGLE(90.0f), reducedEllipse.x).GetFloorHeight();
|
||||
int rightHeight = GetPointCollision(*item, item->Pose.Orientation.y + ANGLE(90.0f), reducedEllipse.x).GetFloorHeight();
|
||||
|
||||
// Calculate height deltas.
|
||||
int forwardHeightDelta = backHeight - frontHeight;
|
||||
|
@ -927,7 +805,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
}
|
||||
|
||||
// Debug probe point
|
||||
// g_Renderer.AddDebugSphere(Vector3(eX, y, eZ), 16, Vector4(1, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
// DrawDebugSphere(Vector3(eX, y, eZ), 16, Vector4(1, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
// Determine front floor probe offset.
|
||||
// It is needed to identify if there is bridge or ceiling split in front.
|
||||
|
@ -943,11 +821,11 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
|
||||
// Get front floor block
|
||||
auto room = GetRoomVector(item->Location, Vector3i(ffpX, y, ffpZ)).RoomNumber;
|
||||
auto block = GetCollision(ffpX, y, ffpZ, room).Block;
|
||||
auto sector = &GetPointCollision(Vector3i(ffpX, y, ffpZ), room).GetSector();
|
||||
|
||||
// Get front floor surface heights
|
||||
auto floorHeight = GetSurfaceHeight(RoomVector(block->RoomNumber, y), ffpX, ffpZ, true).value_or(NO_HEIGHT);
|
||||
auto ceilingHeight = GetSurfaceHeight(RoomVector(block->RoomNumber, y), ffpX, ffpZ, false).value_or(NO_HEIGHT);
|
||||
auto floorHeight = GetSurfaceHeight(RoomVector(sector->RoomNumber, y), ffpX, ffpZ, true).value_or(NO_HEIGHT);
|
||||
auto ceilingHeight = GetSurfaceHeight(RoomVector(sector->RoomNumber, y), ffpX, ffpZ, false).value_or(NO_HEIGHT);
|
||||
|
||||
// If probe landed inside wall (i.e. both floor/ceiling heights are NO_HEIGHT), make a fake
|
||||
// ledge for algorithm to further succeed.
|
||||
|
@ -960,7 +838,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
int height = useCeilingLedge ? ceilingHeight : floorHeight;
|
||||
|
||||
// Determine if there is a bridge in front.
|
||||
auto bridge = block->GetInsideBridgeItemNumber(Vector3i(ffpX, height, ffpZ), true, y == height);
|
||||
auto bridge = sector->GetInsideBridgeItemNumber(Vector3i(ffpX, height, ffpZ), true, y == height);
|
||||
|
||||
// Determine floor probe offset.
|
||||
// This must be slightly in front of own coll radius so no bridge misfires occur.
|
||||
|
@ -969,11 +847,11 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
auto fpZ = eZ + floorProbeOffset * cosForwardAngle;
|
||||
|
||||
// Debug probe point.
|
||||
// g_Renderer.AddDebugSphere(Vector3(fpX, y, fpZ), 16, Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
// DrawDebugSphere(Vector3(fpX, y, fpZ), 16, Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
// Get true room number and block, based on derived height
|
||||
room = GetRoomVector(item->Location, Vector3i(fpX, height, fpZ)).RoomNumber;
|
||||
block = GetCollision(fpX, height, fpZ, room).Block;
|
||||
sector = &GetPointCollision(Vector3i(fpX, height, fpZ), room).GetSector();
|
||||
|
||||
// We don't need actual corner heights to build planes, so just use normalized value here.
|
||||
auto fY = height - 1;
|
||||
|
@ -985,7 +863,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
auto ray = Ray(Vector3(eX, cY, eZ), direction);
|
||||
|
||||
// Debug ray direction.
|
||||
// g_Renderer.AddDebugLine(Vector3(eX, y, eZ), Vector3(eX, y, eZ) + direction * 256, Vector4(1, 0, 0, 1));
|
||||
// DrawDebugLine(Vector3(eX, y, eZ), Vector3(eX, y, eZ) + direction * 256, Vector4(1, 0, 0, 1));
|
||||
|
||||
// Keep origin ray to calculate true centerpoint distance to ledge later.
|
||||
if (p == 0)
|
||||
|
@ -1031,7 +909,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
else
|
||||
{
|
||||
// Determine if we should use floor or ceiling split angle based on early tests.
|
||||
auto splitAngle = (useCeilingLedge ? TO_RAD(block->CeilingSurface.SplitAngle) : TO_RAD(block->FloorSurface.SplitAngle));
|
||||
auto splitAngle = (useCeilingLedge ? TO_RAD(sector->CeilingSurface.SplitAngle) : TO_RAD(sector->FloorSurface.SplitAngle));
|
||||
|
||||
// Get horizontal block corner coordinates.
|
||||
auto fX = floor(eX / BLOCK(1)) * BLOCK(1) - 1;
|
||||
|
@ -1040,7 +918,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
auto cZ = fZ + BLOCK(1) + 1;
|
||||
|
||||
// Debug used block
|
||||
// g_Renderer.AddDebugSphere(Vector3(round(eX / BLOCK(1)) * BLOCK(1) + BLOCK(0.5f), y, round(eZ / BLOCK(1)) * BLOCK(1) + BLOCK(0.5f)), 16, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
// DrawDebugSphere(Vector3(round(eX / BLOCK(1)) * BLOCK(1) + BLOCK(0.5f), y, round(eZ / BLOCK(1)) * BLOCK(1) + BLOCK(0.5f)), 16, Vector4::One, RendererDebugPage::CollisionStats);
|
||||
|
||||
// Get split angle coordinates.
|
||||
auto sX = fX + 1 + BLOCK(0.5f);
|
||||
|
@ -1059,7 +937,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
};
|
||||
|
||||
// If split angle exists, take split plane into account too.
|
||||
auto useSplitAngle = (useCeilingLedge ? block->IsSurfaceSplit(false) : block->IsSurfaceSplit(true));
|
||||
auto useSplitAngle = (useCeilingLedge ? sector->IsSurfaceSplit(false) : sector->IsSurfaceSplit(true));
|
||||
|
||||
// Find closest block edge plane.
|
||||
for (int i = 0; i < (useSplitAngle ? 5 : 4); i++)
|
||||
|
@ -1086,7 +964,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
|
||||
if (i == 4)
|
||||
{
|
||||
auto usedSectorPlane = useCeilingLedge ? block->GetSurfaceTriangleID(eX, eZ, false) : block->GetSurfaceTriangleID(eX, eZ, true);
|
||||
auto usedSectorPlane = useCeilingLedge ? sector->GetSurfaceTriangleID(eX, eZ, false) : sector->GetSurfaceTriangleID(eX, eZ, true);
|
||||
result[p] = FROM_RAD(splitAngle) + ANGLE(usedSectorPlane * 180.0f) + ANGLE(90.0f);
|
||||
}
|
||||
else
|
||||
|
@ -1171,7 +1049,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
|
|||
|
||||
FloorInfo* GetFloor(int x, int y, int z, short* roomNumber)
|
||||
{
|
||||
const auto location = GetRoomVector(RoomVector(*roomNumber, y), Vector3i(x, y, z));
|
||||
auto location = GetRoomVector(RoomVector(*roomNumber, y), Vector3i(x, y, z));
|
||||
*roomNumber = location.RoomNumber;
|
||||
return &GetFloor(*roomNumber, x, z);
|
||||
}
|
||||
|
@ -1188,48 +1066,48 @@ int GetCeiling(FloorInfo* floor, int x, int y, int z)
|
|||
|
||||
int GetDistanceToFloor(int itemNumber, bool precise)
|
||||
{
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
const auto& item = g_Level.Items[itemNumber];
|
||||
|
||||
auto pointColl = GetCollision(item);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
|
||||
// HACK: Remove item from bridge objects temporarily.
|
||||
pointColl.Block->RemoveBridge(itemNumber);
|
||||
int height = GetFloorHeight(pointColl.Block, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z);
|
||||
pointColl.Block->AddBridge(itemNumber);
|
||||
pointColl.GetSector().RemoveBridge(itemNumber);
|
||||
int height = GetFloorHeight(&pointColl.GetSector(), item.Pose.Position.x, item.Pose.Position.y, item.Pose.Position.z);
|
||||
pointColl.GetSector().AddBridge(itemNumber);
|
||||
|
||||
auto bounds = GameBoundingBox(item);
|
||||
auto bounds = GameBoundingBox(&item);
|
||||
int minHeight = precise ? bounds.Y2 : 0;
|
||||
|
||||
return (minHeight + item->Pose.Position.y - height);
|
||||
return (minHeight + item.Pose.Position.y - height);
|
||||
}
|
||||
|
||||
int GetWaterSurface(int x, int y, int z, short roomNumber)
|
||||
{
|
||||
auto* room = &g_Level.Rooms[roomNumber];
|
||||
FloorInfo* floor = GetSector(room, x - room->x, z - room->z);
|
||||
auto* sector = GetSector(room, x - room->x, z - room->z);
|
||||
|
||||
if (TestEnvironment(ENV_FLAG_WATER, room))
|
||||
{
|
||||
while (floor->GetNextRoomNumber(Vector3i(x, y, z), false).has_value())
|
||||
while (sector->GetNextRoomNumber(Vector3i(x, y, z), false).has_value())
|
||||
{
|
||||
room = &g_Level.Rooms[floor->GetNextRoomNumber(Vector3i(x, y, z), false).value_or(floor->RoomNumber)];
|
||||
room = &g_Level.Rooms[sector->GetNextRoomNumber(Vector3i(x, y, z), false).value_or(sector->RoomNumber)];
|
||||
if (!TestEnvironment(ENV_FLAG_WATER, room))
|
||||
return (floor->GetSurfaceHeight(x, z, false));
|
||||
return (sector->GetSurfaceHeight(x, z, false));
|
||||
|
||||
floor = GetSector(room, x - room->x, z - room->z);
|
||||
sector = GetSector(room, x - room->x, z - room->z);
|
||||
}
|
||||
|
||||
return NO_HEIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (floor->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
while (sector->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
{
|
||||
room = &g_Level.Rooms[floor->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(floor->RoomNumber)];
|
||||
room = &g_Level.Rooms[sector->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(sector->RoomNumber)];
|
||||
if (TestEnvironment(ENV_FLAG_WATER, room))
|
||||
return (floor->GetSurfaceHeight(x, z, true));
|
||||
return (sector->GetSurfaceHeight(x, z, true));
|
||||
|
||||
floor = GetSector(room, x - room->x, z - room->z);
|
||||
sector = GetSector(room, x - room->x, z - room->z);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1243,81 +1121,93 @@ int GetWaterSurface(ItemInfo* item)
|
|||
|
||||
int GetWaterDepth(int x, int y, int z, short roomNumber)
|
||||
{
|
||||
FloorInfo* floor;
|
||||
FloorInfo* sector = nullptr;
|
||||
auto* room = &g_Level.Rooms[roomNumber];
|
||||
|
||||
short roomIndex = NO_VALUE;
|
||||
int adjoiningRoomNumber = NO_VALUE;
|
||||
do
|
||||
{
|
||||
int zFloor = (z - room->z) / BLOCK(1);
|
||||
int xFloor = (x - room->x) / BLOCK(1);
|
||||
int zFloor = (z - room->z) / BLOCK(1);
|
||||
|
||||
if (zFloor <= 0)
|
||||
{
|
||||
zFloor = 0;
|
||||
if (xFloor < 1)
|
||||
{
|
||||
xFloor = 1;
|
||||
else if (xFloor > room->xSize - 2)
|
||||
}
|
||||
else if (xFloor > (room->xSize - 2))
|
||||
{
|
||||
xFloor = room->xSize - 2;
|
||||
}
|
||||
}
|
||||
else if (zFloor >= room->zSize - 1)
|
||||
else if (zFloor >= (room->zSize - 1))
|
||||
{
|
||||
zFloor = room->zSize - 1;
|
||||
if (xFloor < 1)
|
||||
{
|
||||
xFloor = 1;
|
||||
else if (xFloor > room->xSize - 2)
|
||||
}
|
||||
else if (xFloor > (room->xSize - 2))
|
||||
{
|
||||
xFloor = room->xSize - 2;
|
||||
}
|
||||
}
|
||||
else if (xFloor < 0)
|
||||
xFloor = 0;
|
||||
else if (xFloor >= room->xSize)
|
||||
xFloor = room->xSize - 1;
|
||||
|
||||
floor = &room->floor[zFloor + xFloor * room->zSize];
|
||||
roomIndex = floor->SidePortalRoomNumber;
|
||||
if (roomIndex != NO_VALUE)
|
||||
{
|
||||
roomNumber = roomIndex;
|
||||
room = &g_Level.Rooms[roomIndex];
|
||||
xFloor = 0;
|
||||
}
|
||||
else if (xFloor >= room->xSize)
|
||||
{
|
||||
xFloor = room->xSize - 1;
|
||||
}
|
||||
|
||||
sector = &room->floor[zFloor + (xFloor * room->zSize)];
|
||||
adjoiningRoomNumber = sector->SidePortalRoomNumber;
|
||||
if (adjoiningRoomNumber != NO_VALUE)
|
||||
{
|
||||
roomNumber = adjoiningRoomNumber;
|
||||
room = &g_Level.Rooms[adjoiningRoomNumber];
|
||||
}
|
||||
}
|
||||
while (roomIndex != NO_VALUE);
|
||||
while (adjoiningRoomNumber != NO_VALUE);
|
||||
|
||||
if (TestEnvironment(ENV_FLAG_WATER, room) ||
|
||||
TestEnvironment(ENV_FLAG_SWAMP, room))
|
||||
{
|
||||
while (floor->GetNextRoomNumber(Vector3i(x, y, z), false).has_value())
|
||||
while (sector->GetNextRoomNumber(Vector3i(x, y, z), false).value_or(NO_VALUE) != NO_VALUE)
|
||||
{
|
||||
room = &g_Level.Rooms[floor->GetNextRoomNumber(Vector3i(x, y, z), false).value_or(floor->RoomNumber)];
|
||||
room = &g_Level.Rooms[sector->GetNextRoomNumber(Vector3i(x, y, z), false).value_or(sector->RoomNumber)];
|
||||
|
||||
if (!TestEnvironment(ENV_FLAG_WATER, room) &&
|
||||
!TestEnvironment(ENV_FLAG_SWAMP, room))
|
||||
{
|
||||
int waterHeight = floor->GetSurfaceHeight(x, z, false);
|
||||
int floorHeight = GetCollision(floor, x, y, z).BottomBlock->GetSurfaceHeight(x, z, true);
|
||||
int waterHeight = sector->GetSurfaceHeight(x, z, false);
|
||||
int floorHeight = GetPointCollision(Vector3i(x, y, z), sector->RoomNumber).GetBottomSector().GetSurfaceHeight(x, z, true);
|
||||
return (floorHeight - waterHeight);
|
||||
}
|
||||
|
||||
floor = GetSector(room, x - room->x, z - room->z);
|
||||
sector = GetSector(room, x - room->x, z - room->z);
|
||||
}
|
||||
|
||||
return DEEP_WATER;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (floor->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
while (sector->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(NO_VALUE) != NO_VALUE)
|
||||
{
|
||||
room = &g_Level.Rooms[floor->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(floor->RoomNumber)];
|
||||
room = &g_Level.Rooms[sector->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(sector->RoomNumber)];
|
||||
|
||||
if (TestEnvironment(ENV_FLAG_WATER, room) ||
|
||||
TestEnvironment(ENV_FLAG_SWAMP, room))
|
||||
{
|
||||
int waterHeight = floor->GetSurfaceHeight(x, z, true);
|
||||
floor = GetFloor(x, y, z, &roomNumber);
|
||||
return (GetFloorHeight(floor, x, y, z) - waterHeight);
|
||||
int waterHeight = sector->GetSurfaceHeight(x, z, true);
|
||||
sector = GetFloor(x, y, z, &roomNumber);
|
||||
return (GetFloorHeight(sector, x, y, z) - waterHeight);
|
||||
}
|
||||
|
||||
floor = GetSector(room, x - room->x, z - room->z);
|
||||
sector = GetSector(room, x - room->x, z - room->z);
|
||||
}
|
||||
|
||||
return NO_HEIGHT;
|
||||
|
@ -1331,10 +1221,10 @@ int GetWaterDepth(ItemInfo* item)
|
|||
|
||||
int GetWaterHeight(int x, int y, int z, short roomNumber)
|
||||
{
|
||||
FloorInfo* sector = nullptr;
|
||||
auto* room = &g_Level.Rooms[roomNumber];
|
||||
FloorInfo* floor;
|
||||
|
||||
short adjoiningRoom = NO_VALUE;
|
||||
int adjoiningRoomNumber = NO_VALUE;
|
||||
do
|
||||
{
|
||||
int xBlock = (x - room->x) / BLOCK(1);
|
||||
|
@ -1344,66 +1234,83 @@ int GetWaterHeight(int x, int y, int z, short roomNumber)
|
|||
{
|
||||
zBlock = 0;
|
||||
if (xBlock < 1)
|
||||
{
|
||||
xBlock = 1;
|
||||
else if (xBlock > room->xSize - 2)
|
||||
}
|
||||
else if (xBlock > (room->xSize - 2))
|
||||
{
|
||||
xBlock = room->xSize - 2;
|
||||
}
|
||||
}
|
||||
else if (zBlock >= room->zSize - 1)
|
||||
else if (zBlock >= (room->zSize - 1))
|
||||
{
|
||||
zBlock = room->zSize - 1;
|
||||
if (xBlock < 1)
|
||||
{
|
||||
xBlock = 1;
|
||||
else if (xBlock > room->xSize - 2)
|
||||
}
|
||||
else if (xBlock > (room->xSize - 2))
|
||||
{
|
||||
xBlock = room->xSize - 2;
|
||||
}
|
||||
}
|
||||
else if (xBlock < 0)
|
||||
xBlock = 0;
|
||||
else if (xBlock >= room->xSize)
|
||||
xBlock = room->xSize - 1;
|
||||
|
||||
floor = &room->floor[zBlock + xBlock * room->zSize];
|
||||
adjoiningRoom = floor->SidePortalRoomNumber;
|
||||
|
||||
if (adjoiningRoom != NO_VALUE)
|
||||
{
|
||||
roomNumber = adjoiningRoom;
|
||||
room = &g_Level.Rooms[adjoiningRoom];
|
||||
xBlock = 0;
|
||||
}
|
||||
else if (xBlock >= room->xSize)
|
||||
{
|
||||
xBlock = room->xSize - 1;
|
||||
}
|
||||
} while (adjoiningRoom != NO_VALUE);
|
||||
|
||||
if (floor->IsWall(x, z))
|
||||
sector = &room->floor[zBlock + (xBlock * room->zSize)];
|
||||
adjoiningRoomNumber = sector->SidePortalRoomNumber;
|
||||
|
||||
if (adjoiningRoomNumber != NO_VALUE)
|
||||
{
|
||||
roomNumber = adjoiningRoomNumber;
|
||||
room = &g_Level.Rooms[adjoiningRoomNumber];
|
||||
}
|
||||
}
|
||||
while (adjoiningRoomNumber != NO_VALUE);
|
||||
|
||||
if (sector->IsWall(x, z))
|
||||
return NO_HEIGHT;
|
||||
|
||||
if (TestEnvironment(ENV_FLAG_WATER, room) ||
|
||||
TestEnvironment(ENV_FLAG_SWAMP, room))
|
||||
{
|
||||
while (floor->GetNextRoomNumber(Vector3i(x, y, z), false).has_value())
|
||||
while (sector->GetNextRoomNumber(Vector3i(x, y, z), false).has_value())
|
||||
{
|
||||
auto* room = &g_Level.Rooms[floor->GetNextRoomNumber(Vector3i(x, y, z), false).value_or(floor->RoomNumber)];
|
||||
auto* room = &g_Level.Rooms[sector->GetNextRoomNumber(Vector3i(x, y, z), false).value_or(sector->RoomNumber)];
|
||||
|
||||
if (!TestEnvironment(ENV_FLAG_WATER, room) &&
|
||||
!TestEnvironment(ENV_FLAG_SWAMP, room))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
floor = GetSector(room, x - room->x, z - room->z);
|
||||
sector = GetSector(room, x - room->x, z - room->z);
|
||||
}
|
||||
|
||||
return GetCollision(floor, x, y, z).Block->GetSurfaceHeight(Vector3i(x, y, z), false);
|
||||
return sector->GetSurfaceHeight(Vector3i(x, y, z), false);
|
||||
}
|
||||
else if (floor->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
else if (sector->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
{
|
||||
while (floor->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
while (sector->GetNextRoomNumber(Vector3i(x, y, z), true).has_value())
|
||||
{
|
||||
auto* room2 = &g_Level.Rooms[floor->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(floor->RoomNumber)];
|
||||
auto* room2 = &g_Level.Rooms[sector->GetNextRoomNumber(Vector3i(x, y, z), true).value_or(sector->RoomNumber)];
|
||||
|
||||
if (TestEnvironment(ENV_FLAG_WATER, room2) ||
|
||||
TestEnvironment(ENV_FLAG_SWAMP, room2))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
floor = GetSector(room2, x - room2->x, z - room2->z);
|
||||
sector = GetSector(room2, x - room2->x, z - room2->z);
|
||||
}
|
||||
|
||||
return GetCollision(floor, x, y, z).Block->GetSurfaceHeight(Vector3i(x, y, z), true);
|
||||
return sector->GetSurfaceHeight(Vector3i(x, y, z), true);
|
||||
}
|
||||
|
||||
return NO_HEIGHT;
|
||||
|
@ -1416,12 +1323,12 @@ int GetWaterHeight(ItemInfo* item)
|
|||
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, int x, int y, int z, int roomNumber)
|
||||
{
|
||||
return TestEnvironment(environmentType, GetCollision(x, y, z, roomNumber).RoomNumber);
|
||||
return TestEnvironment(environmentType, GetPointCollision(Vector3i(x, y, z), roomNumber).GetRoomNumber());
|
||||
}
|
||||
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, Vector3i pos, int roomNumber)
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, const Vector3i& pos, int roomNumber)
|
||||
{
|
||||
return TestEnvironment(environmentType, GetCollision(pos.x, pos.y, pos.z, roomNumber).RoomNumber);
|
||||
return TestEnvironment(environmentType, GetPointCollision(pos, roomNumber).GetRoomNumber());
|
||||
}
|
||||
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, const ItemInfo* item)
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Objects/game_object_ids.h"
|
||||
|
||||
struct ItemInfo;
|
||||
class FloorInfo;
|
||||
struct ROOM_INFO;
|
||||
struct MESH_INFO;
|
||||
enum RoomEnvFlags;
|
||||
class FloorInfo;
|
||||
struct ItemInfo;
|
||||
struct MESH_INFO;
|
||||
struct ROOM_INFO;
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Math;
|
||||
|
||||
constexpr auto NO_LOWER_BOUND = -NO_HEIGHT; // Used by coll->Setup.LowerFloorBound.
|
||||
constexpr auto NO_UPPER_BOUND = NO_HEIGHT; // Used by coll->Setup.UpperFloorBound.
|
||||
constexpr auto COLLISION_CHECK_DISTANCE = BLOCK(8);
|
||||
|
||||
constexpr auto DEFAULT_STEEP_FLOOR_SLOPE_ANGLE = ANGLE(36.0f);
|
||||
constexpr auto DEFAULT_STEEP_CEILING_SLOPE_ANGLE = ANGLE(45.0f);
|
||||
|
||||
enum class CollisionType
|
||||
{
|
||||
None,
|
||||
|
@ -38,58 +44,46 @@ enum class CornerType
|
|||
Outer
|
||||
};
|
||||
|
||||
struct CollisionPosition
|
||||
struct CollisionPositionData
|
||||
{
|
||||
int Floor;
|
||||
int Ceiling;
|
||||
int Bridge;
|
||||
float SplitAngle;
|
||||
bool FloorSlope;
|
||||
bool CeilingSlope;
|
||||
bool DiagonalStep;
|
||||
int Floor = 0;
|
||||
int Ceiling = 0;
|
||||
int Bridge = 0;
|
||||
short SplitAngle = 0;
|
||||
bool FloorSlope = false;
|
||||
bool CeilingSlope = false;
|
||||
bool DiagonalStep = false;
|
||||
|
||||
bool HasDiagonalSplit() { return ((SplitAngle == (45.0f * RADIAN)) || (SplitAngle == (135.0f * RADIAN))); }
|
||||
bool HasFlippedDiagonalSplit() { return (HasDiagonalSplit() && (SplitAngle != (45.0f * RADIAN))); }
|
||||
bool HasDiagonalSplit() { return ((SplitAngle == SectorSurfaceData::SPLIT_ANGLE_0) || (SplitAngle == SectorSurfaceData::SPLIT_ANGLE_1)); }
|
||||
bool HasFlippedDiagonalSplit() { return (HasDiagonalSplit() && (SplitAngle != SectorSurfaceData::SPLIT_ANGLE_0)); }
|
||||
};
|
||||
|
||||
struct CollisionResult
|
||||
struct CollisionSetupData
|
||||
{
|
||||
Vector3i Coordinates;
|
||||
int RoomNumber;
|
||||
// Collider parameters
|
||||
CollisionProbeMode Mode = CollisionProbeMode::Quadrants;
|
||||
int Radius = 0;
|
||||
int Height = 0;
|
||||
short ForwardAngle = 0;
|
||||
|
||||
FloorInfo* Block;
|
||||
FloorInfo* BottomBlock;
|
||||
// Borderline step heights
|
||||
int LowerFloorBound = 0;
|
||||
int UpperFloorBound = 0;
|
||||
int LowerCeilingBound = 0;
|
||||
int UpperCeilingBound = 0;
|
||||
|
||||
CollisionPosition Position;
|
||||
Vector2 FloorTilt; // x = x, y = z
|
||||
Vector2 CeilingTilt; // x = x, y = z
|
||||
|
||||
Vector3 FloorNormal;
|
||||
Vector3 CeilingNormal;
|
||||
};
|
||||
|
||||
struct CollisionSetup
|
||||
{
|
||||
CollisionProbeMode Mode; // Probe rotation mode
|
||||
int Radius; // Collision bounds horizontal size
|
||||
int Height; // Collision bounds vertical size
|
||||
short ForwardAngle; // Forward angle direction
|
||||
|
||||
int LowerFloorBound; // Borderline floor step-up height
|
||||
int UpperFloorBound; // Borderline floor step-down height
|
||||
int LowerCeilingBound; // Borderline ceiling step-up height
|
||||
int UpperCeilingBound; // Borderline ceiling step-down height
|
||||
|
||||
bool BlockFloorSlopeUp; // Treat steep slopes as walls
|
||||
bool BlockFloorSlopeDown; // Treat steep slopes as pits
|
||||
bool BlockCeilingSlope; // Treat steep slopes on ceilings as walls
|
||||
bool BlockDeathFloorDown; // Treat death sectors as pits
|
||||
bool BlockMonkeySwingEdge; // Treat non-monkey sectors as walls
|
||||
// Blocker flags
|
||||
bool BlockFloorSlopeUp = false;
|
||||
bool BlockFloorSlopeDown = false;
|
||||
bool BlockCeilingSlope = false;
|
||||
bool BlockDeathFloorDown = false;
|
||||
bool BlockMonkeySwingEdge = false;
|
||||
|
||||
bool EnableObjectPush; // Can be pushed by objects
|
||||
bool EnableSpasm; // Convulse when pushed
|
||||
// Inquirers
|
||||
bool EnableObjectPush = false;
|
||||
bool EnableSpasm = false;
|
||||
|
||||
// Preserve previous parameters to restore later.
|
||||
// Previous parameters
|
||||
Vector3i PrevPosition = Vector3i::Zero;
|
||||
GAME_OBJECT_ID PrevAnimObjectID = ID_NO_OBJECT;
|
||||
int PrevAnimNumber = 0;
|
||||
|
@ -99,51 +93,42 @@ struct CollisionSetup
|
|||
|
||||
struct CollisionInfo
|
||||
{
|
||||
CollisionSetup Setup; // In parameters
|
||||
CollisionSetupData Setup = {};
|
||||
|
||||
CollisionPosition Middle;
|
||||
CollisionPosition MiddleLeft;
|
||||
CollisionPosition MiddleRight;
|
||||
CollisionPosition Front;
|
||||
CollisionPosition FrontLeft;
|
||||
CollisionPosition FrontRight;
|
||||
CollisionPositionData Middle = {};
|
||||
CollisionPositionData MiddleLeft = {};
|
||||
CollisionPositionData MiddleRight = {};
|
||||
CollisionPositionData Front = {};
|
||||
CollisionPositionData FrontLeft = {};
|
||||
CollisionPositionData FrontRight = {};
|
||||
|
||||
Pose Shift = Pose::Zero;
|
||||
CollisionType CollisionType;
|
||||
Vector3 FloorNormal;
|
||||
Vector3 CeilingNormal;
|
||||
Vector2 FloorTilt; // x = x, y = z
|
||||
Vector2 CeilingTilt; // x = x, y = z
|
||||
short NearestLedgeAngle;
|
||||
float NearestLedgeDistance;
|
||||
CollisionType CollisionType = CollisionType::None;
|
||||
Pose Shift = Pose::Zero;
|
||||
|
||||
int LastBridgeItemNumber;
|
||||
Pose LastBridgeItemPose;
|
||||
Vector3 FloorNormal = Vector3::Zero;
|
||||
Vector3 CeilingNormal = Vector3::Zero;
|
||||
Vector2 FloorTilt = Vector2::Zero; // NOTE: Deprecated.
|
||||
Vector2 CeilingTilt = Vector2::Zero; // NOTE: Deprecated.
|
||||
short NearestLedgeAngle = 0;
|
||||
float NearestLedgeDistance = 0.0f;
|
||||
|
||||
bool HitStatic;
|
||||
bool HitTallObject;
|
||||
int LastBridgeItemNumber = 0;
|
||||
Pose LastBridgeItemPose = Pose::Zero;
|
||||
|
||||
bool TriangleAtRight() { return ((MiddleRight.SplitAngle != 0.0f) && (MiddleRight.SplitAngle == Middle.SplitAngle)); }
|
||||
bool TriangleAtLeft() { return ((MiddleLeft.SplitAngle != 0.0f) && (MiddleLeft.SplitAngle == Middle.SplitAngle)); }
|
||||
bool HitStatic = false;
|
||||
bool HitTallObject = false;
|
||||
|
||||
// Inquirers.
|
||||
bool TriangleAtRight() { return ((MiddleRight.SplitAngle != 0) && (MiddleRight.SplitAngle == Middle.SplitAngle)); }
|
||||
bool TriangleAtLeft() { return ((MiddleLeft.SplitAngle != 0) && (MiddleLeft.SplitAngle == Middle.SplitAngle)); }
|
||||
bool DiagonalStepAtRight() { return (MiddleRight.DiagonalStep && TriangleAtRight() && (NearestLedgeAngle % ANGLE(90.0f))); }
|
||||
bool DiagonalStepAtLeft() { return (MiddleLeft.DiagonalStep && TriangleAtLeft() && (NearestLedgeAngle % ANGLE(90.0f))); }
|
||||
};
|
||||
|
||||
[[nodiscard]] bool TestItemRoomCollisionAABB(ItemInfo* item);
|
||||
|
||||
CollisionResult GetCollision(const ItemInfo& item);
|
||||
CollisionResult GetCollision(const ItemInfo* item);
|
||||
CollisionResult GetCollision(const ItemInfo* item, short headingAngle, float forward, float down = 0.0f, float right = 0.0f);
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber, short headingAngle, float forward, float down = 0.0f, float right = 0.0f);
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber, const EulerAngles& orient, float dist);
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber, const Vector3& dir, float dist);
|
||||
CollisionResult GetCollision(const Vector3i& pos, int roomNumber);
|
||||
CollisionResult GetCollision(int x, int y, int z, short roomNumber);
|
||||
CollisionResult GetCollision(const GameVector& pos);
|
||||
CollisionResult GetCollision(FloorInfo* floor, int x, int y, int z);
|
||||
|
||||
void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offset, bool resetRoom = false);
|
||||
void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, bool resetRoom = false);
|
||||
void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offset, bool resetRoom = false);
|
||||
int GetQuadrant(short angle);
|
||||
short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance);
|
||||
|
||||
|
@ -167,10 +152,10 @@ void SnapItemToGrid(ItemInfo* item, CollisionInfo* coll);
|
|||
|
||||
void AlignEntityToSurface(ItemInfo* item, const Vector2& ellipse, float alpha = 0.75f, short constraintAngle = ANGLE(70.0f));
|
||||
|
||||
// TODO: Deprecated.
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, int x, int y, int z, int roomNumber);
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, Vector3i pos, int roomNumber);
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, const Vector3i& pos, int roomNumber);
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, const ItemInfo* item);
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, int roomNumber);
|
||||
bool TestEnvironment(RoomEnvFlags environmentType, ROOM_INFO* room);
|
||||
bool TestEnvironmentFlags(RoomEnvFlags environmentType, int flags);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "framework.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/Point.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/room.h"
|
||||
#include "Game/Setup.h"
|
||||
|
@ -11,6 +13,7 @@
|
|||
#include "Specific/trutils.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Entities::Generic;
|
||||
using namespace TEN::Math;
|
||||
using namespace TEN::Utils;
|
||||
|
@ -59,7 +62,7 @@ Vector3 FloorInfo::GetSurfaceNormal(int x, int z, bool isFloor) const
|
|||
short FloorInfo::GetSurfaceIllegalSlopeAngle(int x, int z, bool isFloor) const
|
||||
{
|
||||
const auto& tri = GetSurfaceTriangle(x, z, isFloor);
|
||||
return tri.IllegalSlopeAngle;
|
||||
return tri.SteepSlopeAngle;
|
||||
}
|
||||
|
||||
MaterialType FloorInfo::GetSurfaceMaterial(int x, int z, bool isFloor) const
|
||||
|
@ -421,22 +424,22 @@ namespace TEN::Collision::Floordata
|
|||
return roomGridCoords;
|
||||
}
|
||||
|
||||
std::vector<FloorInfo*> GetNeighborSectorPtrs(const Vector3i& pos, int roomNumber, unsigned int searchDepth)
|
||||
std::vector<FloorInfo*> GetNeighborSectors(const Vector3i& pos, int roomNumber, unsigned int searchDepth)
|
||||
{
|
||||
auto sectorPtrs = std::vector<FloorInfo*>{};
|
||||
auto sectors = std::vector<FloorInfo*>{};
|
||||
|
||||
// Run through neighbor rooms.
|
||||
auto& room = g_Level.Rooms[roomNumber];
|
||||
for (int neighborRoomNumber : room.neighbors)
|
||||
{
|
||||
// Collect neighbor sector pointers.
|
||||
// Collect neighbor sectors.
|
||||
auto roomGridCoords = GetNeighborRoomGridCoords(pos, neighborRoomNumber, searchDepth);
|
||||
for (const auto& roomGridCoord : roomGridCoords)
|
||||
sectorPtrs.push_back(&GetFloor(neighborRoomNumber, roomGridCoord));
|
||||
sectors.push_back(&GetFloor(neighborRoomNumber, roomGridCoord));
|
||||
}
|
||||
|
||||
// Return neighbor sector pointers.
|
||||
return sectorPtrs;
|
||||
// Return neighbor sectors.
|
||||
return sectors;
|
||||
}
|
||||
|
||||
FloorInfo& GetFloor(int roomNumber, const Vector2i& roomGridCoord)
|
||||
|
@ -455,89 +458,96 @@ namespace TEN::Collision::Floordata
|
|||
|
||||
FloorInfo& GetFarthestSector(int roomNumber, int x, int z, bool isBottom)
|
||||
{
|
||||
auto* sectorPtr = &GetSideSector(roomNumber, x, z);
|
||||
auto* sector = &GetSideSector(roomNumber, x, z);
|
||||
|
||||
// Find bottom or top sector.
|
||||
bool isWall = sectorPtr->IsWall(x, z);
|
||||
bool isWall = sector->IsWall(x, z);
|
||||
while (isWall)
|
||||
{
|
||||
auto nextRoomNumber = sectorPtr->GetNextRoomNumber(x, z, isBottom);
|
||||
auto nextRoomNumber = sector->GetNextRoomNumber(x, z, isBottom);
|
||||
if (!nextRoomNumber.has_value())
|
||||
break;
|
||||
|
||||
// TODO: Check.
|
||||
sectorPtr = &GetSideSector(*nextRoomNumber, x, z);
|
||||
isWall = sectorPtr->IsWall(x, z);
|
||||
sector = &GetSideSector(*nextRoomNumber, x, z);
|
||||
isWall = sector->IsWall(x, z);
|
||||
}
|
||||
|
||||
return *sectorPtr;
|
||||
return *sector;
|
||||
}
|
||||
|
||||
FloorInfo& GetSideSector(int roomNumber, int x, int z)
|
||||
{
|
||||
auto* sectorPtr = &GetFloor(roomNumber, x, z);
|
||||
auto* sector = &GetFloor(roomNumber, x, z);
|
||||
|
||||
// Find side sector.
|
||||
auto sideRoomNumber = sectorPtr->GetSideRoomNumber();
|
||||
auto sideRoomNumber = sector->GetSideRoomNumber();
|
||||
while (sideRoomNumber.has_value())
|
||||
{
|
||||
sectorPtr = &GetFloor(*sideRoomNumber, x, z);
|
||||
sideRoomNumber = sectorPtr->GetSideRoomNumber();
|
||||
sector = &GetFloor(*sideRoomNumber, x, z);
|
||||
sideRoomNumber = sector->GetSideRoomNumber();
|
||||
}
|
||||
|
||||
return *sectorPtr;
|
||||
return *sector;
|
||||
}
|
||||
|
||||
static std::optional<FarthestHeightData> GetFarthestHeightData(FloorInfo& currentSector, Vector3i pos, bool isBottom)
|
||||
{
|
||||
// Find bottom or top height while bridge exists(?).
|
||||
auto* sectorPtr = ¤tSector;
|
||||
auto* sector = ¤tSector;
|
||||
do
|
||||
{
|
||||
// Set vertical position to lowest bridge ceiling height or highest bridge floor height.
|
||||
pos.y = sectorPtr->GetBridgeSurfaceHeight(pos, !isBottom);
|
||||
pos.y = sector->GetBridgeSurfaceHeight(pos, !isBottom);
|
||||
|
||||
// Find sector at lowest bridge floor height or highest bridge ceiling height.
|
||||
while (isBottom ?
|
||||
(pos.y >= sectorPtr->GetSurfaceHeight(pos.x, pos.z, true)) :
|
||||
(pos.y <= sectorPtr->GetSurfaceHeight(pos.x, pos.z, false)))
|
||||
(pos.y >= sector->GetSurfaceHeight(pos.x, pos.z, true)) :
|
||||
(pos.y <= sector->GetSurfaceHeight(pos.x, pos.z, false)))
|
||||
{
|
||||
auto nextRoomNumber = sectorPtr->GetNextRoomNumber(pos.x, pos.z, isBottom);
|
||||
auto nextRoomNumber = sector->GetNextRoomNumber(pos.x, pos.z, isBottom);
|
||||
if (!nextRoomNumber.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
sectorPtr = &GetSideSector(*nextRoomNumber, pos.x, pos.z);
|
||||
sector = &GetSideSector(*nextRoomNumber, pos.x, pos.z);
|
||||
}
|
||||
}
|
||||
while (sectorPtr->GetInsideBridgeItemNumber(pos, isBottom, !isBottom) != NO_VALUE);
|
||||
while (sector->GetInsideBridgeItemNumber(pos, isBottom, !isBottom) != NO_VALUE);
|
||||
|
||||
return FarthestHeightData{ *sectorPtr, pos.y };
|
||||
return FarthestHeightData{ *sector, pos.y };
|
||||
}
|
||||
|
||||
std::optional<int> GetSurfaceHeight(const RoomVector& location, int x, int z, bool isFloor)
|
||||
{
|
||||
auto* sectorPtr = &GetSideSector(location.RoomNumber, x, z);
|
||||
enum class Polarity
|
||||
{
|
||||
None,
|
||||
Floor,
|
||||
Ceiling
|
||||
};
|
||||
|
||||
auto* sector = &GetSideSector(location.RoomNumber, x, z);
|
||||
|
||||
auto pos = Vector3i(x, location.Height, z);
|
||||
int polarity = 0;
|
||||
auto polarity = Polarity::None;
|
||||
|
||||
if (sectorPtr->IsWall(x, z))
|
||||
if (sector->IsWall(x, z))
|
||||
{
|
||||
sectorPtr = &GetFarthestSector(location.RoomNumber, x, z, !isFloor);
|
||||
sector = &GetFarthestSector(location.RoomNumber, x, z, !isFloor);
|
||||
|
||||
if (!sectorPtr->IsWall(x, z))
|
||||
if (!sector->IsWall(x, z))
|
||||
{
|
||||
pos.y = sectorPtr->GetSurfaceHeight(x, z, isFloor);
|
||||
polarity = isFloor ? -1 : 1;
|
||||
pos.y = sector->GetSurfaceHeight(x, z, isFloor);
|
||||
polarity = isFloor ? Polarity::Floor : Polarity::Ceiling;
|
||||
}
|
||||
else
|
||||
{
|
||||
sectorPtr = &GetFarthestSector(location.RoomNumber, x, z, isFloor);
|
||||
sector = &GetFarthestSector(location.RoomNumber, x, z, isFloor);
|
||||
|
||||
if (!sectorPtr->IsWall(x, z))
|
||||
if (!sector->IsWall(x, z))
|
||||
{
|
||||
pos.y = sectorPtr->GetSurfaceHeight(x, z, !isFloor);
|
||||
polarity = isFloor ? 1 : -1;
|
||||
pos.y = sector->GetSurfaceHeight(x, z, !isFloor);
|
||||
polarity = isFloor ? Polarity::Ceiling : Polarity::Floor;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -546,81 +556,81 @@ namespace TEN::Collision::Floordata
|
|||
}
|
||||
}
|
||||
|
||||
int floorHeight = sectorPtr->GetSurfaceHeight(pos, true);
|
||||
int ceilingHeight = sectorPtr->GetSurfaceHeight(pos, false);
|
||||
int floorHeight = sector->GetSurfaceHeight(pos, true);
|
||||
int ceilingHeight = sector->GetSurfaceHeight(pos, false);
|
||||
|
||||
pos.y = std::clamp(pos.y, std::min(floorHeight, ceilingHeight), std::max(floorHeight, ceilingHeight));
|
||||
|
||||
bool testFloorBorder = (pos.y == ceilingHeight);
|
||||
bool testCeilBorder = (pos.y == floorHeight);
|
||||
int insideBridgeItemNumber = sectorPtr->GetInsideBridgeItemNumber(pos, testFloorBorder, testCeilBorder);
|
||||
int insideBridgeItemNumber = sector->GetInsideBridgeItemNumber(pos, testFloorBorder, testCeilBorder);
|
||||
|
||||
if (insideBridgeItemNumber != NO_VALUE)
|
||||
{
|
||||
if (isFloor ? (polarity <= 0) : (polarity >= 0))
|
||||
if (polarity == Polarity::None || (isFloor ? (polarity == Polarity::Floor) : (polarity == Polarity::Ceiling)))
|
||||
{
|
||||
auto heightData = GetFarthestHeightData(*sectorPtr, pos, !isFloor);
|
||||
auto heightData = GetFarthestHeightData(*sector, pos, !isFloor);
|
||||
if (heightData.has_value())
|
||||
return heightData->Height;
|
||||
}
|
||||
|
||||
if (isFloor ? (polarity >= 0) : (polarity <= 0))
|
||||
if (polarity == Polarity::None || (isFloor ? (polarity == Polarity::Ceiling) : (polarity == Polarity::Floor)))
|
||||
{
|
||||
auto heightData = GetFarthestHeightData(*sectorPtr, pos, isFloor);
|
||||
auto heightData = GetFarthestHeightData(*sector, pos, isFloor);
|
||||
if (!heightData.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
sectorPtr = &heightData->Sector;
|
||||
sector = &heightData->Sector;
|
||||
pos.y = heightData->Height;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFloor ? (polarity >= 0) : (polarity <= 0))
|
||||
if (polarity == Polarity::None || (isFloor ? (polarity == Polarity::Ceiling) : (polarity == Polarity::Floor)))
|
||||
{
|
||||
auto nextRoomNumber = sectorPtr->GetNextRoomNumber(pos, isFloor);
|
||||
auto nextRoomNumber = sector->GetNextRoomNumber(pos, isFloor);
|
||||
while (nextRoomNumber.has_value())
|
||||
{
|
||||
sectorPtr = &GetSideSector(*nextRoomNumber, x, z);
|
||||
nextRoomNumber = sectorPtr->GetNextRoomNumber(pos, isFloor);
|
||||
sector = &GetSideSector(*nextRoomNumber, x, z);
|
||||
nextRoomNumber = sector->GetNextRoomNumber(pos, isFloor);
|
||||
}
|
||||
}
|
||||
|
||||
return sectorPtr->GetSurfaceHeight(pos, isFloor);
|
||||
return sector->GetSurfaceHeight(pos, isFloor);
|
||||
}
|
||||
|
||||
static std::optional<RoomVector> GetFarthestRoomVector(RoomVector location, const Vector3i& pos, bool isBottom)
|
||||
{
|
||||
auto* sectorPtr = &GetSideSector(location.RoomNumber, pos.x, pos.z);
|
||||
location.RoomNumber = sectorPtr->RoomNumber;
|
||||
auto* sector = &GetSideSector(location.RoomNumber, pos.x, pos.z);
|
||||
location.RoomNumber = sector->RoomNumber;
|
||||
|
||||
if (sectorPtr->IsWall(pos.x, pos.z))
|
||||
if (sector->IsWall(pos.x, pos.z))
|
||||
{
|
||||
sectorPtr = &GetFarthestSector(location.RoomNumber, pos.x, pos.z, isBottom);
|
||||
location.RoomNumber = sectorPtr->RoomNumber;
|
||||
sector = &GetFarthestSector(location.RoomNumber, pos.x, pos.z, isBottom);
|
||||
location.RoomNumber = sector->RoomNumber;
|
||||
|
||||
if (sectorPtr->IsWall(pos.x, pos.z))
|
||||
if (sector->IsWall(pos.x, pos.z))
|
||||
return std::nullopt;
|
||||
|
||||
location.Height = sectorPtr->GetSurfaceHeight(pos.x, pos.z, !isBottom);
|
||||
location.Height = sector->GetSurfaceHeight(pos.x, pos.z, !isBottom);
|
||||
}
|
||||
|
||||
int floorHeight = sectorPtr->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), true);
|
||||
int ceilingHeight = sectorPtr->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), false);
|
||||
int floorHeight = sector->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), true);
|
||||
int ceilingHeight = sector->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), false);
|
||||
|
||||
location.Height = std::clamp(location.Height, std::min(ceilingHeight, floorHeight), std::max(ceilingHeight, floorHeight));
|
||||
|
||||
bool testFloorBorder = (location.Height == ceilingHeight);
|
||||
bool testCeilBorder = (location.Height == floorHeight);
|
||||
int insideBridgeItemNumber = sectorPtr->GetInsideBridgeItemNumber(Vector3i(pos.x, location.Height, pos.z), testFloorBorder, testCeilBorder);
|
||||
int insideBridgeItemNumber = sector->GetInsideBridgeItemNumber(Vector3i(pos.x, location.Height, pos.z), testFloorBorder, testCeilBorder);
|
||||
|
||||
if (insideBridgeItemNumber != NO_VALUE)
|
||||
{
|
||||
auto heightData = GetFarthestHeightData(*sectorPtr, Vector3i(pos.x, location.Height, pos.z), isBottom);
|
||||
auto heightData = GetFarthestHeightData(*sector, Vector3i(pos.x, location.Height, pos.z), isBottom);
|
||||
if (!heightData.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
sectorPtr = &heightData->Sector;
|
||||
location.RoomNumber = sectorPtr->RoomNumber;
|
||||
sector = &heightData->Sector;
|
||||
location.RoomNumber = sector->RoomNumber;
|
||||
location.Height = heightData->Height;
|
||||
}
|
||||
|
||||
|
@ -630,19 +640,19 @@ namespace TEN::Collision::Floordata
|
|||
{
|
||||
if (!isFirstSector)
|
||||
{
|
||||
sectorPtr = &GetSideSector(*nextRoomNumber, pos.x, pos.z);
|
||||
location.RoomNumber = sectorPtr->RoomNumber;
|
||||
location.Height = sectorPtr->GetSurfaceHeight(pos.x, pos.z, !isBottom);
|
||||
sector = &GetSideSector(*nextRoomNumber, pos.x, pos.z);
|
||||
location.RoomNumber = sector->RoomNumber;
|
||||
location.Height = sector->GetSurfaceHeight(pos.x, pos.z, !isBottom);
|
||||
}
|
||||
isFirstSector = false;
|
||||
|
||||
if (isBottom)
|
||||
{
|
||||
ceilingHeight = sectorPtr->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), false);
|
||||
if (pos.y < ceilingHeight && sectorPtr->GetNextRoomNumber(Vector3i(pos.x, location.Height, pos.z), false))
|
||||
ceilingHeight = sector->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), false);
|
||||
if (pos.y < ceilingHeight && sector->GetNextRoomNumber(Vector3i(pos.x, location.Height, pos.z), false))
|
||||
return std::nullopt;
|
||||
|
||||
floorHeight = sectorPtr->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), true);
|
||||
floorHeight = sector->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), true);
|
||||
if (pos.y <= floorHeight)
|
||||
{
|
||||
location.Height = std::max(pos.y, ceilingHeight);
|
||||
|
@ -651,11 +661,11 @@ namespace TEN::Collision::Floordata
|
|||
}
|
||||
else
|
||||
{
|
||||
floorHeight = sectorPtr->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), true);
|
||||
if (pos.y > floorHeight && sectorPtr->GetNextRoomNumber(Vector3i(pos.x, location.Height, pos.z), true))
|
||||
floorHeight = sector->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), true);
|
||||
if (pos.y > floorHeight && sector->GetNextRoomNumber(Vector3i(pos.x, location.Height, pos.z), true))
|
||||
return std::nullopt;
|
||||
|
||||
ceilingHeight = sectorPtr->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), false);
|
||||
ceilingHeight = sector->GetSurfaceHeight(Vector3i(pos.x, location.Height, pos.z), false);
|
||||
if (pos.y >= ceilingHeight)
|
||||
{
|
||||
location.Height = std::min(pos.y, floorHeight);
|
||||
|
@ -663,7 +673,7 @@ namespace TEN::Collision::Floordata
|
|||
}
|
||||
}
|
||||
|
||||
nextRoomNumber = sectorPtr->GetNextRoomNumber(Vector3i(pos.x, location.Height, pos.z), isBottom);
|
||||
nextRoomNumber = sector->GetNextRoomNumber(Vector3i(pos.x, location.Height, pos.z), isBottom);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
|
@ -693,34 +703,34 @@ namespace TEN::Collision::Floordata
|
|||
x += bridgeItem.Pose.Position.x;
|
||||
z += bridgeItem.Pose.Position.z;
|
||||
|
||||
auto* sectorPtr = &GetSideSector(bridgeItem.RoomNumber, x, z);
|
||||
sectorPtr->AddBridge(itemNumber);
|
||||
auto* sector = &GetSideSector(bridgeItem.RoomNumber, x, z);
|
||||
sector->AddBridge(itemNumber);
|
||||
|
||||
if (bridge.GetFloorBorder != nullptr)
|
||||
{
|
||||
int floorBorder = bridge.GetFloorBorder(bridgeItem);
|
||||
while (floorBorder <= sectorPtr->GetSurfaceHeight(x, z, false))
|
||||
while (floorBorder <= sector->GetSurfaceHeight(x, z, false))
|
||||
{
|
||||
auto roomNumberAbove = sectorPtr->GetNextRoomNumber(x, z, false);
|
||||
auto roomNumberAbove = sector->GetNextRoomNumber(x, z, false);
|
||||
if (!roomNumberAbove.has_value())
|
||||
break;
|
||||
|
||||
sectorPtr = &GetSideSector(*roomNumberAbove, x, z);
|
||||
sectorPtr->AddBridge(itemNumber);
|
||||
sector = &GetSideSector(*roomNumberAbove, x, z);
|
||||
sector->AddBridge(itemNumber);
|
||||
}
|
||||
}
|
||||
|
||||
if (bridge.GetCeilingBorder != nullptr)
|
||||
{
|
||||
int ceilingBorder = bridge.GetCeilingBorder(bridgeItem);
|
||||
while (ceilingBorder >= sectorPtr->GetSurfaceHeight(x, z, true))
|
||||
while (ceilingBorder >= sector->GetSurfaceHeight(x, z, true))
|
||||
{
|
||||
auto roomNumberBelow = sectorPtr->GetNextRoomNumber(x, z, true);
|
||||
auto roomNumberBelow = sector->GetNextRoomNumber(x, z, true);
|
||||
if (!roomNumberBelow.has_value())
|
||||
break;
|
||||
|
||||
sectorPtr = &GetSideSector(*roomNumberBelow, x, z);
|
||||
sectorPtr->AddBridge(itemNumber);
|
||||
sector = &GetSideSector(*roomNumberBelow, x, z);
|
||||
sector->AddBridge(itemNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -736,34 +746,34 @@ namespace TEN::Collision::Floordata
|
|||
x += bridgeItem.Pose.Position.x;
|
||||
z += bridgeItem.Pose.Position.z;
|
||||
|
||||
auto* sectorPtr = &GetSideSector(bridgeItem.RoomNumber, x, z);
|
||||
sectorPtr->RemoveBridge(itemNumber);
|
||||
auto* sector = &GetSideSector(bridgeItem.RoomNumber, x, z);
|
||||
sector->RemoveBridge(itemNumber);
|
||||
|
||||
if (bridge.GetFloorBorder != nullptr)
|
||||
{
|
||||
int floorBorder = bridge.GetFloorBorder(bridgeItem);
|
||||
while (floorBorder <= sectorPtr->GetSurfaceHeight(x, z, false))
|
||||
while (floorBorder <= sector->GetSurfaceHeight(x, z, false))
|
||||
{
|
||||
auto roomNumberAbove = sectorPtr->GetNextRoomNumber(x, z, false);
|
||||
auto roomNumberAbove = sector->GetNextRoomNumber(x, z, false);
|
||||
if (!roomNumberAbove.has_value())
|
||||
break;
|
||||
|
||||
sectorPtr = &GetSideSector(*roomNumberAbove, x, z);
|
||||
sectorPtr->RemoveBridge(itemNumber);
|
||||
sector = &GetSideSector(*roomNumberAbove, x, z);
|
||||
sector->RemoveBridge(itemNumber);
|
||||
}
|
||||
}
|
||||
|
||||
if (bridge.GetCeilingBorder != nullptr)
|
||||
{
|
||||
int ceilingBorder = bridge.GetCeilingBorder(bridgeItem);
|
||||
while (ceilingBorder >= sectorPtr->GetSurfaceHeight(x, z, true))
|
||||
while (ceilingBorder >= sector->GetSurfaceHeight(x, z, true))
|
||||
{
|
||||
auto roomNumberBelow = sectorPtr->GetNextRoomNumber(x, z, true);
|
||||
auto roomNumberBelow = sector->GetNextRoomNumber(x, z, true);
|
||||
if (!roomNumberBelow.has_value())
|
||||
break;
|
||||
|
||||
sectorPtr = &GetSideSector(*roomNumberBelow, x, z);
|
||||
sectorPtr->RemoveBridge(itemNumber);
|
||||
sector = &GetSideSector(*roomNumberBelow, x, z);
|
||||
sector->RemoveBridge(itemNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -776,8 +786,7 @@ namespace TEN::Collision::Floordata
|
|||
{
|
||||
constexpr auto VERTICAL_MARGIN = 4;
|
||||
|
||||
auto bounds = GameBoundingBox(&item);
|
||||
auto box = bounds.ToBoundingOrientedBox(item.Pose);
|
||||
auto box = GameBoundingBox(&item).ToBoundingOrientedBox(item.Pose);
|
||||
|
||||
auto origin = Vector3(pos.x, pos.y + (useBottomHeight ? VERTICAL_MARGIN : -VERTICAL_MARGIN), pos.z);
|
||||
auto dir = useBottomHeight ? -Vector3::UnitY : Vector3::UnitY;
|
||||
|
@ -785,7 +794,7 @@ namespace TEN::Collision::Floordata
|
|||
// Ray intersects box; return bridge box height.
|
||||
float dist = 0.0f;
|
||||
if (box.Intersects(origin, dir, dist))
|
||||
return (item.Pose.Position.y + (useBottomHeight ? bounds.Y2 : bounds.Y1));
|
||||
return Geometry::TranslatePoint(origin, dir, dist).y;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -880,7 +889,7 @@ namespace TEN::Collision::Floordata
|
|||
if (labelPos2D.has_value())
|
||||
{
|
||||
*labelPos2D += Vector2(0.0f, verticalOffset);
|
||||
g_Renderer.AddDebugString(string, *labelPos2D, color, LABEL_SCALE, 0, RendererDebugPage::CollisionStats);
|
||||
DrawDebugString(string, *labelPos2D, color, LABEL_SCALE, RendererDebugPage::CollisionStats);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -897,7 +906,7 @@ namespace TEN::Collision::Floordata
|
|||
constexpr auto MINECART_STOP_COLOR = Vector4(0.4f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
// Get point collision.
|
||||
auto pointColl = GetCollision(item);
|
||||
auto pointColl = GetPointCollision(item);
|
||||
auto pos = item.Pose.Position.ToVector3();
|
||||
|
||||
// Run through neighboring rooms.
|
||||
|
@ -913,50 +922,50 @@ namespace TEN::Collision::Floordata
|
|||
pos.x = BLOCK(roomGridCoord.x) + neighborRoom.x;
|
||||
pos.z = BLOCK(roomGridCoord.y) + neighborRoom.z;
|
||||
|
||||
pointColl = GetCollision(pos, neighborRoomNumber);
|
||||
pos.y = pointColl.Position.Floor;
|
||||
pointColl = GetPointCollision(pos, neighborRoomNumber);
|
||||
pos.y = pointColl.GetFloorHeight();
|
||||
|
||||
float verticalOffset = STRING_SPACING;
|
||||
|
||||
// Stopper
|
||||
if (pointColl.Block->Stopper)
|
||||
if (pointColl.GetSector().Stopper)
|
||||
{
|
||||
DrawSectorFlagLabel(pos, "Stopper", STOPPER_COLOR, verticalOffset);
|
||||
verticalOffset += STRING_SPACING;
|
||||
}
|
||||
|
||||
// Death
|
||||
if (pointColl.Block->Flags.Death)
|
||||
if (pointColl.GetSector().Flags.Death)
|
||||
{
|
||||
DrawSectorFlagLabel(pos, "Death", DEATH_COLOR, verticalOffset);
|
||||
verticalOffset += STRING_SPACING;
|
||||
}
|
||||
|
||||
// Monkey Swing
|
||||
if (pointColl.Block->Flags.Monkeyswing)
|
||||
if (pointColl.GetSector().Flags.Monkeyswing)
|
||||
{
|
||||
DrawSectorFlagLabel(pos, "Monkey Swing", MONKEY_SWING_COLOR, verticalOffset);
|
||||
verticalOffset += STRING_SPACING;
|
||||
}
|
||||
|
||||
// Beetle / Minecart Right
|
||||
if (pointColl.Block->Flags.MarkBeetle)
|
||||
if (pointColl.GetSector().Flags.MarkBeetle)
|
||||
{
|
||||
auto labelString = std::string("Beetle") + (!pointColl.Block->Flags.MinecartStop() ? " / Minecart Right" : "");
|
||||
auto labelString = std::string("Beetle") + (!pointColl.GetSector().Flags.MinecartStop() ? " / Minecart Right" : "");
|
||||
DrawSectorFlagLabel(pos, labelString, BEETLE_MINECART_RIGHT_COLOR, verticalOffset);
|
||||
verticalOffset += STRING_SPACING;
|
||||
}
|
||||
|
||||
// Activator / Minecart Left
|
||||
if (pointColl.Block->Flags.MarkTriggerer)
|
||||
if (pointColl.GetSector().Flags.MarkTriggerer)
|
||||
{
|
||||
auto labelString = std::string("Activator") + (!pointColl.Block->Flags.MinecartStop() ? " / Minecart Left" : "");
|
||||
auto labelString = std::string("Activator") + (!pointColl.GetSector().Flags.MinecartStop() ? " / Minecart Left" : "");
|
||||
DrawSectorFlagLabel(pos, labelString, ACTIVATOR_MINECART_LEFT_COLOR, verticalOffset);
|
||||
verticalOffset += STRING_SPACING;
|
||||
}
|
||||
|
||||
// Minecart Stop
|
||||
if (pointColl.Block->Flags.MinecartStop())
|
||||
if (pointColl.GetSector().Flags.MinecartStop())
|
||||
{
|
||||
DrawSectorFlagLabel(pos, "Minecart Stop", MINECART_STOP_COLOR, verticalOffset);
|
||||
verticalOffset += STRING_SPACING;
|
||||
|
|
|
@ -49,10 +49,10 @@ enum class MaterialType
|
|||
|
||||
enum class ClimbDirectionFlags
|
||||
{
|
||||
North = (1 << 8),
|
||||
East = (1 << 9),
|
||||
South = (1 << 10),
|
||||
West = (1 << 11)
|
||||
North = 1 << 8,
|
||||
East = 1 << 9,
|
||||
South = 1 << 10,
|
||||
West = 1 << 11
|
||||
};
|
||||
|
||||
// NOTE: Describes vertical room location.
|
||||
|
@ -74,10 +74,10 @@ public:
|
|||
|
||||
struct SectorSurfaceTriangleData
|
||||
{
|
||||
Plane Plane = {};
|
||||
int PortalRoomNumber = 0;
|
||||
short IllegalSlopeAngle = 0;
|
||||
MaterialType Material = MaterialType::Stone;
|
||||
Plane Plane = {};
|
||||
int PortalRoomNumber = 0;
|
||||
short SteepSlopeAngle = 0;
|
||||
MaterialType Material = MaterialType::Stone;
|
||||
};
|
||||
|
||||
struct SectorSurfaceData
|
||||
|
@ -135,17 +135,19 @@ struct SectorFlagData
|
|||
class FloorInfo
|
||||
{
|
||||
public:
|
||||
// Components
|
||||
int RoomNumber = 0;
|
||||
int SidePortalRoomNumber = 0;
|
||||
SectorSurfaceData FloorSurface = {};
|
||||
SectorSurfaceData CeilingSurface = {};
|
||||
std::set<int> BridgeItemNumbers = {};
|
||||
SectorFlagData Flags = {};
|
||||
// Members
|
||||
Vector2i Position = Vector2i::Zero;
|
||||
int RoomNumber = 0;
|
||||
SectorSurfaceData FloorSurface = {};
|
||||
SectorSurfaceData CeilingSurface = {};
|
||||
SectorFlagData Flags = {};
|
||||
|
||||
int Box = 0;
|
||||
int TriggerIndex = 0;
|
||||
bool Stopper = true;
|
||||
std::set<int> BridgeItemNumbers = {};
|
||||
int SidePortalRoomNumber = 0;
|
||||
|
||||
int PathfindingBoxID = 0;
|
||||
int TriggerIndex = 0;
|
||||
bool Stopper = true;
|
||||
|
||||
// Getters
|
||||
int GetSurfaceTriangleID(int x, int z, bool isFloor) const;
|
||||
|
@ -184,7 +186,7 @@ namespace TEN::Collision::Floordata
|
|||
Vector2i GetSectorPoint(int x, int z);
|
||||
Vector2i GetRoomGridCoord(int roomNumber, int x, int z, bool clampToBounds = true);
|
||||
std::vector<Vector2i> GetNeighborRoomGridCoords(const Vector3i& pos, int roomNumber, unsigned int searchDepth);
|
||||
std::vector<FloorInfo*> GetNeighborSectorPtrs(const Vector3i& pos, int roomNumber, unsigned int searchDepth);
|
||||
std::vector<FloorInfo*> GetNeighborSectors(const Vector3i& pos, int roomNumber, unsigned int searchDepth);
|
||||
|
||||
FloorInfo& GetFloor(int roomNumber, const Vector2i& roomGridCoord);
|
||||
FloorInfo& GetFloor(int roomNumber, int x, int z);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue