RED Tweaks - psiberx/cp2077-tweak-xl GitHub Wiki
TweakXL supports the original tweak file format used by REDengine / REDmod, but interprets it differently, merging definitions instead of replacing them. This approach ensures compatibility and maintainability:
- Allows different mods to modify the same records, and in some cases even the same properties
- Makes mods more prepared for game updates, sometimes not requiring any changes
With full syntax support, you can use the REDmod sources as a reference and copy-paste definitions from it. But you shouldn't use entire files as is.
Tweak files can have any name and must have a .tweak
extension,
be placed in the <Cyberpunk 2077>/r6/tweaks
directory,
and can be organized using subdirectories.
Tweak file can define the package name that acts as the namespace for the groups, and import other packages to look for groups in:
package Attacks
using AttackModifier
GenjiReflect : BaseExplosion
{
statModifiers =
[
{
refObject = "Parent";
} : PhysicalAlliedDamage
];
}
The use of packages is optional, full names can be used instead:
Attacks.GenjiReflect : Attacks.BaseExplosion
{
statModifiers =
[
{
refObject = "Parent";
} : AttackModifier.PhysicalAlliedDamage
];
}
Groups can act as a namespace for flats or define records:
// Create flat named MyGroup.value
MyGroup
{
int value = 1;
}
// Create record named MyRecord of type Vehicle
MyRecord : Vehicle
{
type = "Vehicle.Car";
model = "Vehicle.Turbo";
}
Flats can be scalars, structures or arrays.
To assign a value to an existing flat, you need the group name and flat name:
PreventionSystem.setup
{
totalEntitiesLimit = 40;
}
To define a new flat, you must add type declaration:
MySystem
{
CName triggerState = "Combat";
float[] probabilities = [0.2, 0.5, 0.3];
}
This will create two flats MySystem.triggerState
and MySystem.probabilities
.
To change the properties of an existing record, you must use the record name:
Vehicle.v_standard2_archer_bandit_player
{
trafficSuspension = "Vehicle.TrafficSuspension_Sport";
enableDestruction = false;
}
To create a record, you must add a record type declaration:
Items.MyClothingItem : Clothing
{
entityName = "my_item";
appearanceName = "my_item_";
displayName = "My-Item-Name";
}
Unspecified properties will be filled with default values.
The type name can be in any of the following forms:
Form | Value | Comment |
---|---|---|
Base name | Clothing |
Used in WolvenKit and REDmod. |
Script name | Clothing_Record |
Used in redscript. |
Native name | gamedataClothing_Record |
Used in CET and RED4ext. |
To clone a record, you must use the other record name instead of type:
Items.MyClothingItem : Items.GenericFaceClothing
{
entityName = "my_item";
appearanceName = "my_item_";
displayName = "My-Item-Name";
}
The records can be created inline when assigning foreign keys:
Vehicle.v_my_archer_quartz : Vehicle.v_standard2_archer_quartz_player
{
// This will crete new record of VehicleUIData type
vehicleUIData =
{
driveLayout = "LocKey#45371";
horsepower = 250.0;
};
}
Usually you don't need to specify the type of the inline record, because it's already known from the parent definition. But you have to use it for polymorphic relationships:
Items.MyWeapon : WeaponItem
{
statModifiers =
[
{
statType = "BaseStats.BaseDamage";
modifierType = "Additive";
value = 50.0;
} : ConstantStatModifier,
{
statType = "BaseStats.BaseDamage";
modifierType = "Additive";
min = 0.0;
max = 10.0;
} : RandomStatModifier,
];
}
Tweak Type: int
Native Type: Int32
Examples
{
int a = 220;
int b = -1;
}
Tweak Type: float
Native Type: Float
Examples
{
float a = 50.0;
float b = -7.25f; // optional "f" suffix
float c = 123; // no decimal part
}
Tweak Type: bool
Native Type: Bool
Examples
{
bool a = true;
bool b = false;
}
Tweak Type: string
Native Type: String
Examples
{
string a = "This is a string";
string b = "Escape seque\nces a\ren't suppor\ted";
}
Tweak Type: CName
Native Type: CName
Examples
{
CName a = "Thing";
CName b = "None"; // Special value to define empty name
CName c = ""; // Equals to "None"
}
Tweak Type: LocKey
Native Type: gamedataLocKeyWrapper
Examples
{
LocKey a = "LocKey#13245"; // Using primary key
LocKey b = "LocKey#My-Mod-Key"; // Using secondary key defined with ArchiveXL
}
Tweak Type: ResRef
Native Type: raRef:CResource
Examples
{
ResRef a = "base\gameplay\gui\world\lcd_screens\lcdscreen_1x3.inkwidget";
ResRef b = "base/gameplay/gui/fullscreen/photo_mode/frame/v_frame.inkatlas";
ResRef c = "";
}
Resource paths
The path can use backslashes\
, double backslashes\\
, or slashes/
.
For example, all of these paths are valid and equal:
path\to\resource.ext
path\\to\\resource.ext
path/to/resource.ext
Tweak Type: fk<Record>
Native Type: TweakDBID
Examples
{
fk<Stat> a = "BaseStats.Armor";
fk<WeaponItem> b = "Items.Preset_Overture_Default";
fk<IPrereq> c = "";
}
Tweak Type: Quaternion
Native Type: Quaternion
Examples
{
Quaternion a = (0.0, 0.0, 0.923880, 0.382683);
Quaternion b = (0.f, 0.f, 1.f, -0.f);
}
Tweak Type: EulerAngles
Native Type: EulerAngles
Examples
{
EulerAngles a = (0.0, 135.0, 0.0);
EulerAngles b = (0.f, -45.f, 45.f);
}
Tweak Type: Vector3
Native Type: Vector3
Examples
{
Vector3 a = (0.113662, 2.880340, 0.000001);
Vector3 b = (0, 0, 0);
}
Tweak Type: Vector2
Native Type: Vector2
Examples
{
Vector2 a = (15, 7.5);
Vector2 b = (10000, 10000);
}
Arrays are homogeneous and can be of any scalar or structure type.
Examples
{
int[] intArray =
[
1, 3,
5, 7, // trailing comma is allowed
];
string[] stringArray = ["Str1", "Str2", "Str3"];
Vector3[] vecArray =
[
(0.0, 0.0, 0.0),
(-0.1, 0.0, 0.7),
];
}
Arrays can be mutated instead of replaced using operators +=
and -=
.
Items.w_silencer_01
{
// Remove some original modifiers
statModifiers -=
[
"Items.SilencerBase_inline1",
"Items.w_silencer_01_inline0"
];
// Add new modifiers
statModifiers +=
[
{
statType = "BaseStats.StealthHitDamageMultiplier";
modifierType = "Additive";
value = 3.0;
} : ConstantStatModifier
];
}