diff --git a/README.md b/README.md new file mode 100644 index 0000000..57fc726 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# GTA5 handling.meta interface +# Handling Flags Overhaul πŸš€ + +## Live demo: https://vivvvi.github.io/Handling-Tools/ + +## Summary +This branch introduces a **complete overhaul of the Handling Flags system**. It modularizes core logic, enhances the user experience, and introduces **dynamic XML parsing, sub-array support, and raw XML value editing**. The system is now more maintainable, flexible, and ready for future enhancements. + +--- + +## Table of Contents +1. [What's New](#whats-new) + - [New Files & Structure](#new-files--structure) + - [Feature Enhancements](#feature-enhancements) + - [User Interface](#user-interface) +2. [Key Changes](#key-changes) +3. [Bugs / Issues Addressed](#bugs--issues-addressed) +4. [TODO / Future Enhancements](#todo--future-enhancements) +5. [How to Test](#how-to-test) +6. [Notes for Reviewers](#notes-for-reviewers) + +--- + +## [Whats New] + +### New Files & Structure +- πŸ†• **flags.js** β€” Core logic for dynamic flag handling, input validation, and state updates. +- πŸ†• **handling.js** β€” Handles XML parsing, raw input updates, and integration with the UI. +- πŸ†• **2 JSON Files** β€” Metadata files for GTAV flags from Plebs and ikt. +- πŸ“ **File Separation** β€” Extracted and JS logic from `flags.html` and `handling.html` into standalone modules. + +### [Feature Enhancements] +- πŸ–±οΈ **Flag System Overhaul** β€” Unified flag handling logic between `handling.html` and `flags.html`. +- ✍️ **Editable XML UI** β€” Users can directly edit raw XML values for: + - `strModelFlags` + - `strHandlingFlags` + - `strDamageFlags` + - `handlingName` + - `AIHandling` +- πŸ“ **Dynamic Sub-Array Support** β€” Support for `vecCentreOfMassOffset` and `vecInertiaMultiplier` for **X, Y, Z** adjustments. +- πŸ“Š **Mass Comparer Overhaul** β€” Streamlined for flattened views and dynamic column selection. +- πŸ“ **File Upload Enhancements** β€” Uploaded file names are now stored and referenced for mass composer and comparison logic. + +### [User Interface] +- πŸ–₯️ **Interactive Flags UI** β€” Users can toggle, calculate, and edit flags with ease. +- πŸ”₯ **Live XML Parsing** β€” View and edit key XML nodes and sub-array data. +- πŸ–ΌοΈ **Dynamic Tab Support** β€” Handling and Flags tabs now share the same modular logic. +- ⚑ **Real-time Calculations** β€” Flag updates are displayed in real-time, with support for **hexadecimal input validation**. + +--- + +## [Key Changes] + +| **File** | **Type** | **Description** | +|-------------------|-------------|---------------------------------------------------------------------------------| +| **flags.js** | πŸ†• New | Handles flag toggling, input listeners, and dynamic state updates. | +| **handling.js** | πŸ†• New | Parses and updates key XML nodes and inline elements. | +| **flags.html** | ✍️ Updated | Modularized to support shared logic with `flags.js`. | +| **handling.html** | ✍️ Updated | Supports dynamic tabs, raw XML editing, and sub-array parsing. | +| **flags.json** | πŸ†• New | Metadata from Plebs and ikt for GTAV flag definitions. | +| **CSS Updates** | 🎨 Improved| Added styles for XML editing, flags toggles, and mass comparer. | + +--- + +## [Bugs / Issues Addressed] +- 🚫 **Input Restrictions** β€” Hex input validation logic improved. Supports copy-paste while maintaining constraints. +- πŸ› **UI Consistency** β€” Refactored logic to support tabs in `flags.html` and `handling.html` using shared components. +- πŸ”₯ **Sub-Array Support** β€” Improved support for nested items like: +```xml + + + + + +``` + +# [TODO / Future Enhancements] +- πŸ› not all calculations may still be correct trying to remove miles per hour from calculations. +- πŸ“‹ Complete sub-array support β€” Handle all sub-handling elements and nested items. +- βš–οΈ Remove 'miles' from internal logic β€” Store data in KM/H and only convert to MPH when required. +- πŸ“Š Mass Comparer Improvements β€” Full support for flattening and dynamic column selection. +- 🚦 Testing & QA β€” Full review of XML parsing logic, flag toggling, and mass comparer values. + +# [How to Test] +Pull the branch and checkout the new files: +```bash +git checkout feature/handling-flags-overhaul +``` +Open handling.html and flags.html. + +Test the following: +- Toggling Flags β€” Ensure flags toggle on and off properly. +- Input Validation β€” Type hexadecimal values into editable fields and ensure input is constrained to 8 characters. +- File Upload β€” Test XML file uploads and verify that the file name is referenced correctly. +- Mass Comparer β€” Test flattened structure, dynamic columns, and file comparisons. +- Sub-Array Support β€” Verify vecCentreOfMassOffset and vecInertiaMultiplier support. + +# [Notes for Reviewers] +This PR introduces significant changes to the structure and logic. Please review the changes to: +- flags.js, handling.js, and the mass comparer logic. +- Input Validation β€” Ensure user input validation logic works properly. +- Sub-Array Handling β€” Verify XML sub-array parsing is accurate. +- Flag Calculation β€” Review flag calculation logic for consistency. diff --git a/ace_xml.js b/ace_xml.js new file mode 100644 index 0000000..0f3b7dd --- /dev/null +++ b/ace_xml.js @@ -0,0 +1,240 @@ +// ** Initialize Ace Editor ** +var rawEditor = ace.edit("rawEditor"); +rawEditor.setTheme("ace/theme/monokai"); +rawEditor.session.setMode("ace/mode/xml"); +rawEditor.setShowPrintMargin(false); +rawEditor.setFontSize(14); +rawEditor.setOptions({ + autoScrollEditorIntoView: true, + copyWithEmptySelection: true +}); + +// Load XML from the hidden textarea or use default content +const textarea = document.getElementById('handlingFileDisplay'); +const textareaContent = textarea ? textarea.value.trim() : ''; +const defaultContent = textareaContent || ` + + + + + + 4400110 +`; + +rawEditor.setValue(defaultContent, -1); +if (textarea) textarea.value = defaultContent; + +// ** Regexes to match editable regions ** +const valueAttributeRegex = /\bvalue="([a-zA-Z0-9.-]*)"/g; +const tagContentRegex = /<([a-zA-Z0-9]+)>([a-zA-Z0-9.-]*)<\/\1>/g; +const generalAttributeRegex = /\b([a-zA-Z0-9_-]+)="([a-zA-Z0-9.-]*)"/g; // Match any attribute and its value + +// ** Track the last known value of the editable area ** +let lastEditableValue = null; +let lastTag = null; +let lastAttr = null; + + + +// ** Track Caret Position & Log Editable Status ** +const debouncedLogCaretInfo = debounce(logCaretInfo, 150); +rawEditor.on('changeSelection', debouncedLogCaretInfo); +rawEditor.on('click', debouncedLogCaretInfo); + +let isSelecting = false; + +rawEditor.container.addEventListener('mousedown', () => isSelecting = true); +rawEditor.container.addEventListener('mouseup', () => { + setTimeout(() => { + isSelecting = false; + const selectionRange = rawEditor.getSelectionRange(); + if (!selectionRange.isEmpty()) { + console.log('Manual selection detected, skipping programmatic selection.'); + } + }, 50); +}); + + + +// ** Logs caret information, whether user is in an editable region or not ** +function logCaretInfo() { + if (isSelecting) return; // πŸ”₯ Do not interfere with user manual selection + + const selectionRange = rawEditor.getSelectionRange(); + if (!selectionRange.isEmpty()) { + // console.log('Manual selection active, skipping programmatic selection.'); + return; // 🚫 Stop here if a selection is ongoing + } + + + const cursorPosition = rawEditor.getCursorPosition(); + const docText = rawEditor.getValue(); + const index = rawEditor.session.doc.positionToIndex(cursorPosition); + const charAtCursor = docText[index] || 'EOF'; + const { isEditable, tagName, attrName, oldValue } = getEditableInfo(index); + + if (isEditable) { + const attrDisplay = attrName ? `[${attrName}]` : ''; + // console.log(`βœ… Editable position at index: ${index} (character: "${charAtCursor}")`); + // console.log(`🟒 Editing <${tagName}> ${attrDisplay} Current value: "${oldValue}"`); + + // Store the value to detect changes later + lastEditableValue = oldValue; + lastTag = tagName; + lastAttr = attrName; + } else { + //console.warn(`🚫 Not editable at index: ${index} (character: "${charAtCursor}")`); + //console.log( getNearestTag(docText, index) ); + var valAtts = getValuePosition( docText, index ); + + if (valAtts){ + + // Get row and column corresponding to this character index + const startPos = rawEditor.session.doc.indexToPosition(valAtts.start, 0); + const endPos = rawEditor.session.doc.indexToPosition(valAtts.end, 0); + + // ** Create the selection range using Ace's Range class ** + const aceRange = ace.require('ace/range').Range; + const range = new aceRange(endPos.row, endPos.column, startPos.row, startPos.column); + rawEditor.selection.setSelectionRange(range); + + } + // Move the cursor to the calculated (startPos) row and column + //rawEditor.moveCursorTo(startPos.row, startPos.column); + + } +} + +// ** Check if a given index position is within an editable range ** +function getEditableInfo(index) { + const documentText = rawEditor.getValue(); + let isEditable = false, tagName = '', attrName = '', oldValue = ''; + + // Check if position is inside `value="..."` attributes + valueAttributeRegex.lastIndex = 0; + while ((match = valueAttributeRegex.exec(documentText)) !== null) { + const valueStart = match.index + match[0].indexOf('"') + 1; + const valueEnd = valueStart + match[1].length; + if (index >= valueStart && index <= valueEnd) { + isEditable = true; + attrName = 'value'; + oldValue = match[1]; + tagName = getNearestTag(documentText, match.index); + break; + } + } + + // Check if position is inside `value` text content + tagContentRegex.lastIndex = 0; + while ((match = tagContentRegex.exec(documentText)) !== null) { + const valueStart = match.index + match[0].indexOf('>') + 1; + const valueEnd = valueStart + match[2].length; + if (index >= valueStart && index <= valueEnd) { + isEditable = true; + attrName = ''; // No attribute for root value + oldValue = match[2]; + tagName = match[1]; + break; + } + } + + // Check if position is inside any attribute value + generalAttributeRegex.lastIndex = 0; + while ((match = generalAttributeRegex.exec(documentText)) !== null) { + const valueStart = match.index + match[0].indexOf('"') + 1; + const valueEnd = valueStart + match[2].length; + if (index >= valueStart && index <= valueEnd) { + isEditable = true; + attrName = match[1]; + oldValue = match[2]; + tagName = getNearestTag(documentText, match.index); + break; + } + } + + return { isEditable, tagName, attrName, oldValue }; +} + +// ** Get nearest tag from a position in the document ** +function getNearestTag(documentText, position) { + const beforeCursor = documentText.slice(0, position); + const tagMatch = beforeCursor.match(/<([a-zA-Z0-9]+)(?=\s|>)/g); + if (tagMatch && tagMatch.length > 0) { + // console.log( tagMatch[tagMatch.length - 1].replace('<', '') ); + return tagMatch[tagMatch.length - 1].replace('<', ''); + } + return 'UnknownTag'; +} + +function getValuePosition(documentText, position) { + const lineStart = documentText.lastIndexOf('\n', position) + 1; // Start of the current line + const lineEnd = documentText.indexOf('\n', position); + const lineText = documentText.slice(lineStart, lineEnd > -1 ? lineEnd : documentText.length); + + // ** 1. Check for values in attributes like value="1500.000000" ** + const attributeMatch = lineText.match(/\b([a-zA-Z0-9-]+)="([a-zA-Z0-9.-]*)"/); + if (attributeMatch) { + const matchStart = lineText.indexOf(attributeMatch[0]) + lineStart; + const valueStart = matchStart + attributeMatch[0].indexOf('"') + 1; // Start after the first quote + const valueEnd = valueStart + attributeMatch[2].length; + return { start: valueStart, end: valueEnd, value: attributeMatch[2], attrName: attributeMatch[1], type: 'attribute', lineText }; + } + + // ** 2. Check for tag content like 20000 ** + const tagMatch = lineText.match(/<([a-zA-Z0-9]+)>([a-zA-Z0-9.-]+)<\/\1>/); + if (tagMatch) { + const matchStart = lineText.indexOf(tagMatch[0]) + lineStart; + const valueStart = matchStart + tagMatch[0].indexOf('>') + 1; // Start after the ">" character + const valueEnd = valueStart + tagMatch[2].length; + return { start: valueStart, end: valueEnd, value: tagMatch[2], tagName: tagMatch[1], type: 'tag', lineText }; + } + + // ** 3. Check for general attributes, like x="0.000000" y="0.000000" z="0.000000" ** + const generalAttrMatch = lineText.match(/\b([a-zA-Z0-9-]+)="([a-zA-Z0-9.-]*)"/g); + if (generalAttrMatch) { + for (let i = 0; i < generalAttrMatch.length; i++) { + const match = generalAttrMatch[i].match(/([a-zA-Z0-9-]+)="([a-zA-Z0-9.-]*)"/); + const matchStart = lineText.indexOf(match[0], i > 0 ? lineText.indexOf(generalAttrMatch[i - 1]) + generalAttrMatch[i - 1].length : 0) + lineStart; + const valueStart = matchStart + match[0].indexOf('"') + 1; // Start after the first quote + const valueEnd = valueStart + match[2].length; + if (position >= valueStart && position <= valueEnd) { + return { start: valueStart, end: valueEnd, value: match[2], attrName: match[1], type: 'attribute', lineText }; + } + } + } + + return null; // No match found +} + + + +// ** Detect changes and log if a value changes ** +rawEditor.on('change', function() { + const { tagName, attrName, newValue } = getCurrentEditableValue(); + + if (lastEditableValue !== null && lastEditableValue !== newValue) { + const attrDisplay = attrName ? `[${attrName}]` : ''; + console.log(`πŸ”„ Value changed for <${tagName}> ${attrDisplay} from "${lastEditableValue}" to "${newValue}"`); + // console.log( $(`[name="${tagName}${attrDisplay}"].form-control`) ); + } + + // Update last known value + lastEditableValue = newValue; +}); + +function getCurrentEditableValue() { + const cursorPosition = rawEditor.getCursorPosition(); + const docText = rawEditor.getValue(); + const index = rawEditor.session.doc.positionToIndex(cursorPosition); + const { isEditable, tagName, attrName, oldValue } = getEditableInfo(index); + + return { tagName, attrName, newValue: oldValue }; +} + +function debounce(func, delay) { + let timeout; + return function(...args) { + clearTimeout(timeout); + timeout = setTimeout(() => func.apply(this, args), delay); + }; +} diff --git a/flags-ikt.json b/flags-ikt.json new file mode 100644 index 0000000..d4599e9 --- /dev/null +++ b/flags-ikt.json @@ -0,0 +1,521 @@ +{ + "version":"2.6", + "flags": { + "strModelFlags": [{ + "name": "MF_IS_VAN", + "description": "Allows double doors for the rear doors animation." + }, + { + "name": "MF_IS_BUS", + "description": "Uses bus animations for entry/exit." + }, + { + "name": "MF_IS_LOW", + "description": "Uses animations suitable for cars with a low ride-height." + }, + { + "name": "MF_IS_BIG", + "description": "Changes the way that the AI drives around corners." + }, + { + "name": "MF_ABS_STD", + "description": "Arcade Anti-Lock Braking System (ABS) equipped as standard; minimal slip allowed." + }, + { + "name": "MF_ABS_OPTION", + "description": "Arcade Anti-Lock Braking System (ABS) equipped w/ brakes upgrade." + }, + { + "name": "MF_ABS_ALT_STD", + "description": "Realistic Anti-Lock Braking System (ABS) equipped as standard; some slip allowed." + }, + { + "name": "MF_ABS_ALT_OPTION", + "description": "Realistic Anti-Lock Braking System (ABS) equipped w/brakes upgrade." + }, + { + "name": "MF_NO_DOORS", + "description": "For vehicles that don't have any operable doors." + }, + { + "name": "MF_TANDEM_SEATING", + "description": "Two people will use the front passenger seat." + }, + { + "name": "MF_SIT_IN_BOAT", + "description": "Uses seated boat animation instead of standing." + }, + { + "name": "MF_HAS_TRACKS", + "description": "For vehicles with tracks instead of tires." + }, + { + "name": "MF_NO_EXHAUST", + "description": "Removes all exhaust particles." + }, + { + "name": "MF_DOUBLE_EXHAUST", + "description": "Creates a second exhaust by mirroring the model's exhaust over the y-axis." + }, + { + "name": "MF_NO_1STPERSON_LOOKBEHIND", + "description": "Prevents player using rear view when in first-person mode." + }, + { + "name": "MF_CAN_ENTER_IF_NO_DOOR", + "description": "Allows entry into the vehicle despite no currently accessible doors." + }, + { + "name": "MF_AXLE_F_TORSION", + "description": "Front wheels stay vertical to the car." + }, + { + "name": "MF_AXLE_F_SOLID", + "description": "Front wheels stay parallel to each other." + }, + { + "name": "MF_AXLE_F_MCPHERSON", + "description": "Front wheels can tilt." + }, + { + "name": "MF_ATTACH_PED_TO_BODYSHELL", + "description": "???" + }, + { + "name": "MF_AXLE_R_TORSION", + "description": "Rear wheels stay vertical to the car." + }, + { + "name": "MF_AXLE_R_SOLID", + "description": "Rear wheels stay parallel to each other." + }, + { + "name": "MF_AXLE_R_MCPHERSON", + "description": "Rear wheels can tilt." + }, + { + "name": "MF_DONT_FORCE_GRND_CLEARANCE", + "description": "Chassis COL is taken into account when suspension is compressed while hitting the ground, with sparks rendered." + }, + { + "name": "MF_DONT_RENDER_STEER", + "description": "Does not render steering animations." + }, + { + "name": "MF_NO_WHEEL_BURST", + "description": "Has Bulletproof Tires as standard." + }, + { + "name": "MF_INDESTRUCTIBLE", + "description": "Can't explode or be considered inoperable from damage." + }, + { + "name": "MF_DOUBLE_FRONT_WHEELS", + "description": "Places a second instance of each front wheel next to the normal one." + }, + { + "name": "MF_IS_RC", + "description": "For RC vehicles such as the RC Bandito and Invade & Persuade Tank. The player model is hidden upon entering the vehicle." + }, + { + "name": "MF_DOUBLE_REAR_WHEELS", + "description": "Duplicates the skidmarks of the rear tires." + }, + { + "name": "MF_NO_WHEEL_BREAK", + "description": "Prevents wheel bones from detaching off the vehicle due to damage." + }, + { + "name": "MF_IS_HATCHBACK", + "description": "Uses animations suitable for Trunk doors on hatchback-style vehicle bodies." + } + ], + "strHandlingFlags": [{ + "name": "HF_SMOOTHED_COMPRESSION", + "description": "Simulates progressive spring suspension. Makes suspension compression motion smoother." + }, + { + "name": "HF_REDUCED_MOD_MASS", + "description": "Reduces mass added from upgrades." + }, + { + "name": "HF_HAS_KERS", + "description": "Partially enables KERS on the vehicle; disables horn and shows the recharge bar below the minimap. KERS boost itself still needs to be enabled by the SET_VEHICLE_KERS_ALLOWED native." + }, + { + "name": "HF_HAS_TRACKS", + "description": "Inverts the way grip works on the vehicle; with this flag enabled, grip starts at the fTractionCurveMin value and may increase up to the fTractionCurveMax value upon wheel slip. Grip stays at max beyond the vehicle's peak slip angle." + }, + { + "name": "HF_NO_HANDBRAKE", + "description": "Disables handbrake control for the vehicle." + }, + { + "name": "HF_STEER_REARWHEELS", + "description": "Steers the rear wheels instead of the front." + }, + { + "name": "HF_HANDBRAKE_REARWHEELSTEER", + "description": "Handbrake control makes the rear wheels steer as well as the front." + }, + { + "name": "HF_STEER_ALL_WHEELS", + "description": "Steers all wheels, similar to 4-wheel-steering systems found on real vehicles. The rear wheels will steer at the same lock angle as the front, as defined by fSteeringLock." + }, + { + "name": "HF_FREEWHEEL_NO_GAS", + "description": "Disables engine-braking when no throttle is applied." + }, + { + "name": "HF_NO_REVERSE", + "description": "Disables reversing for the vehicle." + }, + { + "name": "_HF_UNKNOWN_10", + "description": "Unknown. Name hash: 0x4C11C7F9" + }, + { + "name": "HF_STEER_NO_WHEELS", + "description": "Disables steering on all wheels, used with tracked vehicles." + }, + { + "name": "HF_CVT", + "description": "Gives the vehicle a fixed-ratio transmission with a gear ratio of 0.90, used for vehicles with nInitialDriveGears=1. If gears amount to more than 1, it will simply force the vehicle into top gear upon acceleration. Recommended for electric vehicles." + }, + { + "name": "HF_ALT_EXT_WHEEL_BOUNDS_BEH", + "description": "???" + }, + { + "name": "HF_DONT_RAISE_BOUNDS_AT_SPEED", + "description": "???" + }, + { + "name": "HF_EXT_WHEEL_BOUNDS_COL", + "description": "???" + }, + { + "name": "HF_LESS_SNOW_SINK", + "description": "Less grip loss from deep mud/snow, most notably in North Yankton." + }, + { + "name": "HF_TYRES_CAN_CLIP", + "description": "Tires are allowed to clip into the pavement when under enough pressure, effectiveness depends on tire sidewall. Generally makes the vehicle deal with uneven terrain better. Notes: this is the reason Offroad Tires improve performance on specific vehicles made by R*." + }, + { + "name": "_HF_UNKNOWN_19", + "description": "Unknown. name hash: 0x2DEA7A05" + }, + { + "name": "HF_HEAVY_VEHICLE", + "description": "???" + }, + { + "name": "HF_OFFROAD_ABILITIES", + "description": "Gravity constant increased by 10% to 10.78 m/s^2, resulting in increased grip and faster falling when airborne. Acceleration and braking performance is also increased by 10%." + }, + { + "name": "HF_OFFROAD_ABILITIES_X2", + "description": "Gravity constant increased by 20% to 11.76 m/s^2, resulting in increased grip and faster falling when airborne. Acceleration and braking performance is also increased by 20%. Vehicle does not react to bushes." + }, + { + "name": "HF_TYRES_RAISE_SIDE_IMPACT_THRESHOLD", + "description": "Includes the tires in the general side collision hitbox of the vehicle. Recommended for vehicles whose wheels extend beyond the bodywork, like monster-trucks." + }, + { + "name": "_HF_INCREASED_GRAVITY", + "description": "Gravity constant increased by 20% to 11.76 m/s^2, resulting in increased grip and faster falling when airborne. Acceleration and braking performance is also increased by 20%. Vehicle does not react to bushes. Identical to HF_OFFROAD_ABILITIES_X2." + }, + { + "name": "HF_ENABLE_LEAN", + "description": "??? Notes: Possibly for motorcycle leaning or boat leaning." + }, + { + "name": "_HF_ALLOW_MOTORCYCLE_TRACTION_LOSS", + "description": "Allows motorcycles to lose traction." + }, + { + "name": "HF_HEAVYARMOUR", + "description": "???" + }, + { + "name": "HF_ARMOURED", + "description": "Prevents vehicle doors (including hood and trunk) from opening in collisions." + }, + { + "name": "HF_SELF_RIGHTING_IN_WATER", + "description": "???" + }, + { + "name": "HF_IMPROVED_RIGHTING_FORCE", + "description": "Adds extra force to the vehicle when attempting to flip it back on its wheels." + }, + { + "name": "HF_USE_EXTRA_SOFT_SURFACE_SUS", + "description": "???" + }, + { + "name": "HF_LAST_AVAILABLE_FLAG", + "description": "Most likely doesn't do anything." + } + ], + "strDamageFlags": [{ + "name": "DF_DRIVER_SIDE_FRONT_DOOR", + "description": "Marks the driver-side front door (door_dside_f) bone as non-breakable." + }, + { + "name": "DF_DRIVER_SIDE_REAR_DOOR", + "description": "Marks the driver-side rear door (door_dside_r) bone as non-breakable." + }, + { + "name": "DF_DRIVER_PASSENGER_SIDE_FRONT_DOOR", + "description": "Marks the passenger-side front door (door_pside_f) bone as non-breakable." + }, + { + "name": "DF_DRIVER_PASSENGER_SIDE_REAR_DOOR", + "description": "Marks the passenger-side rear door (door_pside_r) bone as non-breakable." + }, + { + "name": "DF_BONNET", + "description": "Marks the bonnet bone as non-breakable." + }, + { + "name": "DF_BOOT", + "description": "Marks the boot bone as non-breakable." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + } + ], + "strAdvancedFlags": [{ + "name": "CF_DIFF_FRONT", + "description": "Unknown. Note from Rockstar: 'If we want torsen diffs they will need to know resistance at the wheel as applying the brakes should apply force back to the wheel on the ground'." + }, + { + "name": "CF_DIFF_REAR", + "description": "Unknown. Note from Rockstar: 'If we want torsen diffs they will need to know resistance at the wheel as applying the brakes should apply force back to the wheel on the ground'" + }, + { + "name": "CF_DIFF_CENTRE", + "description": "When enabled, transfers the drive force from the slipping wheels to the less-driven wheels." + }, + { + "name": "CF_DIFF_LIMITED_FRONT", + "description": "Unknown. Seems to have a similar effect to _AF_SMOOTH_REV_1ST, but with later upshifts." + }, + { + "name": "CF_DIFF_LIMITED_REAR", + "description": "???" + }, + { + "name": "CF_DIFF_LIMITED_CENTRE", + "description": "???" + }, + { + "name": "CF_DIFF_LOCKING_FRONT", + "description": "Unknown. Using this flag causes the vehicle's front wheels to wheelspin if the player is holding down the handbrake and forwards/backwards keys." + }, + { + "name": "CF_DIFF_LOCKING_REAR", + "description": "Using the handbrake slows the car down more smoothly and, most of the time, without leaving tire marks." + }, + { + "name": "CF_DIFF_LOCKING_CENTRE", + "description": "???" + }, + { + "name": "CF_GEARBOX_FULL_AUTO", + "description": "???" + }, + { + "name": "CF_GEARBOX_MANUAL", + "description": "Unknown. Sets the clutch value to 0.0 when idling." + }, + { + "name": "CF_GEARBOX_DIRECT_SHIFT", + "description": "???" + }, + { + "name": "CF_GEARBOX_ELECTRIC", + "description": "Used by the Omnis e-GT." + }, + { + "name": "CF_ASSIST_TRACTION_CONTROL", + "description": "???" + }, + { + "name": "CF_ASSIST_STABILITY_CONTROL", + "description": "???" + }, + { + "name": "CF_ALLOW_REDUCED_SUSPENSION_FORCE", + "description": "Allows the vehicle to be stanced using the SET_REDUCED_SUSPENSION_FORCE native. Requires the CF_FIX_OLD_BUGS flag to be enabled." + }, + { + "name": "CF_HARD_REV_LIMIT", + "description": "Only working for Tuner cars, this uncaps the RPM in last gear which causes the power to drop off and lower the top speed of the car (effectively creating a speed cap in last gear). Previously this flag changed gear shift behaviour to cause earlier upshifts with a hard rev limit per gear, but this was changed with the Criminal Enterprises update." + }, + { + "name": "CF_HOLD_GEAR_WITH_WHEELSPIN", + "description": "Later upshifts; usually hits the gear's rev limit before shifting." + }, + { + "name": "CF_INCREASE_SUSPENSION_FORCE_WITH_SPEED", + "description": "Anti-downforce suspension; increases suspension spring force as vehicle goes faster." + }, + { + "name": "CF_BLOCK_INCREASED_ROT_VELOCITY_WITH_DRIVE_FORCE", + "description": "Generates fake wheelspin after an instance of real wheelspin; Tyres will stabilize and show 0.0m/s of slip with debugging data, but the traction behaves like it's still spinning." + }, + { + "name": "CF_REDUCED_SELF_RIGHTING_SPEED", + "description": "Reduces righting force of the vehicle, effectively making it much harder and slower to flip back on its wheels." + }, + { + "name": "CF_CLOSE_RATIO_GEARBOX", + "description": "Extends the duration of the first gear, giving the vehicle a slower launch with greatly reduced wheelspin." + }, + { + "name": "CF_FORCE_SMOOTH_RPM", + "description": "Smooth first-gear revving; resistance to hitting the rev-limit." + }, + { + "name": "CF_ALLOW_TURN_ON_SPOT", + "description": "Allows the vehicle to be rotated left or right while parked on the spot. Intended for tanks/tracked vehicles." + }, + { + "name": "CF_CAN_WHEELIE", + "description": "Allows the vehicle to perform a handbrake wheelie. The Muscle vehicle class is hardcoded to use this flag." + }, + { + "name": "CF_ENABLE_WHEEL_BLOCKER_SIDE_IMPACTS", + "description": "Makes the wheels much less likely to clip into the ground when the vehicle is tipped over." + }, + { + "name": "CF_FIX_OLD_BUGS", + "description": "Forced stock-tyre clipping boundaries, the sidewall gain/loss from a custom tyre will not matter. Refer to strHandlingFlags 00020000 above. Also prevents lowering the vehicle by shooting at its wheels/suspension. This flag is required in addition to CF_ALLOW_REDUCED_SUSPENSION_FORCE to stance the vehicle through script." + }, + { + "name": "CF_USE_DOWNFORCE_BIAS", + "description": "Changes the way Downforce and spoiler tuning works, uses the setup found on Open-Wheel class vehicles in the vanilla game. Each spoiler/bumper tuning has to be given AdvancedData values to affect downforce. Adjusts initial downforce from fDownforceModifier. 'Curb - boosting' seems to be nullified." + }, + { + "name": "CF_REDUCE_BODY_ROLL_WITH_SUSPENSION_MODS", + "description": "Reduces body-roll if suspension upgrades are equipped. In addition, the vehicle gains more grip with each suspension option." + }, + { + "name": "CF_ALLOWS_EXTENDED_MODS", + "description": "Requires AdvancedData to work. Adds Turbo-affecting mods for mod slot 20 (VMT_KNOB) parts, and power-affecting mods for mod slot 22 (VMT_ICE) parts." + }, + { + "name": "N/A", + "description": "Flag does not exist." + }, + { + "name": "N/A", + "description": "Flag does not exist." + } + ] + } +} diff --git a/flags-pleb.json b/flags-pleb.json new file mode 100644 index 0000000..2844ff3 --- /dev/null +++ b/flags-pleb.json @@ -0,0 +1,1129 @@ +[ + { + "index": 0, + "name": "CF_DIFF_FRONT", + "description": "Unknown. Note from Rockstar: 'If we want torsen diffs they will need to know resistance at the wheel as applying the brakes should apply force back to the wheel on the ground'.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags00" + }, + { + "index": 1, + "name": "CF_DIFF_REAR", + "description": "Unknown. Note from Rockstar: 'If we want torsen diffs they will need to know resistance at the wheel as applying the brakes should apply force back to the wheel on the ground'", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags01" + }, + { + "index": 2, + "name": "CF_DIFF_CENTRE", + "description": "When enabled, transfers the drive force from the slipping wheels to the less-driven wheels. Previously known as _AF_ENABLE_DRIVE_BIAS_TRANSFER", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags02" + }, + { + "index": 3, + "name": "CF_DIFF_LIMITED_FRONT", + "description": "If we want torsen diffs they will need to know resistance at the wheel as applying the brakes should apply force back to the wheel on the ground. Previous comment; Seems to have a similar effect to _AF_SMOOTH_REV_1ST, but with later upshifts.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags03" + }, + { + "index": 4, + "name": "CF_DIFF_LIMITED_REAR", + "description": "???", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags04" + }, + { + "index": 5, + "name": "CF_DIFF_LIMITED_CENTRE", + "description": "???", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags05" + }, + { + "index": 6, + "name": "CF_DIFF_LOCKING_FRONT", + "description": "Using this flag causes the vehicle's front wheels to wheelspin if the player is holding down the handbrake and forwards/backwards keys.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags06" + }, + { + "index": 7, + "name": "CF_DIFF_LOCKING_REAR", + "description": "Using the handbrake slows the car down more smoothly and, most of the time, without leaving tire marks. Previously known as _AF_SMOOTH_HANDBRAKE", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags07" + }, + { + "index": 8, + "name": "CF_DIFF_LOCKING_CENTRE", + "description": "???", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags08" + }, + { + "index": 9, + "name": "CF_GEARBOX_FULL_AUTO", + "description": "???", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags09" + }, + { + "index": 10, + "name": "CF_GEARBOX_MANUAL", + "description": "Sets the clutch value to 0.0 when idling.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags10" + }, + { + "index": 11, + "name": "CF_GEARBOX_DIRECT_SHIFT", + "description": "???", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags11" + }, + { + "index": 12, + "name": "CF_GEARBOX_ELECTRIC", + "description": "Used by the Omnis e-GT.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags12" + }, + { + "index": 13, + "name": "CF_ASSIST_TRACTION_CONTROL", + "description": "Just reduce throttle.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags13" + }, + { + "index": 14, + "name": "CF_ASSIST_STABILITY_CONTROL", + "description": "Apply brakes to individual wheels.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags14" + }, + { + "index": 15, + "name": "CF_ALLOW_REDUCED_SUSPENSION_FORCE", + "description": "Reduce suspension force can be used for 'stancing' cars. Previous comment; Allows the vehicle to be stanced using the SET_REDUCED_SUSPENSION_FORCE native. Requires the CF_FIX_OLD_BUGS flag to be enabled. Previously known as _AF_CAN_BE_STANCED", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags15" + }, + { + "index": 16, + "name": "CF_HARD_REV_LIMIT", + "description": "Only working for Tuner cars, this uncaps the RPM in last gear which causes the power to drop off and lower the top speed of the car (effectively creating a speed cap in last gear). Previously this flag changed gear shift behaviour to cause earlier upshifts with a hard rev limit per gear, but this was changed with the Criminal Enterprises update. Previously known as _AF_TRACTION_CONTROL", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags16" + }, + { + "index": 17, + "name": "CF_HOLD_GEAR_WITH_WHEELSPIN", + "description": "Later upshifts; usually hits the gear's rev limit before shifting. Previously known as _AF_HOLD_GEAR_LONGER", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags17" + }, + { + "index": 18, + "name": "CF_INCREASE_SUSPENSION_FORCE_WITH_SPEED", + "description": "Anti-downforce suspension; increases suspension spring force as vehicle goes faster. Previously known as _AF_STIFFER_SPRING_SPEED", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags18" + }, + { + "index": 19, + "name": "CF_BLOCK_INCREASED_ROT_VELOCITY_WITH_DRIVE_FORCE", + "description": "Generates fake wheelspin after an instance of real wheelspin; Tyres will stabilize and show 0.0m/s of slip with debugging data, but the traction behaves like it's still spinning. Previously known as _AF_FAKE_WHEELSPIN", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags19" + }, + { + "index": 20, + "name": "CF_REDUCED_SELF_RIGHTING_SPEED", + "description": "Reduces righting force of the vehicle, effectively making it much harder and slower to flip back on its wheels. Previously known as _AF_REDUCED_RIGHTING_FORCE", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags20" + }, + { + "index": 21, + "name": "CF_CLOSE_RATIO_GEARBOX", + "description": "Extends the duration of the first gear, giving the vehicle a slower launch with greatly reduced wheelspin. Previously known as _AF_LONGER_1ST", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags21" + }, + { + "index": 22, + "name": "CF_FORCE_SMOOTH_RPM", + "description": "Smooth first-gear revving; resistance to hitting the rev-limit. Previously known as _AF_SMOOTH_REV_1ST", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags22" + }, + { + "index": 23, + "name": "CF_ALLOW_TURN_ON_SPOT", + "description": "Allows the vehicle to be rotated left or right while parked on the spot. Intended for tanks/tracked vehicles. Previously known as _AF_NEUTRAL_STEER", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags23" + }, + { + "index": 24, + "name": "CF_CAN_WHEELIE", + "description": "Allows the vehicle to perform a handbrake wheelie. The Muscle vehicle class is hardcoded to use this flag. Previously known as _AF_HANDBRAKE_WHEELIE", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags24" + }, + { + "index": 25, + "name": "CF_ENABLE_WHEEL_BLOCKER_SIDE_IMPACTS", + "description": "Makes the wheels much less likely to clip into the ground when the vehicle is tipped over. Previously known as _AF_REDUCE_EXT_WHEEL_COL_CLIPPING", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags25" + }, + { + "index": 26, + "name": "CF_FIX_OLD_BUGS", + "description": "Forced stock-tyre clipping boundaries, the sidewall gain/loss from a custom tyre will not matter. Refer to strHandlingFlags 00020000 above. Also prevents lowering the vehicle by shooting at its wheels/suspension. This flag is required in addition to 'CF_ALLOW_REDUCED_SUSPENSION_FORCE' to stance the vehicle through script. Previously known as _AF_IGNORE_TUNED_WHEELS_CLIP", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags26" + }, + { + "index": 27, + "name": "CF_USE_DOWNFORCE_BIAS", + "description": "Changes the way Downforce and spoiler tuning works, uses the setup found on Open-Wheel class vehicles in the vanilla game. Each spoiler/bumper tuning has to be given AdvancedData values to affect downforce. Adjusts initial downforce from fDownforceModifier. 'Curb - boosting' seems to be nullified. Previously known as _AF_DOWNFORCE_KERBFIX", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags27" + }, + { + "index": 28, + "name": "CF_REDUCE_BODY_ROLL_WITH_SUSPENSION_MODS", + "description": "Reduces body-roll if suspension upgrades are equipped. In addition, the vehicle gains more grip with each suspension option. Previously known as _AF_DECREASE_BODYROLL_TUNING", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags28" + }, + { + "index": 29, + "name": "CF_ALLOWS_EXTENDED_MODS", + "description": "Requires AdvancedData to work. Adds Turbo-affecting mods for mod slot 20 (VMT_KNOB) parts, and power-affecting mods for mod slot 22 (VMT_ICE) parts.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags29" + }, + { + "index": 30, + "name": "_CF_REMOVED_FLAG_31", + "description": "Flag does not exist.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags30" + }, + { + "index": 31, + "name": "_CF_REMOVED_FLAG_32", + "description": "Flag does not exist.", + "category": "AdvancedFlags", + "dataIdentifier": "AdvancedFlags31" + }, + { + "index": 0, + "name": "DF_DRIVER_SIDE_FRONT_DOOR", + "description": "Marks the driver-side front door (door_dside_f) bone as non-breakable.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags00" + }, + { + "index": 1, + "name": "DF_DRIVER_SIDE_REAR_DOOR", + "description": "Marks the driver-side rear door (door_dside_r) bone as non-breakable.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags01" + }, + { + "index": 2, + "name": "DF_DRIVER_PASSENGER_SIDE_FRONT_DOOR", + "description": "Marks the passenger-side front door (door_pside_f) bone as non-breakable.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags02" + }, + { + "index": 3, + "name": "DF_DRIVER_PASSENGER_SIDE_REAR_DOOR", + "description": "Marks the passenger-side rear door (door_pside_r) bone as non-breakable.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags03" + }, + { + "index": 4, + "name": "DF_BONNET", + "description": "Marks the bonnet bone as non-breakable.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags04" + }, + { + "index": 5, + "name": "DF_BOOT", + "description": "Marks the boot bone as non-breakable.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags05" + }, + { + "index": 6, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags06" + }, + { + "index": 7, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags07" + }, + { + "index": 8, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags08" + }, + { + "index": 9, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags09" + }, + { + "index": 10, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags10" + }, + { + "index": 11, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags11" + }, + { + "index": 12, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags12" + }, + { + "index": 13, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags13" + }, + { + "index": 14, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags14" + }, + { + "index": 15, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags15" + }, + { + "index": 16, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags16" + }, + { + "index": 17, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags17" + }, + { + "index": 18, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags18" + }, + { + "index": 19, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags19" + }, + { + "index": 20, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags20" + }, + { + "index": 21, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags21" + }, + { + "index": 22, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags22" + }, + { + "index": 23, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags23" + }, + { + "index": 24, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags24" + }, + { + "index": 25, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags25" + }, + { + "index": 26, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags26" + }, + { + "index": 27, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags27" + }, + { + "index": 28, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags28" + }, + { + "index": 29, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags29" + }, + { + "index": 30, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags30" + }, + { + "index": 31, + "name": "N/A", + "description": "Flag does not exist.", + "category": "DamageFlags", + "dataIdentifier": "DamageFlags31" + }, + { + "index": 0, + "name": "DF_STOP_FOR_CARS", + "description": "Stops before vehicles.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags00" + }, + { + "index": 1, + "name": "DF_STOP_FOR_PEDS", + "description": "Stops before peds.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags01" + }, + { + "index": 2, + "name": "DF_SWERVE_AROUND_ALL_CARS", + "description": "Avoids vehicles.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags02" + }, + { + "index": 3, + "name": "DF_STEER_AROUND_STATIONARY_CARS", + "description": "Avoids empty vehicles.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags03" + }, + { + "index": 4, + "name": "DF_STEER_AROUND_PEDS", + "description": "Avoids peds.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags04" + }, + { + "index": 5, + "name": "DF_STEER_AROUND_OBJECTS", + "description": "Avoids objects.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags05" + }, + { + "index": 6, + "name": "DF_DONT_STEER_AROUND_PLAYER_PED", + "description": "Will not avoid drive by player ped", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags06" + }, + { + "index": 7, + "name": "DF_STOP_AT_LIGHTS", + "description": "Stops at traffic lights.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags07" + }, + { + "index": 8, + "name": "DF_GO_OFF_ROAD_WHEN_AVOIDING", + "description": "When avoiding anything, allow for going off road.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags08" + }, + { + "index": 9, + "name": "DF_DRIVE_INTO_ONCOMING_TRAFFIC", + "description": "Allows going wrong way. Only does it if the correct lane is full, will try to reach the correct lane again as soon as possible.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags09" + }, + { + "index": 10, + "name": "DF_DRIVE_IN_REVERSE", + "description": "Drives in reverse gear.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags10" + }, + { + "index": 11, + "name": "DF_USE_WANDER_FALLBACK_INSTEAD_OF_STRAIGHT_LINE", + "description": "If pathfinding fails, cruise randomly instead of going on a straight line.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags11" + }, + { + "index": 12, + "name": "DF_AVOID_RESTRICTED_AREAS", + "description": "Avoid restricted areas.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags12" + }, + { + "index": 13, + "name": "DF_PREVENT_BACKGROUND_PATHFINDING", + "description": "These only work on MISSION_CRUISE.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags13" + }, + { + "index": 14, + "name": "DF_ADJUST_CRUISE_SPEED_BASED_ON_ROAD_SPEED", + "description": "Follow road speed limit.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags14" + }, + { + "index": 15, + "name": "DF_PREVENT_JOIN_IN_ROAD_DIRECTION_WHEN_MOVING", + "description": "Flag seems not to be used in Rockstar's decompiled scripts", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags15" + }, + { + "index": 16, + "name": "DF_DONT_AVOID_TARGET", + "description": "Flag seems not to be used in Rockstar's decompiled scripts", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags16" + }, + { + "index": 17, + "name": "DF_TARGET_POSITION_OVERRIDES_ENTITY", + "description": "Flag seems not to be used in Rockstar's decompiled scripts", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags17" + }, + { + "index": 18, + "name": "DF_USE_SHORT_CUT_LINKS", + "description": "Take the shortest path. Removes most pathing limits, the driver even goes on dirt roads. Use if you're going to be primarily driving off road.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags18" + }, + { + "index": 19, + "name": "DF_CHANGE_LANES_AROUND_OBSTRUCTIONS", + "description": "Will change lanes to drive around obstructions. Previously named: Allow overtaking vehicles if possible.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags19" + }, + { + "index": 20, + "name": "DF_AVOID_TARGET_COORS", + "description": "???", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags20" + }, + { + "index": 21, + "name": "DF_USE_SWITCHED_OFF_NODES", + "description": "Will allow for using switched off street nodes. Cruise tasks ignore this anyway--only used for goto's.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags21" + }, + { + "index": 22, + "name": "DF_PREFER_NAVMESH_ROUTE", + "description": "Take the shortest path. Removes most pathing limits, the driver even goes on dirt roads. Use if you're going to be primarily driving off road.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags22" + }, + { + "index": 23, + "name": "DF_PLANE_TAXI_MODE", + "description": "Only works for planes using MISSION_GOTO, will cause them to drive along the ground instead of fly.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags23" + }, + { + "index": 24, + "name": "DF_FORCE_STRAIGHT_LINE", + "description": "Ignore all pathing, goes straight to destination.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags24" + }, + { + "index": 25, + "name": "DF_USE_STRING_PULLING_AT_JUNCTIONS", + "description": "???", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags25" + }, + { + "index": 26, + "name": "DF_AVOID_ADVERSE_CONDITIONS", + "description": "Flag seems not to be used in Rockstar's decompiled scripts", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags26" + }, + { + "index": 27, + "name": "DF_AVOID_TURNS", + "description": "Flag seems not to be used in Rockstar's decompiled scripts", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags27" + }, + { + "index": 28, + "name": "DF_EXTEND_ROUTE_WITH_WANDERS_RESULTS", + "description": "Flag seems not to be used in Rockstar's decompiled scripts", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags28" + }, + { + "index": 29, + "name": "DF_AVOID_HIGHWAYS", + "description": "Avoid highways when possible, will use the highway if there is no other way to get to the destination.", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags29" + }, + { + "index": 30, + "name": "DF_FORCE_JOIN_IN_ROAD_DIRECTION", + "description": "???", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags30" + }, + { + "index": 31, + "name": "DF_DONT_TERMINATE_TASK_WHEN_ACHIEVED", + "description": "???", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags31" + }, + { + "index": 32, + "name": "DF_LAST_FLAG", + "description": "???", + "category": "DrivingStyleFlags", + "dataIdentifier": "DrivingStyleFlags32" + }, + { + "index": 0, + "name": "HF_SMOOTHED_COMPRESSION", + "description": "Simulates progressive spring suspension. Makes suspension compression motion smoother.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags00" + }, + { + "index": 1, + "name": "HF_REDUCED_MOD_MASS", + "description": "Reduces mass added from upgrades.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags01" + }, + { + "index": 2, + "name": "HF_HAS_KERS", + "description": "Partially enables KERS on the vehicle; disables horn and shows the recharge bar below the minimap. KERS boost itself still needs to be enabled by the SET_VEHICLE_KERS_ALLOWED native.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags02" + }, + { + "index": 3, + "name": "HF_HAS_RALLY_TYRES", + "description": "Inverts the way grip works on the vehicle; with this flag enabled, grip starts at the fTractionCurveMin value and may increase up to the fTractionCurveMax value upon wheel slip. Grip stays at max beyond the vehicle's peak slip angle.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags03" + }, + { + "index": 4, + "name": "HF_NO_HANDBRAKE", + "description": "Disables handbrake control for the vehicle.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags04" + }, + { + "index": 5, + "name": "HF_STEER_REARWHEELS", + "description": "Steers the rear wheels instead of the front.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags05" + }, + { + "index": 6, + "name": "HF_HANDBRAKE_REARWHEELSTEER", + "description": "Handbrake control makes the rear wheels steer as well as the front.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags06" + }, + { + "index": 7, + "name": "HF_STEER_ALL_WHEELS", + "description": "Steers all wheels, similar to 4-wheel-steering systems found on real vehicles. The rear wheels will steer at the same lock angle as the front, as defined by fSteeringLock.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags07" + }, + { + "index": 8, + "name": "HF_FREEWHEEL_NO_GAS", + "description": "Disables engine-braking when no throttle is applied.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags08" + }, + { + "index": 9, + "name": "HF_NO_REVERSE", + "description": "Disables reversing for the vehicle.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags09" + }, + { + "index": 10, + "name": "HF_REDUCED_RIGHTING_FORCE", + "description": "???", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags10" + }, + { + "index": 11, + "name": "HF_STEER_NO_WHEELS", + "description": "Disables steering on all wheels, used with tracked vehicles.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags11" + }, + { + "index": 12, + "name": "HF_CVT", + "description": "Gives the vehicle a fixed-ratio transmission with a gear ratio of 0.90, used for vehicles with nInitialDriveGears=1. If gears amount to more than 1, it will simply force the vehicle into top gear upon acceleration. Recommended for electric vehicles.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags12" + }, + { + "index": 13, + "name": "HF_ALT_EXT_WHEEL_BOUNDS_BEH", + "description": "Alternative extra wheel bound behavior. Offset extra wheel bounds forward so they act as bumpers and enable all collisions with them.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags13" + }, + { + "index": 14, + "name": "HF_DONT_RAISE_BOUNDS_AT_SPEED", + "description": "Some vehicles bounds dont respond well to be raised up too far, so this turns off the extra bound raising at speed.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags14" + }, + { + "index": 15, + "name": "HF_EXT_WHEEL_BOUNDS_COL", + "description": "Extra wheel bounds collide with other wheels.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags15" + }, + { + "index": 16, + "name": "HF_LESS_SNOW_SINK", + "description": "Less grip loss from deep mud/snow, most notably in North Yankton.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags16" + }, + { + "index": 17, + "name": "HF_TYRES_CAN_CLIP", + "description": "Tires are allowed to clip into the pavement when under enough pressure, effectiveness depends on tire sidewall. Generally makes the vehicle deal with uneven terrain better. Notes: this is the reason Offroad Tires improve performance on specific vehicles made by R*.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags17" + }, + { + "index": 18, + "name": "HF_REDUCED_DRIVE_OVER_DAMAGE", + "description": "Don't explode vehicles when driving over them.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags18" + }, + { + "index": 19, + "name": "HF_ALT_EXT_WHEEL_BOUNDS_SHRINK", + "description": "???", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags19" + }, + { + "index": 20, + "name": "HF_OFFROAD_ABILITIES", + "description": "Gravity constant increased by 10% to 10.78 m/s^2, resulting in increased grip and faster falling when airborne. Acceleration and braking performance is also increased by 10%.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags20" + }, + { + "index": 21, + "name": "HF_OFFROAD_ABILITIES_X2", + "description": "Gravity constant increased by 20% to 11.76 m/s^2, resulting in increased grip and faster falling when airborne. Acceleration and braking performance is also increased by 20%. Vehicle does not react to bushes.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags21" + }, + { + "index": 22, + "name": "HF_TYRES_RAISE_SIDE_IMPACT_THRESHOLD", + "description": "Includes the tires in the general side collision hitbox of the vehicle. Recommended for vehicles whose wheels extend beyond the bodywork, like monster-trucks.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags22" + }, + { + "index": 23, + "name": "HF_OFFROAD_INCREASED_GRAVITY_NO_FOLIAGE_DRAG", + "description": "Gravity constant increased by 20% to 11.76 m/s^2, resulting in increased grip and faster falling when airborne. Acceleration and braking performance is also increased by 20%. Vehicle does not react to bushes. Identical to HF_OFFROAD_ABILITIES_X2.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags23" + }, + { + "index": 24, + "name": "HF_ENABLE_LEAN", + "description": "??? Notes: Possibly for motorcycle leaning or boat leaning.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags24" + }, + { + "index": 25, + "name": "HF_FORCE_NO_TC_OR_SC", + "description": "Allows motorcycles to lose traction.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags25" + }, + { + "index": 26, + "name": "HF_HEAVYARMOUR", + "description": "Vehicle is resistant to explosions.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags26" + }, + { + "index": 27, + "name": "HF_ARMOURED", + "description": "Vehicle is bullet proof. Prevents vehicle doors (including hood and trunk) from opening in collisions.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags27" + }, + { + "index": 28, + "name": "HF_SELF_RIGHTING_IN_WATER", + "description": "???", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags28" + }, + { + "index": 29, + "name": "HF_IMPROVED_RIGHTING_FORCE", + "description": "Adds extra force to the vehicle when attempting to flip it back on its wheels.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags29" + }, + { + "index": 30, + "name": "HF_LOW_SPEED_WHEELIES", + "description": "???", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags30" + }, + { + "index": 31, + "name": "HF_LAST_AVAILABLE_FLAG", + "description": "Most likely doesn't do anything.", + "category": "HandlingFlags", + "dataIdentifier": "HandlingFlags31" + }, + { + "index": 0, + "name": "MF_IS_VAN", + "description": "Allows double doors for the rear doors animation.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags00" + }, + { + "index": 1, + "name": "MF_IS_BUS", + "description": "Uses bus animations for entry/exit.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags01" + }, + { + "index": 2, + "name": "MF_IS_LOW", + "description": "Uses animations suitable for cars with a low ride-height.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags02" + }, + { + "index": 3, + "name": "MF_IS_BIG", + "description": "Changes the way that the AI drives around corners.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags03" + }, + { + "index": 4, + "name": "MF_ABS_STD", + "description": "Arcade Anti-Lock Braking System (ABS) equipped as standard; minimal slip allowed.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags04" + }, + { + "index": 5, + "name": "MF_ABS_OPTION", + "description": "Arcade Anti-Lock Braking System (ABS) equipped w/ brakes upgrade.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags05" + }, + { + "index": 6, + "name": "MF_ABS_ALT_STD", + "description": "Realistic Anti-Lock Braking System (ABS) equipped as standard; some slip allowed.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags06" + }, + { + "index": 7, + "name": "MF_ABS_ALT_OPTION", + "description": "Realistic Anti-Lock Braking System (ABS) equipped w/brakes upgrade.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags07" + }, + { + "index": 8, + "name": "MF_NO_DOORS", + "description": "For vehicles that don't have any operable doors.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags08" + }, + { + "index": 9, + "name": "MF_TANDEM_SEATING", + "description": "Two people will use the front passenger seat.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags09" + }, + { + "index": 10, + "name": "MF_SIT_IN_BOAT", + "description": "Uses seated boat animation instead of standing.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags10" + }, + { + "index": 11, + "name": "MF_HAS_TRACKS", + "description": "For vehicles with tracks instead of tires.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags11" + }, + { + "index": 12, + "name": "MF_NO_EXHAUST", + "description": "Removes all exhaust particles.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags12" + }, + { + "index": 13, + "name": "MF_DOUBLE_EXHAUST", + "description": "Creates a second exhaust by mirroring the model's exhaust over the y-axis.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags13" + }, + { + "index": 14, + "name": "MF_NO_1STPERSON_LOOKBEHIND", + "description": "Prevents player using rear view when in first-person mode.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags14" + }, + { + "index": 15, + "name": "MF_CAN_ENTER_IF_NO_DOOR", + "description": "Allows entry into the vehicle despite no currently accessible doors.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags15" + }, + { + "index": 16, + "name": "MF_AXLE_F_TORSION", + "description": "Front wheels stay vertical to the car.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags16" + }, + { + "index": 17, + "name": "MF_AXLE_F_SOLID", + "description": "Front wheels stay parallel to each other.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags17" + }, + { + "index": 18, + "name": "MF_AXLE_F_MCPHERSON", + "description": "Front wheels can tilt.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags18" + }, + { + "index": 19, + "name": "MF_ATTACH_PED_TO_BODYSHELL", + "description": "???", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags19" + }, + { + "index": 20, + "name": "MF_AXLE_R_TORSION", + "description": "Rear wheels stay vertical to the car.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags20" + }, + { + "index": 21, + "name": "MF_AXLE_R_SOLID", + "description": "Rear wheels stay parallel to each other.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags21" + }, + { + "index": 22, + "name": "MF_AXLE_R_MCPHERSON", + "description": "Rear wheels can tilt.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags22" + }, + { + "index": 23, + "name": "MF_DONT_FORCE_GRND_CLEARANCE", + "description": "Chassis COL is taken into account when suspension is compressed while hitting the ground, with sparks rendered.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags23" + }, + { + "index": 24, + "name": "MF_DONT_RENDER_STEER", + "description": "Does not render steering animations.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags24" + }, + { + "index": 25, + "name": "MF_NO_WHEEL_BURST", + "description": "Has Bulletproof Tires as standard.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags25" + }, + { + "index": 26, + "name": "MF_INDESTRUCTIBLE", + "description": "Can't explode or be considered inoperable from damage.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags26" + }, + { + "index": 27, + "name": "MF_DOUBLE_FRONT_WHEELS", + "description": "Places a second instance of each front wheel next to the normal one.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags27" + }, + { + "index": 28, + "name": "MF_IS_RC", + "description": "For RC vehicles such as the RC Bandito and Invade & Persuade Tank. The player model is hidden upon entering the vehicle.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags28" + }, + { + "index": 29, + "name": "MF_DOUBLE_REAR_WHEELS", + "description": "Duplicates the skidmarks of the rear tires.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags29" + }, + { + "index": 30, + "name": "MF_NO_WHEEL_BREAK", + "description": "Prevents wheel bones from detaching off the vehicle due to damage.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags30" + }, + { + "index": 31, + "name": "MF_EXTRA_CAMBER", + "description": "The vehicle needs extra wheel camber to stop the wheels clipping the arches. This is only used for the lowrider cars at the moment.", + "category": "ModelFlags", + "dataIdentifier": "ModelFlags31" + } +] \ No newline at end of file diff --git a/flags.html b/flags.html index aa1235d..a765d2d 100644 --- a/flags.html +++ b/flags.html @@ -1,229 +1,87 @@ - - - - Handling Flags - - - - - - -
-

Handling flags and stuff (WIP)

-
- -
- -
-
-
IS_VAN
-
IS_BUS
-
IS_LOW
-
IS_BIG
-
-
-
ABS_STD
-
ABS_OPTION
-
ABS_ALT_STD
-
ABS_ALT_OPTION
-
-
-
NO_DOORS
-
TANDEM_SEATS
-
SIT_IN_BOAT
-
HAS_TRACKS
-
-
-
NO_EXHAUST
-
DOUBLE_EXHAUST
-
NO1FPS_LOOK_BEHIND
-
CAN_ENTER_IF_NO_DOOR
-
-
-
AXLE_F_TORSION
-
AXLE_F_SOLID
-
AXLE_F_MCPHERSON
-
ATTACH_PED_TO_BODYSHELL
-
-
-
AXLE_R_TORSION
-
AXLE_R_SOLID
-
AXLE_R_MCPHERSON
-
DONT_FORCE_GRND_CLEARANCE
-
-
-
DONT_RENDER_STEER
-
NO_WHEEL_BURST
-
INDESTRUCTIBLE
-
DOUBLE_FRONT_WHEELS
-
-
-
RC
-
DOUBLE_RWHEELS
-
MF_NO_WHEEL_BREAK
-
IS_HATCHBACK
-
-
-
-

Result

-
<strModelFlags>00000000<⁄strModelFlags>

- -
-
+ strong[contenteditable="true"] { + background: wheat; + padding: 0 0.5rem 0 0.5rem; + } + span.text-muted { + display: ruby; + } -
- -
-
-
SMOOTH_COMPRESN
-
REDUCED_MOD_MASS
-
-
-
-
-
NO_HANDBRAKE
-
STEER_REARWHEELS
-
HB_REARWHEEL_STEER
-
STEER_ALL_WHEELS
-
-
-
FREEWHEEL_NO_GAS
-
NO_REVERSE
-
-
-
-
-
CVT
-
ALT_EXT_WHEEL_BOUNDS_BEH
-
DONT_RAISE_BOUNDS_AT_SPEED
-
-
-
-
LESS_SNOW_SINK
-
TYRES_CAN_CLI
-
-
-
-
-
OFFROAD_ABILITY
-
OFFROAD_ABILITY2
-
HF_TYRES_RAISE_SIDE_IMPACT_THRESHOLD
-
-
-
-
ENABLE_LEAN
-
HEAVYARMOUR
-
-
ARMOURED
-
-
-
SELF_RIGHTING_IN_WATER
-
IMPROVED_RIGHTING_FORCE
-
-
-
-
-
-

Result

- -
<strHandlingFlags>00000000<⁄strHandlingFlags>

- - -
-
-
-
- - + .pleb:after { + content: 'P'; + font-size: x-small; + font-weight: bold; + baseline-shift: super; + position: absolute; + margin-left: 1rem; + }*/ + + + +
+

Handling flags and stuff (WIP)

+
+
+ + diff --git a/flags.js b/flags.js new file mode 100644 index 0000000..84f7ed7 --- /dev/null +++ b/flags.js @@ -0,0 +1,774 @@ + +const flagMeta = { + modelFlags: { + prefix: 'MF' + }, + handlingFlags: { + prefix: 'HF' + }, + /*advancedFlags: { + prefix: 'CF' + },*/ + damageFlags: { + prefix: 'DF' + }, +}; +const flagData = { + modelFlags: [ + ['IS_VAN', 'IS_BUS', 'IS_LOW', 'IS_BIG'], + ['ABS_STD', 'ABS_OPTION', 'ABS_ALT_STD', 'ABS_ALT_OPTION'], + ['NO_DOORS', 'TANDEM_SEATS', 'SIT_IN_BOAT', 'HAS_TRACKS'], + ['NO_EXHAUST', 'DOUBLE_EXHAUST', 'NO1FPS_LOOK_BEHIND', 'CAN_ENTER_IF_NO_DOOR'], + ['AXLE_F_TORSION', 'AXLE_F_SOLID', 'AXLE_F_MCPHERSON', 'ATTACH_PED_TO_BODYSHELL'], + ['AXLE_R_TORSION', 'AXLE_R_SOLID', 'AXLE_R_MCPHERSON', 'DONT_FORCE_GRND_CLEARANCE'], + ['DONT_RENDER_STEER', 'NO_WHEEL_BURST', 'INDESTRUCTIBLE', 'DOUBLE_FRONT_WHEELS'], + ['IS_RC', 'DOUBLE_RWHEELS', 'NO_WHEEL_BREAK', 'IS_HATCHBACK'] + ], + handlingFlags: [ + ['SMOOTH_COMPRESN', 'REDUCED_MOD_MASS', '', 'HAS_RALLY_TYRES'], + ['NO_HANDBRAKE', 'STEER_REARWHEELS', 'HB_REARWHEEL_STEER', 'STEER_ALL_WHEELS'], + ['FREEWHEEL_NO_GAS', 'NO_REVERSE', 'REDUCED_RIGHTING_FORCE', ''], + ['CVT', 'ALT_EXT_WHEEL_BOUNDS_BEH', 'DONT_RAISE_BOUNDS_AT_SPEED', ''], + ['LESS_SNOW_SINK', 'TYRES_CAN_CLIP', 'REDUCED_DRIVE_OVER_DAMAGE', ''], + ['OFFROAD_ABILITY', 'OFFROAD_ABILITY2', 'TYRES_RAISE_SIDE_IMPACT_THRESHOLD', ''], + ['ENABLE_LEAN', 'HEAVYARMOUR', '', 'ARMOURED'], + ['SELF_RIGHTING_IN_WATER', 'IMPROVED_RIGHTING_FORCE', 'LOW_SPEED_WHEELIES', ''] + ], + /*advancedFlags: [ + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''] + ],*/ + damageFlags: [ + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''], + ['', '', '', ''] + ] + + +}; + + + + + + + + + + + + +// Store global variables for flag descriptions +let plebFlags = {}; +let iktFlags = {}; + +(async function loadFlags() { + try { + // Run both fetches in parallel + const [plebResponse, iktResponse] = await Promise.all([ + fetch('flags-pleb.json'), + fetch('flags-ikt.json') + ]); + + if (!plebResponse.ok) throw new Error(`HTTP error! Status: ${plebResponse.status}`); + if (!iktResponse.ok) throw new Error(`HTTP error! Status: ${iktResponse.status}`); + + const plebData = await plebResponse.json(); + const iktData = await iktResponse.json(); + + console.log('Loaded flags-pleb.json:', plebData); + console.log('Loaded flags-ikt.json:', iktData); + + plebFlags = plebData; + iktFlags = iktData.flags || iktData; + + createFlagSections(); + autoborders(); + } catch (err) { + console.error('Error loading flags files:', err); + } +})(); + + + +function cap1st(str){ + return String(str).charAt(0).toUpperCase(str) + String(str).slice(1); +} + +function low1st(str){ + return String(str).charAt(0).toLowerCase(str) + String(str).slice(1); +} + + +function camelToTitleCase(camelCaseStr) { //ie modelFlags ->Model Flags + + return camelCaseStr + .replace(/([A-Z])/g, ' $1') // Insert space before capital letters + .replace(/^./, str => str.toUpperCase()); // Capitalize the first letter +} + +function rmFlagsPrefix(flag, key){ + + + var fPrefix = flagMeta[flag].prefix; + + var regex = new RegExp(`^_?(?:${fPrefix}_)`); + + var result = key.replace(regex, ''); + + + //console.log(`flag:${flag}, key:${key}, prefix:${fPrefix}\n\nresult:${result}`); + + return result; + +} + + + + +function createFlagSections() { + + Object.entries(flagMeta).forEach(([key, value]) => { + //console.log(key, value.prefix); + createFlagSection(`${key}Section`, camelToTitleCase(key)+` Generator (${flagMeta[key].prefix})`, key, flagData[key], 'str'+cap1st(key) ); + }); + +} + +function createFlagSection(id, title, resultId, flagRows, handlingMetaKey) { + + //console.log( `createFlagSection( \n\t'id:${id}',\n\ttitle:'${title}',\n\tflag:'${resultId}',\n\tflagRows: [${flagRows}],\n\thandlingMetaKey:'${handlingMetaKey}'\n);` ); + + var initFlagVal = "0"; + + const container = document.createElement('div'); + container.id = id; + container.classList.add('col-xxl-5', 'text-center', 'bg-whitesmoke', 'mt-5', 'border', 'border-info', 'p-5', 'mx-auto'); + + container.innerHTML = ` + +
+
+

${handlingMetaKey}

 = ${initFlagVal}
+
+ <${handlingMetaKey}>${initFlagVal}<⁄${handlingMetaKey}> +
+
+
+ +

+ `; + + const flagContainer = container.querySelector('.divTbl'); + flagRows.forEach((row, rowIndex) => { + + + const rowDiv = document.createElement('div'); + rowDiv.classList.add('row'); + + row.forEach((flag, colIndex) => { + + var iktVal = ((rowIndex*4)+colIndex); + + var flagInfo = iktFlags[handlingMetaKey][iktVal]; + + //var iktName = flagInfo.name.replace(/^_?(?:[A-Z]{2}_)/, ''); + //var iktName = flagInfo.name.replace(/^_?(?:${flagMeta[resultId].prefix}_)/, ''); + var iktName = rmFlagsPrefix(resultId, flagInfo.name); + + //console.log('\n iktFlag:', {'index': iktVal, 'flag': resultId, 'rowIndex': rowIndex, 'colIndex': colIndex, 'iktName': iktName} ); + + const colDiv = document.createElement('div'); + + colDiv.classList.add('col-sm-3', 'py-1', 'align-middle'); + colDiv.dataset.flag = resultId; + colDiv.dataset.rowIndex = rowIndex; + colDiv.dataset.colIndex = colIndex; + + + + + + + + var plebFlag = plebFlags.find(item => item.index === iktVal && low1st(item.category) === resultId); + + // error if we find nothing.. + + /*var matchCategory = String(plebFlag.category).charAt(0).toLowerCase() + String(plebFlag.category).slice(1);*/ + //console.log(`${resultId} == ${matchCategory}`); + //console.log(`${resultId} == ${matchCategory}`); + plebFlag.category = cap1st(plebFlag.category); + //console.log(`plebFlag:`, plebFlag); + + + Object.entries(plebFlag).forEach(([key, value]) => { + //console.log(`${key}:\t${value}`); + colDiv.classList.add('pleb'); + colDiv.dataset[`pleb${key}`] = value; + }); + + + + + + + + + + + colDiv.dataset['iktdescription'] = flagInfo.description; + colDiv.dataset['iktname'] = flagInfo.name; + + colDiv.dataset.address = getHexInfo(iktVal); + + colDiv.title = `${colDiv.dataset.address}\n\n`; + colDiv.title += `ikt: \t${flagInfo.name}\n${flagInfo.description}`; + colDiv.title += `\n\n`; + colDiv.title += `pleb:\t${plebFlag.name}\n${plebFlag.description}`; + //colDiv.title = JSON.stringify( colDiv.dataset, null, 4); /*`${iktName}\n${flagInfo.description}`*/; + if( !flag ){ + colDiv.classList.add('ikt'); + colDiv.textContent = rmFlagsPrefix(resultId, iktName) || ''; + } + + if(flag){ + colDiv.textContent = flag || ''; + } + + //console.log( colDiv.dataset ); + + rowDiv.appendChild(colDiv); + }); + flagContainer.appendChild(rowDiv); + }); + + document.querySelector('main .row').appendChild(container); + + makeHexEditable(resultId); +} + + + + + + + + + + + + + + + +/** + * How We Build a Flag + * ------------------- + * Flags are represented as binary numbers where each bit represents an "ON" or "OFF" state of a specific flag. + * Each row contains 4 flags. Each flag corresponds to a bit position in a 4-bit binary number. + * The leftmost flag in the row is the most significant bit (MSB), and the rightmost flag is the least significant bit (LSB). + * + * Example: + * ['IS_VAN', 'IS_BUS', 'IS_LOW', 'IS_BIG'] + * If IS_VAN and IS_LOW are toggled ON, then the binary is: 1010 (binary) = A (hexadecimal) +*/ + +function autoborders() { + const autoborder = document.querySelectorAll(".col-sm-3"); + autoborder.forEach((col) => { + col.onclick = toggle; + col.classList.add('border', /*'text-truncate',*/ 'border-gray'); + }); +} + +function toggle(e) { + const target = e.target; + + var flagType = target.dataset.flag; + target.classList.toggle('bg-success'); + + + + //console.log(`flagType: ${flagType}, calcFlags(${flagType}, flagData['${flagType}'])`); + calcFlags(flagType, flagData[flagType]); + + + /*Object.entries(flagMeta).forEach(([key, value]) => { + console.log(`flagType: ${flagType}, calcFlags(${key}, flagData['${key}'])`); + calcFlags(key, flagData[key]); + + }); + + calcFlags('modelFlags', flagData.modelFlags); + calcFlags('handlingFlags', flagData.handlingFlags); + calcFlags('advancedFlags', flagData.advancedFlags); + calcFlags('damageFlags', flagData.strDamageFlags); + */ +} + +function getHexInfo(flagIndex){ + + + if (flagIndex < 0 || flagIndex > 31) { + console.error(`Invalid flagIndex: ${flagIndex}. Must be between 0 and 31.`); + return; + } + + // Calculate the hexadecimal value of this specific bit + const flagValue = (1 << flagIndex) >>> 0; // Force unsigned 32-bit shift + + returnStr=`Flag ${flagIndex} / 0x${flagValue.toString(16).toUpperCase().padStart(8, '0')} \/\/ ${flagValue}`; + // Log the flag information + //console.log(returnStr); + + return returnStr + +} + +function calcFlags(flagType, flagArray) { + let result = 0 >>> 0; // Force unsigned 32-bit result + + console.log( `calcFlags('${flagType}', flagArray)` ); + + var flaginfoLines = ''; + $(`#${flagType}Section .divTbl div.row`).each((rowIndex, rowElement) => { + let rowResult = 0; + + + var binaryRow = []; + $(rowElement).find('div').each((colIndex, flagElement) => { + + //console.log( `index: `, flagElement.dataset.plebindex ); + + if (flagElement.classList.contains('bg-success')) { + + // Calculate the flag index using the combined row and column position + const flagIndex = (rowIndex * 4) + colIndex; + + // Calculate the bit shift position + const shiftAmount = flagIndex; + + // Calculate the hexadecimal value of this specific bit + const flagValue = (1 << shiftAmount) >>> 0; // Force unsigned 32-bit shift + + // Log the flag information + var flagInfo = `Flag ${flagIndex} / 0x${flagValue.toString(16).toUpperCase().padStart(8, '0')} \/\/ ${flagValue}`; + + flaginfoLines += `${flagInfo}\n` + + // Merge this bit into the overall result + result |= flagValue; + + binaryRow.push("1"); + }else{ + binaryRow.push("0"); + } + + }); + //console.log( `${binaryRow}` ); + + }); + + // Convert the full 32-bit result to an 8-character hexadecimal string + const hexString = (result >>> 0).toString(16).toUpperCase().padStart(8, '0'); + + var truncatedHex = hexString.replace(/^0+/, '') || '0'; + + document.getElementById(`${flagType}`).innerHTML = truncatedHex; + + //if(flaginfoLines){ + console.log(`%c${flagType}%c:\n${flaginfoLines}`, 'color:yellow;background:black;font-weigh:bold;', ''); + + updHexSpan(flagType, truncatedHex); + + console.log(); + //} +} + +function updHexSpan(flagType, hexString){ + + + var flagIndex = `${"str"+cap1st(flagType)}`; + var messg = `#%c${flagIndex}%c: %c${hexString}`; + console.log(`${messg}\n\n`, 'color:yellow;background:black;font-weigh:bold;', '', 'color:yellow;background:blue;font-weigh:bold;'); + + $(`#${flagIndex}`).text(`${hexString}`); + + //handlingArray.handling[flagType] = hexString; + + // function replaceHandlingAttr(tagName, attrName, newValue) { + // replaceHandlingAttr(fDownforceModifier, value, 62.45){}; + // tagName:fDownforceModifier, attrName:value, newValue:62.45 + replaceHandlingAttr(flagIndex, 'string', hexString); +} + +function setFlagState(flagType, hexString) { + + console.log( `%csetFlagState('${flagType}', '${hexString}');`, 'background:blue;color:yellow;font-weigh:bold;' ); + + const binaryValue = parseInt(hexString, 16).toString(2).padStart(32, '0'); + // console.log( 'binaryValue:', binaryValue ); + + const flagArray = flagData[flagType]; + + flagArray.forEach((row, rowIndex) => { + // Reverse the row index to match the binary layout + const reverseRowIndex = flagArray.length - 1 - rowIndex; + const rowBinary = binaryValue.slice(reverseRowIndex * 4, (reverseRowIndex + 1) * 4).split('').reverse(); + + row.forEach((flag, colIndex) => { + var flagNo = ((rowIndex * 4) + colIndex); + var queryFlagDivs = `[data-flag='${flagType}'][data-plebindex='${flagNo}']`; + + const element = document.querySelector(queryFlagDivs); + if (!element) { + console.warn(`Element not found for query: ${queryFlagDivs}`); + return; + } + + if (rowBinary[colIndex] === '1') { + element.classList.add('bg-success'); + } else { + element.classList.remove('bg-success'); + } + }); + + // console.log(`${rowBinary}`); + + }); + + var truncatedHex = hexString.replace(/^0+/, '') || '0'; + + updHexSpan(flagType, truncatedHex); + hexInputEl = document.getElementById(flagType); + + + $(hexInputEl).text(truncatedHex); + + var flagIndex = `${"str"+cap1st(flagType)}`; + var messg = `${flagIndex} flag updated: "${truncatedHex}"`; + $(`#msg_${flagType}`).removeAttr('class').addClass('alert-success').text(messg).show().fadeOut(3600, function(){ + $(this).html(' ').show(); + }); +} + + + + + +// Function to restore the caret position +function restoreCaret(element, position) { + const selection = window.getSelection(); + const range = document.createRange(); + + const textNode = element.childNodes[0]; + const maxPosition = textNode ? textNode.length : 0; // Get the length of the text node safely + + const safePosition = Math.min(position, maxPosition); // Ensure position is within the text length + try { + range.setStart(textNode, safePosition); + } catch (error) { + console.warn(`Failed to set caret position: ${error.message}`); + return; + } + + range.collapse(true); + selection.removeAllRanges(); + selection.addRange(range); +} + + +// Function to replace the current selection with new text +function replaceSelectionWithText(element, newText) { + const selection = window.getSelection(); + const range = selection.getRangeAt(0); + range.deleteContents(); + range.insertNode(document.createTextNode(newText)); +} + +// Function to get the length of the current selection +function getSelectionLength() { + const selection = window.getSelection(); + return selection.toString().length; +} + + +function makeHexEditable(elementId) { + // Get the element by ID + const element = document.getElementById(elementId); + + if (!element) { + console.warn(`Element with id "${elementId}" not found.`); + return; + } + + + $(element).off('change').on('change', (e) => { + + var messg; + const lengthlimit=8; + const targetFlagEl = e.currentTarget; + var flagStr = targetFlagEl.innerHTML; + console.log( flagStr, flagStr.length ); + + if( flagStr.length >= lengthlimit ){ + e.preventDefault(); + targetFlagEl.innerHTML = flagStr.substring(0, lengthlimit); + alert( `max ${lengthlimit} chars`); + } + }) + + // Make it contenteditable + element.setAttribute('contenteditable', 'true'); + + + + + + + $(element).off('keydown input paste').on('keydown input paste', (e) => { + const lengthLimit = 8; // Maximum allowed length + const targetFlagEl = e.currentTarget; + + // ** Save Original Text and Caret Position ** + const originalText = targetFlagEl.textContent; // Original text before change + const selection = window.getSelection(); + const range = selection.getRangeAt(0); + const caretPosition = range.startOffset; + + // Utility to restore text and caret if something goes wrong + const restoreOriginal = () => { + targetFlagEl.textContent = originalText; + restoreCaret(targetFlagEl, caretPosition); + } + + switch (e.type) { + + case 'paste': + e.preventDefault(); // Stop default paste action + + navigator.clipboard.readText().then((pastedText) => { + const cleanValue = pastedText.toUpperCase().replace(/[^0-9A-F]/g, ''); // Hex only + const currentText = targetFlagEl.textContent; + const selectionLength = getSelectionLength(); + const availableChars = lengthLimit - currentText.length + selectionLength; + + const pasteValue = cleanValue.slice(0, availableChars); // Get only what fits + const updatedText = replaceSelectionWithText(originalText, caretPosition, selectionLength, pasteValue); + + + if (cleanValue.length > availableChars) { + //console.warn(`Paste rejected - not enough space for the pasted content.`); + //restoreOriginal(); + var messg = `Paste truncated - text would exceed length limit.`; + console.warn(messg); + $(`#msg_${elementId}`).removeAttr('class').addClass('alert-warning').text(messg).show(); //fadeOut(3600, function(){ $(this).html(' ').show(); }); + + targetFlagEl.textContent = updatedText; + return; + } + + + if (updatedText.length <= lengthLimit) { + targetFlagEl.textContent = updatedText; // Commit change + restoreCaret(targetFlagEl, caretPosition + pasteValue.length); // Move caret + } else { + //console.warn(`Paste rejected - text would exceed length limit.`); + //restoreOriginal(); + + console.warn(`Paste truncated - text would exceed length limit.`); + targetFlagEl.textContent = updatedText; + + } + }).catch(err => { + console.warn(`Error reading clipboard: ${err}`); + restoreOriginal(); + }); + + $(`#msg_${elementId}`).removeAttr('class').text(" ").show(); + + break; + + case 'input': + const cleanValue = targetFlagEl.textContent.toUpperCase().replace(/[^0-9A-F]/g, ''); + + if (cleanValue.length > lengthLimit) { + console.warn(`Input rejected - character limit of ${lengthLimit} exceeded.`); + restoreOriginal(); + return; + } + + targetFlagEl.textContent = cleanValue; // Commit change + restoreCaret(targetFlagEl, caretPosition); + + $(`#msg_${elementId}`).removeAttr('class').text(" ").show(); + + break; + + case 'keydown': + const validKeys = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; + const key = e.key.toUpperCase(); + + // Handle Enter Key: If 8 chars are present, submit via setFlagState + if (e.key === 'Enter') { + e.preventDefault(); + var currentText = targetFlagEl.textContent; + + if (currentText.length <= lengthLimit) { + + + if( currentText.length < lengthLimit) { + console.log( `before: %c${currentText}`, 'color:red;'); + //currentText = currentText.padEnd( lengthLimit, '0'); + //currentText = currentText.padStart( lengthLimit, '0'); + console.log( `after: %c${currentText}`, 'color:red;'); + + } + + var messg = `Submitting setFlagState('${targetFlagEl.id}', '${currentText}');`; + //console.log(messg); + $(`#msg_${elementId}`).removeAttr('class').addClass('alert-warning').text(messg); + try { + setFlagState(`${targetFlagEl.id}`, `${currentText}`); + } catch (error) { + console.error('❌ Error in setFlagState:', error); + } + + } else { + var messg = `You must enter exactly ${lengthLimit} characters. Current: ${currentText.length}`; + console.log(messg); + $(`#msg_${elementId}`).removeAttr('class').addClass('alert-danger').text(messg).show(); //fadeOut(3600, function(){ $(this).html(' ').show(); }); + + } + return; + } + + // Allow Ctrl+V, Ctrl+X (paste, cut) + if ((key === "A" || key === "V" || key === "Z" || key === "X") && e.ctrlKey) { + return; + } + + // Allow navigation, backspace, delete, arrow keys + if (['Shift', 'Control', 'Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) { + return; + } + + // Reject non-hex characters + if (!validKeys.includes(key)) { + e.preventDefault(); + + var messg = `${elementId} Invalid key "${key}" ignored. Only hex characters (0-9, A-F) allowed. `; + console.warn(messg); + $(`#msg_${elementId}`).removeAttr('class').addClass('alert-danger').text(messg).show(); //fadeOut(3600, function(){ $(this).html(' ').show(); }); + + restoreOriginal(); + return; + } + + // Check if we have space for more characters + var currentText = targetFlagEl.textContent; + if (currentText.length >= lengthLimit && !getSelectionLength()) { + e.preventDefault(); + var messg = `Max length of ${lengthLimit} reached. Ignoring further input.`; + console.warn(messg); + $(`#msg_${elementId}`).removeAttr('class').addClass('alert-warning').text(messg).show(); // + + restoreOriginal(); + return; + } + + console.log(`#msg_${elementId}`); + $(`#msg_${elementId}`).text(" "); + /* + var el = $(`#msg_${elementId}`); + + console.log( $(el) ); + $(el).innerHTML(" "); + $(el).removeAttr('class'); + $(el).show(); + */ + + break; + + } + + /** + * Restore the caret position to the previous location. + * Ensures the position is valid and doesn't exceed text length. + */ + function restoreCaret(element, position) { + const selection = window.getSelection(); + const range = document.createRange(); + + const textNode = element.childNodes[0]; + const maxPosition = textNode ? textNode.length : 0; // Get the length of the text node safely + + const safePosition = Math.min(position, maxPosition); // Ensure position is within the text length + try { + range.setStart(textNode, safePosition); + } catch (error) { + console.warn(`Failed to set caret position: ${error.message}`); + return; + } + + range.collapse(true); + selection.removeAllRanges(); + selection.addRange(range); + } + + /** + * Replace the current selection with new text. + * Handles the current selection and replaces it with the provided newText. + */ + function replaceSelectionWithText(currentText, startPos, selectionLength, newText) { + const before = currentText.slice(0, startPos); + const after = currentText.slice(startPos + selectionLength); + return before + newText + after; + } + + /** + * Get the length of the current selection. + * Useful for determining how much text is currently highlighted. + */ + function getSelectionLength() { + const selection = window.getSelection(); + return selection.toString().length; + } + + }); + + + + + + + + + + + + + + + + + + + + console.log(`Hexadecimal input/keydown enabled for element with id "${elementId}"`); + +} diff --git a/handling.html b/handling.html index cec0a24..cc62818 100644 --- a/handling.html +++ b/handling.html @@ -1,8 +1,10 @@ + + @@ -18,6 +20,81 @@ Handling + + + @@ -96,7 +173,7 @@ Antiroll