diff --git a/.editorconfig b/.editorconfig
index a71ed8c..d7aa82e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,10 +1,8 @@
root = true
-[*]
+[*.{lua,py}]
indent_style = tab
indent_size = 4
end_of_line = crlf
insert_final_newline = true
-
-[*.{lua,py}]
charset = utf-8
diff --git a/.github/workflows/offsets.yml b/.github/workflows/offsets.yml
index f20998e..11e0d97 100644
--- a/.github/workflows/offsets.yml
+++ b/.github/workflows/offsets.yml
@@ -7,7 +7,7 @@ on:
concurrency:
- group: offsets-${{ github.ref }}
+ group: ss_offsets-${{ github.ref }}
cancel-in-progress: true
@@ -21,54 +21,67 @@ jobs:
- name: Fetch Upstream
run: |
- git ls-remote https://github.com/calamity-inc/GTA-V-Decompiled-Scripts HEAD | cut -f1 > upstream_commit.txt
+ git ls-remote https://github.com/acidlabsgg/gtav-legacy-scripts HEAD | cut -f1 > legacy_upstream.txt
+ git ls-remote https://github.com/acidlabsgg/gtav-enhanced-scripts HEAD | cut -f1 > enhanced_upstream.txt
- - name: Read Last Commit Hash
- id: last
+ - name: Read Saved Commit Hashes
+ id: saved_commits
run: |
- if [ -f scripts/offsets/.last_commit_hash ]; then
- cat scripts/offsets/.last_commit_hash > last_commit.txt
+ if [ -f scripts/offsets/legacy.last_commit_hash ]; then
+ cat scripts/offsets/legacy.last_commit_hash > last_commit_legacy
else
- echo "none" > last_commit.txt
+ echo "none" > last_commit_legacy
fi
- - name: Compare Commit
- id: compare_commit
+ if [ -f scripts/offsets/enhanced.last_commit_hash ]; then
+ cat scripts/offsets/enhanced.last_commit_hash > last_commit_enhanced
+ else
+ echo "none" > last_commit_enhanced
+ fi
+
+ - name: Compare Commits
+ id: compare_commits
run: |
- UPSTREAM=$(cat upstream_commit.txt)
- LAST=$(cat last_commit.txt)
+ LEGACY_UPSTREAM=$(cat legacy_upstream.txt)
+ ENHANCED_UPSTREAM=$(cat enhanced_upstream.txt)
+ LEGACY_LAST=$(cat last_commit_legacy)
+ ENHANCED_LAST=$(cat last_commit_enhanced)
- echo "Upstream: $UPSTREAM"
- echo "Last run: $LAST"
+ echo "Legacy Upstream: $LEGACY_UPSTREAM"
+ echo "Legacy Last Run: $LEGACY_LAST"
+ echo "Enhanced Upstream: $ENHANCED_UPSTREAM"
+ echo "Enhanced Last Run: $ENHANCED_LAST"
- if [ "$UPSTREAM" = "$LAST" ] && [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
+ if [ "$LEGACY_UPSTREAM" = "$LEGACY_LAST" ] && [ "$ENHANCED_UPSTREAM" = "$ENHANCED_LAST" ] && [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
echo "run=false" >> $GITHUB_OUTPUT
else
echo "run=true" >> $GITHUB_OUTPUT
fi
- name: Setup Python
- if: steps.compare_commit.outputs.run == 'true'
+ if: steps.compare_commits.outputs.run == 'true'
uses: actions/setup-python@v5
with:
python-version: "3.12.x"
- name: Run Offset Updater
- if: steps.compare_commit.outputs.run == 'true'
+ if: steps.compare_commits.outputs.run == 'true'
run: |
python ./scripts/offsets/update_offsets.py
- - name: Save New Commit Hash
- if: steps.compare_commit.outputs.run == 'true'
+ - name: Save New Commit Hashes
+ if: steps.compare_commits.outputs.run == 'true'
run: |
- cp upstream_commit.txt ./scripts/offsets/.last_commit_hash
+ cp legacy_upstream.txt ./scripts/offsets/legacy.last_commit_hash
+ cp enhanced_upstream.txt ./scripts/offsets/enhanced.last_commit_hash
- name: Commit Changes
- if: steps.compare_commit.outputs.run == 'true'
+ if: steps.compare_commits.outputs.run == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- git add scripts/offsets/.last_commit_hash
+ git add scripts/offsets/legacy.last_commit_hash
+ git add scripts/offsets/enhanced.last_commit_hash
git add includes/data/globals_locals.lua
- git diff --cached --quiet || git commit -m "chore(offsets): update script globals & locals from upstream"
+ git diff --cached --quiet || git commit -m "chore(offsets): update script globals & locals"
git push
diff --git a/.github/workflows/zip-release.yml b/.github/workflows/zip-release.yml
index 9b333c7..e0a801f 100644
--- a/.github/workflows/zip-release.yml
+++ b/.github/workflows/zip-release.yml
@@ -60,7 +60,7 @@ jobs:
- name: Check Changes
id: check_changes
run: |
- if git diff --name-only HEAD^ HEAD | grep '\.lua$' > /dev/null; then
+ if git diff --name-only origin/main | grep '\.lua$' > /dev/null; then
echo "should_release=true" >> $GITHUB_OUTPUT
else
echo "should_release=false" >> $GITHUB_OUTPUT
@@ -74,6 +74,7 @@ jobs:
- name: Increment Tag
id: increment_tag
+ if: steps.check_changes.outputs.should_release == 'true'
uses: actions/github-script@v7
with:
script: |
@@ -107,6 +108,7 @@ jobs:
core.setOutput("old_tag", old_tag);
- name: Bump Version
+ if: steps.check_changes.outputs.should_release == 'true'
run: |
sed -i "s|return \".*\"|return \"${{steps.increment_tag.outputs.no_prefix}}\"|" includes/version.lua
sed -i "s|https://img.shields.io/badge/Script%20Version-v[0-9]\+\.[0-9]\+\.[0-9]\+-blue|https://img.shields.io/badge/Script%20Version-${{steps.increment_tag.outputs.version_number}}-blue|g" README.md
@@ -117,6 +119,7 @@ jobs:
git push
- name: Create Archive
+ if: steps.check_changes.outputs.should_release == 'true'
uses: thedoctor0/zip-release@0.7.6
with:
type: 'zip'
@@ -124,6 +127,7 @@ jobs:
exclusions: /.git* /scripts* /docs* *.json *.md *.editorconfig *.py
- name: Upload Release
+ if: steps.check_changes.outputs.should_release == 'true'
uses: softprops/action-gh-release@v2
with:
name: Samurai's Scripts ${{steps.increment_tag.outputs.version_number}}
diff --git a/README.md b/README.md
index fa6cac9..1fd65a1 100644
--- a/README.md
+++ b/README.md
@@ -1,41 +1,87 @@
-
- Samurai's-Scripts
-
+
-#### A Lua script written for [YimMenu](https://github.com/YimMenu/YimMenu) and [Tupoye-Menu](https://github.com/TupoyeMenu/TupoyeMenu), centered around roleplaying and having fun in a game full of ad bots and toxic cheaters
+# About
-[](https://github.com/YimMenu-Lua/Samurais-Scripts/releases/latest)
-[](https://github.com/YimMenu-Lua/Samurais-Scripts)
-[](https://github.com/YimMenu-Lua/Samurais-Scripts)
+
-###
+A modular GTA V Lua framework focused on enhancing the player's experience through fun features, online business options, and unpopular opinions.
-> [!Note]
-> **Legacy Only.**
+## Getting Started
-___
+### Setup
-## Setup
-
-1. Download the latest zip archive from the [releases section](https://github.com/YimMenu-Lua/Samurais-Scripts/releases).
-2. Extract the archive to YimMenu's `scripts` folder:
+- Download the latest zip archive from the [releases section](https://github.com/YimMenu-Lua/Samurais-Scripts/releases/latest).
+- Extract the archive to YimMenu's `scripts` folder:
%AppData%\YimMenu\scripts
-3. Once in-game, press **[F5]** to toggle the script's UI.
+- Once in-game, press **[F5]** to toggle the script's UI.
-## Commands
+### Commands Console
-- Use **[F4]** to toggle the command executor window.
+- Use **[F4]** to toggle the console window.
- Type `!ls` or `!dump` to dump all available commands.
-- Default commands are prefixed with an exclamation mark.
+- All default commands are prefixed with an exclamation mark ``.
+
+## Contributing
+
+Contributions are what make the open source community a great place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
+
+If you have a suggestion that would make this project better, please fork the repo and create a pull request. You can also simply open a [feature request](https://github.com/YimMenu-Lua/Samurais-Scripts/issues/new?template=request.yml).
+
+Don't forget to give the project a star!
+
+1. Fork the repo
+2. Create your feature branch.
+3. Commit your changes.
+4. Open a Pull Request.
+
+Refer to the [Contribution Guidelines](./CONTRIBUTING.md) for more details on the project's structure and conventions.
+
+## Documentation
+
+This project was rewritten from scratch using [SmallBase](https://github.com/xesdoog/SmallBase). For API documentation, please refer to the [docs](https://github.com/xesdoog/SmallBase/tree/main/docs).
+
+>[!Note]
+> Some parts of the API were refactored or extended but nothing has drastically changed.
+> All changes introduced in this project are documented in the source.
+
+## Contact
+
+
-## Credits
+## Acknowledgments
-| Awesome Person | Contribution |
-| :---: | :---: |
+| | |
+| :---: | :---: |
| [Harmless](https://github.com/harmless05) | Shift-Drift |
| [NiiV3AU](https://github.com/NiiV3AU) | German translations |
| [gir489returns](https://github.com/gir489returns) | [Casino Pacino](https://github.com/YimMenu-Lua/Casino-Pacino) |
| [tupoy-ya](https://github.com/tupoy-ya) | Several contributions and shared knowledge |
-| [szalikdev](https://github.com/szalikdev) | Revived the project |
+| [szalikdev](https://github.com/szalikdev) | Revived the project and joined the cause |
+| [ShinyWasabi](https://github.com/shinywasabi) | Foundational community tooling frequently used as reference |
+| [UnknownCheats.me](https://unknowncheats.me) | A treasure trove of information |
diff --git a/docs/ss.png b/docs/ss.png
new file mode 100644
index 0000000..b54fa98
Binary files /dev/null and b/docs/ss.png differ
diff --git a/includes/backend.lua b/includes/backend.lua
index 3887506..e579800 100644
--- a/includes/backend.lua
+++ b/includes/backend.lua
@@ -88,24 +88,34 @@ end
---@return eAPIVersion
function Backend:GetAPIVersion()
- if self.api_version then
- return self.api_version
- end
+ if (not self.api_version) then
+ if (script and (type(script) == "table")) then
+ if (menu_event and menu_event.Wndproc) then
+ if (type(_G["get_game_branch"]) == "function") then
+ local branch = _G["get_game_branch"]()
+ if (type(branch) ~= "number" or branch > 1) then
+ error("Unknown or unsupported game branch.")
+ end
- if (script and (type(script) == "table")) then
- if (menu_event and menu_event.Wndproc) then
- return Enums.eAPIVersion.V1
- end
+ self.api_version = _G["get_game_branch"]() + 1
+ else
+ self.api_version = Enums.eAPIVersion.V1
+ end
+ end
- if (type(script["run_in_callback"]) == "function") then
- return Enums.eAPIVersion.V2
+ if (type(script["run_in_callback"]) == "function") then
+ error(
+ "YmMenu V2 is not supported. If you want to run this script in GTA V Enhanced, download YimLuaAPI.") -- test error; add Github link later
+ end
+ ---@diagnostic disable-next-line: undefined-global
+ elseif (util or (menu and menu.root) or SCRIPT_SILENT_START or (_VERSION ~= "Lua 5.4")) then -- should probably place these in a lookup table
+ error("Failed to load: Unknown or unsupported Lua environment.")
+ else
+ self.api_version = Enums.eAPIVersion.L54
end
- ---@diagnostic disable-next-line: undefined-global
- elseif (util or (menu and menu.root) or SCRIPT_SILENT_START or (_VERSION ~= "Lua 5.4")) then -- should probably place these in a lookup table
- error("Failed to load: Unknown or unsupported environment.")
end
- return Enums.eAPIVersion.L54
+ return self.api_version
end
---@return boolean
@@ -248,15 +258,15 @@ end
---@param handle integer
function Backend:CheckFeatureEntities(handle)
- if Decorator:IsEntityRegistered(handle, "EntityForge") then
+ if Decorator:ExistsOn(handle, "EntityForge") then
EntityForge:RemoveEntityByHandle(handle)
end
- if Decorator:IsEntityRegistered(handle, "BillionaireServices") then
+ if Decorator:ExistsOn(handle, "BillionaireServices") then
BillionaireServices:RemoveEntityByHandle(handle)
end
- if Decorator:IsEntityRegistered(handle, "YimActions") then
+ if Decorator:ExistsOn(handle, "YimActions") then
YimActions.CompanionManager:RemoveCompanionByHandle(handle)
end
end
@@ -287,7 +297,7 @@ function Backend:EntitySweep()
end
function Backend:PoolMgr()
- local timeout = self.debug_mode and 500 or 5e3
+ local timeout = self.debug_mode and 500 or 2e3
for index, category in ipairs({ self.SpawnedEntities[Enums.eEntityType.Object], self.SpawnedEntities[Enums.eEntityType.Ped], self.SpawnedEntities[Enums.eEntityType.Vehicle] }) do
if (next(category) == nil) then
@@ -442,7 +452,7 @@ function Backend:RegisterHandlers()
self:OnPlayerSwitch()
self:OnSessionSwitch()
PreviewService:Update()
-
+ Decorator:CollectGarbage()
yield()
end)
diff --git a/includes/classes/CEntity.lua b/includes/classes/CEntity.lua
index 52f186e..5561e27 100644
--- a/includes/classes/CEntity.lua
+++ b/includes/classes/CEntity.lua
@@ -1,5 +1,7 @@
---@diagnostic disable: param-type-mismatch
+local fwDrawData = require("includes.classes.fwDrawData")
+
---@ignore
---@class CBaseModelInfo : GenericClass
local CBaseModelInfo = GenericClass
@@ -14,18 +16,19 @@ local CAttackers = GenericClass
---@ignore
---@class CEntity: ClassMeta
---@field private m_ptr pointer
----@field m_model_info pointer // 0x0020
----@field m_entity_type uint8_t // 0x0028
----@field m_model_type pointer // CBaseModelInfo + 0x009D
----@field m_flags pointer // 0x002D
----@field m_transform_matrix pointer // 0x0060
----@field m_render_focus_distance pointer // 0x00A8
----@field m_shadow_flags pointer // 0x00B0
----@field m_damage_bits pointer // 0x0188
----@field m_hostility pointer // 0x018C
----@field m_health pointer // 0x0280
----@field m_max_health pointer // 0x0284
----@field m_max_attackers pointer // 0x0288
+---@field m_model_info pointer -- 0x0020
+---@field m_entity_type uint8_t -- 0x0028
+---@field m_model_type pointer -- CBaseModelInfo + 0x009D
+---@field m_flags pointer -- 0x002D
+---@field m_draw_data fwDrawData -- 0x0048
+---@field m_transform_matrix pointer -- 0x0060
+---@field m_render_focus_distance pointer -- 0x00A8
+---@field m_shadow_flags pointer -- 0x00B0
+---@field m_damage_bits pointer -- 0x0188
+---@field m_hostility pointer -- 0x018C
+---@field m_health pointer -- 0x0280
+---@field m_max_health pointer -- 0x0284
+---@field m_max_attackers pointer -- 0x0288
---@overload fun(entity: handle): CEntity
local CEntity = Class("CEntity", nil, 0x290)
@@ -36,22 +39,21 @@ function CEntity:init(entity)
error("Invalid entity!")
end
- local ptr = memory.handle_to_ptr(entity)
-
+ local ptr = memory.handle_to_ptr(entity)
---@type CEntity
- local instance = setmetatable({}, CEntity)
-
- instance.m_ptr = ptr
- instance.m_model_info = ptr:add(0x0020):deref()
- instance.m_model_type = instance.m_model_info:add(0x009D)
- instance.m_flags = ptr:add(0x002D)
- instance.m_transform_matrix = ptr:add(0x0060)
+ local instance = setmetatable({}, CEntity)
+ instance.m_ptr = ptr
+ instance.m_model_info = ptr:add(0x0020):deref()
+ instance.m_model_type = instance.m_model_info:add(0x009D)
+ instance.m_flags = ptr:add(0x002D)
+ instance.m_draw_data = fwDrawData(ptr:add(0x0048):deref())
+ instance.m_transform_matrix = ptr:add(0x0060)
instance.m_render_focus_distance = ptr:add(0x00A8)
- instance.m_shadow_flags = ptr:add(0x00B0)
- instance.m_hostility = ptr:add(0x018C)
- instance.m_health = ptr:add(0x0280)
- instance.m_max_health = ptr:add(0x0284)
- instance.m_max_attackers = ptr:add(0x0288)
+ instance.m_shadow_flags = ptr:add(0x00B0)
+ instance.m_hostility = ptr:add(0x018C)
+ instance.m_health = ptr:add(0x0280)
+ instance.m_max_health = ptr:add(0x0284)
+ instance.m_max_attackers = ptr:add(0x0288)
return instance
end
diff --git a/includes/classes/CVehicle.lua b/includes/classes/CVehicle.lua
index 3b7e5ed..f79c8b1 100644
--- a/includes/classes/CVehicle.lua
+++ b/includes/classes/CVehicle.lua
@@ -5,6 +5,7 @@ local CCarHandlingData = require("includes.classes.CCarHandlingData")
local CBikeHandlingData = require("includes.classes.CBikeHandlingData")
local CFlyingHandlingData = require("includes.classes.CFlyingHandlingData")
local phFragInst = require("includes.structs.phFragInst")
+local CVehicleDrawData = require("includes.classes.CVehicleDrawData")
---@class CAdvancedData : GenericClass
local CAdvancedData = GenericClass
@@ -34,6 +35,7 @@ local SubHandlingCtorMap = {
---@class CVehicle : CEntity
---@field private m_ptr pointer
---@field public m_physics_fragments phFragInst //0x30 `struct rage::phFragInst`
+---@field public m_draw_data CVehicleDrawData
---@field public m_handling_data pointer
---@field public m_model_info pointer
---@field public m_vehicle_damage pointer
@@ -50,7 +52,7 @@ local SubHandlingCtorMap = {
---@field public m_is_targetable pointer `bool`
---@field public m_door_lock_status pointer
---@field public m_model_info_flags pointer
----@field public m_mass pointer -- //0x000C
+---@field public m_mass pointer -- 0x000C
---@field public m_initial_drag_coeff pointer
---@field public m_drive_bias_rear pointer
---@field public m_drive_bias_front pointer
@@ -62,6 +64,8 @@ local SubHandlingCtorMap = {
---@field public m_steering_lock pointer
---@field public m_steering_lock_ratio pointer
---@field public m_traction_curve_max pointer
+---@field public m_low_speed_traction_loss_mult pointer -- 0x00A8
+---@field public m_traction_loss_mult pointer -- 0x00B8
---@field public m_monetary_value pointer
---@field public m_model_flags pointer
---@field public m_handling_flags pointer
@@ -69,8 +73,9 @@ local SubHandlingCtorMap = {
---@field public m_deform_mult pointer
---@field public m_wheel_scale pointer
---@field public m_wheel_scale_rear pointer
----@field public m_wheels atArray // 0xC30
----@field public m_num_wheels number // 0xC38
+---@field public m_wheels atArray -- 0xC30
+---@field public m_num_wheels number -- 0xC38
+---@field public m_ride_height pointer
---@field private DumpFlags fun(self: CVehicle, enum_flags: Enum, get_func: fun(self: CVehicle, flag: integer): boolean): nil
---@overload fun(vehicle: integer): CVehicle|nil
local CVehicle = Class("CVehicle", CEntity, 0xC40)
@@ -90,44 +95,48 @@ function CVehicle:init(vehicle)
---@diagnostic disable-next-line: param-type-mismatch
instance:super().init(instance, vehicle)
- instance.m_ptr = ptr
- instance.m_model_info = ptr:add(0x20):deref()
- instance.m_vehicle_damage = ptr:add(0x0420)
- instance.m_handling_data = ptr:add(0x0960):deref()
- instance.m_sub_handling_data = atArray(instance.m_handling_data:add(0x158), CCarHandlingData)
- instance.m_model_info_layout = instance.m_model_info:add(0x00B0):deref()
- instance.m_physics_fragments = phFragInst(ptr:add(0x30):deref())
- instance.m_can_boost_jump = ptr:add(0x03A4)
- instance.m_deform_god = ptr:add(0x096C)
- instance.m_is_targetable = ptr:add(0x0AEE)
- instance.m_door_lock_status = ptr:add(0x13D0)
- instance.m_water_damage = ptr:add(0xD8)
- instance.m_next_gear = ptr:add(0x0880)
- instance.m_current_gear = ptr:add(0x0882)
- instance.m_top_gear = ptr:add(0x0886)
- instance.m_engine_health = ptr:add(0x0910)
- instance.m_model_info_flags = instance.m_model_info:add(0x057C)
- instance.m_mass = instance.m_handling_data:add(0x000C)
- instance.m_initial_drag_coeff = instance.m_handling_data:add(0x0010)
- instance.m_drive_bias_rear = instance.m_handling_data:add(0x0044)
- instance.m_drive_bias_front = instance.m_handling_data:add(0x0048)
- instance.m_acceleration = instance.m_handling_data:add(0x004C)
- instance.m_initial_drive_gears = instance.m_handling_data:add(0x0050)
- instance.m_initial_drive_force = instance.m_handling_data:add(0x0060)
- instance.m_drive_max_flat_velocity = instance.m_handling_data:add(0x0064)
- instance.m_initial_drive_max_flat_vel = instance.m_handling_data:add(0x0068)
- instance.m_steering_lock = instance.m_handling_data:add(0x0080)
- instance.m_steering_lock_ratio = instance.m_handling_data:add(0x0084)
- instance.m_traction_curve_max = instance.m_handling_data:add(0x0088)
- instance.m_monetary_value = instance.m_handling_data:add(0x0118)
- instance.m_model_flags = instance.m_handling_data:add(0x0124)
- instance.m_handling_flags = instance.m_handling_data:add(0x0128)
- instance.m_damage_flags = instance.m_handling_data:add(0x012C)
- instance.m_deform_mult = instance.m_handling_data:add(0x00F8)
- instance.m_wheel_scale = instance.m_model_info:add(0x048C)
- instance.m_wheel_scale_rear = instance.m_model_info:add(0x0490)
- instance.m_wheels = atArray(ptr:add(0xC30), CWheel)
- instance.m_num_wheels = ptr:add(0xC38):get_int()
+ instance.m_ptr = ptr
+ instance.m_model_info = ptr:add(0x20):deref()
+ instance.m_vehicle_damage = ptr:add(0x0420)
+ instance.m_handling_data = ptr:add(0x0960):deref()
+ instance.m_sub_handling_data = atArray(instance.m_handling_data:add(0x158), CCarHandlingData)
+ instance.m_model_info_layout = instance.m_model_info:add(0x00B0):deref()
+ instance.m_physics_fragments = phFragInst(ptr:add(0x0030):deref())
+ instance.m_draw_data = CVehicleDrawData:init(ptr:add(0x0048):deref())
+ instance.m_can_boost_jump = ptr:add(0x03A4)
+ instance.m_deform_god = ptr:add(0x096C)
+ instance.m_is_targetable = ptr:add(0x0AEE)
+ instance.m_door_lock_status = ptr:add(0x13D0)
+ instance.m_water_damage = ptr:add(0xD8)
+ instance.m_next_gear = ptr:add(0x0880)
+ instance.m_current_gear = ptr:add(0x0882)
+ instance.m_top_gear = ptr:add(0x0886)
+ instance.m_engine_health = ptr:add(0x0910)
+ instance.m_model_info_flags = instance.m_model_info:add(0x057C)
+ instance.m_mass = instance.m_handling_data:add(0x000C)
+ instance.m_initial_drag_coeff = instance.m_handling_data:add(0x0010)
+ instance.m_drive_bias_rear = instance.m_handling_data:add(0x0044)
+ instance.m_drive_bias_front = instance.m_handling_data:add(0x0048)
+ instance.m_acceleration = instance.m_handling_data:add(0x004C)
+ instance.m_initial_drive_gears = instance.m_handling_data:add(0x0050)
+ instance.m_initial_drive_force = instance.m_handling_data:add(0x0060)
+ instance.m_drive_max_flat_velocity = instance.m_handling_data:add(0x0064)
+ instance.m_initial_drive_max_flat_vel = instance.m_handling_data:add(0x0068)
+ instance.m_steering_lock = instance.m_handling_data:add(0x0080)
+ instance.m_steering_lock_ratio = instance.m_handling_data:add(0x0084)
+ instance.m_traction_curve_max = instance.m_handling_data:add(0x0088)
+ instance.m_low_speed_traction_loss_mult = instance.m_handling_data:add(0x00A8)
+ instance.m_traction_loss_mult = instance.m_handling_data:add(0x00B8)
+ instance.m_deform_mult = instance.m_handling_data:add(0x00F8)
+ instance.m_monetary_value = instance.m_handling_data:add(0x0118)
+ instance.m_model_flags = instance.m_handling_data:add(0x0124)
+ instance.m_handling_flags = instance.m_handling_data:add(0x0128)
+ instance.m_damage_flags = instance.m_handling_data:add(0x012C)
+ instance.m_wheel_scale = instance.m_model_info:add(0x048C)
+ instance.m_wheel_scale_rear = instance.m_model_info:add(0x0490)
+ instance.m_wheels = atArray(ptr:add(0xC30), CWheel)
+ instance.m_num_wheels = ptr:add(0xC38):get_int()
+ instance.m_ride_height = ptr:add(0xC30):deref():add(0x07C)
return instance
end
@@ -414,4 +423,49 @@ function CVehicle:RotateBoneMatrix(boneIndex, axis, angle)
self:SetBoneMatrix(boneIndex, new_matrix)
end
+---@param wheelIndex integer
+---@return boolean
+function CVehicle:IsWheelBrokenOff(wheelIndex)
+ if (not self:IsValid()) then
+ return false
+ end
+
+ -- Thanks tupoy-ya
+ return (self.m_ptr:add(0xA98):get_dword() >> (wheelIndex & 0x1F) & 1) ~= 0
+end
+
+---@return float -- Wheel width or 0.f if invalid
+function CVehicle:GetWheelWidth()
+ return self.m_draw_data:GetWheelWidth()
+end
+
+---@return float -- Wheel size or 0.f if invalid
+function CVehicle:GetWheelSize()
+ return self.m_draw_data:GetWheelSize()
+end
+
+---@param fValue float
+function CVehicle:SetWheelWidth(fValue)
+ self.m_draw_data:SetWheelWidth(fValue)
+end
+
+---@param fValue float
+function CVehicle:SetWheelSize(fValue)
+ self.m_draw_data:SetWheelSize(fValue)
+end
+
+function CVehicle:HasWheelDrawData()
+ return self.m_draw_data:GetWheelDrawData():IsValid()
+end
+
+---@param fHeight float positive = lower, negative = higher. should use values between `-0.1` and `0.1`
+function CVehicle:SetRideHeight(fHeight)
+ if (not self:IsValid()) then
+ return
+ end
+
+ -- should probably start sanitizing values before writing to memory
+ self.m_ride_height:set_float(fHeight)
+end
+
return CVehicle
diff --git a/includes/classes/CVehicleDrawData.lua b/includes/classes/CVehicleDrawData.lua
new file mode 100644
index 0000000..dffded3
--- /dev/null
+++ b/includes/classes/CVehicleDrawData.lua
@@ -0,0 +1,86 @@
+local fwDrawData = require("includes.classes.fwDrawData")
+
+---@class CWheelDrawData
+---@field m_ptr pointer
+---@field m_wheel_size pointer // 0x008 -- this seems to hold a float value equal to `CWheel.m_tire_radius * 2` and affects all 4 wheels
+---@field m_wheel_width pointer // 0xBA0 -- this one is weird. the value is a little less that `CWheel.m_tire_width * 2` on 5 different cars and a little more on the Adder. Also affects all 4 wheels
+local CWheelDrawData = {}
+CWheelDrawData.__index = CWheelDrawData
+
+---@param ptr pointer
+---@return CWheelDrawData
+function CWheelDrawData.new(ptr)
+ return setmetatable({
+ m_ptr = ptr,
+ m_wheel_size = ptr:add(0x008),
+ m_wheel_width = ptr:add(0xBA0),
+ }, CWheelDrawData)
+end
+
+function CWheelDrawData:IsValid()
+ return self.m_ptr and self.m_ptr:is_valid()
+end
+
+---@class CVehicleDrawData : fwDrawData
+---@field m_wheel_draw_data CWheelDrawData
+---@overload fun(ptr: pointer): CVehicleDrawData
+local CVehicleDrawData = Class("CVehicleDrawData", fwDrawData)
+
+---@param ptr pointer
+---@return CVehicleDrawData
+function CVehicleDrawData:init(ptr)
+ self.m_ptr = ptr
+ -- This will be null if the vehicle has stock wheels.
+ self.m_wheel_draw_data = CWheelDrawData.new(ptr:add(0x370):deref())
+ return self
+end
+
+function CVehicleDrawData:GetWheelDrawData()
+ if not (self.m_wheel_draw_data and self.m_wheel_draw_data:IsValid()) then
+ self.m_wheel_draw_data = CWheelDrawData.new(self.m_ptr:add(0x370):deref())
+ end
+
+ return self.m_wheel_draw_data
+end
+
+---@return float -- Wheel width or 0.f if invalid
+function CVehicleDrawData:GetWheelWidth()
+ local cwdd = self:GetWheelDrawData()
+ if (not cwdd:IsValid()) then
+ return 0.0
+ end
+
+ return cwdd.m_wheel_width:get_float()
+end
+
+---@return float -- Wheel size or 0.f if invalid
+function CVehicleDrawData:GetWheelSize()
+ local cwdd = self:GetWheelDrawData()
+ if (not cwdd:IsValid()) then
+ return 0.0
+ end
+
+ return cwdd.m_wheel_size:get_float()
+end
+
+---@param fValue float
+function CVehicleDrawData:SetWheelWidth(fValue)
+ local cwdd = self:GetWheelDrawData()
+ if (not cwdd:IsValid()) then
+ return
+ end
+
+ cwdd.m_wheel_width:set_float(fValue)
+end
+
+---@param fValue float
+function CVehicleDrawData:SetWheelSize(fValue)
+ local cwdd = self:GetWheelDrawData()
+ if (not cwdd:IsValid()) then
+ return
+ end
+
+ cwdd.m_wheel_size:set_float(fValue)
+end
+
+return CVehicleDrawData
diff --git a/includes/classes/CWheel.lua b/includes/classes/CWheel.lua
index 2ab535a..3a276f9 100644
--- a/includes/classes/CWheel.lua
+++ b/includes/classes/CWheel.lua
@@ -7,28 +7,28 @@
---@class CWheel
---@field private m_ptr pointer
---@field private m_size uint16_t
+---@field m_y_rotation pointer //0x008
+---@field m_y_rotation_inv pointer //0x010
---@field m_offset_from_body pointer //0x020
----@field m_unk_0030 pointer // ?? 0x030
----@field m_world_pos pointer // 0x03C
+---@field m_x_offset pointer // 0x030 same as offset from body?
+---@field m_last_ground_pos pointer // 0x03C
---@field m_wheel_transform array> // 0x090 - 0x0BC `rage::fMatrix44`
---@field m_unk_flags pointer //0x0C8
----@field m_rotation_speed pointer // 0x168 `radians`
+---@field m_tire_radius pointer //0x110
+---@field m_tire_width pointer //0x118
+---@field m_suspension_compression pointer // 0x168 `radians`
---@field m_traction_loss pointer // 0x16C
----@field m_unk0170 pointer // ?? 0x170
+---@field m_rotation_speed pointer // 0x170
---@field m_unk0190 pointer // ?? 0x190
---@field m_unk0194 pointer // ?? 0x194
---@field m_tire_drag_coeff pointer // 0x198
---@field m_top_speed_mult pointer // 0x19C
----@field m_steer_angle pointer // 0x1C4 `radians`
----@field m_brake_pressure pointer // 0x1D4
----@field m_throttle pointer // 0x1D8
----@field m_cur_health pointer // 0x1E0
----@field m_max_health pointer //0x1E4
----@field unk_flags_1EC pointer // 0x1EC
+---@field m_steering_angle pointer // 0x1CC `radians`
+---@field m_brake_pressure pointer // 0x1D0
+---@field m_power pointer // 0x1D4
+---@field m_health pointer // 0x1E8
+---@field m_surface_id pointer // 0x1EC
---@field unk_flags_1F0 pointer // 0x1F0
----@field m_surface_id pointer // 0x1F2
----@field m_is_in_air pointer // 0x1F3 `bool`
----@field m_is_burst pointer // 0x1F4 `bool`
---@overload fun(addr: pointer): CWheel|nil
local CWheel = { m_size = 0x1FC }
CWheel.__index = CWheel
@@ -45,31 +45,30 @@ function CWheel.new(addr)
return nil
end
- local instance = setmetatable({}, CWheel)
-
- instance.m_ptr = addr
- instance.m_offset_from_body = addr:add(0x020)
- instance.m_unk_0030 = addr:add(0x030)
- instance.m_world_pos = addr:add(0x03C)
- instance.m_wheel_transform = { addr:add(0x090), addr:add(0x0A0), addr:add(0x0B0), addr:add(0x0C0) }
- instance.m_unk_flags = addr:add(0x0C8)
- instance.m_rotation_speed = addr:add(0x168)
- instance.m_traction_loss = addr:add(0x16C)
- instance.m_unk0170 = addr:add(0x170)
- instance.m_unk0190 = addr:add(0x190)
- instance.m_unk0194 = addr:add(0x194)
- instance.m_tire_drag_coeff = addr:add(0x198)
- instance.m_top_speed_mult = addr:add(0x19C)
- instance.m_steer_angle = addr:add(0x1C4)
- instance.m_brake_pressure = addr:add(0x1D4)
- instance.m_throttle = addr:add(0x1D8)
- instance.m_cur_health = addr:add(0x1E0)
- instance.m_max_health = addr:add(0x1E4)
- instance.unk_flags_1EC = addr:add(0x1EC)
- instance.unk_flags_1F0 = addr:add(0x1F0)
- instance.m_surface_id = addr:add(0x1F2)
- instance.m_is_in_air = addr:add(0x1F3)
- instance.m_is_burst = addr:add(0x1F4)
+ local instance = setmetatable({}, CWheel)
+ instance.m_ptr = addr
+ instance.m_y_rotation = addr:add(0x008)
+ instance.m_y_rotation_inv = addr:add(0x010)
+ instance.m_offset_from_body = addr:add(0x020)
+ instance.m_x_offset = addr:add(0x030)
+ instance.m_last_ground_pos = addr:add(0x03C)
+ instance.m_wheel_transform = { addr:add(0x090), addr:add(0x0A0), addr:add(0x0B0), addr:add(0x0C0) }
+ instance.m_unk_flags = addr:add(0x0C8)
+ instance.m_tire_radius = addr:add(0x110)
+ instance.m_tire_width = addr:add(0x118)
+ instance.m_suspension_compression = addr:add(0x168)
+ instance.m_traction_loss = addr:add(0x16C)
+ instance.m_rotation_speed = addr:add(0x170)
+ instance.m_unk0190 = addr:add(0x190)
+ instance.m_unk0194 = addr:add(0x194)
+ instance.m_tire_drag_coeff = addr:add(0x198)
+ instance.m_top_speed_mult = addr:add(0x19C)
+ instance.m_steering_angle = addr:add(0x1CC)
+ instance.m_brake_pressure = addr:add(0x1D0)
+ instance.m_power = addr:add(0x1D4)
+ instance.m_health = addr:add(0x1E8)
+ instance.m_surface_id = addr:add(0x1EC)
+ instance.unk_flags_1F0 = addr:add(0x1F0)
return instance
end
@@ -90,7 +89,7 @@ function CWheel:GetWorldPosition()
return vec3:zero()
end
- return self.m_world_pos:get_vec3()
+ return self.m_last_ground_pos:get_vec3()
end
-- test
diff --git a/includes/classes/atArray.lua b/includes/classes/atArray.lua
index 6ee2ac9..d4bec6a 100644
--- a/includes/classes/atArray.lua
+++ b/includes/classes/atArray.lua
@@ -30,8 +30,8 @@ setmetatable(atArray, {
function atArray.new(address, data_type)
local instance = setmetatable(
{
- m_address = NULLPTR,
- m_data_ptr = NULLPTR,
+ m_address = nullptr,
+ m_data_ptr = nullptr,
m_size = 0x0,
m_count = 0x0,
m_data = {},
@@ -80,8 +80,8 @@ function atArray:IsEmpty()
end
function atArray:Clear()
- self.m_address = NULLPTR
- self.m_data_ptr = NULLPTR
+ self.m_address = nullptr
+ self.m_data_ptr = nullptr
self.m_data = {}
self.m_size = 0x0
self.m_count = 0x0
diff --git a/includes/classes/fwDrawData.lua b/includes/classes/fwDrawData.lua
new file mode 100644
index 0000000..f07e922
--- /dev/null
+++ b/includes/classes/fwDrawData.lua
@@ -0,0 +1,17 @@
+---@class fwDrawData
+---@field private m_ptr pointer
+---@field m_stream_render_gfx pointer
+---@overload fun(ptr: pointer): fwDrawData
+local fwDrawData = Class("fwDrawData")
+
+---@param ptr pointer
+---@return fwDrawData
+function fwDrawData:init(ptr)
+ return setmetatable({
+ m_ptr = ptr,
+ m_stream_render_gfx = ptr:add(0x370)
+ ---@diagnostic disable-next-line
+ }, fwDrawData)
+end
+
+return fwDrawData
diff --git a/includes/data/config.lua b/includes/data/config.lua
index 9bc4dbb..d89a8ab 100644
--- a/includes/data/config.lua
+++ b/includes/data/config.lua
@@ -137,6 +137,7 @@ local Config = {
performance_only = false,
burble_tune = false,
launch_control = false,
+ launch_control_mode = 0,
abs_lights = false,
subwoofer = false,
horn_beams = false,
diff --git a/includes/data/globals_locals.lua b/includes/data/globals_locals.lua
index 0ae5ecb..52becde 100644
--- a/includes/data/globals_locals.lua
+++ b/includes/data/globals_locals.lua
@@ -7,17 +7,25 @@ return {
pattern = [[switch \((Global_\w{6})\.f_\w{4}\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 262145,
+ pattern = [[switch \((Global_\w{6})\.f_\w{4}\)]],
+ capture_group = 1
+ }
},
freemode_business_global = {
description = "Freemode Business Global",
file = "freemode.c",
LEGACY = {
value = 1673807,
- pattern = [[if \(\((Global_\w{7})\[\w+0\] != 0 && func_\w{5}\(\w+0\)\) && \w+2\)]],
+ pattern = [[if \(Global_\d{7}\[.*?\] != 0 && func_\w+\(.*?\) && \w+\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1673830,
+ pattern = [[if \(Global_\d{7}\[PLAYER::PLAYER_ID\(\) /\*883\*/\]\.f_\d{3}\.f_\d{3}\[.*?/\*13\*/\] != HUD_COLOUR_PURE_WHITE && (Global_\d{7})\[.*?\] != 0\)]],
+ capture_group = 1
+ }
},
personal_vehicle_global = {
description = "Personal Vehicle Global",
@@ -27,7 +35,11 @@ return {
pattern = [[if \(VEHICLE::GET_IS_VEHICLE_ENGINE_RUNNING\((Global_\w{7})\)\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1572199,
+ pattern = [[if \(VEHICLE::GET_IS_VEHICLE_ENGINE_RUNNING\((Global_\w{7})\)\)]],
+ capture_group = 1
+ }
},
business_hub_global_1 = {
description = "Business Hub Global 1",
@@ -37,70 +49,100 @@ return {
pattern = [[else if \(Global_\w{7}\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1950567,
+ pattern = [[else if \(Global_\w{7}\)]],
+ capture_group = 1
+ }
},
business_hub_global_2 = {
description = "Business Hub Global 2",
file = "apparcadebusinesshub.c",
LEGACY = {
value = 1970093,
- pattern = [[if \(MISC::IS_STRING_NULL_OR_EMPTY\(\w+\) \|\| (Global_\w{7}) == -1\)]],
+ pattern = [[if \(MISC::IS_STRING_NULL_OR_EMPTY\(\w+\) \|\| (Global_\w{7}) ==.*?\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1970664,
+ pattern = [[if \(MISC::IS_STRING_NULL_OR_EMPTY\(\w+\) \|\| (Global_\w{7}) ==.*?\)]],
+ capture_group = 1
+ }
},
gb_contraband_buy_local_1 = {
description = "Contraband Buy Local 1",
file = "gb_contraband_buy.c",
LEGACY = {
value = 625,
- pattern = [[switch \(((?:[buisf]?Local_\d{3}))\.f_5\)]],
+ pattern = [[switch \(((.*?Local_\d{3}))\.f_5]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 627,
+ pattern = [[switch \(((.*?Local_\d{3}))\.f_5]],
+ capture_group = 1
+ }
},
gb_contraband_buy_local_2 = {
description = "Contraband Buy Local 2",
file = "fm_content_cargo.c",
LEGACY = {
value = 5991,
- pattern = [[if \(func_\w{2}\(&((?:[buisf]?Local_[5-7]\d{3})), \w+0\)\)]],
+ pattern = [[func_303\(&u(Local_59..?), \w+\);]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 5993,
+ pattern = [[func_303\(&u(Local_59..?), \w+\);]],
+ capture_group = 1
+ }
},
gb_contraband_buy_local_3 = {
description = "Contraband Buy Local 3",
file = "fm_content_cargo.c",
LEGACY = {
- value = 1180,
- pattern = [[if \((?:[buisf]?Local_[5-9]\d{3})(\.f_\d{4}) == 0]],
+ value = 6110,
+ pattern = [[if \(.*?(Local_\d{4})\.(f_\d{4}) == 0]],
capture_group = 1,
offsets = {
{
- value = 6110,
+ value = 1180,
capture_group = 2
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 6112,
+ pattern = [[if \(.*?(Local_\d{4})\.(f_\d{4}) == 0]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 1180,
+ capture_group = 2
+ }
+ }
+ }
},
gb_contraband_sell_local = {
description = "Contraband Sell Local",
file = "gb_contraband_sell.c",
LEGACY = {
value = 567,
- pattern = [[MISC::CLEAR_BIT\(&\((?:[buisf]?Local_\d{3})\.f_\d{1,2}\), \w+0]],
+ pattern = [[MISC::CLEAR_BIT\(&\((.*?Local_\d{3})\.f_\d{1,2}\), \w+0]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 569,
+ pattern = [[MISC::CLEAR_BIT\(&\((.*?Local_\d{3})\.f_\d{1,2}\), \w+0]],
+ capture_group = 1
+ }
},
gb_biker_contraband_sell_local = {
description = "Biker Contraband Sell Local",
file = "gb_biker_contraband_sell.c",
LEGACY = {
value = 729,
- pattern = [[else if \(!func_\w+\(1\) && ((?:[buisf]?Local_\d{3}))(\.f_\d{3}) > 0\)]],
+ pattern = [[else if \(!func_\w+\(.*?\) &&.*?(Local_\d{3})(\.f_\d{3}) > 0\)]],
capture_group = 1,
offsets = {
{
@@ -109,14 +151,24 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 731,
+ pattern = [[else if \(!func_\w+\(.*?\) &&.*?(Local_\d{3})(\.f_\d{3}) > 0\)]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 122,
+ capture_group = 2
+ }
+ }
+ }
},
gb_smuggler_sell_air_local_1 = {
description = "Hangar Sell Local 1 (air)",
file = "gb_smuggler.c",
LEGACY = {
value = 1989,
- pattern = [[while \(\w+ < func_\w{2}\(func_\w{4}\(\), func_\w{2}\(\), ((?:[buisf]?Local_\d{4}))(\.f_\d{4}), -1]],
+ pattern = [[for \(i = 0; i < func_\w{2}\(func_\w{4}\(\), func_\w{2}\(\), .*?(Local_\d{4})\.(f_\d{4}), -1\); i = i \+ 1\)]],
capture_group = 1,
offsets = {
{
@@ -125,14 +177,24 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1991,
+ pattern = [[for \(i = 0; i < func_\w{2}\(func_\w{4}\(\), func_\w{2}\(\), .*?(Local_\d{4})\.(f_\d{4}), -1\); i = i \+ 1\)]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 1035,
+ capture_group = 2
+ }
+ }
+ }
},
gb_smuggler_sell_air_local_2 = {
description = "Hangar Sell Local 2 (air)",
file = "gb_smuggler.c",
LEGACY = {
value = 1989,
- pattern = [[if .*?((?:[buisf]?Local_\d{4}))(\.f_\d{4}) > 0 && func_.*?&.*?Local_\d{4}\.f_\d{4}\), 30000, 0]],
+ pattern = [[if .*?(Local_\d{4})\.(f_\d{4}) > 0 && func_.*?&.*?Local_\d{4}\.f_\d{4}\), 30000, \w+]],
capture_group = 1,
offsets = {
{
@@ -141,72 +203,116 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1991,
+ pattern = [[if .*?(Local_\d{4})\.(f_\d{4}) > 0 && func_.*?&.*?Local_\d{4}\.f_\d{4}\), 30000, \w+]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 1078,
+ capture_group = 2
+ }
+ }
+ }
},
gb_gunrunning_sell_local_1 = {
description = "Bunker Sell Local 1",
file = "gb_gunrunning.c",
LEGACY = {
- value = 774,
- pattern = [[(?:[buisf]?Local_1\d{3}?)(\.f_\d{3}) = func_\w+\(func_\w+\(\),.*?Local_1\d{3}\.f_\d{3}, \w+, -1\);]],
+ value = 1266,
+ pattern = [[Local_1\d{3}\.f_\d{3} = func_\w+\(func_\w+\(\),.*?(Local_1\d{3})\.(f_\d{3}), \w+, -1\);]],
capture_group = 1,
offsets = {
{
- value = 1266,
+ value = 762,
capture_group = 2
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1268,
+ pattern = [[Local_1\d{3}\.f_\d{3} = func_\w+\(func_\w+\(\),.*?(Local_1\d{3})\.(f_\d{3}), \w+, -1\);]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 762,
+ capture_group = 2
+ }
+ }
+ }
},
gb_gunrunning_sell_local_2 = {
description = "Bunker Sell Local 2",
file = "gb_gunrunning.c",
LEGACY = {
- value = 816,
- pattern = [[func_\w+\((?:[buisf]?Local_\d{4})(\.f_\d{3}), \w+, "GR_HUD_TOT", \w+, 1, 4, 0, 0, 0, 0, 0, 1, 1, 0, 255, 0\);]],
+ value = 1266,
+ pattern = [[func_\w+\((.*?Local_\d{4})(\.f_\d{3}), \w+, "GR_HUD_TOT".*?, 255, 0\);]],
capture_group = 1,
offsets = {
{
- value = 2976,
+ value = 816,
capture_group = 2
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1268,
+ pattern = [[func_\w+\((.*?Local_\d{4})(\.f_\d{3}), \w+, "GR_HUD_TOT".*?, 255, 0\);]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 816,
+ capture_group = 2
+ }
+ }
+ }
},
acid_lab_sell_local = {
description = "Acid Lab Sell Local",
file = "fm_content_acid_lab_sell.c",
LEGACY = {
- value = 1339,
- pattern = [[if \((?:[buisf]?Local_5\d{3})(\.f_\d{4}) == 0\)]],
+ value = 5723,
+ pattern = [[if \((.*?Local_5\d{3})(\.f_\d{4}) == 0\)]],
capture_group = 1,
offsets = {
{
- value = 5723,
+ value = 1339,
capture_group = 2
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 5725,
+ pattern = [[if \((.*?Local_5\d{3})(\.f_\d{4}) == 0\)]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 1339,
+ capture_group = 2
+ }
+ }
+ }
},
acid_lab_sell_bitset = {
description = "Acid Lab Sell Generic Bitset",
file = "fm_content_acid_lab_sell.c",
LEGACY = {
- value = 7613,
- pattern = [[if \(func_\w+\((?:[buisf]?Local_5\d{3}), \w+\)\)]],
+ value = 301,
+ pattern = [[func_\w{3}\(&.?Local_5\d+, \w+\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 301,
+ pattern = [[func_\w{3}\(&.?Local_5\d+, \w+\)]],
+ capture_group = 1
+ }
},
three_card_poker_table = {
description = "Three Card Poker Table Local",
file = "three_card_poker.c",
LEGACY = {
value = 771,
- pattern = [[if \((.*?Local_\d{3})\[.*? /\*(\d+)\*/\]\.f_\d+ == \w+ && \(.*?Local_\d{3}\[.*?\]\.f_\d+ > 0 \|\| .*?Local_\d{3}\[.*?\]\.f_\d+ > 0\)\)]],
+ pattern = [[if \((.*?Local_\d{3})\[.*? /\*(\d+)\*/\]\.f_\d+ ==.*?&&.*?Local_\d{3}\[.*?\]\.f_\d+ > 0 \|\| .*?Local_\d{3}\[.*?\]\.f_\d+ > 0\)]],
capture_group = 1,
offsets = {
{
@@ -215,7 +321,17 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 773,
+ pattern = [[if \((.*?Local_\d{3})\[.*? /\*(\d+)\*/\]\.f_\d+ ==.*?&&.*?Local_\d{3}\[.*?\]\.f_\d+ > 0 \|\| .*?Local_\d{3}\[.*?\]\.f_\d+ > 0\)]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 9,
+ capture_group = 2
+ }
+ }
+ }
},
three_card_poker_cards = {
description = "Three Card Poker Cards Local",
@@ -232,7 +348,18 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 140,
+ pattern = [[STREAMING::REQUEST_MODEL\(func_\d+\(.*?(Local_\d{3})(\.f_\d{3})\[.*?\]\.f_\d+\[.*?\], .*?Local_\d{4}\.f_\d+\)\);]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 168,
+ capture_group = 2,
+ description = "current deck"
+ }
+ }
+ }
},
three_card_poker_deck_size = {
description = "Three Card Poker Deck Size",
@@ -242,14 +369,18 @@ return {
pattern = [[if \(!NETWORK::NETWORK_HAS_CONTROL_OF_NETWORK_ID\(.*?Local_\d{3}(\.f_\d{2})\[\w+\(\w+, 0\)\]\)\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 55,
+ pattern = [[if \(!NETWORK::NETWORK_HAS_CONTROL_OF_NETWORK_ID\(.*?Local_\d{3}(\.f_\d{2})\[\w+\(\w+, 0\)\]\)\)]],
+ capture_group = 1
+ }
},
three_card_poker_anti_cheat = {
description = "Three Card Poker Anti Cheat",
file = "three_card_poker.c",
LEGACY = {
value = 1060,
- pattern = [[if \(.*?(Local_\d{4})(\.f_\d{3})\.f_\d+\[.*?\] != Local_\d{3}\.f_\d+\[PLAYER::PLAYER_ID\(\) .*?\]\.f_1\[.*?\]\)]],
+ pattern = [[if \(.*?(Local_\d{4})(\.f_\d{3})\.f_\d+\[.*?\] !=.*?Local_\d{3}\.f_\d+\[PLAYER::PLAYER_ID\(\) .*?\]\.f_1\[.*?\]\)]],
capture_group = 1,
offsets = {
{
@@ -259,7 +390,18 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1062,
+ pattern = [[if \(.*?(Local_\d{4})(\.f_\d{3})\.f_\d+\[.*?\] !=.*?Local_\d{3}\.f_\d+\[PLAYER::PLAYER_ID\(\) .*?\]\.f_1\[.*?\]\)]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 856,
+ capture_group = 2,
+ description = "anti cheat deck"
+ }
+ }
+ }
},
blackjack_table_players = {
description = "Blackjack Table Players Local",
@@ -275,7 +417,17 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1800,
+ pattern = [[if \(.*?Local_\d{4}\[.*?/\*(\d+)\*/\]\.f_\d+ == \w+ && \w+\(.*?Local_\d{4}\[.*?\], \d+\)\)]],
+ capture_group = 2,
+ offsets = {
+ {
+ value = 8,
+ capture_group = 1
+ }
+ }
+ }
},
blackjack_cards = {
description = "Blackjack Cards Local",
@@ -291,7 +443,17 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 140,
+ pattern = [[if \(func_\w+\(.*?(Local_\d{3})(\.f_\d{3})\[.*?\]\) == 10 \|\| func_\d+\(.*?Local_\d{3}\.f_\d{3}\[.*?\]\) == 11\)]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 846,
+ capture_group = 2
+ }
+ }
+ }
},
roulette_master_table = {
description = "Roulette Master Table Local",
@@ -308,7 +470,18 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 148,
+ pattern = [[NETWORK::NETWORK_REGISTER_HOST_BROADCAST_VARIABLES\(&\(.*?(Local_\d{3})(\.f_\d{4})\), 295, 0\);]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 1357,
+ capture_group = 2,
+ description = "roulette outcomes table"
+ }
+ }
+ }
},
roulette_ball_table_offset = {
description = "Roulette Ball Table Offset",
@@ -318,7 +491,11 @@ return {
pattern = [[\w+\.f_1 = \w+->f_\d{4}(\.f_\d{3})\[.*?\];]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 153,
+ pattern = [[\w+\.f_1 = \w+->f_\d{4}(\.f_\d{3})\[.*?\];]],
+ capture_group = 1
+ }
},
slots_random_result_table = {
description = "Slots Random Results Table Local",
@@ -328,7 +505,11 @@ return {
pattern = [[\w+ = func_\d+\(.*?(Local_\d{4})\.f_1\[.*?\]\[.*?Local_\d+\[0\]\], .*?Local_\d+?\.f_1\[.*?\]\[.*?Local_\d+\[1\]\], .*?Local_\d{4}\.f_1\[.*?\]\[.*?Local_\d+\[2\]\]\);]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1374,
+ pattern = [[\w+ = func_\d+\(.*?(Local_\d{4})\.f_1\[.*?\]\[.*?Local_\d+\[0\]\], .*?Local_\d+?\.f_1\[.*?\]\[.*?Local_\d+\[1\]\], .*?Local_\d{4}\.f_1\[.*?\]\[.*?Local_\d+\[2\]\]\);]],
+ capture_group = 1
+ }
},
slots_slot_machine_state = {
description = "Slots Slot Machine State",
@@ -338,23 +519,37 @@ return {
pattern = [[MISC::CLEAR_BIT\(&.*?(Local_\d{4}), 18\)]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1664,
+ pattern = [[MISC::CLEAR_BIT\(&.*?(Local_\d{4}), 18\)]],
+ capture_group = 1
+ }
},
prize_wheel_win_state = {
description = "Prize Wheel Win State Local",
file = "casino_lucky_wheel.c",
LEGACY = {
- value = 14,
- pattern = [[(?:[buisf]?Local_\d{3})(\.f_\d{2}) = \(.*?Local_\d{3}\.f_\d{2} % 20\);]],
+ value = 302,
+ pattern = [[(Local_\d{3})(\.f_\d{2}) =.*?Local_\d{3}\.f_\d{2} % 20]],
capture_group = 1,
offsets = {
{
- value = 302,
+ value = 14,
capture_group = 2
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 304,
+ pattern = [[(Local_\d{3})(\.f_\d{2}) =.*?Local_\d{3}\.f_\d{2} % 20]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 14,
+ capture_group = 2
+ }
+ }
+ }
},
prize_wheel_prize_state = {
description = "Prize Wheel Prize State Offset",
@@ -370,17 +565,31 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 304,
+ pattern = [[if \(.?(Local_\d{3})(\.f_..) >= 5 && .?Local_\d{3}\.f_\d{2} <= 12\)]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 45,
+ capture_group = 2
+ }
+ }
+ }
},
gb_casino_heist_planning = {
description = "Casino Heist Planning Global",
file = "gb_casino_heist_planning.c",
LEGACY = {
value = 1971952,
- pattern = [[if \(Global_\d{7}\.f_\d{4} == func_\d{2}\(\) \|\| !NETWORK::NETWORK_IS_PLAYER_ACTIVE\(Global_\d{7}\.f_\d{4}\)\)]],
+ pattern = [[!NETWORK::NETWORK_IS_PLAYER_ACTIVE\(Global_\d{7}\.f_\d{4}]],
capture_group = 1
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1973231,
+ pattern = [[!NETWORK::NETWORK_IS_PLAYER_ACTIVE\(Global_\d{7}\.f_\d{4}]],
+ capture_group = 1
+ }
},
gb_casino_heist_planning_cut_offset = {
description = "Casino Heist Planning Cut Offset",
@@ -400,7 +609,21 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 1497,
+ pattern = [[\w+->(f_\d{4})(\.f_\d{3})(\.f_\d{2})\[4\] > 0]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 736,
+ capture_group = 2
+ },
+ {
+ value = 92,
+ capture_group = 3
+ }
+ }
+ }
},
fm_mission_controller_cart_grab = {
description = "FM Mission Controller Cart Grab Local",
@@ -417,6 +640,17 @@ return {
}
}
},
- ENHANCED = {}
+ ENHANCED = {
+ value = 10697,
+ pattern = [[PED::SET_SYNCHRONIZED_SCENE_RATE\(NETWORK::NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID\(.?Local_\d{5}\.f_\d+\), .?(Local_\d{5})(\.f_\d+\))]],
+ capture_group = 1,
+ offsets = {
+ {
+ value = 14,
+ capture_group = 2,
+ description = "grab speed"
+ }
+ }
+ }
}
}
diff --git a/includes/data/pointers.lua b/includes/data/pointers.lua
index 255af58..632ad49 100644
--- a/includes/data/pointers.lua
+++ b/includes/data/pointers.lua
@@ -1,5 +1,8 @@
PatternScanner = require("includes.services.PatternScanner"):init()
+--- A place to store callable naems returned from `memory.dynamic_call`
+---@class DynamicFuncNames
+---@field dfn_IsVehicleWheelBrokenOff? string
-- ### A place to store pointers globally.
--
@@ -9,74 +12,151 @@ PatternScanner = require("includes.services.PatternScanner"):init()
--
-- **NOTE:** Please make sure no modules/files try to use a pointer before the scan is complete.
--
--- You can call `PointerScanner:IsDone()` to double check.
+-- You can call `PatternScanner:IsDone()` to double check.
---@class GPointers
+---@field ScriptGlobals pointer
---@field GameState pointer
---@field GameTime pointer
+---@field GameVersion { _build: string, _online: string }
+---@field ScreenResolution vec2
+---@field IsVehicleWheelBrokenOff pointer
+---@field DynamicFuncNames DynamicFuncNames
local GPointers = {
- Init = function()
- PatternScanner:Scan()
- end,
- Retry = function()
- PatternScanner:RetryScan()
- end
+ Init = function() PatternScanner:Scan() end,
+ Retry = function() PatternScanner:RetryScan() end,
+ ScriptGlobals = nullptr,
+ GameState = nullptr,
+ GameTime = nullptr,
+ IsVehicleWheelBrokenOff = nullptr,
+ GameVersion = { _build = "nil", _online = "nil" },
+ ScreenResolution = vec2:zero(),
}
-PatternScanner:Add("ScriptGlobals", "48 8D 15 ? ? ? ? 4C 8B C0 E8 ? ? ? ? 48 85 FF 48 89 1D", function(ptr)
- GPointers.ScriptGlobals = ptr:add(0x3):rip()
-end)
-
--- PatternScanner:Add("CWheelOffset", "3B B7 ? ? ? ? 7D 0D", function(ptr)
--- if ptr:is_null() then
--- GPointers.CWheelOffset = 0
--- return
--- end
-
--- GPointers.CWheelOffset = ptr:get_disp32(0x2) -- cmp esi, [rdi+0000C38h] (b3586.0)
--- end)
-
-PatternScanner:Add("GameVersion", "8B C3 33 D2 C6 44 24 20", function(ptr)
- if ptr:is_null() then
- GPointers.GameVersion = { _build = "nil", _online = "nil" }
- return
- end
-
- local pGameBuild = ptr:add(0x24):rip()
- local pOnlineVersion = pGameBuild:add(0x20)
- GPointers.GameVersion = {
- _build = pGameBuild:get_string(),
- _online = pOnlineVersion:get_string()
+GPointers.DynamicFuncNames = {}
+
+
+---@class MemoryBatch
+---@field m_name string
+---@field m_pattern string
+---@field m_callback fun(ptr: pointer)
+local MemoryBatch = {}
+MemoryBatch.__index = MemoryBatch
+---@param name string
+---@param ida_sig string
+---@param callback fun(ptr: pointer)
+function MemoryBatch.new(name, ida_sig, callback)
+ return {
+ m_name = name,
+ m_pattern = ida_sig,
+ m_callback = callback
}
-end)
-
-PatternScanner:Add("GameState", "83 3D ? ? ? ? ? 75 17 8B 43 20 25", function(ptr)
- if ptr:is_null() then
- GPointers.GameState = ptr
- return
- end
-
- GPointers.GameState = ptr:add(0x2):rip():add(0x1)
-end)
-
-PatternScanner:Add("GameTime", "8B 05 ? ? ? ? 89 ? 48 8D 4D C8", function(ptr)
- if ptr:is_null() then
- GPointers.GameTime = ptr
- return
- end
-
- GPointers.GameTime = ptr:add(0x2):rip()
-end)
-
-PatternScanner:Add("ScreenResolution", "66 0F 6E 0D ? ? ? ? 0F B7 3D", function(ptr)
- if ptr:is_null() then
- GPointers.ScreenResolution = vec2:zero()
- return
- end
-
- GPointers.ScreenResolution = vec2:new(
- ptr:sub(0x4):rip():get_word(),
- ptr:add(0x4):rip():get_word()
- )
-end)
+end
+
+---@type table>
+local mem_batches = {
+ [Enums.eAPIVersion.V1] = {
+ MemoryBatch.new("ScriptGlobals", "48 8D 15 ? ? ? ? 4C 8B C0 E8 ? ? ? ? 48 85 FF 48 89 1D", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.ScriptGlobals = ptr:add(0x3):rip()
+ end),
+ MemoryBatch.new("GameVersion", "8B C3 33 D2 C6 44 24 20", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ local pGameBuild = ptr:add(0x24):rip()
+ local pOnlineVersion = pGameBuild:add(0x20)
+ GPointers.GameVersion = {
+ _build = pGameBuild:get_string(),
+ _online = pOnlineVersion:get_string()
+ }
+ end),
+ MemoryBatch.new("GameState", "83 3D ? ? ? ? ? 75 17 8B 43 20 25", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.GameState = ptr:add(0x2):rip():add(0x1)
+ end),
+ MemoryBatch.new("GameTime", "8B 05 ? ? ? ? 89 ? 48 8D 4D C8", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.GameTime = ptr:add(0x2):rip()
+ end),
+ MemoryBatch.new("ScreenResolution", "66 0F 6E 0D ? ? ? ? 0F B7 3D", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.ScreenResolution = vec2:new(
+ ptr:sub(0x4):rip():get_word(),
+ ptr:add(0x4):rip():get_word()
+ )
+ end),
+ -- MemoryBatch.new("IsVehicleWheelBrokenOff", "E8 ? ? ? ? 48 8B CD 41 88 84 1F", function(ptr)
+ -- if ptr:is_null() then
+ -- return
+ -- end
+
+ -- local func_ptr = ptr:add(0x1):rip()
+ -- GPointers.IsVehicleWheelBrokenOff = func_ptr -- not needed for this but we'll just go ahead and store it
+ -- GPointers.DynamicFuncNames.dfn_IsVehicleWheelBrokenOff = memory.dynamic_call(
+ -- "bool",
+ -- { "void*", "int" },
+ -- func_ptr
+ -- )
+ -- end),
+ },
+ [Enums.eAPIVersion.V2] = {
+ MemoryBatch.new("ScriptGlobals", "48 8B 8E B8 00 00 00 48 8D 15 ? ? ? ? 49 89 D8", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.ScriptGlobals = ptr:add(0x7):add(0x3):rip()
+ end),
+ MemoryBatch.new("GameVersion", "4C 8D 0D ? ? ? ? 48 8D 5C 24 ? 48 89 D9 48 89 FA", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.GameVersion = {
+ _build = ptr:add(0x3):rip():get_string(),
+ _online = ptr:add(0x47):add(0x3):rip():get_string()
+ }
+ end),
+ MemoryBatch.new("GameState", "83 3D ? ? ? ? ? 0F 85 ? ? ? ? BA ? 00", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.GameState = ptr:add(0x2):rip():add(0x1)
+ end),
+ MemoryBatch.new("ScreenResolution", "75 39 0F 57 C0 F3 0F 2A 05", function(ptr)
+ if ptr:is_null() then
+ return
+ end
+
+ GPointers.ScreenResolution = vec2:new(
+ ptr:add(0x5):add(0x4):rip():get_word(),
+ ptr:add(0x1E):add(0x4):rip():get_word()
+ )
+ end),
+ },
+ [Enums.eAPIVersion.L54] = {
+ -- dummy
+ },
+}
+
+local API_VERSON = Backend:GetAPIVersion()
+local batches = mem_batches[API_VERSON]
+for _, batch in ipairs(batches) do
+ PatternScanner:Add(batch.m_name, batch.m_pattern, batch.m_callback)
+end
return GPointers
diff --git a/includes/features/BillionaireServicesV2.lua b/includes/features/BillionaireServicesV2.lua
index be3a853..65edaae 100644
--- a/includes/features/BillionaireServicesV2.lua
+++ b/includes/features/BillionaireServicesV2.lua
@@ -105,12 +105,12 @@ end
---@param entity integer
function BillionaireServices:RegisterEntity(entity)
- Decorator:RegisterEntity(entity, "BillionaireServices", true)
+ Decorator:Register(entity, "BillionaireServices", true)
end
---@param entity integer
function BillionaireServices:UnregisterEntity(entity)
- Decorator:RemoveEntity(entity, "BillionaireServices")
+ Decorator:RemoveEntity(entity)
end
function BillionaireServices:GetServiceCount()
diff --git a/includes/features/EntityForge.lua b/includes/features/EntityForge.lua
index dc7c0f7..d965a89 100644
--- a/includes/features/EntityForge.lua
+++ b/includes/features/EntityForge.lua
@@ -65,12 +65,12 @@ end
---@param entity handle
function EntityForge:RegisterEntity(entity)
- Decorator:RegisterEntity(entity, "EntityForge", true)
+ Decorator:Register(entity, "EntityForge", true)
end
---@param entity handle
function EntityForge:UnregisterEntity(entity)
- Decorator:RemoveEntity(entity, "EntityForge")
+ Decorator:RemoveEntity(entity)
end
---@return ForgeEntity
diff --git a/includes/features/Speedometer.lua b/includes/features/Speedometer.lua
index 6a5c23e..d061fe8 100644
--- a/includes/features/Speedometer.lua
+++ b/includes/features/Speedometer.lua
@@ -523,6 +523,7 @@ function Speedometer:Draw(offset)
ImGui.SetNextWindowPos(GVars.features.speedometer.pos.x, GVars.features.speedometer.pos.y, ImGuiCond.Always)
if ImGui.Begin("##SpeedometerWindow", windowFlags | ImGuiWindowFlags.NoBackground) then
if (not self._state.should_draw) then
+ ImGui.End()
return
end
diff --git a/includes/features/YimResupplierV3.lua b/includes/features/YimResupplierV3.lua
index 7e47120..7ce6de0 100644
--- a/includes/features/YimResupplierV3.lua
+++ b/includes/features/YimResupplierV3.lua
@@ -1254,28 +1254,28 @@ YRV3.t_SellScripts = {
}
YRV3.t_CEOwarehouses = {
- { id = 1, size = 0, max = 16, coords = vec3:new(51.311188, -2568.470947, 6.004591) },
- { id = 2, size = 0, max = 16, coords = vec3:new(-1081.083740, -1261.013184, 5.648909) },
- { id = 3, size = 0, max = 16, coords = vec3:new(898.484314, -1031.882446, 34.966454) },
- { id = 4, size = 0, max = 16, coords = vec3:new(249.246918, -1955.651978, 23.161957) },
- { id = 5, size = 0, max = 16, coords = vec3:new(-424.773499, 184.146530, 80.752899) },
- { id = 6, size = 2, max = 111, coords = vec3:new(-1045.004395, -2023.150146, 13.161570) },
- { id = 7, size = 1, max = 42, coords = vec3:new(-1269.286133, -813.215820, 17.107399) },
- { id = 8, size = 2, max = 111, coords = vec3:new(-876.108032, -2734.502930, 13.844264) },
- { id = 9, size = 0, max = 16, coords = vec3:new(272.409424, -3015.267090, 5.707359) },
- { id = 10, size = 1, max = 42, coords = vec3:new(1563.832031, -2135.110840, 77.616447) },
- { id = 11, size = 1, max = 42, coords = vec3:new(-308.772247, -2698.393799, 6.000292) },
- { id = 12, size = 1, max = 42, coords = vec3:new(503.738037, -653.082642, 24.751144) },
- { id = 13, size = 1, max = 42, coords = vec3:new(-528.074585, -1782.701904, 21.483055) },
- { id = 14, size = 1, max = 42, coords = vec3:new(-328.013458, -1354.755371, 31.296524) },
- { id = 15, size = 1, max = 42, coords = vec3:new(349.901184, 327.976440, 104.303856) },
- { id = 16, size = 2, max = 111, coords = vec3:new(922.555481, -1560.048950, 30.756647) },
- { id = 17, size = 2, max = 111, coords = vec3:new(762.672363, -909.193054, 25.250854) },
- { id = 18, size = 2, max = 111, coords = vec3:new(1041.059814, -2172.653076, 31.488876) },
- { id = 19, size = 2, max = 111, coords = vec3:new(1015.361633, -2510.986572, 28.302608) },
- { id = 20, size = 2, max = 111, coords = vec3:new(-245.651718, 202.504669, 83.792648) },
- { id = 21, size = 1, max = 42, coords = vec3:new(541.587646, -1944.362793, 24.985096) },
- { id = 22, size = 2, max = 111, coords = vec3:new(93.278641, -2216.144775, 6.033320) },
+ { size = 0, max = 16, coords = vec3:new(51.311188, -2568.470947, 6.004591) },
+ { size = 0, max = 16, coords = vec3:new(-1081.083740, -1261.013184, 5.648909) },
+ { size = 0, max = 16, coords = vec3:new(898.484314, -1031.882446, 34.966454) },
+ { size = 0, max = 16, coords = vec3:new(249.246918, -1955.651978, 23.161957) },
+ { size = 0, max = 16, coords = vec3:new(-424.773499, 184.146530, 80.752899) },
+ { size = 2, max = 111, coords = vec3:new(-1045.004395, -2023.150146, 13.161570) },
+ { size = 1, max = 42, coords = vec3:new(-1269.286133, -813.215820, 17.107399) },
+ { size = 2, max = 111, coords = vec3:new(-876.108032, -2734.502930, 13.844264) },
+ { size = 0, max = 16, coords = vec3:new(272.409424, -3015.267090, 5.707359) },
+ { size = 1, max = 42, coords = vec3:new(1563.832031, -2135.110840, 77.616447) },
+ { size = 1, max = 42, coords = vec3:new(-308.772247, -2698.393799, 6.000292) },
+ { size = 1, max = 42, coords = vec3:new(503.738037, -653.082642, 24.751144) },
+ { size = 1, max = 42, coords = vec3:new(-528.074585, -1782.701904, 21.483055) },
+ { size = 1, max = 42, coords = vec3:new(-328.013458, -1354.755371, 31.296524) },
+ { size = 1, max = 42, coords = vec3:new(349.901184, 327.976440, 104.303856) },
+ { size = 2, max = 111, coords = vec3:new(922.555481, -1560.048950, 30.756647) },
+ { size = 2, max = 111, coords = vec3:new(762.672363, -909.193054, 25.250854) },
+ { size = 2, max = 111, coords = vec3:new(1041.059814, -2172.653076, 31.488876) },
+ { size = 2, max = 111, coords = vec3:new(1015.361633, -2510.986572, 28.302608) },
+ { size = 2, max = 111, coords = vec3:new(-245.651718, 202.504669, 83.792648) },
+ { size = 1, max = 42, coords = vec3:new(541.587646, -1944.362793, 24.985096) },
+ { size = 2, max = 111, coords = vec3:new(93.278641, -2216.144775, 6.033320) },
}
YRV3.t_BikerBusinessIDs = {
@@ -1287,11 +1287,11 @@ YRV3.t_BikerBusinessIDs = {
}
YRV3.t_Hangars = {
- [1] = { name = "LSIA Hangar 1", coords = vec3:new(-1148.908447, -3406.064697, 13.945053) },
- [2] = { name = "LSIA Hangar A17", coords = vec3:new(-1393.322021, -3262.968262, 13.944828) },
- [3] = { name = "Fort Zancudo Hangar A2", coords = vec3:new(-2022.336304, 3154.936768, 32.810272) },
- [4] = { name = "Fort Zancudo Hangar 3497", coords = vec3:new(-1879.105957, 3106.792969, 32.810234) },
- [5] = { name = "Fort Zancudo Hangar 3499", coords = vec3:new(-2470.278076, 3274.427734, 32.835461) },
+ { name = "LSIA Hangar 1", coords = vec3:new(-1148.908447, -3406.064697, 13.945053) },
+ { name = "LSIA Hangar A17", coords = vec3:new(-1393.322021, -3262.968262, 13.944828) },
+ { name = "Fort Zancudo Hangar A2", coords = vec3:new(-2022.336304, 3154.936768, 32.810272) },
+ { name = "Fort Zancudo Hangar 3497", coords = vec3:new(-1879.105957, 3106.792969, 32.810234) },
+ { name = "Fort Zancudo Hangar 3499", coords = vec3:new(-2470.278076, 3274.427734, 32.835461) },
}
YRV3.t_Bunkers = {
diff --git a/includes/features/self/laser_sights.lua b/includes/features/self/laser_sights.lua
index 7f52dd6..379e097 100644
--- a/includes/features/self/laser_sights.lua
+++ b/includes/features/self/laser_sights.lua
@@ -40,13 +40,19 @@ function LaserSights:Init()
KeyManager:RegisterKeybind(
GVars.features.weapon.laser_sights.keybind,
function()
- GVars.features.weapon.laser_sights.enabled = not GVars.features.weapon.laser_sights.enabled
- AUDIO.PLAY_SOUND_FRONTEND(
- -1,
- "TARGET_COUNTER_TICK",
- "DLC_SM_GENERIC_MISSION_SOUNDS",
- false
- )
+ ThreadManager:Run(function()
+ if (not PLAYER.IS_PLAYER_FREE_AIMING(Self:GetPlayerID())) then
+ return
+ end
+
+ GVars.features.weapon.laser_sights.enabled = not GVars.features.weapon.laser_sights.enabled
+ AUDIO.PLAY_SOUND_FRONTEND(
+ -1,
+ "TARGET_COUNTER_TICK",
+ "DLC_SM_GENERIC_MISSION_SOUNDS",
+ false
+ )
+ end)
end,
false
)
diff --git a/includes/features/self/miscellaneous.lua b/includes/features/self/miscellaneous.lua
index 1c2cff8..fb446f2 100644
--- a/includes/features/self/miscellaneous.lua
+++ b/includes/features/self/miscellaneous.lua
@@ -281,10 +281,12 @@ function SelfMisc:UpdateFlagBasedFeatures()
GVars.features.self.sprint_inside_interiors
)
- self:TogglePedConfigFlag(
- Enums.ePedConfigFlags.AllowBikeAlternateAnimations,
- GVars.features.self.mc_alt_bike_anims
- )
+ if (Game.IsOnline()) then
+ self:TogglePedConfigFlag(
+ Enums.ePedConfigFlags.AllowBikeAlternateAnimations,
+ GVars.features.self.mc_alt_bike_anims
+ )
+ end
if (GVars.features.self.sprint_inside_interiors and not Self:IsOutside()) then
Self:SetPedResetFlag(Enums.ePedResetFlags.DisablePlayerJumping, false)
diff --git a/includes/features/vehicle/brake_force_display.lua b/includes/features/vehicle/brake_force_display.lua
index 421982c..3531445 100644
--- a/includes/features/vehicle/brake_force_display.lua
+++ b/includes/features/vehicle/brake_force_display.lua
@@ -42,7 +42,8 @@ function BFD:Toggle()
if VEHICLE.IS_VEHICLE_ON_ALL_WHEELS(PV:GetHandle())
and PAD.IS_CONTROL_PRESSED(0, 72)
- and (PV:GetSpeed() >= 19.44) then
+ and (PV:GetSpeed() >= 19.44)
+ and (PV:GetCurrentGear() > 0) then
self.m_is_toggled = not self.m_is_toggled
else
self.m_is_toggled = false
diff --git a/includes/features/vehicle/car_crashes.lua b/includes/features/vehicle/car_crashes.lua
index f997cc1..34de2c6 100644
--- a/includes/features/vehicle/car_crashes.lua
+++ b/includes/features/vehicle/car_crashes.lua
@@ -93,12 +93,12 @@ function CarCrash:Init()
end
function CarCrash:ShouldRun()
- return (self.m_entity
+ return (GVars.features.vehicle.strong_crash
+ and self.m_entity
and self.m_entity:IsValid()
- and self.m_entity:IsLandVehicle()
+ and self.m_entity:IsCar()
and Self:IsAlive()
and Self:IsDriving()
- and GVars.features.vehicle.strong_crash
and not VEHICLE.IS_VEHICLE_STUCK_ON_ROOF(self.m_entity:GetHandle())
)
end
diff --git a/includes/features/vehicle/drift_mode.lua b/includes/features/vehicle/drift_mode.lua
index ca2afc1..15d02aa 100644
--- a/includes/features/vehicle/drift_mode.lua
+++ b/includes/features/vehicle/drift_mode.lua
@@ -37,7 +37,7 @@ function DriftMode:IsActive()
end
function DriftMode:UpdateFX()
- if (not GVars.features.vehicle.drift.smoke_fx.enabled) then
+ if (not GVars.features.vehicle.drift.smoke_fx.enabled or not self.m_entity:IsCar()) then
return
end
@@ -72,7 +72,7 @@ function DriftMode:UpdateFX()
Color(r, g, b)
)
end
- elseif self.m_smoke_fx then
+ elseif (self.m_smoke_fx) then
Game.StopParticleEffects(self.m_smoke_fx, "scr_ba_bb")
self.m_smoke_fx = nil
end
@@ -102,7 +102,7 @@ function DriftMode:UpdateFX()
if (self.m_smoke_fx and #self.m_smoke_fx > 0) then
for _, fx in ipairs(self.m_smoke_fx) do
- GRAPHICS.SET_PARTICLE_FX_LOOPED_COLOUR(fx, col.x, col.y, col.z, false)
+ GRAPHICS.SET_PARTICLE_FX_LOOPED_COLOUR(fx, r, g, b, false)
end
end
end
diff --git a/includes/features/vehicle/flatbed.lua b/includes/features/vehicle/flatbed.lua
index db4daa6..6351a9b 100644
--- a/includes/features/vehicle/flatbed.lua
+++ b/includes/features/vehicle/flatbed.lua
@@ -96,7 +96,7 @@ function Flatbed:Spawn()
return
end
- Decorator:RegisterEntity(self.m_handle, "Flatbed", true)
+ Decorator:Register(self.m_handle, "Flatbed", true)
PED.SET_PED_INTO_VEHICLE(Self:GetHandle(), self.m_handle, -1)
STREAMING.SET_MODEL_AS_NO_LONGER_NEEDED(self.modelHash)
ENTITY.SET_ENTITY_AS_NO_LONGER_NEEDED(self.m_handle)
@@ -265,7 +265,7 @@ function Flatbed:Attach()
tries = tries + 1
final_z = final_z + step
until success or tries > (maxLift / step)
- Decorator:RegisterEntity(self.m_towed_vehicle.m_handle, "Flatbed", true)
+ Decorator:Register(self.m_towed_vehicle.m_handle, "Flatbed", true)
end
---@param x float
@@ -406,7 +406,7 @@ function Flatbed:Detach()
VEHICLE.SET_VEHICLE_ON_GROUND_PROPERLY(self.m_towed_vehicle.m_handle, 5.0)
end
- Decorator:RemoveEntity(self.m_towed_vehicle.m_handle, "Flatbed")
+ Decorator:RemoveEntity(self.m_towed_vehicle.m_handle)
self.m_towed_vehicle = nil
end
end
@@ -430,7 +430,7 @@ function Flatbed:ForceCleanup()
false
)
VEHICLE.SET_VEHICLE_ON_GROUND_PROPERLY(attachedVehicle, 5.0)
- Decorator:RemoveEntity(self.m_towed_vehicle.m_handle, "Flatbed")
+ Decorator:RemoveEntity(self.m_towed_vehicle.m_handle)
self.m_towed_vehicle = nil
end
end
@@ -453,10 +453,10 @@ function Flatbed:Reset()
}
if self.m_towed_vehicle then
- Decorator:RemoveEntity(self.m_towed_vehicle.m_handle, "Flatbed")
+ Decorator:RemoveEntity(self.m_towed_vehicle.m_handle)
end
- Decorator:RemoveEntity(self.m_handle, "Flatbed")
+ Decorator:RemoveEntity(self.m_handle)
self.m_previous_handle = 0
self.m_search_pos = vec3:zero()
self.m_fwd_vec = vec3:zero()
diff --git a/includes/features/vehicle/launch_control.lua b/includes/features/vehicle/launch_control.lua
index 5194be4..8e0457c 100644
--- a/includes/features/vehicle/launch_control.lua
+++ b/includes/features/vehicle/launch_control.lua
@@ -2,6 +2,11 @@
local FeatureBase = require("includes.modules.FeatureBase")
+local eLaunchMode = {
+ REALISTIC = 0,
+ RIDICULOUS = 1
+}
+
---@enum eLaunchControlState
local eLaunchControlState = {
NONE = 1,
@@ -44,9 +49,10 @@ function LaunchControl:ShouldRun()
return self.m_entity
and self.m_entity:IsValid()
and self.m_entity:IsCar()
+ and Self:IsAlive()
+ and Self:IsDriving()
and (not GVars.features.vehicle.performance_only or self.m_entity:IsPerformanceCar())
and (GVars.features.vehicle.launch_control or GVars.features.vehicle.burble_tune)
- and not self.m_entity:IsElectric()
end
-- function LaunchControl:OnEnable()
@@ -193,8 +199,7 @@ function LaunchControl:OnTick()
if (not PV:IsMoving() and PV:IsEngineOn()) then
if (PAD.IS_CONTROL_PRESSED(0, 71) and PAD.IS_CONTROL_PRESSED(0, 72) and not PV:IsDriftButtonPressed()) then
if (PV:GetEngineHealth() <= 400) then
- Toast:ShowWarning("Samurai's Scripts",
- "Launch control is unavailable at the moment. Your engine is damaged.", false, 5)
+ Toast:ShowWarning("Samurai's Scripts", _T("VEH_LAUNCH_CTRL_ERR"), false, 5)
sleep(5000)
return
end
@@ -209,7 +214,7 @@ function LaunchControl:OnTick()
Game.DrawText(
vec2:new(0.42, 0.936),
- "Launch Control",
+ _T("VEH_LAUNCH_CTRL"),
Color(r, g, b, a),
vec2:new(0, 0.35),
2
@@ -229,7 +234,7 @@ function LaunchControl:OnTick()
self.m_timer:pause()
end
elseif (self.m_state ~= eLaunchControlState.NONE and self.m_state ~= eLaunchControlState.READY) then
- if (PAD.IS_CONTROL_RELEASED(0, 71) or PAD.IS_CONTROL_RELEASED(0, 72)) then
+ if (PAD.IS_CONTROL_RELEASED(0, 71) or PAD.IS_CONTROL_RELEASED(0, 72) or not self:ShouldRun()) then
r, g, b, a = 255, 255, 255, 255
PV:Unfreeze()
self.m_timer:reset()
@@ -240,19 +245,38 @@ function LaunchControl:OnTick()
end
if (self.m_state == eLaunchControlState.READY) then
- if PAD.IS_CONTROL_PRESSED(0, 71) and PAD.IS_CONTROL_RELEASED(0, 72) then
+ if (PAD.IS_CONTROL_PRESSED(0, 71) and PAD.IS_CONTROL_RELEASED(0, 72)) then
+ local realistic = GVars.features.vehicle.launch_control_mode == eLaunchMode.REALISTIC
+ local max_speed = realistic and PV:GetDefaultMaxSpeed() - 1 or PV:GetMaxSpeed() - 1
+ local max_force = realistic and 2000 or 5000
+ local max_push = realistic and max_speed * 0.55 or max_speed
+ local start_time = Game.GetGameTimer()
+ local end_time = start_time + 1200
+
PHYSICS.SET_IN_ARENA_MODE(true)
- VEHICLE.SET_VEHICLE_MAX_LAUNCH_ENGINE_REVS_(handle, -1)
+ VEHICLE.SET_VEHICLE_MAX_LAUNCH_ENGINE_REVS_(handle, 0)
PV:Unfreeze()
- for i = 5, 0.1, -1 do
- VEHICLE.SET_VEHICLE_CHEAT_POWER_INCREASE(handle, 10)
- VEHICLE.MODIFY_VEHICLE_TOP_SPEED(handle, 100)
- VEHICLE.SET_VEHICLE_FORWARD_SPEED(handle, PV:GetSpeed() + i)
- end
self.m_state = eLaunchControlState.RUNNING
- sleep(4269)
- VEHICLE.MODIFY_VEHICLE_TOP_SPEED(handle, -1)
- VEHICLE.SET_VEHICLE_CHEAT_POWER_INCREASE(handle, 1.0)
+
+ while (PAD.IS_CONTROL_PRESSED(0, 71) and PV:GetSpeed() < max_push) do
+ local now = Game.GetGameTimer()
+ local t = math.min(1.0, (now - start_time) / (end_time - start_time))
+ local power = math.lerp(0.0, max_force, t)
+ ENTITY.APPLY_FORCE_TO_ENTITY_CENTER_OF_MASS(
+ handle,
+ 1,
+ 0.0,
+ power,
+ 0.0,
+ false,
+ true,
+ false,
+ false
+ )
+
+ yield()
+ end
+
VEHICLE.SET_VEHICLE_MAX_LAUNCH_ENGINE_REVS_(handle, 1.0)
PHYSICS.SET_IN_ARENA_MODE(false)
self.m_state = eLaunchControlState.NONE
diff --git a/includes/features/vehicle/misc_vehicle.lua b/includes/features/vehicle/misc_vehicle.lua
index 740be30..2133be2 100644
--- a/includes/features/vehicle/misc_vehicle.lua
+++ b/includes/features/vehicle/misc_vehicle.lua
@@ -220,20 +220,38 @@ function MiscVehicle:Update()
local handle = PV:GetHandle()
if (GVars.features.vehicle.fast_jets and PV:IsPlane() and (VEHICLE.GET_VEHICLE_FLIGHT_NOZZLE_POSITION(handle) ~= 1.0)) then
- local speedIncrement = 0.21
- local planeRotation = ENTITY.GET_ENTITY_ROTATION(handle, 2)
- local speed = self.m_entity:GetSpeed()
-
- if (planeRotation.x >= 30) then
- speedIncrement = 0.4
- elseif (planeRotation.x >= 60) then
- speedIncrement = 0.8
+ local speed = PV:GetSpeed()
+ local gearState = PV:GetLandingGearState()
+ local rot = PV:GetRotation(2)
+ local pitch = rot.x
+ local baseThrust = 2e4
+ local minThrust = 5e3
+ local maxSpeed = 164.0
+ local thrustMult = 1.0
+
+ if (pitch >= 60) then
+ thrustMult = 2.0
+ elseif (pitch >= 30) then
+ thrustMult = 1.4
end
- if (speed >= 73 and speed < 160) then
- if (PAD.IS_CONTROL_PRESSED(0, 87) and PV:GetLandingGearState() == Enums.eLandingGearState.RETRACTED) then
- VEHICLE.SET_VEHICLE_FORWARD_SPEED(handle, (speed + speedIncrement))
- end
+ if speed >= 72 and speed < maxSpeed
+ and PAD.IS_CONTROL_PRESSED(0, 87)
+ and gearState == Enums.eLandingGearState.RETRACTED
+ then
+ local lerp = math.min(1.0, (speed) / (maxSpeed))
+ local thrust = math.min(minThrust, baseThrust * thrustMult * (1.0 - lerp))
+ ENTITY.APPLY_FORCE_TO_ENTITY_CENTER_OF_MASS(
+ handle,
+ 1,
+ 0.0,
+ thrust,
+ 0.0,
+ false,
+ true,
+ false,
+ false
+ )
end
end
diff --git a/includes/features/vehicle/stancer.lua b/includes/features/vehicle/stancer.lua
new file mode 100644
index 0000000..8f793a5
--- /dev/null
+++ b/includes/features/vehicle/stancer.lua
@@ -0,0 +1,397 @@
+---@diagnostic disable: param-type-mismatch, return-type-mismatch, assign-type-mismatch
+
+-- Unfinished, WIP
+
+local FeatureBase = require("includes.modules.FeatureBase")
+local CWheel = require("includes.classes.CWheel")
+
+---@class StanceObject
+---@field m_track_width float
+---@field m_camber float
+---@field m_wheel_width float
+---@field m_wheel_size float
+local StanceObject = {}
+
+---@return StanceObject
+function StanceObject.new()
+ return {
+ m_track_width = 0.0,
+ m_camber = 0.0,
+ m_wheel_width = 0.0,
+ m_wheel_size = 0.0,
+ }
+end
+
+---@class Stancer : FeatureBase
+---@field private m_entity PlayerVehicle
+---@field private m_last_tick milliseconds
+---@field public m_base_values table
+---@field public m_deltas table
+---@field public m_wheels table>
+---@field public m_suspension_height { m_current: float, m_last_seen: float }
+---@field public m_is_active boolean
+local Stancer = setmetatable({}, FeatureBase)
+Stancer.__index = Stancer
+
+---@class eWheelSide
+Stancer.eWheelSide = {
+ FRONT = 1,
+ BACK = 2,
+}
+
+Stancer.m_base_values = {
+ [Stancer.eWheelSide.FRONT] = StanceObject.new(),
+ [Stancer.eWheelSide.BACK] = StanceObject.new(),
+}
+
+Stancer.m_deltas = {
+ [Stancer.eWheelSide.FRONT] = StanceObject.new(),
+ [Stancer.eWheelSide.BACK] = StanceObject.new(),
+}
+
+---@alias ptr_read fun(w: CWheel): anyval
+---@type array<{ key: string, wheel_side: eWheelSide, read_func: ptr_read, write_func: fun(w: CWheel, v: anyval, veh?: PlayerVehicle), side_dont_care?: boolean}>
+Stancer.decorators = {
+ {
+ key = "m_camber",
+ wheel_side = Stancer.eWheelSide.FRONT,
+ read_func = function(w)
+ return w.m_y_rotation:get_float()
+ end,
+ write_func = function(w, v)
+ w.m_y_rotation:set_float(v)
+ w.m_y_rotation_inv:set_float(-v)
+ end
+ },
+ {
+ key = "m_track_width",
+ wheel_side = Stancer.eWheelSide.FRONT,
+ read_func = function(w)
+ return w.m_x_offset:get_float()
+ end,
+ write_func = function(w, v)
+ w.m_x_offset:set_float(v)
+ end
+ },
+ {
+ key = "m_wheel_width",
+ wheel_side = Stancer.eWheelSide.FRONT, -- doesn't matter
+ side_dont_care = true,
+ read_func = function(w)
+ return w.m_tire_width:get_float()
+ end,
+ write_func = function(w, v, veh)
+ w.m_tire_width:set_float(v)
+ veh:SetVisualWheelWidth(v * 2)
+ end
+ },
+ {
+ key = "m_wheel_size",
+ wheel_side = Stancer.eWheelSide.FRONT, -- doesn't matter
+ side_dont_care = true,
+ read_func = function(w)
+ return w.m_tire_radius:get_float()
+ end,
+ write_func = function(w, v, veh)
+ w.m_tire_radius:set_float(v)
+ veh:SetVisualWheelSize(v * 2)
+ end
+ },
+ {
+ key = "m_camber",
+ wheel_side = Stancer.eWheelSide.BACK,
+ read_func = function(w)
+ return w.m_y_rotation:get_float()
+ end,
+ write_func = function(w, v)
+ w.m_y_rotation:set_float(v)
+ w.m_y_rotation_inv:set_float(-v)
+ end
+ },
+ {
+ key = "m_track_width",
+ wheel_side = Stancer.eWheelSide.BACK,
+ read_func = function(w)
+ return w.m_x_offset:get_float()
+ end,
+ write_func = function(w, v)
+ w.m_x_offset:set_float(v)
+ end
+ },
+}
+
+---@param pv PlayerVehicle
+---@return Stancer
+function Stancer.new(pv)
+ local self = FeatureBase.new(pv)
+ return setmetatable(self, Stancer)
+end
+
+function Stancer:Init()
+ self.m_last_tick = 0
+ self.m_suspension_height = {
+ m_current = 0.0,
+ m_last_seen = 0.0
+ }
+
+ if (self.m_entity:IsValid()) then
+ self:ReadWheelArray()
+ end
+end
+
+function Stancer:ShouldRun()
+ return self.m_entity and self.m_entity:IsValid()
+end
+
+function Stancer:ReadWheelArray()
+ if (self.m_wheels) then
+ return
+ end
+
+ self.m_wheels = {
+ [self.eWheelSide.FRONT] = {},
+ [self.eWheelSide.BACK] = {}
+ }
+
+ local wheel_array = self.m_entity:Resolve().m_wheels
+ local wheel_count = self.m_entity:GetNumberOfWheels()
+ if (wheel_count == 2) then
+ table.insert(self.m_wheels[self.eWheelSide.FRONT], CWheel(wheel_array:Get(1)))
+ table.insert(self.m_wheels[self.eWheelSide.BACK], CWheel(wheel_array:Get(2)))
+ else
+ -- I don't think there are any "cars" in GTA with more or less than 2 front wheels
+ local front_count = 2
+ local back_count = wheel_count - front_count
+ for i = 1, front_count do
+ self.m_wheels[self.eWheelSide.FRONT][i] = CWheel(wheel_array:Get(i))
+ end
+
+ if (back_count == 1) then -- I think there's one vehicle with just one back wheel. I have the memory of a goldfish so I can't remember
+ self.m_wheels[self.eWheelSide.BACK][1] = CWheel(wheel_array:Get(3))
+ else
+ for i = 1, back_count do
+ self.m_wheels[self.eWheelSide.BACK][i] = CWheel(wheel_array:Get(i + front_count))
+ end
+ end
+ end
+end
+
+---@return table>
+function Stancer:GetWheels()
+ if (not self.m_wheels) then
+ self:ReadWheelArray()
+ end
+
+ return self.m_wheels
+end
+
+---@param side eWheelSide
+---@return array?
+function Stancer:GetAllWheelsForSide(side)
+ self.m_wheels = self:GetWheels()
+ if (#self.m_wheels[side] == 0) then
+ return
+ end
+
+ return self.m_wheels[side]
+end
+
+---@param side eWheelSide
+---@return CWheel?
+function Stancer:GetFirstWheelForSide(side)
+ local wheelsbyside = self.m_wheels[side]
+ if (#wheelsbyside == 0) then
+ return
+ end
+
+ return wheelsbyside[1]
+end
+
+---@param side eWheelSide
+---@param wheel_n integer
+---@return CWheel?
+function Stancer:GetNthWheelForSide(side, wheel_n)
+ local wheelsbyside = self.m_wheels[side]
+ local count = #wheelsbyside
+ if (count == 0 or wheel_n > count) then
+ return
+ end
+
+ return self.m_wheels[side][wheel_n]
+end
+
+---@return boolean
+function Stancer:AreDefaultsRegistered()
+ if (not self.m_wheels) then
+ return false
+ end
+
+ local handle = self.m_entity:GetHandle()
+ for _, v in ipairs(self.decorators) do
+ local wheel_array = self:GetAllWheelsForSide(v.wheel_side)
+ for i = 1, #wheel_array do
+ local decor = _F("%s_%d", v.key, i)
+ if (not Decorator:ExistsOn(handle, decor)) then
+ return false
+ end
+ end
+ end
+
+ return true
+end
+
+---@param array array
+---@param fn function
+function Stancer:ForEach(array, fn)
+ if (not array or #array == 0) then
+ return
+ end
+
+ for i, v in ipairs(array) do
+ if (v and v:IsValid()) then
+ fn(i, v)
+ end
+ end
+end
+
+function Stancer:ReadDefaults()
+ if (not self.m_entity:IsValid() or not self.m_entity:IsCar()) then
+ return
+ end
+
+ local queued_decors_loaded = self:RestoreQueueFromDecors()
+
+ if (self:AreDefaultsRegistered()) then
+ return
+ end
+
+ for _, v in ipairs(self.decorators) do
+ local key = v.key
+ local read_func = v.read_func
+ local wheel_array = self:GetAllWheelsForSide(v.wheel_side)
+
+ self:ForEach(wheel_array, function(i, cwheel)
+ local default_val = read_func(cwheel)
+ local wheel_key = _F("%s_%d", key, i)
+ Decorator:Register(self.m_entity:GetHandle(), wheel_key, default_val)
+
+ -- our values are based on the first wheel per axle
+ if (i == 1) then
+ self.m_base_values[v.wheel_side][v.key] = default_val
+ if (not queued_decors_loaded) then
+ local pending_key = wheel_key .. "_queue"
+ local decor_func = Decorator:ExistsOn(self.m_entity:GetHandle(), pending_key)
+ and Decorator.UpdateDecor
+ or Decorator.Register
+
+ decor_func(Decorator, self.m_entity:GetHandle(), pending_key, default_val)
+ self.m_deltas[v.wheel_side][v.key] = 0.0
+ end
+ end
+ end)
+ end
+end
+
+---@param wheelIndex integer
+---@param value number
+---@return number
+function Stancer:GetValueByWheelIndex(wheelIndex, value)
+ -- this is not flipped. default values are referenced from the first wheel per side (front/back)
+ return wheelIndex == 1 and value or -value
+end
+
+---@return boolean
+function Stancer:CanApplyDrawData()
+ return self.m_entity and self.m_entity:HasWheelDrawData()
+end
+
+function Stancer:Reset()
+ if (not self.m_wheels) then
+ return
+ end
+
+ self.m_entity:SetRideHeight(0.0)
+ self.m_suspension_height.m_current = 0.0
+ self.m_suspension_height.m_last_seen = 0.0
+
+ for _, v in ipairs(self.decorators) do
+ self.m_deltas[v.wheel_side][v.key] = 0.0
+ end
+end
+
+function Stancer:Cleanup()
+ if (not self.m_wheels) then
+ return
+ end
+
+ self:Reset()
+ Decorator:RemoveEntity(self.m_entity:GetHandle())
+end
+
+---@return boolean
+function Stancer:RestoreQueueFromDecors()
+ local handle = self.m_entity:GetHandle()
+ if (not Decorator:IsEntityRegistered(handle)) then
+ return false
+ end
+
+ local success = true
+ for _, v in ipairs(self.decorators) do
+ local wheel_array = self:GetAllWheelsForSide(v.wheel_side)
+ self:ForEach(wheel_array, function(i)
+ local queued_key = _F("%s_%d_queue", v.key, i)
+ local val = Decorator:GetDecor(handle, queued_key)
+ if (val == nil) then
+ success = false
+ else
+ if (i == 1) then
+ self.m_deltas[v.wheel_side][v.key] = val
+ end
+ end
+ end)
+ end
+
+ return success
+end
+
+function Stancer:Update()
+ self.m_is_active = self.m_entity:IsCar()
+
+ if (not self.m_is_active or not self.m_wheels) then
+ return
+ end
+
+ -- thanks for making me reload this slow ass game 15 times.
+ -- here's a guard dog
+ if (not self:AreDefaultsRegistered()) then
+ return
+ end
+
+ if (Game.GetGameTimer() - self.m_last_tick < 5) then
+ return
+ end
+
+ if (self.m_suspension_height.m_current ~= self.m_suspension_height.m_last_seen) then
+ self.m_entity:SetRideHeight(self.m_suspension_height.m_current)
+ self.m_suspension_height.m_last_seen = self.m_suspension_height.m_current
+ end
+
+ for _, v in ipairs(self.decorators) do
+ local wheel_array = self:GetAllWheelsForSide(v.wheel_side)
+ local base_val = self.m_base_values[v.wheel_side][v.key]
+ local delta_val = self.m_deltas[v.wheel_side][v.key]
+
+ self:ForEach(wheel_array, function(i, cwheel)
+ local desired = v.side_dont_care and base_val + delta_val or
+ self:GetValueByWheelIndex(i, base_val + delta_val)
+
+ if (math.abs(desired) ~= math.abs(v.read_func(cwheel))) then
+ v.write_func(cwheel, desired, self.m_entity)
+ end
+ end)
+ end
+
+ self.m_last_tick = Game.GetGameTimer()
+end
+
+return Stancer
diff --git a/includes/frontend/self_ui.lua b/includes/frontend/self_ui.lua
index f1a9837..c94a9d7 100644
--- a/includes/frontend/self_ui.lua
+++ b/includes/frontend/self_ui.lua
@@ -206,7 +206,7 @@ local function SelfUI()
if (GVars.features.weapon.katana.enabled) then
if (ImGui.BeginCombo(_T("SELF_KATANA_REPLACE_MODEL"), GVars.features.weapon.katana.name)) then
for _, pair in pairs(katana_replace_weapons) do
- local is_selected = GVars.features.weapon.katana.name == pair.first
+ local is_selected = GVars.features.weapon.katana.model == pair.second
if (ImGui.Selectable(pair.first, is_selected)) then
GVars.features.weapon.katana.name = pair.first
GVars.features.weapon.katana.model = pair.second
@@ -216,11 +216,11 @@ local function SelfUI()
end
local handle = Self:GetHandle()
- if WEAPON.IS_PED_ARMED(handle, 7) then
+ if (WEAPON.IS_PED_ARMED(handle, 7)) then
WEAPON.SET_CURRENT_PED_WEAPON(handle, 0xA2719263, true)
end
- if WEAPON.HAS_PED_GOT_WEAPON(handle, pair.second, false) then
+ if (WEAPON.HAS_PED_GOT_WEAPON(handle, pair.second, false)) then
sleep(300)
WEAPON.SET_CURRENT_PED_WEAPON(handle, pair.second, true)
end
diff --git a/includes/frontend/settings/debug_ui.lua b/includes/frontend/settings/debug_ui.lua
index 32569b9..4d69ddf 100644
--- a/includes/frontend/settings/debug_ui.lua
+++ b/includes/frontend/settings/debug_ui.lua
@@ -1,3 +1,4 @@
+local CWheel = require "includes.classes.CWheel"
local RED = Color("red")
local GREEN = Color("green")
local BLUE = Color("blue")
@@ -551,6 +552,7 @@ local function DrawMiscTests()
PV:Resolve():DumpModelInfoFlags()
end)
end
+
ImGui.SameLine()
if (ImGui.Button("Advanced Flags")) then
script.run_in_fiber(function()
@@ -561,17 +563,6 @@ local function DrawMiscTests()
PV:Resolve():DumpAdvancedFlags()
end)
end
-
- if (ImGui.Button("Get Subhandling Data")) then
- script.run_in_fiber(function()
- local PV = Self:GetVehicle()
- if (not PV:IsValid()) then
- return
- end
-
- print(PV:GetHandlingData())
- end)
- end
end
return function()
diff --git a/includes/frontend/vehicle/flatbed_ui.lua b/includes/frontend/vehicle/flatbed_ui.lua
index 7f8e214..0d66108 100644
--- a/includes/frontend/vehicle/flatbed_ui.lua
+++ b/includes/frontend/vehicle/flatbed_ui.lua
@@ -1,5 +1,6 @@
local Flatbed = require("includes.features.vehicle.flatbed")
local flatbed_tab = GUI:RegisterNewTab(Enums.eTabID.TAB_VEHICLE, "SUBTAB_FLATBED", nil, nil, true)
+
flatbed_tab:AddLoopedCommand("FLTBD_MAIN_CB",
"features.flatbed.enabled",
function()
diff --git a/includes/frontend/vehicle/stancer_ui.lua b/includes/frontend/vehicle/stancer_ui.lua
new file mode 100644
index 0000000..94fe0f6
--- /dev/null
+++ b/includes/frontend/vehicle/stancer_ui.lua
@@ -0,0 +1,79 @@
+local PV = Self:GetVehicle()
+local Stancer = PV.m_stance_mgr
+local frontStanceDeltas = Stancer.m_deltas[Stancer.eWheelSide.FRONT]
+local backStanceDeltas = Stancer.m_deltas[Stancer.eWheelSide.BACK]
+
+local ref = {
+ m_camber = { label = "VEH_STANCE_CAMBER", fmt = "%.2f°", min = -1.0, max = 1.0 },
+ m_track_width = { label = "VEH_STANCE_TRACK_WIDTH", fmt = "%.2f", min = -0.5, max = 0.5 },
+ m_wheel_width = { label = "VEH_STANCE_WHEEL_WIDTH", fmt = "%.2f", min = -0.5, max = 1.5, drawdata_only = true, tooltip = "VEH_STANCE_NON_STOCK" },
+ m_wheel_size = { label = "VEH_STANCE_WHEEL_SIZE", fmt = "%.2f", min = -0.5, max = 1.5, drawdata_only = true, tooltip = "VEH_STANCE_NON_STOCK" },
+}
+
+---@param key string
+---@param deltaTable table
+---@param side integer
+local function DrawSlider(key, deltaTable, side)
+ local meta = ref[key]
+ local disabled = (meta.drawdata_only and not Stancer:CanApplyDrawData())
+
+ if (disabled) then
+ ImGui.BeginDisabled()
+ end
+ deltaTable[key], _ = ImGui.SliderFloat(
+ _F("%s##%d", _T(meta.label), side),
+ deltaTable[key],
+ meta.min,
+ meta.max, meta.fmt
+ )
+ if (disabled) then
+ ImGui.EndDisabled()
+ GUI:Tooltip(_T(meta.tooltip or "VEH_STANCE_INCOMPATIBLE"))
+ end
+end
+
+return function()
+ if (self.get_veh() == 0) then
+ ImGui.Text(_T("GENERIC_NOT_IN_VEH"))
+ return
+ elseif (not Stancer.m_is_active) then
+ ImGui.Text(_T("GENERIC_CARS_ONLY"))
+ return
+ end
+
+ ImGui.SeparatorText(_T("VEH_STANCE_FRONT_AXLE"))
+ DrawSlider("m_camber", frontStanceDeltas, Stancer.eWheelSide.FRONT)
+ DrawSlider("m_track_width", frontStanceDeltas, Stancer.eWheelSide.FRONT)
+
+ ImGui.SeparatorText(_T("VEH_STANCE_REAR_AXLE"))
+ DrawSlider("m_camber", backStanceDeltas, Stancer.eWheelSide.BACK)
+ DrawSlider("m_track_width", backStanceDeltas, Stancer.eWheelSide.BACK)
+
+ if (GUI:Button(_T("VEH_STANCE_COPY_FB"))) then
+ backStanceDeltas.m_camber = frontStanceDeltas.m_camber
+ backStanceDeltas.m_track_width = frontStanceDeltas.m_track_width
+ end
+
+ ImGui.SeparatorText(_T("VEH_STANCE_GEN_OPTIONS"))
+ Stancer.m_suspension_height.m_current, _ = ImGui.SliderFloat(
+ _T("VEH_STANCE_RIDE_HEIGHT"),
+ Stancer.m_suspension_height.m_current,
+ -0.2,
+ 0.2
+ )
+
+ DrawSlider("m_wheel_width", frontStanceDeltas, Stancer.eWheelSide.FRONT)
+ DrawSlider("m_wheel_size", frontStanceDeltas, Stancer.eWheelSide.FRONT)
+
+ if (GUI:Button(_T("GENERIC_RESET"))) then
+ Stancer:Reset()
+ ThreadManager:Run(function()
+ if (not PV:IsValid()) then
+ return
+ end
+ VEHICLE.RESET_VEHICLE_WHEELS(PV:GetHandle(), true)
+ end)
+ end
+
+ ImGui.Dummy(1, 10)
+end
diff --git a/includes/frontend/vehicle/vehicle_ui.lua b/includes/frontend/vehicle/vehicle_ui.lua
index 0dc61e6..d4c95c6 100644
--- a/includes/frontend/vehicle/vehicle_ui.lua
+++ b/includes/frontend/vehicle/vehicle_ui.lua
@@ -453,6 +453,7 @@ vehicleTab:RegisterGUI(function()
"%.0f RPM", GVars.features.vehicle.bangs_rpm_max
)
end
+
if (GVars.features.vehicle.rgb_lights.enabled) then
GVars.features.vehicle.rgb_lights.speed, _ = ImGui.SliderInt("RGB Lights Speed",
GVars.features.vehicle.rgb_lights.speed,
@@ -498,6 +499,13 @@ vehicleTab:RegisterGUI(function()
nosOptionsWindow.m_should_draw = true
end
end
+
+ if (GVars.features.vehicle.launch_control) then
+ GVars.features.vehicle.launch_control_mode, _ = ImGui.Combo(_T("VEH_LAUNCH_CTRL_MODE"),
+ GVars.features.vehicle.launch_control_mode,
+ _F("%s\0%s\0", _T("VEH_LAUNCH_CTRL_REALISTIC"), _T("VEH_LAUNCH_CTRL_RIDICULOUS"))
+ )
+ end
end)
--#region Handling Editor
@@ -522,20 +530,29 @@ for key, data in pairs(Self:GetVehicle().m_flag_registry) do
end
handlingEditorTab:RegisterGUI(function()
+ if (self.get_veh() == 0) then
+ ImGui.Text(_T("GENERIC_NOT_IN_VEH"))
+ return
+ end
+
handlingEditorTab:GetGridRenderer():Draw()
end)
--#endregion
+--#region stancer
+vehicleTab:RegisterSubtab("SUBTAB_STANCER", require("includes.frontend.vehicle.stancer_ui"), nil, true)
+--#endregion
+
local swap_btn_size = vec2:new(140, 35)
local swap_wnd_height = 260
vehicleTab:RegisterSubtab("VEH_ENGINE_SWAP", function()
- if (Self:GetVehicle():GetHandle() == 0) then
+ if (self.get_veh() == 0) then
ImGui.Text(_T("GENERIC_NOT_IN_VEH"))
return
end
if (not Self:GetVehicle().m_engine_swap_compatible) then
- ImGui.Text(_T("VEH_ENGINE_SWAP_INCOMPATIBE"))
+ ImGui.Text(_T("GENERIC_CARS_ONLY"))
return
end
diff --git a/includes/init.lua b/includes/init.lua
index 4f4dddc..a529c7a 100644
--- a/includes/init.lua
+++ b/includes/init.lua
@@ -32,10 +32,6 @@ require("includes.classes.Set")
require("includes.classes.fMatrix44")
require("includes.classes.atArray")
-GPointers = require("includes.data.pointers")
-Memory = require("includes.modules.Memory")
-require("includes.modules.Game")
-
-- ### Global Runtime Variables
--
@@ -45,18 +41,18 @@ require("includes.modules.Game")
--
-- For temporary or internal state that should not be saved, use `_G` directly.
---@class GVars : Config
-GVars = {}
+GVars = {}
----------------------------------------------------------------------------------------------------
-- These services must be loaded before any class that registers with/uses them -------------------
ThreadManager = require("includes.services.ThreadManager"):init()
-GPointers:Init() -- needs ThreadManager
-Serializer = require("includes.services.Serializer"):init("ssv2", DEFAULT_CONFIG, GVars)
-
+Serializer = require("includes.services.Serializer"):init("ssv2", DEFAULT_CONFIG, GVars)
require("includes.classes.Vector2")
require("includes.classes.Vector3")
require("includes.classes.Vector4")
+GPointers = require("includes.data.pointers")
+Memory = require("includes.modules.Memory")
KeyManager = require("includes.services.KeyManager"):init()
GUI = require("includes.services.GUI"):init()
Toast = require("includes.services.ToastNotifier").new()
diff --git a/includes/lib/compat.lua b/includes/lib/compat.lua
index 180240d..85dc911 100644
--- a/includes/lib/compat.lua
+++ b/includes/lib/compat.lua
@@ -4,9 +4,9 @@
local Compat = {}
Compat.__index = Compat
----@param version integer eAPIVersion
+---@param version eAPIVersion
function Compat.SetupEnvironment(version)
- if (version == Enums.eAPIVersion.V1) then
+ if (version == Enums.eAPIVersion.V1 or version == Enums.eAPIVersion.V2) then
print = function(...)
local out = {}
@@ -53,8 +53,6 @@ function Compat.SetupEnvironment(version)
end
end
end
- elseif (version == Enums.eAPIVersion.V2) then
- error("YmMenu V2 is not supported. Please remove the script.")
elseif (version == Enums.eAPIVersion.L54) then
require("includes.lib.mock_env")
end
diff --git a/includes/lib/mock_env.lua b/includes/lib/mock_env.lua
index 4429889..96db72e 100644
--- a/includes/lib/mock_env.lua
+++ b/includes/lib/mock_env.lua
@@ -105,7 +105,7 @@ if (not memory) then
free = function(ptr) end,
handle_to_ptr = function(handle) return memory.pointer end,
ptr_to_handle = function(ptr) return 0x0 end,
- dynamic_call = function(addr, ret_type, arg_types, ...) end
+ dynamic_call = function(ret_type, arg_types, ptr) end
}
end
diff --git a/includes/lib/translations/de-DE.lua b/includes/lib/translations/de-DE.lua
index 752e6e8..4f8f81c 100644
--- a/includes/lib/translations/de-DE.lua
+++ b/includes/lib/translations/de-DE.lua
@@ -357,7 +357,7 @@ return {
["VEH_PAINT_PRIMARY_CB"] = "Als Primär",
["VEH_COBRA_MANEUVER_NOT_LEVEL"] = "Bitte nivellieren Sie zuerst Ihren Jet.",
["VEH_COBRA_MANEUVER_TOO_lOW"] = "Ihre aktuelle Höhe ist zu niedrig, um ein Cobra-Manöver durchzuführen!",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "Diese Funktion ist nur mit Pkw und Lkw kompatibel.",
+ ["GENERIC_CARS_ONLY"] = "Diese Funktion ist nur mit Pkw und Lkw kompatibel.",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "Ihre aktuelle Geschwindigkeit ist zu niedrig, um ein Cobra-Manöver durchzuführen!",
["VEH_COBRA_MANEUVER"] = "Cobra-Manöver",
["VEH_COBRA_MANEUVER_TT"] = "Drücken Sie [X] auf der Tastatur, um ein Cobra-Manöver durchzuführen. Nur für Jets verfügbar.",
@@ -489,5 +489,21 @@ return {
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Deaktivieren Sie die Abklingzeit für illegale Arbeit",
["YRV3_CWASH_LEGAL_WORK_CD"] = "Deaktivieren Sie die Abklingzeit für legale Arbeit",
["SELF_MC_BIKE_ANIMS"] = "Aktivieren Sie den MC-Fahrstil",
- ["SELF_MC_BIKE_ANIMS_TT"] = "Stellt die alternativen Fahrradfahranimationen wieder her, die aus irgendeinem Grund deaktiviert waren. Damit diese Animationen funktionieren, müssen Sie als MC registriert sein und diese Option aktiviert haben."
+ ["SELF_MC_BIKE_ANIMS_TT"] = "Stellt die alternativen Fahrradfahranimationen wieder her, die aus irgendeinem Grund deaktiviert waren. Damit diese Animationen funktionieren, müssen Sie als MC registriert sein und diese Option aktiviert haben.",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Lächerlich",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Realistisch",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Starten Sie den Kontrollmodus",
+ ["SUBTAB_STANCER"] = "Stancer",
+ ["VEH_LAUNCH_CTRL_ERR"] = "Die Startsteuerung ist derzeit nicht verfügbar. Ihr Motor ist beschädigt.",
+ ["VEH_STANCE_CAMBER"] = "Sturz",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Radgröße",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Radbreite",
+ ["VEH_STANCE_NON_STOCK"] = "Für diese Option sind nicht serienmäßige Räder erforderlich.",
+ ["VEH_STANCE_INCOMPATIBLE"] = "Diese Option ist mit dem aktuellen Fahrzeug nicht kompatibel.",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Spurbreite",
+ ["VEH_STANCE_GEN_OPTIONS"] = "Allgemeine Optionen",
+ ["VEH_STANCE_FRONT_AXLE"] = "Vorderachse",
+ ["VEH_STANCE_COPY_FB"] = "Von vorne nach hinten kopieren",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Fahrhöhe",
+ ["VEH_STANCE_REAR_AXLE"] = "Hinterachse"
}
diff --git a/includes/lib/translations/en-US.lua b/includes/lib/translations/en-US.lua
index a90723e..3845d79 100644
--- a/includes/lib/translations/en-US.lua
+++ b/includes/lib/translations/en-US.lua
@@ -11,6 +11,7 @@ return {
["SUBTAB_AIRCRAFT"] = "Aircraft",
["SUBTAB_FLATBED"] = "Flatbed Script",
["SUBTAB_HANDLING_EDITOR"] = "Handling Editor",
+ ["SUBTAB_STANCER"] = "Stancer",
["SUBTAB_GUI"] = "User Interface",
--#endregion
@@ -88,6 +89,7 @@ return {
["GENERIC_NOT_IN_VEH"] = "You are not in a vehicle.",
["GENERIC_NOT_IN_PLANE"] = "You are not in an aircraft.",
["GENERIC_NOT_IN_COMBAT"] = "You are not in combat with anyone.",
+ ["GENERIC_CARS_ONLY"] = "This feature is only compatible with cars and trucks.",
--#endregion
--#region CasinoPacino
@@ -348,6 +350,10 @@ return {
"Automatically locks your vehicle when you move away from it and unlocks it again when you try to re-enter or switch to a different vehicle.",
["VEH_LAUNCH_CTRL"] = "Launch Control",
["VEH_LAUNCH_CTRL_TT"] = "Simulates launch control. Only available for performance cars.",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Launch Control Mode",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Realistic",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Ridiculous",
+ ["VEH_LAUNCH_CTRL_ERR"] = "Launch control is unavailable at the moment. Your engine is damaged.",
["VEH_IV_EXIT"] = "IV-Style Exit",
["VEH_IV_EXIT_TT"] =
"Imitates GTA IV's vehicle exit style: Hold [F] for one second to turn off the engine or normal press to leave it running.",
@@ -399,7 +405,6 @@ return {
["VEH_SEAT_NEXT"] = "Next Seat",
["VEH_ENGINE_SWAP"] = "Engine Swap",
["VEH_ENGINE_SWAP_SAME_ERR"] = "Your vehicle already has this engine.",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "This feature is only compatible with cars and trucks.",
["VEH_PAINT_NOTE"] = "Colors look different on game shaders.",
["VEH_PAINT_FILTER_TXT"] = "Filter By: ",
["VEH_PAINT_FILTER_ALL"] = "All",
@@ -459,6 +464,17 @@ return {
["VEH_STEER_HANDBRAKE"] = "Handbrake Steering",
["VEH_STEER_HANDBRAKE_TT"] =
"Steers your vehicle's rear whels when you hold the handbrake, similar to monster cars.",
+ ["VEH_STANCE_CAMBER"] = "Camber",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Track Width",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Wheel Width",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Wheel Size",
+ ["VEH_STANCE_NON_STOCK"] = "This option requires non-stock wheels.",
+ ["VEH_STANCE_INCOMPATIBLE"] = "This option is incompatible with current vehicle.",
+ ["VEH_STANCE_FRONT_AXLE"] = "Front Axle",
+ ["VEH_STANCE_REAR_AXLE"] = "Rear Axle",
+ ["VEH_STANCE_COPY_FB"] = "Copy Front To Back",
+ ["VEH_STANCE_GEN_OPTIONS"] = "General Options",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Ride Height",
--#endregion
--#region World
diff --git a/includes/lib/translations/es-ES.lua b/includes/lib/translations/es-ES.lua
index 94c824e..5e04f5f 100644
--- a/includes/lib/translations/es-ES.lua
+++ b/includes/lib/translations/es-ES.lua
@@ -361,7 +361,7 @@ return {
["VEH_COBRA_MANEUVER_TOO_lOW"] = "¡Tu altitud actual es demasiado baja para realizar una maniobra Cobra!",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "¡Tu velocidad actual es demasiado baja para realizar una maniobra Cobra!",
["VEH_COBRA_MANEUVER"] = "Maniobra de cobra",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "Esta función sólo es compatible con automóviles y camionetas.",
+ ["GENERIC_CARS_ONLY"] = "Esta función sólo es compatible con automóviles y camionetas.",
["VEH_COBRA_MANEUVER_INTERRUPT"] = "¡La maniobra Cobra fue interrumpida! Devolver el control al jugador.",
["VEH_COBRA_MANEUVER_CANCEL"] = "Realizando maniobra de cobra. Presione [CTRL] para cancelar y recuperar el control.",
["GENERIC_REMOVE"] = "Eliminar",
@@ -489,5 +489,21 @@ return {
["YRV3_CWASH_WORK_EARNINGS"] = "Ganancias laborales:",
["YRV3_WEED_SHOP_LABEL"] = "Tienda de marihuana",
["YRV3_HELITOURS_LABEL"] = "Helitours Higgins",
- ["YRV3_CWASH_HEAT"] = "Nivel de calor:"
+ ["YRV3_CWASH_HEAT"] = "Nivel de calor:",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Realista",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Ridículo",
+ ["VEH_STANCE_CAMBER"] = "Comba",
+ ["SUBTAB_STANCER"] = "postura",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Ancho de pista",
+ ["VEH_LAUNCH_CTRL_ERR"] = "El control de lanzamiento no está disponible en este momento. Tu motor está dañado.",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Ancho de la rueda",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Modo de control de lanzamiento",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Tamaño de la rueda",
+ ["VEH_STANCE_INCOMPATIBLE"] = "Esta opción es incompatible con el vehículo actual.",
+ ["VEH_STANCE_FRONT_AXLE"] = "Eje delantero",
+ ["VEH_STANCE_NON_STOCK"] = "Esta opción requiere ruedas no originales.",
+ ["VEH_STANCE_REAR_AXLE"] = "Eje trasero",
+ ["VEH_STANCE_GEN_OPTIONS"] = "Opciones generales",
+ ["VEH_STANCE_COPY_FB"] = "Copiar de adelante hacia atrás",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Altura de manejo"
}
diff --git a/includes/lib/translations/fr-FR.lua b/includes/lib/translations/fr-FR.lua
index c5b40d1..00a4d13 100644
--- a/includes/lib/translations/fr-FR.lua
+++ b/includes/lib/translations/fr-FR.lua
@@ -362,7 +362,7 @@ return {
["VEH_COBRA_MANEUVER_TOO_lOW"] = "Votre altitude actuelle est trop basse pour effectuer une manœuvre Cobra !",
["VEH_COBRA_MANEUVER_NOT_LEVEL"] = "Veuillez d'abord mettre votre jet à niveau.",
["VEH_COBRA_MANEUVER_INTERRUPT"] = "La manœuvre Cobra a été interrompue ! Redonner le contrôle au joueur.",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "Cette fonctionnalité n'est compatible qu'avec les voitures et les camions.",
+ ["GENERIC_CARS_ONLY"] = "Cette fonctionnalité n'est compatible qu'avec les voitures et les camions.",
["VEH_COBRA_MANEUVER_CANCEL"] = "Effectuer une manœuvre de cobra. Appuyez sur [CTRL] pour annuler et reprendre le contrôle.",
["GENERIC_SAVE"] = "Sauvegarder",
["GENERIC_LOAD"] = "Charger",
@@ -489,5 +489,21 @@ return {
["YRV3_HELITOURS_LABEL"] = "Higgins Hélitours",
["YRV3_WEED_SHOP_LABEL"] = "Magasin de mauvaises herbes",
["SELF_MC_BIKE_ANIMS_TT"] = "Restaure les animations alternatives de conduite de vélo qui ont été désactivées pour une raison quelconque. Vous devez être enregistré en tant que MC et activer cette option pour que ces animations fonctionnent.",
- ["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Désactiver le temps de recharge du travail illégal"
+ ["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Désactiver le temps de recharge du travail illégal",
+ ["VEH_STANCE_CAMBER"] = "Courbure",
+ ["VEH_STANCE_REAR_AXLE"] = "Essieu arrière",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Largeur de voie",
+ ["VEH_STANCE_FRONT_AXLE"] = "Essieu avant",
+ ["SUBTAB_STANCER"] = "Stancer",
+ ["VEH_STANCE_GEN_OPTIONS"] = "Options générales",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Largeur de roue",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Taille des roues",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Réaliste",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Mode de contrôle de lancement",
+ ["VEH_STANCE_COPY_FB"] = "Copier du recto vers l'arrière",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Ridicule",
+ ["VEH_STANCE_INCOMPATIBLE"] = "Cette option est incompatible avec le véhicule actuel.",
+ ["VEH_STANCE_NON_STOCK"] = "Cette option nécessite des roues non-stock.",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Hauteur de caisse",
+ ["VEH_LAUNCH_CTRL_ERR"] = "Le contrôle de lancement n'est pas disponible pour le moment. Votre moteur est endommagé."
}
diff --git a/includes/lib/translations/it-IT.lua b/includes/lib/translations/it-IT.lua
index 8b52e89..4ff4733 100644
--- a/includes/lib/translations/it-IT.lua
+++ b/includes/lib/translations/it-IT.lua
@@ -355,7 +355,7 @@ return {
["VEH_PAINT_PRIMARY_CB"] = "Come Primario",
["VEH_PAINT_SECONDARY_CB"] = "Come secondario",
["VEH_PAINT_SAVE_TT"] = "Per salvare questo colore su un veicolo personale, vai in un negozio di moda e acquista qualcosa come una tinta per i finestrini, uno stile per la targa o altro.",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "Questa funzione è compatibile solo con auto e camion.",
+ ["GENERIC_CARS_ONLY"] = "Questa funzione è compatibile solo con auto e camion.",
["VEH_COBRA_MANEUVER_TOO_lOW"] = "La tua altitudine attuale è troppo bassa per eseguire una manovra Cobra!",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "La tua velocità attuale è troppo bassa per eseguire una manovra Cobra!",
["VEH_COBRA_MANEUVER"] = "Manovra del Cobra",
@@ -489,5 +489,21 @@ return {
["YRV3_HELITOURS_LABEL"] = "Higgins Helitour",
["YRV3_CWASH_LEGAL_WORK_CD"] = "Disabilita il tempo di recupero del lavoro legale",
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Disabilita il tempo di recupero per lavoro illegale",
- ["SELF_MC_BIKE_ANIMS_TT"] = "Ripristina le animazioni alternative di guida in bicicletta che erano state disabilitate per qualche motivo. Devi essere registrato come MC e avere questa opzione abilitata affinché queste animazioni funzionino."
+ ["SELF_MC_BIKE_ANIMS_TT"] = "Ripristina le animazioni alternative di guida in bicicletta che erano state disabilitate per qualche motivo. Devi essere registrato come MC e avere questa opzione abilitata affinché queste animazioni funzionino.",
+ ["VEH_STANCE_CAMBER"] = "Campanatura",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Larghezza ruota",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Realistico",
+ ["SUBTAB_STANCER"] = "Stancer",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Avvia la modalità di controllo",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Ridicolo",
+ ["VEH_STANCE_REAR_AXLE"] = "Asse posteriore",
+ ["VEH_STANCE_INCOMPATIBLE"] = "Questa opzione non è compatibile con il veicolo attuale.",
+ ["VEH_STANCE_GEN_OPTIONS"] = "Opzioni generali",
+ ["VEH_STANCE_FRONT_AXLE"] = "Assale anteriore",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Larghezza della traccia",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Dimensioni della ruota",
+ ["VEH_LAUNCH_CTRL_ERR"] = "Il Launch Control non è al momento disponibile. Il tuo motore è danneggiato.",
+ ["VEH_STANCE_NON_STOCK"] = "Questa opzione richiede ruote non di serie.",
+ ["VEH_STANCE_COPY_FB"] = "Copia fronte-retro",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Altezza di marcia"
}
diff --git a/includes/lib/translations/ja-JP.lua b/includes/lib/translations/ja-JP.lua
index 602fa6e..d8e9a2e 100644
--- a/includes/lib/translations/ja-JP.lua
+++ b/includes/lib/translations/ja-JP.lua
@@ -355,7 +355,7 @@ return {
["VEH_PAINT_SAVE_TT"] = "この色を個人の車両に保存するには、MODSHOP に行って、窓の色合いやプレート スタイルなどを購入します。",
["VEH_PAINT_PRIMARY_CB"] = "プライマリとして",
["VEH_PAINT_NOT_SELECTED_ERR"] = "プライマリまたはセカンダリ、あるいはその両方を選択してください。",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "この機能は乗用車とトラックのみに対応しています。",
+ ["GENERIC_CARS_ONLY"] = "この機能は乗用車とトラックのみに対応しています。",
["CP_AUTOPLAY_SLOTS_TIME_DELAY"] = "プレイ間の遅延",
["VEH_COBRA_MANEUVER_TOO_lOW"] = "現在の高度はコブラ マニューバーを実行するには低すぎます。",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "現在の速度はコブラ マニューバーを実行するには低すぎます。",
@@ -489,5 +489,21 @@ return {
["YRV3_HELITOURS_LABEL"] = "ヒギンズ・ヘリツアーズ",
["YRV3_WEED_SHOP_LABEL"] = "雑草屋",
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "違法な作業のクールダウンを無効にする",
- ["YRV3_CWASH_LEGAL_WORK_CD"] = "法務作業のクールダウンを無効にする"
+ ["YRV3_CWASH_LEGAL_WORK_CD"] = "法務作業のクールダウンを無効にする",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "現実的な",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "ばかげている",
+ ["VEH_STANCE_WHEEL_SIZE"] = "ホイールサイズ",
+ ["VEH_LAUNCH_CTRL_ERR"] = "現時点ではローンチコントロールは利用できません。エンジンが損傷しています。",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "ホイール幅",
+ ["VEH_STANCE_CAMBER"] = "キャンバー",
+ ["VEH_STANCE_NON_STOCK"] = "このオプションには非純正ホイールが必要です。",
+ ["VEH_STANCE_INCOMPATIBLE"] = "このオプションは現在の車両と互換性がありません。",
+ ["VEH_LAUNCH_CTRL_MODE"] = "ローンチコントロールモード",
+ ["VEH_STANCE_TRACK_WIDTH"] = "トラック幅",
+ ["VEH_STANCE_GEN_OPTIONS"] = "一般的なオプション",
+ ["SUBTAB_STANCER"] = "スタンサー",
+ ["VEH_STANCE_REAR_AXLE"] = "リアアクスル",
+ ["VEH_STANCE_COPY_FB"] = "前から後ろへコピー",
+ ["VEH_STANCE_FRONT_AXLE"] = "フロントアクスル",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "車高"
}
diff --git a/includes/lib/translations/ko-KR.lua b/includes/lib/translations/ko-KR.lua
index 4c0800f..5a148c0 100644
--- a/includes/lib/translations/ko-KR.lua
+++ b/includes/lib/translations/ko-KR.lua
@@ -355,7 +355,7 @@ return {
["VEH_PAINT_MATTE_TT"] = "선택한 페인트 작업에 무광택 마감을 적용하거나 제거합니다.",
["VEH_PAINT_MATTE_CB"] = "무광택 색상",
["VEH_PAINT_SAVE_TT"] = "개인 차량에 이 색상을 저장하려면 개조 상점에 가서 창문 선팅이나 플레이트 스타일 등을 구입하세요.",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "이 기능은 자동차 및 트럭에만 호환됩니다.",
+ ["GENERIC_CARS_ONLY"] = "이 기능은 자동차 및 트럭에만 호환됩니다.",
["VEH_COBRA_MANEUVER_TOO_lOW"] = "현재 고도가 너무 낮아서 Cobra Maneuver를 수행할 수 없습니다!",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "현재 속도가 너무 낮아 Cobra Maneuver를 수행할 수 없습니다!",
["CP_AUTOPLAY_SLOTS_TIME_DELAY"] = "재생 간 지연",
@@ -489,5 +489,21 @@ return {
["YRV3_HELITOURS_LABEL"] = "히긴스 헬리투어",
["SELF_MC_BIKE_ANIMS_TT"] = "어떤 이유로 비활성화된 대체 자전거 타기 애니메이션을 복원합니다. 이러한 애니메이션이 작동하려면 MC로 등록하고 이 옵션을 활성화해야 합니다.",
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "불법 작업 쿨다운 비활성화",
- ["YRV3_CWASH_LEGAL_WORK_CD"] = "법적 업무 쿨다운 비활성화"
+ ["YRV3_CWASH_LEGAL_WORK_CD"] = "법적 업무 쿨다운 비활성화",
+ ["SUBTAB_STANCER"] = "스탠서",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "현실적",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "말도 안 되는",
+ ["VEH_LAUNCH_CTRL_ERR"] = "지금은 발사 제어를 사용할 수 없습니다. 엔진이 손상되었습니다.",
+ ["VEH_STANCE_WHEEL_SIZE"] = "휠 크기",
+ ["VEH_STANCE_CAMBER"] = "캠버",
+ ["VEH_STANCE_TRACK_WIDTH"] = "트랙 폭",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "휠 폭",
+ ["VEH_LAUNCH_CTRL_MODE"] = "발사 제어 모드",
+ ["VEH_STANCE_FRONT_AXLE"] = "프론트 액슬",
+ ["VEH_STANCE_REAR_AXLE"] = "후방 차축",
+ ["VEH_STANCE_NON_STOCK"] = "이 옵션에는 재고가 없는 바퀴가 필요합니다.",
+ ["VEH_STANCE_INCOMPATIBLE"] = "이 옵션은 현재 차량과 호환되지 않습니다.",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "탑승 높이",
+ ["VEH_STANCE_GEN_OPTIONS"] = "일반 옵션",
+ ["VEH_STANCE_COPY_FB"] = "앞에서 뒤로 복사"
}
diff --git a/includes/lib/translations/pl-PL.lua b/includes/lib/translations/pl-PL.lua
index 15c11c1..e3c2b7c 100644
--- a/includes/lib/translations/pl-PL.lua
+++ b/includes/lib/translations/pl-PL.lua
@@ -355,7 +355,7 @@ return {
["VEH_PAINT_SAVE_TT"] = "Aby zapisać ten kolor w pojeździe osobistym, udaj się do modshopu i kup coś w rodzaju przyciemniacza szyb, wzoru tabliczki lub czegokolwiek innego.",
["VEH_PAINT_SECONDARY_CB"] = "Jako drugorzędne",
["VEH_PAINT_PRIMARY_CB"] = "Jako podstawowy",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "Ta funkcja jest kompatybilna tylko z samochodami osobowymi i ciężarówkami.",
+ ["GENERIC_CARS_ONLY"] = "Ta funkcja jest kompatybilna tylko z samochodami osobowymi i ciężarówkami.",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "Twoja aktualna prędkość jest zbyt niska, aby wykonać Manewr Kobry!",
["VEH_COBRA_MANEUVER_TOO_lOW"] = "Twoja aktualna wysokość jest zbyt niska, aby wykonać Manewr Kobry!",
["VEH_COBRA_MANEUVER_TT"] = "Naciśnij [X] na klawiaturze, aby wykonać Manewr Kobry. Dostępne tylko dla odrzutowców.",
@@ -489,5 +489,21 @@ return {
["YRV3_CWASH_WORK_EARNINGS"] = "Zarobki w pracy:",
["SELF_MC_BIKE_ANIMS_TT"] = "Przywraca alternatywne animacje jazdy na rowerze, które z jakiegoś powodu zostały wyłączone. Aby te animacje działały, musisz być zarejestrowany jako MC i mieć włączoną tę opcję.",
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Wyłącz czas odnowienia nielegalnej pracy",
- ["YRV3_CWASH_LEGAL_WORK_CD"] = "Wyłącz czas odnowienia legalnej pracy"
+ ["YRV3_CWASH_LEGAL_WORK_CD"] = "Wyłącz czas odnowienia legalnej pracy",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Realistyczny",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Śmieszny",
+ ["VEH_STANCE_CAMBER"] = "Wygięcie",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Uruchom tryb sterowania",
+ ["SUBTAB_STANCER"] = "Stancer",
+ ["VEH_LAUNCH_CTRL_ERR"] = "Kontrola uruchamiania jest obecnie niedostępna. Twój silnik jest uszkodzony.",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Szerokość koła",
+ ["VEH_STANCE_REAR_AXLE"] = "Tylna oś",
+ ["VEH_STANCE_COPY_FB"] = "Kopiuj od przodu do tyłu",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Szerokość ścieżki",
+ ["VEH_STANCE_NON_STOCK"] = "Ta opcja wymaga kół innych niż standardowe.",
+ ["VEH_STANCE_INCOMPATIBLE"] = "Ta opcja jest niekompatybilna z obecnym pojazdem.",
+ ["VEH_STANCE_FRONT_AXLE"] = "Oś przednia",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Wysokość jazdy",
+ ["VEH_STANCE_GEN_OPTIONS"] = "Opcje ogólne",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Rozmiar koła"
}
diff --git a/includes/lib/translations/pt-BR.lua b/includes/lib/translations/pt-BR.lua
index 17270a3..8b6e46d 100644
--- a/includes/lib/translations/pt-BR.lua
+++ b/includes/lib/translations/pt-BR.lua
@@ -358,7 +358,7 @@ return {
["VEH_COBRA_MANEUVER"] = "Manobra da Cobra",
["CP_AUTOPLAY_SLOTS_TIME_DELAY"] = "Atraso entre jogadas",
["VEH_COBRA_MANEUVER_NOT_LEVEL"] = "Nivele seu jato primeiro.",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "Este recurso é compatível apenas com carros e caminhões.",
+ ["GENERIC_CARS_ONLY"] = "Este recurso é compatível apenas com carros e caminhões.",
["VEH_COBRA_MANEUVER_CANCEL"] = "Realizando manobra de cobra. Pressione [CTRL] para cancelar e recuperar o controle.",
["VEH_COBRA_MANEUVER_INTERRUPT"] = "A Manobra Cobra foi interrompida! Devolvendo o controle ao jogador.",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "Sua velocidade atual é muito baixa para realizar uma Manobra Cobra!",
@@ -489,5 +489,21 @@ return {
["YRV3_CWASH_LEGAL_WORK_CD"] = "Desativar tempo de espera para trabalho jurídico",
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Desativar tempo de espera para trabalho ilegal",
["SELF_MC_BIKE_ANIMS_TT"] = "Restaura as animações alternativas de andar de bicicleta que foram desativadas por algum motivo. Você deve estar registrado como MC e ter esta opção habilitada para que essas animações funcionem.",
- ["SELF_MC_BIKE_ANIMS"] = "Ativar estilo de pilotagem MC"
+ ["SELF_MC_BIKE_ANIMS"] = "Ativar estilo de pilotagem MC",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Ridículo",
+ ["SUBTAB_STANCER"] = "Stancer",
+ ["VEH_STANCE_CAMBER"] = "Cambagem",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Realista",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Largura da roda",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Tamanho da roda",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Largura da trilha",
+ ["VEH_LAUNCH_CTRL_ERR"] = "O controle de lançamento não está disponível no momento. Seu motor está danificado.",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Modo de controle de inicialização",
+ ["VEH_STANCE_INCOMPATIBLE"] = "Esta opção é incompatível com o veículo atual.",
+ ["VEH_STANCE_COPY_FB"] = "Copiar da frente para trás",
+ ["VEH_STANCE_GEN_OPTIONS"] = "Opções Gerais",
+ ["VEH_STANCE_FRONT_AXLE"] = "Eixo dianteiro",
+ ["VEH_STANCE_REAR_AXLE"] = "Eixo traseiro",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Altura do passeio",
+ ["VEH_STANCE_NON_STOCK"] = "Esta opção requer rodas sem estoque."
}
diff --git a/includes/lib/translations/ru-RU.lua b/includes/lib/translations/ru-RU.lua
index 77bed12..1a2cc2c 100644
--- a/includes/lib/translations/ru-RU.lua
+++ b/includes/lib/translations/ru-RU.lua
@@ -358,7 +358,7 @@ return {
["VEH_COBRA_MANEUVER"] = "Маневр Кобры",
["CP_AUTOPLAY_SLOTS_TIME_DELAY"] = "Задержка между играми",
["VEH_COBRA_MANEUVER_TT"] = "Нажмите [X] на клавиатуре, чтобы выполнить маневр Кобры. Доступно только для самолетов.",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "Эта функция совместима только с легковыми и грузовыми автомобилями.",
+ ["GENERIC_CARS_ONLY"] = "Эта функция совместима только с легковыми и грузовыми автомобилями.",
["VEH_COBRA_MANEUVER_TOO_lOW"] = "Ваша текущая высота слишком мала для выполнения маневра Кобры!",
["VEH_COBRA_MANEUVER_TOO_SlOW"] = "Ваша текущая скорость слишком мала для выполнения маневра Кобры!",
["VEH_COBRA_MANEUVER_NOT_LEVEL"] = "Пожалуйста, сначала выровняйте свой самолет.",
@@ -489,5 +489,21 @@ return {
["SELF_MC_BIKE_ANIMS_TT"] = "Восстанавливает альтернативную анимацию езды на велосипеде, которая по какой-то причине была отключена. Чтобы эти анимации работали, вы должны быть зарегистрированы как MC и включить эту опцию.",
["YRV3_CWASH_LEGAL_WORK_CD"] = "Отключить время восстановления юридической работы",
["SELF_MC_BIKE_ANIMS"] = "Включить стиль езды MC",
- ["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Отключить время восстановления незаконной работы"
+ ["YRV3_CWASH_ILLEGAL_WORK_CD"] = "Отключить время восстановления незаконной работы",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "Нелепый",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "Реалистичный",
+ ["VEH_LAUNCH_CTRL_ERR"] = "В данный момент управление запуском недоступно. Ваш двигатель поврежден.",
+ ["SUBTAB_STANCER"] = "Стэнсер",
+ ["VEH_LAUNCH_CTRL_MODE"] = "Режим управления запуском",
+ ["VEH_STANCE_TRACK_WIDTH"] = "Ширина гусеницы",
+ ["VEH_STANCE_CAMBER"] = "Камбер",
+ ["VEH_STANCE_FRONT_AXLE"] = "Передний мост",
+ ["VEH_STANCE_INCOMPATIBLE"] = "Эта опция несовместима с текущим автомобилем.",
+ ["VEH_STANCE_GEN_OPTIONS"] = "Общие параметры",
+ ["VEH_STANCE_WHEEL_SIZE"] = "Размер колеса",
+ ["VEH_STANCE_NON_STOCK"] = "Для этого варианта требуются нестандартные колеса.",
+ ["VEH_STANCE_REAR_AXLE"] = "Задний мост",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "Ширина колеса",
+ ["VEH_STANCE_COPY_FB"] = "Копировать спереди назад",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "Высота посадки"
}
diff --git a/includes/lib/translations/zh-CN.lua b/includes/lib/translations/zh-CN.lua
index cfd0636..df80c35 100644
--- a/includes/lib/translations/zh-CN.lua
+++ b/includes/lib/translations/zh-CN.lua
@@ -356,7 +356,7 @@ return {
["VEH_PAINT_SAVE_TT"] = "要在个人车辆上保留这种颜色,请前往改装店购买诸如车窗贴膜或板式或任何东西之类的东西。",
["VEH_PAINT_NOT_SELECTED_ERR"] = "请选择小学或中学或两者兼而有之。",
["CP_AUTOPLAY_SLOTS_TIME_DELAY"] = "比赛之间的延迟",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "此功能仅与汽车和卡车兼容。",
+ ["GENERIC_CARS_ONLY"] = "此功能仅与汽车和卡车兼容。",
["VEH_COBRA_MANEUVER"] = "眼镜蛇机动",
["VEH_COBRA_MANEUVER_TT"] = "按键盘上的 [X] 执行眼镜蛇机动。仅适用于喷气式飞机。",
["VEH_COBRA_MANEUVER_TOO_lOW"] = "您当前的海拔太低,无法执行眼镜蛇机动!",
@@ -489,5 +489,21 @@ return {
["YRV3_CWASH_LEGAL_WORK_CD"] = "禁用法律工作冷却",
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "禁用非法工作冷却",
["SELF_MC_BIKE_ANIMS_TT"] = "恢复由于某种原因禁用的备用自行车骑行动画。您必须注册为 MC 并启用此选项才能使这些动画正常工作。",
- ["SELF_MC_BIKE_ANIMS"] = "启用 MC 骑行风格"
+ ["SELF_MC_BIKE_ANIMS"] = "启用 MC 骑行风格",
+ ["SUBTAB_STANCER"] = "斯坦瑟",
+ ["VEH_LAUNCH_CTRL_MODE"] = "发射控制模式",
+ ["VEH_STANCE_CAMBER"] = "外倾角",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "实际的",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "荒谬的",
+ ["VEH_LAUNCH_CTRL_ERR"] = "目前无法使用启动控制。你的发动机损坏了。",
+ ["VEH_STANCE_TRACK_WIDTH"] = "轨道宽度",
+ ["VEH_STANCE_NON_STOCK"] = "此选项需要非库存车轮。",
+ ["VEH_STANCE_WHEEL_SIZE"] = "车轮尺寸",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "轮宽",
+ ["VEH_STANCE_FRONT_AXLE"] = "前轴",
+ ["VEH_STANCE_REAR_AXLE"] = "后桥",
+ ["VEH_STANCE_COPY_FB"] = "从前到后复印",
+ ["VEH_STANCE_GEN_OPTIONS"] = "一般选项",
+ ["VEH_STANCE_INCOMPATIBLE"] = "此选项与当前车辆不兼容。",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "行驶高度"
}
diff --git a/includes/lib/translations/zh-TW.lua b/includes/lib/translations/zh-TW.lua
index 1a3bf80..dbd57b5 100644
--- a/includes/lib/translations/zh-TW.lua
+++ b/includes/lib/translations/zh-TW.lua
@@ -355,7 +355,7 @@ return {
["VEH_PAINT_NOT_SELECTED_ERR"] = "請選擇小學或中學或兩者兼而有之。",
["VEH_PAINT_SECONDARY_CB"] = "作為次要",
["VEH_PAINT_SAVE_TT"] = "要在個人車輛上保留這種顏色,請前往改裝店購買諸如車窗貼膜或板式或任何東西之類的東西。",
- ["VEH_ENGINE_SWAP_INCOMPATIBE"] = "此功能僅與汽車和卡車兼容。",
+ ["GENERIC_CARS_ONLY"] = "此功能僅與汽車和卡車兼容。",
["VEH_COBRA_MANEUVER_TT"] = "按鍵盤上的 [X] 執行眼鏡蛇機動。僅適用於噴氣式飛機。",
["VEH_COBRA_MANEUVER"] = "眼鏡蛇機動",
["CP_AUTOPLAY_SLOTS_TIME_DELAY"] = "比賽之間的延遲",
@@ -489,5 +489,21 @@ return {
["SELF_MC_BIKE_ANIMS"] = "啟用 MC 騎行風格",
["YRV3_CWASH_LEGAL_WORK_CD"] = "禁用法律工作冷卻",
["YRV3_CWASH_ILLEGAL_WORK_CD"] = "禁用非法工作冷卻",
- ["SELF_MC_BIKE_ANIMS_TT"] = "恢復由於某種原因禁用的備用自行車騎行動畫。您必須註冊為 MC 並啟用此選項才能使這些動畫正常工作。"
+ ["SELF_MC_BIKE_ANIMS_TT"] = "恢復由於某種原因禁用的備用自行車騎行動畫。您必須註冊為 MC 並啟用此選項才能使這些動畫正常工作。",
+ ["VEH_LAUNCH_CTRL_MODE"] = "發射控制模式",
+ ["SUBTAB_STANCER"] = "斯坦瑟",
+ ["VEH_LAUNCH_CTRL_REALISTIC"] = "實際的",
+ ["VEH_LAUNCH_CTRL_RIDICULOUS"] = "荒謬的",
+ ["VEH_STANCE_CAMBER"] = "外傾角",
+ ["VEH_STANCE_WHEEL_SIZE"] = "車輪尺寸",
+ ["VEH_LAUNCH_CTRL_ERR"] = "目前無法使用啟動控制。你的發動機損壞了。",
+ ["VEH_STANCE_TRACK_WIDTH"] = "軌道寬度",
+ ["VEH_STANCE_FRONT_AXLE"] = "前軸",
+ ["VEH_STANCE_WHEEL_WIDTH"] = "輪寬",
+ ["VEH_STANCE_INCOMPATIBLE"] = "此選項與當前車輛不兼容。",
+ ["VEH_STANCE_NON_STOCK"] = "此選項需要非庫存車輪。",
+ ["VEH_STANCE_REAR_AXLE"] = "後橋",
+ ["VEH_STANCE_RIDE_HEIGHT"] = "行駛高度",
+ ["VEH_STANCE_COPY_FB"] = "從前到後復印",
+ ["VEH_STANCE_GEN_OPTIONS"] = "一般選項"
}
diff --git a/includes/lib/types.lua b/includes/lib/types.lua
index ca0972f..7954885 100644
--- a/includes/lib/types.lua
+++ b/includes/lib/types.lua
@@ -68,5 +68,5 @@ GenericClass = setmetatable({}, {
---@alias Comparator fun(a: A, b: B): boolean
-- A poor man's `nullptr` 🥲
----@class NULLPTR : pointer
-NULLPTR = memory.pointer:new(0)
+---@class nullptr : pointer
+nullptr = memory.pointer:new(0)
diff --git a/includes/modules/Accessor.lua b/includes/modules/Accessor.lua
index e3752d9..c8a4cf3 100644
--- a/includes/modules/Accessor.lua
+++ b/includes/modules/Accessor.lua
@@ -170,7 +170,7 @@ function Accessor:GetPointer()
return locals.get_pointer(self.m_script, self:GetIndex())
end
- return NULLPTR
+ return nullptr
end
---------------------------
diff --git a/includes/modules/Bodyguard.lua b/includes/modules/Bodyguard.lua
index cabc2a1..74d99c5 100644
--- a/includes/modules/Bodyguard.lua
+++ b/includes/modules/Bodyguard.lua
@@ -1387,7 +1387,7 @@ end
function EscortVehicle:Recover(lastCoords, passengers, lastHeading, groupName)
if self:Exists() then
Game.DeleteEntity(self.handle)
- Decorator:RemoveEntity(self.handle, "BillionaireServices")
+ Decorator:RemoveEntity(self.handle)
end
if not lastCoords then
@@ -1400,7 +1400,7 @@ function EscortVehicle:Recover(lastCoords, passengers, lastHeading, groupName)
end
self.handle = Game.CreateVehicle(self.model, vec3:zero())
- Decorator:RegisterEntity(self.handle, "BillionaireServices")
+ Decorator:Register(self.handle, "BillionaireServices")
ENTITY.FREEZE_ENTITY_POSITION(self.handle, true)
local r, g, b, _ = Color("#000100"):AsRGBA()
diff --git a/includes/modules/Decorator.lua b/includes/modules/Decorator.lua
index ab38c0d..80e63ce 100644
--- a/includes/modules/Decorator.lua
+++ b/includes/modules/Decorator.lua
@@ -5,48 +5,69 @@
--
-- Custom decorator to mark entities owned by this script.
---@class Decorator
-Decorator = {}
+---@field RegisteredEntities table>
+---@field private m_last_gc seconds
+Decorator = { m_last_gc = 0 }
Decorator.RegisteredEntities = {}
---@param entity integer
----@param key string
-function Decorator:IsEntityRegistered(entity, key)
- return self.RegisteredEntities[entity]
- and self.RegisteredEntities[entity].key
- and self.RegisteredEntities[entity].key == key
+function Decorator:IsEntityRegistered(entity)
+ return self.RegisteredEntities[entity] ~= nil
end
---@param entity integer
---@param key string
----@param expectedValue any
-function Decorator:ExistsOn(entity, key, expectedValue)
- if not self:IsEntityRegistered(entity, key) then
+---@return boolean
+function Decorator:ExistsOn(entity, key)
+ if (not self:IsEntityRegistered(entity)) then
return false
end
- return self.RegisteredEntities[entity].value
- and self.RegisteredEntities[entity].value == expectedValue
+ return self.RegisteredEntities[entity][key] and self.RegisteredEntities[entity][key] ~= nil
end
----@param entity integer
+---@param entity handle
---@param key string
----@param value any
-function Decorator:RegisterEntity(entity, key, value)
- if self:IsEntityRegistered(entity, key) then
+---@return any
+function Decorator:GetDecor(entity, key)
+ if (not self:ExistsOn(entity, key)) then
return
end
- self.RegisteredEntities[entity] = {
- handle = entity,
- key = key,
- value = value
- }
+ return self.RegisteredEntities[entity][key]
+end
+
+---@param entity handle
+---@param key string
+---@param new_value anyval
+---@return any
+function Decorator:UpdateDecor(entity, key, new_value)
+ if (not self:ExistsOn(entity, key)) then
+ return
+ end
+
+ self.RegisteredEntities[entity][key] = new_value
end
---@param entity integer
---@param key string
-function Decorator:RemoveEntity(entity, key)
- if not self:IsEntityRegistered(entity, key) then
+---@param value any
+function Decorator:Register(entity, key, value)
+ local existing = self.RegisteredEntities[entity]
+ if (existing) then
+ if (existing[key]) then
+ return
+ end
+
+ existing[key] = value
+ else
+ self.RegisteredEntities[entity] = { [key] = value }
+ end
+end
+
+---@param entity integer
+function Decorator:RemoveEntity(entity)
+ if not self:IsEntityRegistered(entity) then
return
end
@@ -54,9 +75,22 @@ function Decorator:RemoveEntity(entity, key)
end
---@param entity integer
--- only bool decorators for now
function Decorator:Validate(entity)
- return ENTITY.DOES_ENTITY_EXIST(entity) and (self.RegisteredEntities[entity] ~= nil)
+ return self:IsEntityRegistered(entity) and ENTITY.DOES_ENTITY_EXIST(entity)
+end
+
+function Decorator:CollectGarbage()
+ if (Time.now() - self.m_last_gc < 5) then
+ return
+ end
+
+ for handle, _ in pairs(self.RegisteredEntities) do
+ if (not ENTITY.DOES_ENTITY_EXIST(handle)) then
+ self.RegisteredEntities[handle] = nil
+ end
+ end
+
+ self.m_last_gc = Time.now()
end
---@param entity integer
@@ -72,10 +106,9 @@ function Decorator:DebugDump(entity)
Backend:debug(
_F(
- "[%s] is registered to %s as %s",
+ "[%s] is registered with: %s",
entity,
- self.RegisteredEntities[entity].key,
- self.RegisteredEntities[entity].value
+ self.RegisteredEntities[entity]
)
)
end
diff --git a/includes/modules/Entity.lua b/includes/modules/Entity.lua
index f98f3e8..31b9617 100644
--- a/includes/modules/Entity.lua
+++ b/includes/modules/Entity.lua
@@ -162,15 +162,14 @@ function Entity:GetModelHash()
return self.m_modelhash
end
----@return pointer|nil
+---@return pointer
function Entity:GetPointer()
if not self.m_ptr then
local handle = self:GetHandle()
local ptr = memory.handle_to_ptr(handle)
- if not ptr:is_valid() then
- log.fwarning("Failed to get pointer for entity with handle %d", handle)
- return
+ if (not ptr:is_valid()) then
+ error("Invalid entity.")
end
self.m_ptr = ptr
diff --git a/includes/modules/Memory.lua b/includes/modules/Memory.lua
index ff0ff84..c73cb9f 100644
--- a/includes/modules/Memory.lua
+++ b/includes/modules/Memory.lua
@@ -310,5 +310,6 @@ function Memory:SetWeaponEffectGroup(dword)
end
--]]
+require("includes.modules.Game")
-- inline
return Memory()
diff --git a/includes/modules/PlayerVehicle.lua b/includes/modules/PlayerVehicle.lua
index b29b474..2f31eeb 100644
--- a/includes/modules/PlayerVehicle.lua
+++ b/includes/modules/PlayerVehicle.lua
@@ -16,6 +16,7 @@ local VehMines = require("includes.features.vehicle.mines")
local MiscVehicle = require("includes.features.vehicle.misc_vehicle")
local CobraManeuver = require("includes.features.vehicle.cobra_maneuver")
local HandlingEditor = require("includes.structs.HandlingEditor")
+local Stancer = require("includes.features.vehicle.stancer")
---@class GenericToggleable
---@field is_toggled boolean
@@ -47,6 +48,7 @@ local HandlingEditor = require("includes.structs.HandlingEditor")
---@field public m_engine_swap_compatible boolean
---@field public m_is_shooting_flares boolean
---@field public m_is_flatbed boolean cache it so we don't have to call natives in UI threads
+---@field public m_stance_mgr Stancer
---@overload fun(handle: handle): PlayerVehicle
local PlayerVehicle = Class("PlayerVehicle", Vehicle)
@@ -90,10 +92,11 @@ function PlayerVehicle:AddFeature(feat)
end
function PlayerVehicle:InitFeatures()
- self.m_feat_mgr = FeatureMgr.new(self)
- self.m_lctrl_mgr = self.m_feat_mgr:Add(LaunchControlMgr.new(self))
- self.m_nos_mgr = self.m_feat_mgr:Add(NosMgr.new(self))
- self.m_abs_mgr = self.m_feat_mgr:Add(BFD.new(self))
+ self.m_feat_mgr = FeatureMgr.new(self)
+ self.m_lctrl_mgr = self.m_feat_mgr:Add(LaunchControlMgr.new(self))
+ self.m_nos_mgr = self.m_feat_mgr:Add(NosMgr.new(self))
+ self.m_abs_mgr = self.m_feat_mgr:Add(BFD.new(self))
+ self.m_stance_mgr = self.m_feat_mgr:Add(Stancer.new(self))
self.m_feat_mgr:Add(FlappyDoors.new(self))
self.m_feat_mgr:Add(DriftMode.new(self))
@@ -181,16 +184,22 @@ function PlayerVehicle:Set(handle)
self.m_autopilot.eligible = self:IsAircraft()
self.m_handling_editor:Apply()
+ if (GVars.features.vehicle.no_turbulence and VEHICLE.IS_THIS_MODEL_A_PLANE(new_model)) then
+ VEHICLE.SET_PLANE_TURBULENCE_MULTIPLIER(handle, 0.0)
+ end
+
+ self.m_stance_mgr:ReadDefaults()
-- self:ResumeThreads()
-- self.m_feat_mgr:OnEnable()
end
function PlayerVehicle:Reset()
- -- self.m_feat_mgr:OnDisable()
-- self:SuspendThreads()
- if (self:IsLocked()) then
+ -- self.m_feat_mgr:Cleanup()
+ if (self:IsValid() and self:IsLocked()) then
VEHICLE.SET_VEHICLE_DOORS_LOCKED(self:GetHandle(), 1)
self.m_generic_toggleables["autolockdoors"] = nil
+ self.m_last_model = self:GetModelHash()
end
self:RestoreHeadlights()
@@ -199,13 +208,14 @@ function PlayerVehicle:Reset()
self:RestoreAllPatches()
self:ResetAllGenericToggleables()
self.m_handling_editor:Reset()
+ self.m_stance_mgr:Cleanup()
self.m_autopilot = {
eligible = false,
state = self.eAutoPilotState.NONE,
initial_nozzle_pos = 1,
}
- self.m_last_model = self:GetModelHash()
+
self:Destroy()
self.m_handle = 0
end
@@ -281,11 +291,11 @@ function PlayerVehicle:ResetAllGenericToggleables()
return
end
- for name, generic in pairs(self.m_generic_toggleables) do
+ for _, generic in pairs(self.m_generic_toggleables) do
local toggled = generic.is_toggled
local func = generic.onDisable
local args = generic.args
- if (toggled and type(generic.onDisable) == "function") then
+ if (toggled and type(generic.onDisable) == "function" and self:IsValid()) then
func(table.unpack(args))
end
end
@@ -442,13 +452,15 @@ function PlayerVehicle:AutolockDoors()
end
---@param gvarKey string
-function PlayerVehicle:SetVehicleFlag(gvarKey, toggle)
+---@param toggle boolean
+---@param reset? boolean
+function PlayerVehicle:SetVehicleFlag(gvarKey, toggle, reset)
local obj = self.m_handling_editor:GetFlagObject(gvarKey)
if (not obj) then
return
end
- self.m_handling_editor:SetFlag(obj, toggle)
+ self.m_handling_editor:SetFlag(obj, toggle, reset)
table.set_nested_key(GVars, gvarKey, toggle)
end
@@ -609,7 +621,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.no_engine_brake", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.no_engine_brake", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.no_engine_brake", false, true)
end,
},
["features.vehicle.kers_boost"] = {
@@ -638,7 +650,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.kers_boost", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.kers_boost", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.kers_boost", false, true)
end,
},
["features.vehicle.offroad_abilities"] = {
@@ -653,7 +665,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.offroad_abilities", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.offroad_abilities", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.offroad_abilities", false, true)
end,
},
["features.vehicle.rallye_tyres"] = {
@@ -683,7 +695,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.no_traction_control", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.no_traction_control", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.no_traction_control", false, true)
end,
},
["features.vehicle.low_speed_wheelies"] = {
@@ -698,7 +710,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.low_speed_wheelies", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.low_speed_wheelies", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.low_speed_wheelies", false, true)
end,
},
["features.vehicle.rocket_boost"] = {
@@ -717,7 +729,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.rocket_boost", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.rocket_boost", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.rocket_boost", false, true)
end,
cb_label = "VEH_ROCKET_BOOST",
cb_tt = "VEH_ROCKET_BOOST_TT",
@@ -746,7 +758,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.jump_capability", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.jump_capability", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.jump_capability", false, true)
end,
cb_label = "VEH_JUMP",
cb_tt = "VEH_JUMP_TT",
@@ -761,7 +773,7 @@ PlayerVehicle.m_flag_registry = {
Self:GetVehicle():SetVehicleFlag("features.vehicle.parachute", true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.parachute", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.parachute", false, true)
end,
cb_label = "VEH_PARACHUTE",
cb_tt = "VEH_PARACHUTE_TT",
@@ -775,11 +787,11 @@ PlayerVehicle.m_flag_registry = {
on_cb_enable = function()
local PV = Self:GetVehicle()
PV:SetVehicleFlag("features.vehicle.steer_rear_wheels", true)
- PV:SetVehicleFlag("features.vehicle.steer_all_wheels", false)
- PV:SetVehicleFlag("features.vehicle.steer_handbrake", false)
+ PV:SetVehicleFlag("features.vehicle.steer_all_wheels", false, true)
+ PV:SetVehicleFlag("features.vehicle.steer_handbrake", false, true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.steer_rear_wheels", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.steer_rear_wheels", false, true)
end,
cb_label = "VEH_STEER_REAR_WHEELS",
},
@@ -792,11 +804,11 @@ PlayerVehicle.m_flag_registry = {
on_cb_enable = function()
local PV = Self:GetVehicle()
PV:SetVehicleFlag("features.vehicle.steer_all_wheels", true)
- PV:SetVehicleFlag("features.vehicle.steer_rear_wheels", false)
- PV:SetVehicleFlag("features.vehicle.steer_handbrake", false)
+ PV:SetVehicleFlag("features.vehicle.steer_rear_wheels", false, true)
+ PV:SetVehicleFlag("features.vehicle.steer_handbrake", false, true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.steer_all_wheels", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.steer_all_wheels", false, true)
end,
cb_label = "VEH_STEER_ALL_WHEELS",
},
@@ -809,11 +821,11 @@ PlayerVehicle.m_flag_registry = {
on_cb_enable = function()
local PV = Self:GetVehicle()
PV:SetVehicleFlag("features.vehicle.steer_handbrake", true)
- PV:SetVehicleFlag("features.vehicle.steer_rear_wheels", false)
- PV:SetVehicleFlag("features.vehicle.steer_all_wheels", false)
+ PV:SetVehicleFlag("features.vehicle.steer_rear_wheels", false, true)
+ PV:SetVehicleFlag("features.vehicle.steer_all_wheels", false, true)
end,
on_cb_disable = function()
- Self:GetVehicle():SetVehicleFlag("features.vehicle.steer_handbrake", false)
+ Self:GetVehicle():SetVehicleFlag("features.vehicle.steer_handbrake", false, true)
end,
cb_label = "VEH_STEER_HANDBRAKE",
cb_tt = "VEH_STEER_HANDBRAKE_TT",
diff --git a/includes/modules/PrivateHeli.lua b/includes/modules/PrivateHeli.lua
index 5274b21..4eea53f 100644
--- a/includes/modules/PrivateHeli.lua
+++ b/includes/modules/PrivateHeli.lua
@@ -355,8 +355,8 @@ end
function PrivateHeli:Cleanup()
Game.DeleteEntity(self.pilot)
Game.DeleteEntity(self.m_handle)
- Decorator:RemoveEntity(self.pilot, "BillionaireServices")
- Decorator:RemoveEntity(self.m_handle, "BillionaireServices")
+ Decorator:RemoveEntity(self.pilot)
+ Decorator:RemoveEntity(self.m_handle)
self.pilot = nil
self.m_handle = nil
diff --git a/includes/modules/PrivateJet.lua b/includes/modules/PrivateJet.lua
index 9d63d6c..77afc5b 100644
--- a/includes/modules/PrivateJet.lua
+++ b/includes/modules/PrivateJet.lua
@@ -539,9 +539,9 @@ function PrivateJet:Cleanup()
Game.DeleteEntity(self.pilot)
Game.DeleteEntity(self.copilot)
Game.DeleteEntity(self.m_handle)
- Decorator:RemoveEntity(self.pilot, "BillionaireServices")
- Decorator:RemoveEntity(self.copilot, "BillionaireServices")
- Decorator:RemoveEntity(self.m_handle, "BillionaireServices")
+ Decorator:RemoveEntity(self.pilot)
+ Decorator:RemoveEntity(self.copilot)
+ Decorator:RemoveEntity(self.m_handle)
self.pilot = nil
self.copilot = nil
diff --git a/includes/modules/Self.lua b/includes/modules/Self.lua
index 09e2f1e..00eed3d 100644
--- a/includes/modules/Self.lua
+++ b/includes/modules/Self.lua
@@ -238,7 +238,7 @@ end
function Self:IsPedMyEnemy(pedHandle)
local ped = Ped(pedHandle)
- if not ped:IsValid() then
+ if (not ped or not ped:IsValid()) then
return false
end
@@ -463,7 +463,7 @@ ThreadManager:RegisterLooped("SS_PV_HANDLER", function()
Self.m_vehicle:Set(Self:GetVehicleNative())
end
- if (Self.m_vehicle:GetHandle() ~= 0 and Self.m_vehicle:IsAnyThreadRunning() and not Self.m_vehicle:IsValid()) then
+ if (Self.m_vehicle:GetHandle() ~= 0 and not Self.m_vehicle:IsValid()) then
Self.m_vehicle:Reset()
sleep(1000)
end
diff --git a/includes/modules/Vehicle.lua b/includes/modules/Vehicle.lua
index 85cb261..91ca8a7 100644
--- a/includes/modules/Vehicle.lua
+++ b/includes/modules/Vehicle.lua
@@ -32,6 +32,7 @@ local collisionInvalidModels = Set.new(
---@field private m_num_seats number
---@field private m_max_passengers number
---@field private m_has_loud_radio boolean
+---@field private m_last_ram_time seconds
---@field Resolve fun() : CVehicle
---@field Create fun(_, modelHash: joaat_t, entityType: eEntityType, pos?: vec3, heading?: number, isNetwork?: boolean, isScriptHostPed?: boolean): Vehicle
---@overload fun(handle: handle): Vehicle
@@ -373,6 +374,24 @@ function Vehicle:HasLandingGear()
return VEHICLE.GET_VEHICLE_HAS_LANDING_GEAR(self:GetHandle())
end
+---@return boolean
+function Vehicle:HasCustomTyres()
+ if (not self:IsValid()) then
+ return false
+ end
+
+ return VEHICLE.GET_VEHICLE_MOD_VARIATION(self:GetHandle(), 23) ~= 0
+end
+
+---@return boolean
+function Vehicle:HasWheelDrawData()
+ if (not self:IsValid()) then
+ return false
+ end
+
+ return self:Resolve():HasWheelDrawData()
+end
+
function Vehicle:HasCrashed()
if (not self:HasCollidedWithAnything()) then
return false, ""
@@ -497,21 +516,68 @@ function Vehicle:IsElectric()
end
-- Returns whether the vehicle is an F1 race car.
+---@return boolean
function Vehicle:IsFormulaOne()
return self:GetModelInfoFlag(Enums.eVehicleModelInfoFlags.IS_FORMULA_VEHICLE)
or (self:GetClassID() == Enums.eVehicleClasses.OpenWheel)
end
-- Returns whether the vehicle is a lowrider equipped with hydraulic suspension.
+---@return boolean
function Vehicle:IsLowrider()
return self:GetModelInfoFlag(Enums.eVehicleModelInfoFlags.HAS_LOWRIDER_HYDRAULICS)
or self:GetModelInfoFlag(Enums.eVehicleModelInfoFlags.HAS_LOWRIDER_DONK_HYDRAULICS)
end
+---@return boolean
function Vehicle:IsLocked()
return VEHICLE.GET_VEHICLE_DOOR_LOCK_STATUS(self:GetHandle()) > 1
end
+---@param wheelIndex integer
+---@return boolean
+function Vehicle:IsWheelBrokenOff(wheelIndex)
+ if (not self:IsValid()) then
+ return false
+ end
+
+ local numWheels = self:GetNumberOfWheels()
+ if (wheelIndex > numWheels) then
+ Backend:debug("Wheel index out of bounds.")
+ return false
+ end
+
+ return self:Resolve():IsWheelBrokenOff(wheelIndex)
+end
+
+---@return float -- Wheel width or 0.f if invalid
+function Vehicle:GetWheelWidth()
+ return self:Resolve():GetWheelWidth()
+end
+
+---@return float -- Wheel size or 0.f if invalid
+function Vehicle:GetWheelSize()
+ return self:Resolve():GetWheelSize()
+end
+
+---@param fValue float
+function Vehicle:SetVisualWheelWidth(fValue)
+ if (not self:HasWheelDrawData()) then
+ return
+ end
+
+ self:Resolve():SetWheelWidth(fValue)
+end
+
+---@param fValue float
+function Vehicle:SetVisualWheelSize(fValue)
+ if (not self:HasWheelDrawData()) then
+ return
+ end
+
+ self:Resolve():SetWheelSize(fValue)
+end
+
function Vehicle:ClearPrimaryTask()
TASK.CLEAR_PRIMARY_VEHICLE_TASK(self:GetHandle())
end
@@ -1190,7 +1256,7 @@ end
---@param flag eVehicleAdvancedFlags
---@return boolean
function Vehicle:GetAdvancedFlag(flag)
- if not self:IsValid() then
+ if (not self:IsValid() or not self:IsCar()) then
return false
end
@@ -1201,13 +1267,23 @@ end
---@param flag eVehicleAdvancedFlags
---@param toggle boolean
function Vehicle:SetAdvancedFlag(flag, toggle)
- if not self:IsValid() then
+ if (not self:IsValid() or not self:IsCar()) then
return
end
self:Resolve():SetAdvancedFlag(flag, toggle)
end
+---@param fHeight float positive = lower, negative = higher. should use values between `-0.1` and `0.1`
+function Vehicle:SetRideHeight(fHeight)
+ if (not self:IsValid()) then
+ return
+ end
+
+ -- should probably start sanitizing values before writing to memory
+ self:Resolve():SetRideHeight(fHeight)
+end
+
---@param bone_index number
---@return fMatrix44
function Vehicle:GetBoneMatrix(bone_index)
@@ -1245,10 +1321,20 @@ function Vehicle:GetHandlingData()
return self:Resolve():GetSubHandlingData(handlingType)
end
+---@return integer
function Vehicle:GetMaxPassengers()
return VEHICLE.GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(self:GetHandle())
end
+---@return integer
+function Vehicle:GetNumberOfWheels()
+ if (not self:IsValid()) then
+ return 0
+ end
+
+ return self:Resolve().m_num_wheels
+end
+
---@param seatIndex integer
---@param atGetIn? boolean
---@return handle
@@ -1417,6 +1503,95 @@ function Vehicle:Wander(opts)
)
end
+function Vehicle:RamForward()
+ if not self:IsValid()
+ or not self:IsCar()
+ or not VEHICLE.IS_VEHICLE_ON_ALL_WHEELS(self:GetHandle())
+ then
+ return
+ end
+
+ ThreadManager:Run(function()
+ self.m_last_ram_time = self.m_last_ram_time or 0
+ if (Time.now() - self.m_last_ram_time < 3) then
+ return
+ end
+
+ local last_speed = self:GetSpeed()
+ ENTITY.APPLY_FORCE_TO_ENTITY_CENTER_OF_MASS(
+ self:GetHandle(),
+ 1,
+ 0.0,
+ math.min(1e5, self:GetSpeed() * 3e3),
+ 0.0,
+ false,
+ true,
+ false,
+ false
+ )
+
+ sleep(500)
+ VEHICLE.SET_VEHICLE_FORWARD_SPEED(self:GetHandle(), last_speed)
+ self.m_last_ram_time = Time.now()
+ end)
+end
+
+function Vehicle:RamLeft()
+ if not self:IsValid()
+ or not self:IsCar()
+ or not VEHICLE.IS_VEHICLE_ON_ALL_WHEELS(self:GetHandle())
+ then
+ return
+ end
+
+ self.m_last_ram_time = self.m_last_ram_time or 0
+ if (Time.now() - self.m_last_ram_time < 3) then
+ return
+ end
+
+ ENTITY.APPLY_FORCE_TO_ENTITY_CENTER_OF_MASS(
+ self:GetHandle(),
+ 1,
+ -math.min(1e5, self:GetSpeed() * 3e3),
+ 0.0,
+ 0.0,
+ false,
+ true,
+ false,
+ false
+ )
+
+ self.m_last_ram_time = Time.now()
+end
+
+function Vehicle:RamRight()
+ if not self:IsValid()
+ or not self:IsCar()
+ or not VEHICLE.IS_VEHICLE_ON_ALL_WHEELS(self:GetHandle())
+ then
+ return
+ end
+
+ self.m_last_ram_time = self.m_last_ram_time or 0
+ if (Time.now() - self.m_last_ram_time < 3) then
+ return
+ end
+
+ ENTITY.APPLY_FORCE_TO_ENTITY_CENTER_OF_MASS(
+ self:GetHandle(),
+ 1,
+ math.min(1e5, self:GetSpeed() * 3e3),
+ 0.0,
+ 0.0,
+ false,
+ true,
+ false,
+ false
+ )
+
+ self.m_last_ram_time = Time.now()
+end
+
-- Serializes a vehicle to JSON.
--
-- If a file name isn't provided, the vehicle's name will be used.
diff --git a/includes/services/CompanionManager.lua b/includes/services/CompanionManager.lua
index 182bbdf..6f6eb57 100644
--- a/includes/services/CompanionManager.lua
+++ b/includes/services/CompanionManager.lua
@@ -47,12 +47,12 @@ end
---@param entity integer
function CompanionManager:RegisterEntity(entity)
- Decorator:RegisterEntity(entity, "YimActions", true)
+ Decorator:Register(entity, "YimActions")
end
---@param entity integer
function CompanionManager:UnregisterEntity(entity)
- Decorator:RemoveEntity(entity, "YimActions")
+ Decorator:RemoveEntity(entity)
end
---@param pedModel hash|string
diff --git a/includes/services/GUI.lua b/includes/services/GUI.lua
index f39b96c..76453fa 100644
--- a/includes/services/GUI.lua
+++ b/includes/services/GUI.lua
@@ -329,35 +329,35 @@ end
function GUI:DrawDummyTab()
ImGui.SetNextWindowBgAlpha(0)
+ ImGui.BeginChild("##clock", 480, 400)
DrawClock()
ImGui.Dummy(1, 10)
ImGui.SetWindowFontScale(1.2)
ImGui.SeparatorText(_T("GENERIC_IMPORTANT"))
ImGui.SetWindowFontScale(1.0)
- ImGui.Text(_F(_T("GUI_NEW_LAYOUT_NOTICE"), GVars.keyboard_keybinds.gui_toggle))
+ ImGui.TextWrapped(_F(_T("GUI_NEW_LAYOUT_NOTICE"), GVars.keyboard_keybinds.gui_toggle))
ImGui.Spacing()
- ImGui.Separator()
+ ImGui.EndChild()
ImGui.SetNextWindowBgAlpha(0)
- if ImGui.BeginChild("##footer", -1, 40, false) then
- ImGui.Spacing()
- ImGui.TextDisabled(("v%s"):format(Backend.__version))
- if (self:IsItemClicked(self.MouseButtons.LEFT)) then
- debug_counter = debug_counter + 1
-
- if (debug_counter == 7) then
- self:PlaySound(GUI.Sounds.Nav)
- log.debug("Debug mode activated.")
- GVars.backend.debug_mode = true
- elseif (debug_counter > 7) then
- self:PlaySound(GUI.Sounds.Cancel)
- log.debug("Debug mode deactivated.")
- GVars.backend.debug_mode = false
- debug_counter = 0
- end
+ ImGui.BeginChild("##footer", 480, 40)
+ ImGui.Separator()
+ ImGui.TextDisabled(("v%s"):format(Backend.__version))
+ if (self:IsItemClicked(self.MouseButtons.LEFT)) then
+ debug_counter = debug_counter + 1
+
+ if (debug_counter == 7) then
+ self:PlaySound(GUI.Sounds.Nav)
+ log.debug("Debug mode activated.")
+ GVars.backend.debug_mode = true
+ elseif (debug_counter > 7) then
+ self:PlaySound(GUI.Sounds.Cancel)
+ log.debug("Debug mode deactivated.")
+ GVars.backend.debug_mode = false
+ debug_counter = 0
end
- ImGui.EndChild()
end
+ ImGui.EndChild()
end
local underlineX = 0.0
@@ -519,8 +519,8 @@ function GUI:DrawSideBar(yPos)
end
end
end
+ ImGui.End()
end
- ImGui.End()
ThemeManager:PopTheme()
self.m_is_drawing_sidebar = true
elseif (ctabsCount == 1) then
diff --git a/includes/services/ThreadManager.lua b/includes/services/ThreadManager.lua
index 87fcc40..5130f18 100644
--- a/includes/services/ThreadManager.lua
+++ b/includes/services/ThreadManager.lua
@@ -282,11 +282,16 @@ function ThreadManager:init()
},
[Enums.eAPIVersion.V2] = {
dispatch = function(callback)
- ---@diagnostic disable-next-line: undefined-field
- script.run_in_callback(function(s)
+ script.run_in_fiber(function(s)
callback(s)
end)
end
+ -- dispatch = function(callback)
+ -- ---@diagnostic disable-next-line: undefined-field
+ -- script.run_in_callback(function(s)
+ -- callback(s)
+ -- end)
+ -- end
}
}
diff --git a/includes/structs/HandlingEditor.lua b/includes/structs/HandlingEditor.lua
index 41e9a6b..a540458 100644
--- a/includes/structs/HandlingEditor.lua
+++ b/includes/structs/HandlingEditor.lua
@@ -1,7 +1,7 @@
---@enum eHandlingEditorTypes
Enums.eHandlingEditorTypes = {
- TYPE_HF = 0, -- handling flag
- TYPE_AF = 1, -- advanced flag
+ TYPE_HF = 0, -- handling flag
+ TYPE_AF = 1, -- advanced flag
TYPE_MIF = 2, -- model info flag
}
@@ -75,7 +75,7 @@ end
function HandlingEditor:GetFlagDefault(obj)
return Switch(obj.m_type) {
[Enums.eHandlingEditorTypes.TYPE_HF] = self.m_pv:GetHandlingFlag(obj.m_flag),
- [Enums.eHandlingEditorTypes.TYPE_AF] = self.m_pv:GetHandlingFlag(obj.m_flag),
+ [Enums.eHandlingEditorTypes.TYPE_AF] = self.m_pv:GetAdvancedFlag(obj.m_flag),
[Enums.eHandlingEditorTypes.TYPE_MIF] = self.m_pv:GetModelInfoFlag(obj.m_flag),
default = false
}
@@ -89,7 +89,8 @@ end
---@param obj HandlingObject
---@param toggle boolean
-function HandlingEditor:SetFlag(obj, toggle)
+---@param reset? boolean
+function HandlingEditor:SetFlag(obj, toggle, reset)
if (not self.m_pv or not self.m_pv:IsValid()) then
return
end
@@ -123,7 +124,12 @@ function HandlingEditor:SetFlag(obj, toggle)
callback()
end
- obj.m_was_edited = toggle
+ if (reset) then
+ obj.m_was_edited = false
+ return
+ end
+
+ obj.m_was_edited = true
end
---@param obj HandlingObject
@@ -137,7 +143,7 @@ function HandlingEditor:ResetFlag(obj)
end
obj.m_was_edited = false
- self:SetFlag(obj, obj.m_default)
+ self:SetFlag(obj, obj.m_default, true)
if (type(obj.m_on_disable) == "function") then
obj.m_on_disable()
end
diff --git a/samurais_scripts.lua b/samurais_scripts.lua
index 96b1c16..b5ca11b 100644
--- a/samurais_scripts.lua
+++ b/samurais_scripts.lua
@@ -3,6 +3,7 @@
local commandRegistry = require("includes.lib.commands")
require("includes.init")
+GPointers:Init()
Serializer:FlushObjectQueue()
Backend:RegisterHandlers()
Translator:Load()
@@ -52,6 +53,18 @@ script.run_in_fiber(function()
end
end
+ KeyManager:RegisterKeybind(eVirtualKeyCodes.NUMPAD8, function()
+ Self:GetVehicle():RamForward()
+ end)
+
+ KeyManager:RegisterKeybind(eVirtualKeyCodes.NUMPAD4, function()
+ Self:GetVehicle():RamLeft()
+ end)
+
+ KeyManager:RegisterKeybind(eVirtualKeyCodes.NUMPAD6, function()
+ Self:GetVehicle():RamRight()
+ end)
+
while not PatternScanner:IsDone() do
yield()
end
diff --git a/scripts/offsets/.last_commit_hash b/scripts/offsets/.last_commit_hash
deleted file mode 100644
index d72b459..0000000
--- a/scripts/offsets/.last_commit_hash
+++ /dev/null
@@ -1 +0,0 @@
-6c18d3e8b447d919a4d4310ecadcefb2fe295173
diff --git a/scripts/offsets/enhanced.last_commit_hash b/scripts/offsets/enhanced.last_commit_hash
new file mode 100644
index 0000000..e4a5de1
--- /dev/null
+++ b/scripts/offsets/enhanced.last_commit_hash
@@ -0,0 +1 @@
+c9635c0ae26b9d960a9e0dfcff25521a796e8056
diff --git a/scripts/offsets/legacy.last_commit_hash b/scripts/offsets/legacy.last_commit_hash
new file mode 100644
index 0000000..f289a5a
--- /dev/null
+++ b/scripts/offsets/legacy.last_commit_hash
@@ -0,0 +1 @@
+b7cbd9809843017a959df818c17e3275de6506c5
diff --git a/scripts/offsets/update_offsets.py b/scripts/offsets/update_offsets.py
index 3146733..3ba8ae2 100644
--- a/scripts/offsets/update_offsets.py
+++ b/scripts/offsets/update_offsets.py
@@ -2,12 +2,8 @@
#
# Usage:
# python update_offsets.py : normal run (just hit F5 if in VS Code and have Python Debugger installed, reads raw files from a remote repository)
-# python update_offsets.py --version : 1: Legacy | 2: Enhanced; defaults to 1: Legacy
+# python update_offsets.py --version : 0: Legacy | 1: Enhanced; defaults to 0: Legacy
# python update_offsets.py --local : Read from local files; this must be followed by the path to local decompiled scritps
-# python update_offsets.py --owner : Repository owner (if reading from remote repository)
-# python update_offsets.py --repo : Repository name (if reading from remote repository)
-# python update_offsets.py --branch : Repository branch (if reading from remote repository)
-# python update_offsets.py --folder : Repository folder (if reading from remote repository. Optional, must end with a forward slash if provided)
#
# CI Run: Don't pass any arguments
@@ -31,6 +27,10 @@
PARENT_PATH = Path(__file__).resolve().parent
SCRIPT_ROOT = PARENT_PATH.parent.parent
+REPO_URLS = [
+ "https://raw.githubusercontent.com/acidlabsgg/gtav-legacy-scripts/refs/heads/main/scripts",
+ "https://raw.githubusercontent.com/acidlabsgg/gtav-enhanced-scripts/refs/heads/main/scripts",
+]
def has_c_file(path) -> bool:
@@ -41,8 +41,8 @@ def has_c_file(path) -> bool:
return False
-def read_raw_file(file_name: str, owner: str, repo: str, branch: str, folder: str) -> str:
- url = f"https://raw.githubusercontent.com/{owner}/{repo}/refs/heads/{branch}/{folder}{file_name}"
+def read_raw_file(file_name: str, version: int=0) -> str:
+ url = f"{REPO_URLS[version]}/{file_name}"
try:
resp = requests.get(url)
resp.raise_for_status()
@@ -61,14 +61,14 @@ def read_local_file(file_path: str) -> str:
return f.read()
-def read_file(local: bool, file_name: str, decomps_path: str, owner: str, repo: str, branch: str, folder: str):
+def read_file(local: bool, file_name: str, decomps_path: str, version: int):
if local:
if not (os.path.isdir(decomps_path) and has_c_file(decomps_path)):
print("The path specified is invalid.")
sys.exit(1)
return read_local_file(script_file_path(decomps_path, file_name))
else:
- return read_raw_file(file_name, owner, repo, branch, folder)
+ return read_raw_file(file_name, version)
def read_lua_table(path: str):
@@ -171,35 +171,8 @@ def serialize_lua(v, indent=1):
return f'"{s}"'
-def main():
- table_path = SCRIPT_ROOT / "includes/data/globals_locals.lua"
- if not os.path.exists(table_path):
- print("Lookup file not found: globals_locals.lua")
- sys.exit(1)
-
-
- parser = ArgParser(description="Update offsets from local path or GitHub repository.")
- parser.add_argument("--version", type=int, help="Choose game version. (1: Legacy | 2: Enhanced)")
- parser.add_argument("--local", action="store_true", help="Read from local decompiled scripts")
- parser.add_argument("decomps_path", type=str, nargs="?", default="", help="Path to your local decompiled scripts")
- parser.add_argument("--owner", type=str, default="calamity-inc", help="GitHub repo owner for remote files")
- parser.add_argument("--repo", type=str, default="GTA-V-Decompiled-Scripts", help="GitHub repo name for remote files")
- parser.add_argument("--branch", type=str, default="senpai", help="GitHub repo branch for remote files")
- parser.add_argument("--folder", type=str, default="decompiled_scripts/", help="Optional GitHub repo folder. If provided, it must end with a forward slash.")
- args = parser.parse_args()
-
- version: int = args.version or 1
- offsets_table = read_lua_table(table_path)
- version = args.version or 1
- local = args.local
- path = args.decomps_path
- owner = args.owner
- repo = args.repo
- branch = args.branch
- folder = args.folder
-
- offsets_table = read_lua_table(table_path)
- version_key = "LEGACY" if version == 1 else "ENHANCED"
+def generate(offsets_table: list, version: int, local: bool, path: str):
+ version_key = "LEGACY" if version == 0 else "ENHANCED"
for name, data in offsets_table.items():
ver = data.get(version_key)
@@ -208,7 +181,7 @@ def main():
print(f"\n--- Scanning for: {name} ({version_key}) ---")
file_name = data["file"]
- file_content = read_file(local, file_name, path, owner, repo, branch, folder)
+ file_content = read_file(local, file_name, path, version)
result = scan_entry(ver, file_content, file_name)
if not result:
print(f"[MISS] {name} (pattern not found in {file_name})")
@@ -225,6 +198,30 @@ def main():
print(f"\tFound offset for {name} ({version_key}): .f_{newv}")
ver["offsets"][i]["value"] = newv
+
+
+def main(auto: bool = True):
+ table_path = SCRIPT_ROOT / "includes/data/globals_locals.lua"
+ if not os.path.exists(table_path):
+ print("Lookup file not found: globals_locals.lua")
+ sys.exit(1)
+
+ offsets_table = read_lua_table(table_path)
+
+ if auto:
+ generate(offsets_table, 0, False, "")
+ generate(offsets_table, 1, False, "")
+ else:
+ parser = ArgParser(description="Update offsets from local path or GitHub repository.")
+ parser.add_argument("--version", type=int, help="Choose game version. (0: Legacy | 1: Enhanced)")
+ parser.add_argument("--local", action="store_true", help="Read from local decompiled scripts")
+ parser.add_argument("decomps_path", type=str, nargs="?", default="", help="Path to your local decompiled scripts")
+ args = parser.parse_args()
+ version = args.version or 0
+ local = args.local
+ path = args.decomps_path
+ generate(offsets_table, version, local, path)
+
data = serialize_lua(offsets_table)
with open(table_path, "w", encoding="utf-8") as f:
f.write("return ")
diff --git a/scripts/translations/generate_translations.py b/scripts/translations/generate_translations.py
index 6903c34..ce4a267 100644
--- a/scripts/translations/generate_translations.py
+++ b/scripts/translations/generate_translations.py
@@ -177,7 +177,6 @@ def write_hashmap():
print("Updating hash map...")
with open(HASHMAP_PATH, "w", encoding="utf-8") as f:
json.dump(HASHMAP, f, indent=4)
- print("Done.")
def generate_translations(dry_run: bool = False, diff_only: bool = False):
diff --git a/scripts/translations/hashmap.json b/scripts/translations/hashmap.json
index 4b82115..96c4b95 100644
--- a/scripts/translations/hashmap.json
+++ b/scripts/translations/hashmap.json
@@ -356,7 +356,7 @@
"SETTINGS_ENTITY_REPLACE": 171535354,
"SETTINGS_ENTITY_REPLACE_TT": 59617883,
"CP_AUTOPLAY_SLOTS_TIME_DELAY": 1687112399,
- "VEH_ENGINE_SWAP_INCOMPATIBE": 3435064276,
+ "GENERIC_CARS_ONLY": 3435064276,
"VEH_COBRA_MANEUVER": 1495230376,
"VEH_COBRA_MANEUVER_TT": 4096238823,
"VEH_COBRA_MANEUVER_TOO_lOW": 2453306327,
@@ -489,5 +489,21 @@
"YRV3_CWASH_LEGAL_WORK_CD": 1888241516,
"YRV3_CWASH_ILLEGAL_WORK_CD": 3778589484,
"SELF_MC_BIKE_ANIMS": 3787903104,
- "SELF_MC_BIKE_ANIMS_TT": 2261171158
+ "SELF_MC_BIKE_ANIMS_TT": 2261171158,
+ "SUBTAB_STANCER": 1457316635,
+ "VEH_LAUNCH_CTRL_MODE": 902945881,
+ "VEH_LAUNCH_CTRL_REALISTIC": 3556046693,
+ "VEH_LAUNCH_CTRL_RIDICULOUS": 3121743094,
+ "VEH_LAUNCH_CTRL_ERR": 817410668,
+ "VEH_STANCE_CAMBER": 2314729583,
+ "VEH_STANCE_TRACK_WIDTH": 3796057203,
+ "VEH_STANCE_WHEEL_WIDTH": 4108370513,
+ "VEH_STANCE_WHEEL_SIZE": 1236796012,
+ "VEH_STANCE_NON_STOCK": 2462804441,
+ "VEH_STANCE_INCOMPATIBLE": 1676346899,
+ "VEH_STANCE_FRONT_AXLE": 3200455966,
+ "VEH_STANCE_REAR_AXLE": 2802365256,
+ "VEH_STANCE_COPY_FB": 294869527,
+ "VEH_STANCE_GEN_OPTIONS": 3430492750,
+ "VEH_STANCE_RIDE_HEIGHT": 4113493823
}
\ No newline at end of file