Object Improvements¶
Upgrade Cameos¶
Added support for UpgradeCameo6-9 slots. These need to be defined in the controlbar .wnd files to work.
WeaponSet¶
Added new parameter to an object's WeaponSet definition
WeaponReloadSharedAcrossSets = NoIf a unit switched between weaponset, it's reload time and ammo count (in percent) will be kept. For instance Migs will not reload in air when they get BlackNapalm.
AutoChooseSources¶
Added new types for AutoChooseSources
SYNC_TO_PRIMARYThis weapon slot cannot fire on its own, but will be fired whenever PRIMARY is fired.SYNC_TO_SECONDARYThis weapon slot cannot fire on its own, but will be fired whenever SECONDARY is fired.SYNC_TO_TERTIARYThis weapon slot cannot fire on its own, but will be fired whenever TERTIARY is fired.
Syncs a weapon slot to another. The weapon slot cannot be used except when it's parent weapon is fired. This ignores all conditions and checks of the synced weapon.
Example:
Weapon = PRIMARY MainWeapon
Weapon = SECONDARY SyncedWeapon
AutoChooseSources = SECONDARY SYNC_TO_PRIMARY
AmmoPips style¶
Added options to customize Ammo Pips, e.g. for Aircraft with a very large clip size.
Added a new parameter for object definitions:
AmmoPipsStyle = DEFAULTChange the unit's display style for ammo pips to one of these:DEFAULTdefault ZH style; 1 yellow pip symbol for each shot.PERCENTAGE_BARdisplay a yellow bar similar to the health bar, showing the ammo count in percent.SINGLEdefault ZH pip visuals, but only show a single symbol regardless of clip size. Ammo count is displayed via fading yellow color.
Note
This parameter might be moved to individual weapons in the future, to allow displaying ammo pips for multiple weapon slots at once.
Display Decal New¶
A ground decal drawn under the object, for auras, faction markers and similar. It is separate from
the object's shadow: an object can carry a Shadow and a display decal at the same time, and the
decal keeps drawing when the player turns 2D or 3D shadows off in the video options. It does hide
under shroud, while the object is hidden, and once the object dies, slow death included.
Added new parameters for object definitions:
DisplayDecal = Yes ; default No
DecalTexture = ShadowIH ; required; the engine appends .tga
DecalSizeX = 14 ; world-space size in X
DecalSizeY = 14 ; world-space size in Y
DecalOffsetX = 0 ; world-space offset in X
DecalOffsetY = 0 ; world-space offset in Y
DecalStyle = SHADOW_ALPHA_DECAL ; SHADOW_DECAL, SHADOW_ALPHA_DECAL or SHADOW_ADDITIVE_DECAL
DecalColor = R:255 G:255 B:255 ; tint, default white
DecalOpacity = 100% ; default 100%
DecalHideWhenDisabled = No ; default No
DecalTexturehas no default, unlikeShadowTexture. An object that setsDisplayDecal = Yeswithout naming a texture draws nothing.DecalStyletakes only the three decal blend styles; the projection and volume types need a shadow-casting setup a display decal does not have, and fall back toSHADOW_ALPHA_DECAL.SHADOW_DECALmultiplies, exactly like a 2D shadow. White is invisible and darker pixels darken the ground, so the art needs no alpha channel at all - a plain DXT1 works.SHADOW_ALPHA_DECALalpha blends, for a painted marker. Needs a real alpha channel.SHADOW_ADDITIVE_DECALadds, for a glow. Ignores alpha; black is what reads as nothing.
- Whichever style, the decal always rasterizes the full
DecalSizeXbyDecalSizeYrectangle, snapped outward to whole terrain cells, and relies on clamped texture addressing. The art has to fade out at its own edges - an opaque edge texel gets stretched across the whole footprint. DecalHideWhenDisabled = Yesstops drawing the decal while the object is disabled - EMP, hacked, subdued, unmanned, out of power, disabled by script and so on - and brings it back when the object recovers. Useful when the decal reads as something the unit is actively doing.DecalColortints the texture. Any alpha written here is ignored -DecalOpacityis what fades the decal. Both are ignored underSHADOW_DECAL, whose blend has no way to apply them.DecalOpacitymeans different things per style. UnderSHADOW_ALPHA_DECALit is an ordinary alpha fade. UnderSHADOW_ADDITIVE_DECALthe blend ignores alpha entirely, so opacity instead scales the colour toward black, dimming the glow.- A unit with several draw modules gets one decal, not one per module.
- The whole feature can be switched off by the player with
ObjectDecals = Noin Options.ini.
This is for a decal that belongs to a unit for its whole life. For a temporary decal spawned by an
effect — a scorch mark or a footprint — use the Decal FX nugget with W3DDecalDraw instead.
Object Modules¶
AIUpdateInterface (And all other AIUpdate types)¶
New experimental parameter:
PreferredAttackAngle = <angle> [MIRRORED]mirrored keyword is optional) When a unit turns to attack, it will attempt to turn to this angle. If mirrored is enable it can also use the same angle +180°. Possibly useful for battleship setups with multiple turrets. Only works for locomotors that can turn in place (minTurnSpeed = 0
Note
this is NOT needed for limited turret angles (See below). Units will follow the actual turret angles when trying to attack.
New AutoAcquireEnemiesWhenIdle value:
NOTWHILEMOVINGthe object will not shoot on the move. Intended for artillery that has to be stationary to fire, which previously had to be faked in other ways. Combine it with the other values as usual, e.g.AutoAcquireEnemiesWhenIdle = Yes NOTWHILEMOVING.
What it does, by order type:
| Order | Behaviour |
|---|---|
| Move | Drives past enemies without stopping or engaging. |
| Attack-move | Drives, spots a target, halts once in range, fires, then carries on. |
| Attack (direct order) | Closes on the target, halts, fires. |
| Stationary | Fires normally. |
This takes two separate checks, because the two halves pull against each other. Targets of opportunity - the idle scans, including a turret scanning while the chassis under it drives - are suppressed while the object is in motion, which is what keeps it from shooting on an ordinary move. Attack-move deliberately still acquires on the move, because spotting a target while driving is exactly what makes the unit stop for it; the object then keeps aiming, without firing, until it has actually come to rest. It holds its target throughout and fires the moment it settles, so any PreAttackDelay wind-up plays where the shot is taken rather than being spent on the approach.
DeployStyleAIUpdate¶
New command for deploying artillery, replacing the old trick of pointing a FIRE_WEAPON button at a dummy
weapon slot. That worked, but it went through the weapon lock and brought its bugs with it.
CommandButton Command_Deploy
Command = TOGGLE_DEPLOY
Options = OK_FOR_MULTI_SELECT
ButtonImage = SNNukeCannonDeploy
ButtonBorderType = ACTION
TextLabel = CONTROLBAR:ToolTipDeploy
UnitSpecificSound = NukeCannonVoiceDeploy
End
TOGGLE_DEPLOY needs no WeaponSlot. It flips the object between deployed and packed, and the button shows
as toggled on while deployed. It works on any object with a DeployStyleAIUpdate; on anything else the
button is unavailable.
A deploy asked for this way latches, so the unit holds the stance instead of packing up again the moment nothing is in range - which is the point, since it lets a unit deploy before the enemy arrives. The latch is dropped when the player gives any order other than an attack, so a move order packs the unit up as usual. Automatic deploying when a target comes into range is unchanged.
Selecting a mixed group and pressing the button moves the whole group to one stance rather than flipping each unit separately, so a second press does not undo half of them.
Turret¶
New paramters for Turret or AltTurret entries
MinTurretAngle = 0Minimum angle the turret is allowed to turnMaxTurretAngle = 0Maximum angle the turret is allowed to turn
Notes
- Angles are relative to the hull. Positive turns the turret to its left, negative to its right, so
MinTurretAngleis always the rightmost edge of the arc andMaxTurretAnglethe leftmost. - To mirror an arc onto the other side, negate and swap the values: a left sponson with
MinTurretAngle = 0/MaxTurretAngle = 50becomesMinTurretAngle = -50/MaxTurretAngle = 0on the right. - For backwards facing configurations, set MaxTurretAngle < MinTurretAngle; the arc then wraps through the rear (e.g.
150/-150covers the rear 60 degrees). Currently this is not working 100% reliably. - Remove the angle limit lines to use unlimited angle. A value of 0 will use 0 as limit.
- If the turret cannot turn to the front (e.g. side mounted gun on a helicopter), the unit will attempt to turn to the turret's firing arc
- this feature only works for locomotors that can turn in place (minTurnSpeed = 0)
WeaponSetUpgrade¶
Added new parameters for WeaponSetUpgrade
WeaponSetFlag = <WeaponSetFlag>define which Weaponset to enable (default = PLAYER_UPGRADE)WeaponSetFlagsToClear = <WeaponSetFlag1> <WeaponSetFlag2> ..define which Weaponsets to disableNeedsParkedAircraft = NoUnits with JetAIUpdate need to be parked in hangar to research this upgrade
Notes: WeaponSetFlagsToClear can be used to switch between WeaponSets using multiple upgrades. example:
Behavior = WeaponSetUpgrade ModuleTag_04a
WeaponSetFlag = PLAYER_UPGRADE
WeaponSetFlagsToClear = PLAYER_UPGRADE2 PLAYER_UPGRADE3
TriggeredBy = Upgrade_GLAWorkerFakeCommandSet
RemovesUpgrades = Upgrade_GLAWorkerRealCommandSet Upgrade_GLAWorkerFakeCommandSet Test_Upgrade_DummyToggle
End
Behavior = WeaponSetUpgrade ModuleTag_04b
WeaponSetFlag = PLAYER_UPGRADE2
WeaponSetFlagsToClear = PLAYER_UPGRADE PLAYER_UPGRADE3
TriggeredBy = Upgrade_GLAWorkerRealCommandSet
RemovesUpgrades = Upgrade_GLAWorkerRealCommandSet Upgrade_GLAWorkerFakeCommandSet Test_Upgrade_DummyToggle
End
Behavior = WeaponSetUpgrade ModuleTag_04c
WeaponSetFlag = PLAYER_UPGRADE3
WeaponSetFlagsToClear = PLAYER_UPGRADE PLAYER_UPGRADE2
TriggeredBy = Test_Upgrade_DummyToggle
RemovesUpgrades = Upgrade_GLAWorkerRealCommandSet Upgrade_GLAWorkerFakeCommandSet Test_Upgrade_DummyToggle
End
ArmorUpgrade¶
Added new parameters for ArmorUpgrade
ArmorSetFlag = <ArmorSetFlag>define which Armorset to enable (default = PLAYER_UPGRADE)ArmorSetFlagsToClear = <ArmorSetFlag1> <ArmorSetFlag2> ..define which ArmorSets to disable
Notes: ArmorSetFlagsToClear can be used to switch between ArmorSets using multiple upgrades (see WeaponSetUpgrade).
LocomotorSetUpgrade¶
Added new parameters for LocomotorSetUpgrade
EnableUpgrade = Noif 'Yes' (default), locomotor is switched to SET_NORMAL_UPGRADED; if 'No' locomotor is switched back to SET_NORMALExplicitLocomotorType = SET_SUPERSONICOptional; explicitly switch to the defined locomotor set (This is not persistant, unlike EnableUpgrade)
Notes: EnableUpgrade only allows for a single locomotor upgrade, but it can be toggled on/off with multiple upgrades. With ExplicitLocomotorType, Locomotor sets can be set freely, but they will not persist if the unit changes its locomotor through other means (e.g. Aircraft taking off, or combat bike switching rider)
MaxHealthUpgrade¶
Added new parameter for MaxHealthUpgrade
MultiplyMaxHealth = 1.0multiplier on the unit's current HP; default = 1.0 -> no change.
Notes:
- It is recommended to change all health upgrades to multiplicative as they will not be affected by other HP changes like veterancy, and can be freely stacked (and even reversed).
- You can still use AddMaxHealth for additive boni, and could even combine it with MultiplyMaxHealth. The formula is
NewHP = (CurrentHP * MultiplyMaxHealth) + AddMaxHealth.
ArmorDamageScalarUpdate New¶
This module was designed for a temporary armor buff ability. The module will apply a damage/armor scale value to every unit in the area for the given amount of time. In addition, various visual effects can be added.
example:
Behavior = ArmorDamageScalarUpdate ModuleTag_01
AllowedAffectKindOf = VEHICLE STRUCTURE ; (required; any object matching *any* of these KindOfs is a valid target)
ForbiddenAffectKindOf = INFANTRY ; (optional; any object matching *any* of these KindOfs is an invalid target)
AffectsTargets = ALLIES NEUTRALS ; (required; any combination of ALLIES, NEUTRALS, ENEMIES)
AffectAirborne = Yes ; (default = Yes; Should this affect units currently in the air)
BonusDuration = 10000 ; (required; How long effect lasts, in ms)
BonusRange = 100 ; (required; Radius of the effect)
ArmorDamageScalar = 0.9; ; (default = 1.0; damage scalar to apply; 1.0 = no effect; 0.5 = takes half damage; 2.0 = takes double damage; min = 0.01)
EffectParticleSystem = <entry from particlesystem.ini> ; (optional; apply particlesystem to affected objects. SystemLifeTime is scaled automatically. If VolumeType = BOX, the size will be changed to the object's geometry.)
OverrideDamageFX = <entry from damageFX.ini> ; (optional; change the object's DamageFX to this entry over the duration)
ScaleParticleSystem = Yes ; (default = No; If enabled, the particle system's spawn rate will be adjusted for the object's size)
ApplyColorTint = Yes ; (default = No; Apply a dark red color tint to the objects for the duration)
End
- This module is designed to be put on a dummy object marker, like for EmergencyRepair or Frenzy.
- To correctly track the objects over the duration, the marker object needs to stay alive for the duration. Lifetime is tracked in the module itself. You do not need to add a lifetimeupdate as well. If the object is killed earlier, the effect will be removed from all units.
- The effect is applied once at the beginning. Objects leaving or entering the radius later will not get the effect.
- The module can be used to apply a damage increase to enemy units (i.e. lower their armor)
CostModiferUpgrade¶
New Parameters added. Example:
Behavior = CostModiferUpgrade ModuleTag_123
TriggeredBy = Upgrade_CostReduction ; entry from upgrade.ini
EffectKindOf = VEHICLE ; Units with this KindOf will be affected
Percentage = -20% ; amount that cost will be reduced
IsOneShotUpgrade = No ; (NEW) Is this a one time global upgrade, or should it be removed when the object dies or changes owner?
BonusStacksWith = DIFFERENT_VALUE ; (NEW) Stacking behavior when multiple bonus sources exist
End
** BonusStacksWith types **
DIFFERENT_VALUEDefault behavior: Does not stack with other bonus with the same value. Does stack with bonus with different value.OTHER_TYPEDoes stack with bonus from other type of unit with the same value. Does not stack with bonus from the same type of unit. I.e. Multiple OilRefineries would not stack, but a Refinery would stack with an IndustrialPlant if it had the same value.SAME_TYPEBonus from multiple sources of the same type will stack. I.e. Owning multiple Refineries grants additional bonus.
Notes:
- Bonus stacking is additive, not multiplicative
ProductionTimeModiferUpgrade New¶
This works just like CostModiferUpgrade (Oil Refinery) to apply a global production time reduction for the given KindOf example:
Behavior = ProductionTimeModifierUpgrade ModuleTag_123
TriggeredBy = Upgrade_CostReduction ; entry from upgrade.ini
EffectKindOf = VEHICLE ; Units with this KindOf will be affected
Percentage = -20% ; amount that build time will be reduced
IsOneShotUpgrade = No ; Is this a one time global upgrade, or should it be removed when the object dies or changes owner?
BonusStacksWith = DIFFERENT_VALUE ; Stacking behavior when multiple bonus sources exist
End
ExperienceScalarUpgrade¶
~~Added parameter to make module active by default (useful for negativ scalars):~~
- ~~
StartsActive = False~~
Update: removed this, because it didn't work. You will need to grant a dummy upgrade instead.
Added new parameter to modify XP value of a unit (i.e. XP that is gained for the enemy when the unit is killed)
-
AddXPValueScalar = 0.0Additive modifier for XP value scalar. I.e.: XPValueNew = XPValueOld * (1.0 + AddXPValueScalar). -
SetMaxVeterancyLevel = <VeterancyLevel>Raises the unit's maximum veterancy level (e.g. toLEVEL_FOURorLEVEL_FIVE) when this upgrade is active. Lets you unlock the extra veterancy levels via an upgrade. See Veterancy Object Parameters.
Laser Improvements¶
LaserUpdate¶
New parameters are added to allow the laser to grow/shrink or fade in/out
BeamFadeInDuration = 0time in ms. Alpha scalar is linear interpolated from 0 to 1 over the given time at the start.BeamFadeOutDuration = 0time in ms. Alpha scalar is linear interpolated from 1 to 0 at the end of the beam's lifetime. Requires LifetimeUpdateBeamGrowDuration = 0time in ms. Beam width is linear interpolated from 0 to 1 over the given time at the start.BeamShrinkDuration = 0time in ms. Beam width is linear interpolated from 1 to 0 at the end of the beam's lifetime. Requires LifetimeUpdateUseMultiLaserDraw = NoThis flag is needed, if a Laser object has multiple LaserDraw modules, to correctly update all of themUseHouseColoredParticles = NoApply house colored tint to the laser's muzzle and target particle systems
W3DLaserDraw¶
Added parameters to specify grid animation. Currently only a 1xn grid is allowed (i.e. multiple columns) to work together with scrollRate.
TextureGridTotalColumns = 1total number of columns in the textureTextureGridColumns = 1actual number of columns used for the animationUseHouseColorOuter = Noapply house color to the laser's outer colorUseHouseColorOuter = Noapply house color to the laser's inner color
Note
Usually both TextureGridColumns and TextureGridTotalColumns numbers would be the same. But having separate numbers allows to use an odd number of frames and still keep proper DDS texture sizes. E.g. you have a texture width of 512, with 8 frames of 64. But you only want 7 frames, so you can set TextureGridTotalColumns=8 and TextureGridColumns=7.
MissileAIUpdate¶
Added new parameters to MissileAIUpdate module:
-
RandomPathOffset = 0.0distance in meters. Missile projectils will spread out randomly to fly a random arc pattern for more interesting visuals. -
ZCorrectionFactor = 2.0Missiles attacking air units will have their direction shifted upwards by this factor. (2.0 is vZH default) -
ApplyLauncherBonus = NoAny extra weapon that is fired from the projectile (On death, fireweaponupdate, etc.) will inherit the shooter's weapon bonus values
Notes
- ZCorrectionFactor is what causes AA missiles in vZH to be never aligned to the launcher. For units with actual fire pitch (e.g. Patriot), it is recommended to set this value to 0. For units that cannot pitch (e.g. Missile Defender) a value between 1 and 2 is recommended.
DumbProjectileBehavior¶
New parameters:
-
ApplyLauncherBonus = NoAny extra weapon that is fired from the projectile (On death, fireweaponupdate, etc.) will inherit the shooter's weapon bonus values -
DynamicHeightMinScale = 1.0Scales the projectile's arc height based on the distance to the target. At maximum weapon range the full arc height is used; the closer the target, the more the height is scaled down towards this value.1.0= no scaling (default). Useful so short-range shots don't arc as high, e.g. for torpedoes/arcing guns. DynamicHeightMinRange = 1.0The target distance at/below whichDynamicHeightMinScaleis fully reached. The height scale interpolates between this range and the weapon's max range.
FreeFallProjectileBehavior¶
New type of projectile module that mimics the behavior of Bombs dropped by genpowers. Projectiles will move based on physics, making it suitable for carpet bomb or strafing run aircraft weapons. On collision, the weapon's damage and detonation effects are applied.
Example:
Behavior = FreeFallProjectileBehavior ModuleTag_009
MaxLifespan = 10000 ; Maximum lifetime of the object
TumbleRandomly = No ; Adds random rotation, same as for DumbProjectileBehavior
CourseCorrectionScalar = 1.0 ; guide the bomb towards the intended target. 1=no homing, 0=snapto; 0.99=smooth, 0.95=too-fast
UseWeaponSpeed = No ; apply additional speed from the unit's weapon
ExitPitchRate = 0 ; Angle tilt per second to apply (respects centerOfMassOffset in the projectile's physics)
ApplyLauncherBonus = Yes ; Apply weapon bonus from launcher for any secondary weapon effects
DetonateOnGround = Yes ; Will the projectile detonate when hitting the ground or live on (to bounce or rest on ground)?
DetonateOnCollide = Yes ; Same as above, when hitting another object (See Weapon for collission settings)
GarrisonHitKillRequiredKindOf = <Kindof list> ; Same as MissileAI/DumbProjectile
GarrisonHitKillForbiddenKindOf= <Kindof list> ; Same as MissileAI/DumbProjectile
GarrisonHitKillCount = 0 ; Same as MissileAI/DumbProjectile
GarrisonHitKillFX = <FXList> ; Same as MissileAI/DumbProjectile
End
Notes
- This module's behavior depends a lot on the projectile's physics settings, such as mass, friction, etc. It takes some finetuning to get the exact behavior you want.
- For basic carpet bombing, you can copy the settings from existing genpowers.
ScatterShotUpdate New¶
New module intended for weapon projectiles, to allow scattering in mid air and fire multiple shots to targets within range.
Parameters:
Weapon=- (The weapon to be fired at targets.) NumShots=- (default = 0; number of shots to fire) TargetSearchRadius=- (default = 0; range around the weapon's target location or object that we look for targets) TargetMinRadius=- (default = 0; minimum range targets need to be away from the original target) MaxShotsPerTarget=- (default = 0; How many shots to fire at each target. 0 = randomly attack ground only; 1 = attack each target once; >1 when each target was attacked once, start from the beginning) PreferSimilarTargets=- (default = No; Choose air or ground targets similar to the main target object. I.e. if we attack an air unit, all targets will be picked from air units first) PreferNearestTargets=- (default = No; Prefer targets closest to the original target; Otherwise choose randomly) NoTargetsScatterRadius=- (default = 0; If not targets were found/picked, use this random scatter radius to attack the ground) NoTargetsScatterMinRadius=- (default = 0; Minimum scatter radius when no target is found) NoTargetsScatterMaxAngle=- (default = 0; Acceptable aim delta angle for scatter targets) AttackGroundWhenNoTargets=- (default = yes; If Yes, when we run out of targets, fire randomly at the ground; If No, do not fire.) AvoidOriginalTargetObject=- (default = no; If Yes, we never try to hit the original target of the attack) AvoidPreviousTargetWhenChain=- (default = no; When the attack was fired from another ScatterShot module, avoid that modules original target) TriggerDistanceToTarget=- (default = 0; How close the projectile needs to be to the target to trigger the scatter shot.) TriggerLifetime=- (default = 0; How long after the projectile was created to trigger the scatter shot. 0 = no limit.) TriggerOnImpact=- (default = No; Trigger scatter shot on projectile impact.) TriggerInstantly=- (default = No; Trigger scatter shot instantly after the projectile was created) StayAliveAfterTrigger=- (default = No; The original weapon's projectile will stay alive after the scatter shot was triggered.) TriggeredDeathType=- (default = NORMAL; The death type to use for the projectile object when the scatter shot is triggered.) ScatterFX=- (default = None; entry from FXList.ini to play when scatter shot is triggered.)
Notes:
- The weapon used for the scatter shot needs to have a clip size large enough to fire all shots.
- When picking targets for the scatter shots, they need to be viable targets for the weapon's damage type.
- When the original weapon targets an object, that original target will always be picked to fire a scatter weapon at.
- This module can be used on non-projectile objects as well (using lifetime or instant triggers), e.g. to create an object that fires at multiple units in range simultaneously
Examples:
Behavior = ScatterShotUpdate ModuleTag_Scatter
Weapon = TomahawkMissileScatterWeapon ; simple guided rocket weapon
NumShots = 5
TargetSearchRadius = 120.0 ; Pick targets in 120 range
NoTargetsScatterRadius = 60.0 ; If no targets, scatter randomly in 60 radius
MaxShotsPerTarget = 1 ; Fire at each targets once. If we have more than 5 targets, hit the ground randomly
TriggerDistanceToTarget = 150.0 ; Trigger at this distance to target
End
Contain Modules¶
Added new features for all contain modules. WeaponBonus types that are passed to passengers can now be configured.
PassengerWeaponBonusList = <BONUS1> <BONUS2>provide a list of WeaponBonus types that will be applied to the contained objects
Default values:
- GarrisonContain: GARRISONED
- TransportContain: CONTAINED
Setting PassengerWeaponBonusList = None will override the default value.
Note
HelixContain grants GARRISONED to its passengers in vanilla ZH. This is changed to CONTAINED. To restore vanilla behaviour you will need to manually set the bonus here.
Targeting through addon turrets¶
A unit whose weapons live on a contained addon turret (an OverlordContain or MultiAddOnContain rider) could not be ordered to attack anything only the turret can hit -- the cursor showed a red cross, and the workaround was a dummy weapon on the carrier with the turret's range. This key replaces the dummy weapon. It works on every contain module except TunnelContain and CaveContain, where it parses but stays inert: their contained list is the player's whole shared network, so the answers would come from units sitting at other entrances.
AcceptTargetsForPassengers = NoYes lets the container accept attack orders on behalf of its passengers: when the container's own weapons cannot attack a target, the passengers' weapons are asked instead, and their best answer drives the cursor and the order. RequiresPassengersAllowedToFire = Yes.
Behavior = OverlordContain ModuleTag_Turret
Slots = 1
AllowInsideKindOf = PORTABLE_STRUCTURE
PassengersAllowedToFire = Yes
PassengersInTurret = Yes
PayloadTemplateName = AmericaThorTurretBolt
AcceptTargetsForPassengers = Yes ; New
End
Behaviour notes:
- When the order is given, the turret is told to attack (the engine already forwards attack orders to firing passengers); the carrier's own guns do not try to aim at a target they cannot attack.
- A turret that is EMP'd, hacked, subdued or paralyzed does not answer for the carrier.
- The turret cannot move, so a target beyond its range shows the out-of-range cursor rather than a green attack cursor -- the carrier does not automatically drive into range. Keep a dummy weapon if you want the carrier to approach on its own.
Add-on turret range from the carrier's center¶
An add-on turret is a separate object placed at a bone on its carrier -- AddOnBoneName for
MultiAddOnContain, the FIREPOINT bones for OverlordContain -- and with PassengersInTurret = Yes
that bone rides the carrier's turret. Weapon range is measured from the firing object's own
position and bounding circle, so the turret's reach swings by the bone's offset as the carrier's
turret sweeps: longer the way the barrel points, shorter the other way. The Overlord's gattling
shows it, and a turret mounted at the front of a chassis shows it plainly -- it opens fire early
forward and falls short backward, and no single AttackRange works in both directions.
AddOnWeaponRangeFromCenter = NoYes measures the add-on's weapon range from the carrier's center, using the carrier's bounding circle, instead of from its own attachment point.
Behavior = OverlordContain ModuleTag_Turret
Slots = 1
AllowInsideKindOf = PORTABLE_STRUCTURE
PassengersAllowedToFire = Yes
PassengersInTurret = Yes
PayloadTemplateName = AmericaThorTurretBolt
AddOnWeaponRangeFromCenter = Yes ; New
End
Behaviour notes:
- An add-on whose
AttackRangeequals the carrier's now reaches exactly as far as the carrier does, in every direction, at every turret angle -- the range no longer has to be tuned to compensate for where the bone sits. MinimumAttackRangemoves with it, so the too-close band is measured from the carrier's hull too, as it would be for a weapon mounted on the carrier.- The approach distance moves with it, so a carrier ordered to attack stops where its add-on can actually reach.
- Only the range test moves. The add-on still aims and fires from its own barrel, and its line of sight, muzzle effects and projectiles are unchanged.
- Parses on every contain module but stays inert on TunnelContain and CaveContain, whose passengers sit at whichever entrance they used rather than on a bone of the container.
Load slowdown from occupants¶
A container can be slowed by what it carries. The penalty scales with how full it is, so each passenger costs a share of it and leaving gives that share back; an emptied container returns to exactly its original speed. Fullness is measured in slots, not bodies, so a unit that takes three slots slows the transport three times as much as one that takes a single slot.
The defaults come from GameData's TransportLoadSpeedPenalty and friends, and these four override
them per container. Each is the fraction of that value lost at a full load.
LoadSpeedPenalty = 0%Fraction ofSpeedlost at a full load.LoadTurnRatePenalty = 0%Fraction ofTurnRatelost at a full load.LoadAccelerationPenalty = 0%Fraction ofAccelerationlost at a full load.LoadLiftPenalty = 0%Fraction ofLiftlost at a full load.LoadPenaltyEnabled = YesNoexempts this container entirely, whatever GameData sets. Use it to keep one transport at full speed without restating every percentage.LoadPenaltyKindOf = <KindOf list>If set, only occupants with one of these KindOfs count toward the load. Everything counts by default.LoadPenaltyForbidKindOf = <KindOf list>Occupants with any of these KindOfs never count toward the load. Nothing is excluded by default.
Example - a transport that is dragged down by vehicles but not by the infantry it carries:
Behavior = TransportContain ModuleTag_07
Slots = 8
LoadSpeedPenalty = 40%
LoadAccelerationPenalty = 25%
LoadPenaltyForbidKindOf = INFANTRY
End
Behaviour notes:
- Each penalty covers the damaged variant of its value, so
SpeedDamagedscales by the same percentage asSpeed. - The penalty follows the container across locomotor sets, so an upgrade that grants
SET_NORMAL_UPGRADED, or a switch toSET_PANIC, keeps it in effect. - A container that cannot move ignores all of this. The keys parse on every contain module, but a garrisoned building has no locomotor to slow down.
- Slot counts come from the occupant's
TransportSlotCount, so a bunker riding an Overlord is weighed by what is inside it. - A loaded transport moving with a group slows the whole group, the same way any slow unit does.
- Leaving every penalty at
0%is the previous behavior exactly, so existing INI is unaffected.
Filtering by object name¶
AllowInsideKindOf and ForbidInsideKindOf can only speak in whole KindOfs. These two name
individual objects instead, and work on every contain module -- TunnelContain, TransportContain,
GarrisonContain, CaveContain, OverlordContain, HelixContain and the rest.
ForbidInsideObjects = <object list>These objects can never enter. Checked first, so it beats everything else, includingAllowInsideObjects.AllowInsideObjects = <object list>If set, ONLY these objects may enter, whatever their KindOfs say. Leave it out to allow everything the other filters permit.
Example -- a tunnel network that refuses one specific unit:
Behavior = TunnelContain ModuleTag_05
TimeForFullHeal = 5000
ForbidInsideObjects = Aslt_GLAInfantryHijacker
End
Example -- a transport that carries nothing but two named units:
Behavior = TransportContain ModuleTag_07
ContainMax = 4
AllowInsideObjects = Aslt_GLAInfantryJarmenKell Aslt_GLAInfantryHijacker
End
Both keys take several names per line and append across repeated lines, so a long list can be split up. Matching is on the object name and ignores case.
Note
these filters decide whether a unit may enter. They do not evict anyone already inside, so changing them does not affect units that are already loaded.
StickyBombUpdate¶
Added new parameters to customize the 2D anim visuals:
Animation2DBase = <entry from Animation2D.ini>2D anim for background bomb visuals (default = BombRemote)Animation2DTimed = <entry from Animation2D.ini>2D anim for foreground/timer visuals; This is used when the bomb object has a LifeTimeUpdate (default = BombTimed)ShowTimer = YesFlag to disable Animation2DTimed for timed bombs - Only use base animation.
Note
Setting Animation2DBase or Timed to "None" will hide them.
CrateCollide¶
Added new parameters for all CrateCollide modules:
AllowNeutralPlayer = NoCrate can be picked up by the neutral playerAllowPickAboveTerrain = NoCrate can be picked up when it is above ground.
StickyBombCrateCollide¶
CrateCollide module to apply sticky bombs to objects. Can be used with pickup crates or projectiles.
Example:
Behavior = StickyBombCrateCollide ModuleTag_419
NeedsTarget = No ; Needs an intended target object (e.g. from a projectile) cannot be picked up by regular collission
StickyBombObject = <Object with StickyBombUpdate> ; The object to create
AllowMultiCollide = No ; If used as a crate, can the effect be applied to multiple objects at once?
ShowInfiltrationEvent = No ; If enabled, shows a radar event for the target player
ChanceToTriggerPercent = 100%; Chance to create the StickyBombObject.
End
Example to use on a Missile or DumbProjectile to apply a sticksBomb to the target:
Behavior = StickyBombCrateCollide ModuleTag_419
RequiredKindOf = STRUCTURE
ForbiddenKindOf = VEHICLE INFANTRY
BuildingPickup = Yes
ExecuteFX = FX_SniperDroneTargetTracerPingFX
AllowNeutralPlayer = Yes
AllowPickAboveTerrain = Yes
NeedsTarget = Yes
StickyBombObject = Lazr_SniperDroneTargetTracerStickyBomb
End
; Needs separate modules for Building/Unit collissions
Behavior = StickyBombCrateCollide ModuleTag_420
;RequiredKindOf = VEHICLE INFANTRY
ForbiddenKindOf = STRUCTURE
BuildingPickup = No
ExecuteFX = FX_SniperDroneTargetTracerPingFX
AllowNeutralPlayer = Yes
AllowPickAboveTerrain = Yes
NeedsTarget = Yes
StickyBombObject = Lazr_SniperDroneTargetTracerStickyBomb
End
AdvancedCollide New¶
A collide module with more versatile parameters
CollideWeapon = <weapon entry>Weapon to fire on collideOCL = <OCL entry>OCL to create on collideFX = <FXList entry>FX to create on collideFireOnce = Notrigger once or for every collissionCollideWithGround = Notrigger collision when hitting the groundCollideWithObjects = Yestrigger collission when hitting objects.RequiredStatus = <status entry>required status for this objectForbiddenStatus = <status entry>forbidden status for this objectTargetRequiredStatus = <status entry>required status for the object we collide withTargetForbiddenStatus = <status entry>forbidden status for the object we collide withRequiredKindOf = <KindOf entry>required KindOf for the object we collide withForbiddenKindOf = <KindOf entry>forbidden KindOf for the object we collide withChanceToTriggerPercent = 100%Chance to trigger effects on collideRollOnceForTrigger = NoRoll for trigger chance every time we collide, or only the first time (and then keep the result)
Note
This module allows to trigger effects when objects collides with the ground, e.g. when a projectile misses it's target.
LifeTimeUpdate¶
Add new parameter:
*ShowProgressBar = No Enables progress bar above unit health to visualize lifetime. Requires SHOW_PROGRESS_BAR KindOf.
RadiusDecalBehavior New¶
New module to create a radius decal that follows a unit. Can be triggered via upgrade.
Example:
Behavior = RadiusDecalBehavior ModuleTag_decal1
TriggeredBy = <Upgrade entry> ; Optional
; < All other basic upgrade entries (ConflictsWith, RemovesUpgrades, FXListUpgrade, RequiresAllTriggers) >
StartsActive = No ; Set to yes, to enable initially
Radius = 100.0 ; (radius in meters)
RadiusDecal ; Decal Template, Same parameters as DeliveryDecal in OCL ini
Texture = SCCFuelAirBomb_USA ; Texture name
Style = SHADOW_ALPHA_DECAL ; SHADOW_DECAL, SHADOW_ALPHA_DECAL or SHADOW_ADDITIVE_DECAL
OpacityMin = 25% ; default = 100%, Opacity will move between min and max
OpacityMax = 50% ; default = 100%
OpacityThrobTime = 500 ; default = 1000
Color = R:255 G:0 B:0 A:255
OnlyVisibleToOwningPlayer = Yes ; Disable to make the decal visible to all players
End
End
Note
This module reacts to the upgrade being removed (by a different upgrade). This means you can make the decal toggle on/off.
Added parameters:
DecalRadius = 0.0Overrides the decal radius separately from theRadiusfield; if 0,Radiusis used.WorksWhileContained = NoIf Yes, the decal stays visible/active while the object is contained inside a transport or structure.
ParkingPlaceBehavior¶
Added new features and parameters to ParkingPlaceBehavior (Airfield)
ParkedUnitsDamageScalar = 1.0scalar for damage taken applied to all parked aircraft (0.9 = only take 90% of damage)ParkedUnitsDamageScalarUpgraded = 1.0same as above, after upgradeDamageScalarUpgradedTriggeredBy = <upgrade name>upgrade to trigger the upgraded scalar valueRequiredKindOf = <KindOf list>if set, only aircraft that has these KindOfs is allowed to dock hereForbiddenKindOf = <KindOf list>if set, aircraft that has these KindOfs is not allowed to dock here.
Notes
- ParkedUnitsDamageScalar can be used to apply an upgrade that grants damage protection to parked aircraft
- Required/Forbidden KindOf can be used to allow only specific kinds of aircraft to land (i.e. to use different sizes, or differ between VTOL/Regular jets)
Filtering by object name¶
RequiredKindOf and ForbiddenKindOf can only speak in whole KindOfs. These two name individual
objects instead, so a single aircraft can be kept off an airfield without inventing a KindOf for it.
ForbiddenObjects = <object list>These aircraft can never land here. Checked first, so it beats everything else, includingAllowedObjects.AllowedObjects = <object list>If set, ONLY these aircraft may land here. Leave it out to allow everything the other filters permit.
Example - an airfield that takes only two of the player's jets:
Behavior = ParkingPlaceBehavior ModuleTag_park
NumRows = 2
NumCols = 2
HasRunways = Yes
ApproachHeight = 40
AllowedObjects = AirF_AmericaJetRaptor SupW_AmericaJetStealthFighter
End
Both keys take several names on one line, and a second line of the same key replaces the first rather than adding to it. Matching is on the object name and ignores case.
Notes
- These filters are checked in addition to
RequiredKindOfandForbiddenKindOf, not instead of them. An aircraft has to pass both to land, so naming it inAllowedObjectsdoes not get it past aForbiddenKindOfthat rejects it. - Leaving both keys out is the previous behavior exactly, so existing INI is unaffected.
- The filters decide whether an aircraft may land or be produced here. They do not evict anything already parked, so changing them does not affect aircraft that are on the airfield.
- Aircraft with
KINDOF_PRODUCED_AT_HELIPADskip these filters, as they already skip the KindOf ones.
DozerAIUpdate / WorkerAIUpdate¶
Both modules build and repair structures, and both take the same restriction keys. A module without them behaves exactly as before.
Restricting what may be built¶
ForbiddenBuildObjects = <object list>These may never be built. Checked first, so it beats everything else, includingAllowedBuildObjects.AllowedBuildObjects = <object list>If set, ONLY these may be built. Leave it out to allow everything the unit's CommandSet offers.
Example - a worker that may only put up the two cheapest structures:
Behavior = WorkerAIUpdate ModuleTag_worker
RepairHealthPercentPerSecond = 2%
BoredTime = 5000
BoredRange = 150
AllowedBuildObjects = GLAPowerPlant GLABarracks
End
Both keys take several names on one line, and a second line of the same key adds to the first rather than replacing it. Matching is on the object name and ignores case.
Notes
- The list gates starting a building, resuming one somebody else began, and a GLA hole rebuild. An AI player is held to it too, unlike the normal build validation which AI players skip.
- A forbidden structure's command button greys out rather than disappearing, so button positions stay the same across units that share a CommandSet.
- This is checked in addition to the unit's CommandSet, not instead of it. Naming something in
AllowedBuildObjectsdoes not let a unit build what its CommandSet never offered.
Removing the repair ability¶
CanRepair = YesDefault.Notakes the repair ability away entirely.
A unit with CanRepair = No shows no repair cursor over a damaged building, ignores a repair order,
and does not go looking for something to repair when it gets bored.
Giving a dozer to an armed unit¶
A stock dozer carries no weapon except a mine clearing one. When it has been idle for BoredTime it
looks for something to repair, and failing that it sets its mine clearing weapon set and attacks the
nearest enemy or neutral object within BoredRange. That search does not check that the target is a
mine - it checks that the target is attackable, which on a stock dozer only mines are.
Put DozerAIUpdate or WorkerAIUpdate on a unit that keeps a real weapon and the same search starts
returning ordinary neutral objects, so the unit opens fire on scenery whenever it goes idle. Two ways
around it:
BoredRange = 0the search runs with a zero radius and finds nothing, so the unit never picks a bored target. This also switches off the bored auto-repair scan, which shares the same range. Direct repair orders still work.- Give the unit a weapon set under
WEAPONSET_MINE_CLEARING_DETAILthat cannot hit ordinary ground targets. The bored search then fails the attackability test for everything but mines, the same way it does on a stock dozer, and bored auto-repair keeps working.
BoredTime = 0 does not help - the check is idle time > BoredTime, so zero makes the unit run the
search on every idle frame rather than never.
PoisonedBehavior¶
Added Beta and Gamma poison tiers, so the poison-over-time effect can be strengthened once the attacker owns an upgrade. The retail parameters keep working unchanged.
PoisonBetaDamageInterval = 0tick interval while Beta poison is active. 0 usesPoisonDamageIntervalPoisonBetaDuration = 0how long Beta poison lasts after the last dose. 0 usesPoisonDurationPoisonBetaDamageBonus = 1.0multiplier on the per-tick damage (1.2 = 20% more)PoisonBetaTriggeredBy = <upgrade name>upgrade the attacker needs for Beta poison. Empty disables the tierPoisonGammaDamageInterval = 0as above, for GammaPoisonGammaDuration = 0as above, for GammaPoisonGammaDamageBonus = 1.0as above, for GammaPoisonGammaTriggeredBy = <upgrade name>as above, for Gamma
Notes
- The tier is picked per hit from the attacker, not the victim. The upgrade counts if the attacking player has researched it or the attacking object itself carries it, so both player and object upgrades work.
- Gamma is checked before Beta. If neither upgrade is present the hit applies normal poison.
- Only one tier is active at a time and poison never stacks. A stronger hit takes over damage, interval and duration; an equally strong hit refreshes them as retail does; a weaker hit is ignored while the stronger poison is still running.
- A hit with
DeathType = POISONEDis promoted toPOISONED_BETAorPOISONED_GAMMAfor the active tier, so die modules and death FX can tell the tiers apart. A weapon that already names a tier death type is left alone. - If the attacker no longer exists when the damage lands, the hit counts as normal poison.
- Healing of any kind still cures poison completely and clears the tier.
NeutronBlastBehavior¶
The neutron blast that kills infantry and leaves vehicles unmanned. Two parameters were added so the effect can be kept off things it should not touch.
Behavior = NeutronBlastBehavior ModuleTag_neutron
BlastRadius = 100.0
AffectAirborne = No
AffectAllies = No
AffectGarrison = Yes ; New
RejectEffectOnUnit = CyborgCommando AnotherUnit YetAnotherUnit ; New
End
Added parameters:
AffectGarrison = YesNo spares infantry garrisoned in a structure. Only garrisons are affected by this: passengers of transports, tunnels and bunkers are killed either way, as before.RejectEffectOnUnit = <object list>Object names that the blast skips entirely, whatever their KindOfs. This is the only way to spare a unit the hardcoded infantry and vehicle rules, which is what it exists for: riders such as the Cyborg Commando. A rejected object keeps its passengers too. All names go on one line; a second line replaces the first. Matching ignores case.
UnitProductionBonusUpgrade New¶
This upgrade module allows to set a cost and/or build time modifier for individual types of units. This affects the whole player and not just individual factories.
Parameters:
<All common upgrade params; e.g. TriggeredBy>CostModifierPercentage = 0Percentage amount that the unit's costs are modifiedBuildTimeModifierPercentage = 0Percentage amount that the unit's build time is modifiedUnitTemplateName = <Name of an Object>The unit to apply this bonus to. (multiple lines are allowed)IsOneShotUpgrade = NoYes makes the bonus permanent: it is never removed when the granting object dies and does not transfer when it is captured.BonusStacksWith = NO_STACKINGNO_STACKING|OTHER_TYPE|SAME_TYPE. How the bonus stacks when several objects grant it.NO_STACKINGis the previous behaviour, where only differing percentages stack;OTHER_TYPEstacks across different source object types;SAME_TYPEstacks across objects of the same type.
Example
Behavior = UnitProductionBonusUpgrade ModuleTag_01
TriggeredBy = Upgrade_CostReduction ; The upgrade trigger
CostModifierPercentage = -40% ; Cost is reduced by 40%
BuildTimeModifierPercentage = -80% ; Build time is reduced by 80%
UnitTemplateName = Tank_ChinaInfantryRedguard ; The units this bonus applies to
UnitTemplateName = Tank_ChinaTankBattleMaster
End
Notes
- The bonus is now removed when the granting object is destroyed and transfers with it on capture,
so it works for per-building upgrades such as Tech OilRefinery and not only as a global upgrade.
Set
IsOneShotUpgrade = Yesto get the old permanent behaviour back.
StealthUpgrade¶
Added new parameters
-
EnableStealth = YesIf set to No, this will disable the object's stealth instead of enabling it. Can be used for a toggleable upgrade. -
OverrideStealthForbiddenConditions = <StealthForbiddenConditionFlags>Override StealthForbiddenConditions in StealthUpdate for this unit.
Note
if OverrideStealthForbiddenConditions is set, EnableStealth is ignored as there is no reason to use both functionalities at the same time.
BattlePlanBonusBehavior New¶
New module that can be used to customize the effects of BattlePlans for individual units. This module needs to go to the unit that receives the battle plan bonus effects, not the StrategyCenter.
Parameters:
Behavior = BattlePlanBonusBehavior ModuleTag_BPB
; Generic Upgrade parameters:
TriggeredBy = <Upgrade entry>
; ---
StartsActive = No ; Active immediately or requires upgrade?
OverrideGlobalBonus = No ; Enable to skip default BattlePlan bonus effects (i.e. values from BattlePlanUpdate, or WeaponBonus effects) for this unit
ShouldParalyzeOnPlanChange = Yes ; Should this unit be paralyzed/disabled while switching battle plans?
; -- Bonus entries -- Valid <BATTLE_PLAN_NAME> are BOMBARDMENT, SEARCH_AND_DESTROY and HOLD_THE_LINE
WeaponSet = <BATTLE_PLAN_NAME> <WEAPON_SET_FLAG> ; Set this weaponset flag while this battleplan is active
ArmorSet = <BATTLE_PLAN_NAME> <WEAPON_SET_FLAG> ; Set this armorset flag while this battleplan is active
WeaponBonus = <BATTLE_PLAN_NAME> <WEAPON_BONUS_NAME> ; Grant this weaponbonus while this battleplan is active
ArmorDamageScalar = <BATTLE_PLAN_NAME> 1.0 ; Set damage reduction while this battleplan is active
SightRangeScalar = <BATTLE_PLAN_NAME> 1.0 ; Set a sight range bonus while this battleplan is active
StatusToSet = <BATTLE_PLAN_NAME> <STATUS_TYPE> ; Set this status when enabling this battle plan. Clear it on battle plan removal
StatusToClear = <BATTLE_PLAN_NAME> <STATUS_TYPE> ; Clear this status when enabling this battle plan. Set it on battle plan removal
End
Examples¶
Example 1 - Give extra effects to Battle plans
Behavior = BattlePlanBonusBehavior ModuleTag_BP1
TriggeredBy = Upgrade_BattlePlanBonusExample
OverrideGlobalBonus = No
ShouldParalyzeOnPlanChange = Yes
WeaponSet = BOMBARDMENT PLAYER_UPGRADE
WeaponBonus = SEARCH_AND_DESTROY FRENZY_THREE
StatusToClear = HOLD_THE_LINE CAN_STEALTH
ArmorDamageScalar = HOLD_THE_LINE 0.9
End
- With BOMBARDMENT we switch to the upgraded WeaponSet
- With SEARCH_AND_DESTROY we gain an extra weapon bonus
- With HoldTheLine we gain additional damage reduction, but lose the ability to stealth.
Example 2 - Allow units to gain battle plans
Behavior = BattlePlanBonusBehavior ModuleTag_BP0
StartsActive = Yes
OverrideGlobalBonus = Yes
ConflictsWith = Upgrade_GrantBattlePlans
ShouldParalyzeOnPlanChange = No
End
Behavior = BattlePlanBonusBehavior ModuleTag_BP1
TriggeredBy = Upgrade_GrantBattlePlans
OverrideGlobalBonus = No
ShouldParalyzeOnPlanChange = Yes
End
Note
For this to work, the unit needs to be inlcuded in the BattlePlan's valid KindOfs, even though the intention is to not give them the battlePlan effects by default.
WeaponBonusUpdate¶
Added Parameters:
AffectsTargets= [ALLIES/ENEMIES/NEUTRALS] ; Allows applying a bonus to enemiesAffectsAirborne= Yes ; allow/disallow the bonus be applied to currently airborne unitsTintStatusType= [TINT_STATUS type] ; which color tint to applyBonusConditionType= [WeaponBonus type] ; The WeaponBonus condition flag that is granted to affected units (default = the module's own bonus). Lets you pick which WeaponBonus the module applies.
SpecialAbilityUpdate¶
The valid targets for the laser lock ability (SPECIAL_MISSILE_DEFENDER_LASER_GUIDED_MISSILES) used to be hardcoded to
VEHICLE, which in Zero Hour covers aircraft as well as ground vehicles, and to enemies only. These three keys make
the target filter data-driven.
ForbiddenTargetKindOf = <KindOf list>The target may have none of these. Checked first, so it beatsRequiredTargetKindOf. Default =STRUCTURE.RequiredTargetKindOf = <KindOf list>The target must have all of these. Default =VEHICLE.TargetRelationship = [ALLIES/ENEMIES/NEUTRALS]Which relationships to the owner may be targeted. Several may be listed together. Default =ENEMIES.
Example - an Avenger that can only lock onto enemy ground vehicles:
Behavior = SpecialAbilityUpdate ModuleTag_09
SpecialPowerTemplate = SpecialAbilityLaserGuidedMissiles
StartAbilityRange = 200.0
RequiredTargetKindOf = VEHICLE
ForbiddenTargetKindOf = STRUCTURE AIRCRAFT ; New
TargetRelationship = ENEMIES ; New
End
The defaults reproduce the original hardcoded behaviour exactly, so leaving all three keys out changes nothing.
Behaviour notes:
RequiredTargetKindOfis an all of test, not an any of test. Listing two KindOfs means the target must have both.- All three keys are honoured in two places, and always agree: the check that decides whether the cursor and the order are valid, and the check that runs while a lock is already in progress and cancels it if the target stops qualifying. Because the relationship is part of that test, a lock breaks off if the target changes sides mid lock - by being hijacked or captured - unless the new relationship is also allowed.
- To let the ability target allies, both
TargetRelationshiphere andNEED_TARGET_ALLY_OBJECTon the CommandButton are needed. The button filters the player's click; this key covers the paths that never see a button and keeps checking while the lock is held. - Allowing a relationship other than
ENEMIESmeans the ability really will shoot that target - the missile is fired as a forced attack, so the usual "you may not attack allies" rule does not stop it. Do not allow allies unless that is what you want. - The AI never reads CommandButton target options, and its own scan only considers enemies, so it will not use ally or neutral locking even when both are configured.
- These keys currently affect the laser lock ability only. Other abilities that use
SpecialAbilityUpdatekeep their own built in target rules and ignore all three.
DelayedUpgradeBehavior New¶
Applies or Removes Upgrade(s) after a set time. Initially triggered by an upgrade. This can be used to make temporary upgrades.
Example:
Behavior = DelayedUpgradeBehavior ModuleTag_DelUp
TriggeredBy = <Upgrade entry> ; Initial Trigger
; additional generic Upgrade params (ConflictsWith, RemovesUpgrades, FXListUpgrade, RequiresAllTriggers)
UpgradesToTrigger = <Upgrade1, Upgrade2, ...> ; Upgrades that will be triggered after the delay
UpgradesToRemove = <Upgrade1, Upgrade2, ...> ; Upgrades that will be removed after the delay
TriggerAfterTime = <time in msec> ; Time delay
End
UpgradeSpecialPower New¶
Trigger an upgrade via a special power. This can be used to (e.g. in combination with DelayedUpgradeBehavior) to create a temporary upgrade with a cooldown.
Example:
Behavior = UpgradeSpecialPower ModuleTag_SpecUp01
SpecialPowerTemplate = <SpecialPower Entry>
; Other params from SpecialPower module (UpdateModuleStartsAttack, StartsPaused, InitiateSound, ScriptedSpecialPowerOnly)
UpgradeToGrant = <Upgrade Entry>
End
OCLSpecialPower¶
Added new parameter:
*SelectCreatedObject = No The (first) created object will be automatically selected by the player
MinDistToSimilarRadius = 0.0If > 0, the special power cannot be targeted within this radius of another object created by the same OCL special power. Useful to prevent stacking multiple deployments on top of each other. Default = 0 = no limit
OCLUpdate¶
Added parameters for directional payload delivery (e.g. for OCLs that spawn a delivery aircraft, to make it approach from a consistent direction):
DirectionalDelivery = NoIf Yes, the delivered payload/aircraft is aligned to the source object's direction instead of a fixed/default direction.DirectionalDeliveryFurthestEdge = NoIf Yes, always pick the map edge furthest along the delivery angle as the spawn/approach point.
TeleporterAIUpdate New · Experimental¶
** Warning: This module is experimental, i.e. it is not fully tested and might undergo revisions**
AIUpdate module designed to work like a Chrono Legionnaire in RA2. I.e. The unit teleports instead of moving normally, and needs to recharge depending on the distance it teleported. ** Note: Currently this module is only working properly for infantry units. It currently does not work properly for vehicles and it is not certain it ever will.**
Example:
Behavior = TeleporterAIUpdate ModuleTag_123
TeleportStartFX = [FXList entry] ; FX to play at the unit's previous position when it teleports
TeleportTargetFX = [FXList entry] ; FX to play at the unit's target position when it teleports
TeleportRecoverEndFX = [FXList entry] ; FX to play on the unit, when it has finished recovering
MinDistanceForTeleport = 20.0 ; distance in which the unit moves normally instead of teleporting
DisabledDurationPerDistance = 10.0 ; How long the unit will need to recover, linear to the distance (in MS per distance). Recommended values = 5-10.
TeleportRecoverSoundAmbient = [AudioEvent entry] ; Ambient sound played on the unit while it recovers from a teleport.
TeleportRecoverOpacityStart = 10% ; Unit maximum transparency when it starts to recover.
TeleportRecoverOpacityEnd = 80% ; Unit minimum transparency when it has finished recovering.
TeleportRecoverTint = TELEPORT_RECOVER ; Color tint status to apply while recovering
[entries from AIUpdate]
End
TELEPORT_RECOVER is set. Note: In most cases, the unit will also be MOVING after a teleport, so it's recommended to define both states.
ChronoDeathBehavior New¶
Death Module for "Chrono" death. This makes the unit fade out and shrink.
Example:
Behavior = ChronoDeathBehavior ModuleTag_ChronoDeath
DeathTypes = NONE +CHRONO ; Death types to use
; Additional DieModule params (VeterancyLevels, ExemptStatus, RequiredStatus)
StartFX = <FXList entry> ; FX to play at the start
EndFX = <FXList entry> ; FX to play at the end
; Note: The following params are meant to be used (instead of StartFX/EndFX) when used in Default/Object.ini:
StartFXInfantry = <FXList entry> ; played if the object is INFANTRY
StartFXVehicle = <FXList entry> ; VEHICLE
StartFXStructure = <FXList entry> ; STRUCTURE
EndFXInfantry = <FXList entry> ; played if the object is INFANTRY
EndFXVehicle = <FXList entry> ; VEHICLE
EndFXStructure = <FXList entry> ; STRUCTURE
OCL = <OCL entry> ; OCL to create at the start
OCLDynamicGeometryScaleFactor = 0.0; Used in combination with DynamicGeometryClientUpdate. If this is set, the created object will be scaled to the parent object's radius. The value here should be set to the model's default size (e.g. a value of 10.0 corresponds to a sphere with radius 10.0)
StartScale = 1.0 ; Unit scale at the start
EndScale = 0.1 ; Unit scale at the end
StartOpacity = 25% ; Opacity at the start
EndOpacity = 0% ; Opacity at the end
DestructionDelay = 500 ; Duration of the sequence in ms
End
DynamicGeometryClientUpdate New¶
Client module for simple animations on a drawable's opacity and scale. Can be useful for effects like EMP bubbles.
Example:
ClientUpdate = DynamicGeometryClientUpdate ModuleTag_02
Opacity = INITIAL 0.0 ; value when object is created
Opacity = MIDPOINT 1.0 ; value at midpoint duration
Opacity = FINAL 0.0 ; value at end of duration
Scale = INITIAL 0.0
Scale = MIDPOINT 1.0
Scale = FINAL 0.0
Interpolation = SMOOTH ; How values in between are interpolated - SMOOTH (sinus curve) or LINEAR
TotalDuration = 666 ; in ms
MidpointDuration = 200 ; in ms
End
ResetSpecialPowerTimerWhileAliveUpdate New¶
Update Module to reset a player global (shared synch timer) superweapon while a unit is alive, this allows super unit deploys to start the cooldown when the unit is dead
Example:
Behavior = ResetSpecialPowerTimerWhileAliveUpdate ModuleTag_x
SpecialPowerTemplate = Tank_SuperweaponUniqueUnit ; a superweapon template with shared synch timer ( like genpowers)
End
W3DModelDraw¶
Added parameters (To the main Draw module block, not the individual ConditionStates):
-
IgnoreAnimationSpeedScaling = Noignore animation scaling (e.g. for PreAttackDelay) for a draw module. Useful for having Looping animations (e.g. rotor blades or flags) along with a pre_attack anim in another draw module. -
IgnoreRotation = NoThis model will always stay aligned to the world (i.e. Z up), ignoring rotation via movement. Do not use this on modules with Firebones or Turrets. -
OnlyVisibleToOwningPlayer = NoThis model will only be visible to the owning player. Do not use it on modules with Firebones or Turrets.
Energy Shields¶
Added a Body and Behavior module for rechargable energy shields. This adds another health bar on top and absorbs damage until it's depleted.
ShieldBody¶
This Body is required for shields to work.
Body = ShieldBody ModuleTag_ES1
;<ActiveBody paramters>
StartsActive = No ; Enable Shields by default; Otherwise an upgrade is required (defined in EnergyShieldBehavior)
ShieldMaxHealth = 100 ; Health points of the shield (only needed if ShieldMaxHealthPercent is not set)
ShieldMaxHealthPercent = 30% ; Health points relative to MaxHealth (overrides ShieldMaxHealth)
ShieldArmorSetFlag = PLAYER_UPGRADE ; (Optional) ArmorSetFlag to use while the shield is up
ShieldPassThroughDamageTypes = <Damage Types> ; List of damage types that will go through the shield and damage the Health. NONE +X, ALL -Y notation.
DefaultShieldPassThroughDamageTypes = <Damage Types> ; This has the same functionalty as above, but is predefined with all utility damage types that should always be passed through. This should not be defined in most cases, but can be overriden
End
Note
DefaultShieldPassThroughDamageTypes default values: NONE +STATUS +DEPLOY +UNRESISTABLE +HEALING +PENALTY +DISARM +HAZARD_CLEANUP +TOPPLING +SUBDUAL_UNRESISTABLE +CHRONO_UNRESISTABLE
EnergyShieldBehavior¶
The second required module for shield logic
Behavior = EnergyShieldBehavior ModuleTag_ES2
StartsActive = No ; Enabled by default (no upgrade required)
TriggeredBy = <Upgrade Name>
ShieldRechargeDelay = 5000 ; Time (ms) of no damage taken, until shield starts recharging.
ShieldRechargeRate = 100 ; Delay (ms) between shield recharge ticks
ShieldRechargeAmount = 0 ; How much shield to recharge per tick (Absolute. Use only one)
ShieldRechargeAmountPercent = 2% ; How much shield to recharge per tick (Percentage. Use only one)
ShieldHealthBarColor = R:128 G:255 B:255 A:255 ; RGBA color for the shield health bar
ShieldHealthBarBackgroundColor = R:0 G:0 B:0 A:255 ; RGBA color for the shield health bar outline
ShowHealthBarBackgroundWhenEmpty = No ; Show empty frame when shield is depleted
ShowHealthBarWhenUnselected = No ; Show shield health bar when the unit is not selected or mousover
ShieldModelCondition = <ConditionStateName> ; Optional: Conditionstate to set when shield is active
ShieldSubObjectName = <SubObjName> ; Optional: Model subobject to show when the shield is active
ShieldHitModelCondition = <ConditionStateName> ; Optional: Conditionstate to set when shield was hit
ShieldHitSubObjectName = <SubObjName> ; Optional: Model subobject to show when the shield was hit
ShieldHitConditionDuration = 500 ; Optional: How long to show conditionstate when shield was hit
ShieldDownFX = <FXList> ; Optional: FX to play when shield is depleted
ShieldUpFX = <FXList> ; Optional: FX to play when a depleted shield starts recharging
End
** Note: for the shield health bar to work, the KindOf "SHOW_PROGRESS_BAR" is required on the object**
** Note2: When using both ShieldHitModelCondition and ShieldModelCondition parameters: When the shield is hit, both conditionstates are active at the same time. So a setup like this is required:
Draw = W3DModelDraw ModuleTag_ES0
; Inactive Shield
DefaultConditionState
Model = None
End
; Active Energy Shield
ConditionState = USER_1
Model = ShieldActive
End
; Energy Shield Hit
ConditionState = USER_1 USER_2
Model = ShieldHit
End
End
MultiAddOnContain New¶
New contain module to replicate MARV turret functionality from Kane's Wrath: The object (Can be used on a structure or vehicle) has a container for multiple infantry units. Each contained infantry, will spawn a portable structure on the unit, that will move and attack along with it. Each type of infantry has it's own portable structure defined. Only units defined in the list can enter. There is no limit on how many addOns can be defined.
Example:
Behavior = MultiAddOnContain ModuleTag_123
; Params from TransportContain:
Slots = 4
EnterSound = GarrisonEnter
ExitSound = GarrisonExit
ImmuneToClearBuildingAttacks = Yes
DamagePercentToUnits = 100%
IsEnclosingContainer = No
; New Params
PayloadTemplateName = <Name of Infantry object to be contained by default> ; can have multiple PayloadTemplateName entries
AddOnBoneName = STATION ;Name of bone to place the addOns (uses numbering from 00-99 for available slots)
AddOnEntry = <Name of contained Infantry object 1> <Name of Portable Structure object 1>
AddOnEntry = <Name of contained Infantry object 2> <Name of Portable Structure object 2>
AddOnEntry = <Name of contained Infantry object 3> <Name of Portable Structure object 3>
...
EmptySlotSubObjectName = COVER_EMPTY ;Name of any subobject (numbered) that should be visible when a slot is empty
OccupiedSlotSubObjectName = COVER_OCCUPIED ;Name of any subobject (numbered) that should be visible when a slot is filled (hide this in art code by default)
End
Container Draw Module Requirements¶
Like with OverlordContain, the container object needs to have one of
W3DOverlordTankDrawW3DOverlordTruckDrawW3DOverlordAircraftDrawNote: Contary to the name, this is the default module to use (e.g for Structures) when no extra behavior is required
A new parameter was added to these modules that needs to be set when used with MultiAddOnContain:
HasMultiAddOns = Yes
AddOn Draw Module Requirements¶
Like with Overlord addOns, the contained portable structure object needs to have W3DDependencyModelDraw
AttachToBoneInContainer should now be set to the same numbered bone used for AddOnBoneName in MultiAddonContain. E.g. "STATION" if using STATION01-XX
Drone Carrier system¶
Added modules to support a simplified mobile aircraft carrier.
DoneCarrierContain¶
Behavior = DroneCarrierContain ModuleTag_Contain
;<TransportContain parameters>
Slots = 123
HealthRegen%PerSec = 3.0
ExitBone = STATION
ExitDelay = 300
HealthRegen%PerSec = 3.0
...
;
LaunchVelocityBoost = 2.5
LaunchBone = STATION
NumLaunchBones = 1
EnterPositionOffset = X:0 Y:0 Z:0
EnterPositionOffset = X:0 Y:0 Z:0 ;Multiple entries allowed
...
ContainedUnitsDeathType = TOPPLED
KeepSlotAssignment = Yes
End
DroneCarrierAIUpdate¶
Behavior = DroneCarrierAIUpdate ModuleTag_AI
;<AIUpdate parameters>
Slots = 8
RespawnTime = 3000
DroneTemplateName = Lazr_AmericaVehicleCarrierDrone
DronesEnterMainDoor = Yes
End
DroneCarrierSlavedUpdate¶
Behavior = DroneCarrierSlavedUpdate ModuleTag_123
<SlavedUpdate params>
LeashRange = 400.0
End
CarrierDroneAIUpdate¶
Behavior = CarrierDroneAIUpdate ModuleTag_312
DockingDistance = 70.0
DockingLocomotorType = SET_SLUGGISH
LaunchingLocomotorType = SET_TAXIING
LaunchTime = 750
End
BuffUpdate¶
Works similar to WeaponBonusUpdate (Frenzy module) to apply buffs to objects in an area
RequiredAffectKindOf = <List of KindOfs>RequiresAllKindOfs = Yes/No ; Require all listed KindOfs, or just one of themForbiddenAffectKindOf = <List of KindOfs>AffectsTargets = <combination of ALLIES | ENEMIES | NEUTRALS>AffectAirborne = Yes/NoBuffDuration = duration in msec ; how long to apply the buffBuffDelay = duration in msec ; how often to apply the buffBuffRange = 0.0 ; area radiusBuffTemplateName = <BuffTemplate.ini entry> ; the template to apply
Naval / Water Modules¶
PhysicsBehavior¶
Added parameters to support objects floating/impacting on water (used together with the ship death behavior and water effects).
DoWaterPhysics = NoIf Yes, the object reacts to the water surface, e.g. floating and slowing down in water instead of falling through. Default = NoWaterExtraFriction = 0.0Additional friction applied while the object is in/on water. Default = 0.0WaterImpactFX = <FXList>FXList played once when the object first impacts the water surface. Default = None
ShipSlowDeathBehavior New¶
A death behavior for ships and other large naval objects. It plays a multi-stage sinking sequence: an initial delay, an optional toppling motion, and finally sinking below the water surface, each with their own FX/OCL and model condition states.
The module has a lot of parameters, grouped by stage below. All durations are in milliseconds, all angles in degrees.
Behavior = ShipSlowDeathBehavior ModuleTag_ShipDeath
; --- common DieModule params (DeathTypes, VeterancyLevels, ExemptStatus, ...) ---
; --- Initial delay before the death sequence starts ---
InitialDelay = 0
InitialDelayVariance = 0
InitialConditionFlag = <ModelCondition> ; condition flag set when the death starts (default = RUBBLE)
; --- Wobble (gentle rocking while sinking) ---
WobbleMaxAnglePitch = 0
WobbleMaxAngleYaw = 0
WobbleMaxAngleRoll = 0
WobbleInterval = 0
; --- Topple stage (ship tips over) ---
ToppleStyle = TOPPLE_FRONT ; TOPPLE_FRONT, TOPPLE_BACK, TOPPLE_SIDE_LEFT, TOPPLE_SIDE_RIGHT (random if omitted)
ToppleFrontMinPitch = 0
ToppleFrontMaxPitch = 0
ToppleBackMinPitch = 0
ToppleBackMaxPitch = 0
ToppleSideMinRoll = 0
ToppleSideMaxRoll = 0
ToppleMinHeightOffset = 0
ToppleMaxHeightOffset = 0
ToppleDuration = 0
ToppleDurationVariance = 0
ToppleMinPushForce = 0
ToppleMaxPushForce = 0
ToppleMinPushForceSide = 0
ToppleMaxPushForceSide = 0
ToppleAngleCorrectionRate = 0 ; angular velocity used to settle the topple angle
ToppleConditionFlag = <ModelCondition> ; condition flag set when toppling starts (default = RUBBLE)
FXStartTopple = <FXList>
OCLStartTopple = <OCL>
; --- Sink stage (ship goes below water) ---
SinkHowFast = 100% ; sink speed as a percentage
SinkConditionFlag = <ModelCondition> ; condition flag set when sinking starts (default = RUBBLE)
FXStartSink = <FXList>
OCLStartSink = <OCL>
SinkAttachParticle = <ParticleSystem> ; particle system attached while sinking (e.g. bubbles)
SinkAttachParticleBones = <Bone1> <Bone2> ... ; bones to attach the particle to
SoundSinkLoop = <AudioEvent> ; looping sound while sinking
; --- Pilot / ground impact ---
OCLEjectPilot = <OCL> ; OCL created to eject a pilot/crew
FXHitGround = <FXList> ; FX when the wreck reaches the sea/ground floor
OCLHitGround = <OCL> ; OCL when the wreck reaches the sea/ground floor
End
Notes
- The three condition flags (
InitialConditionFlag,ToppleConditionFlag,SinkConditionFlag) all default toRUBBLE. Set them to distinct states if you want different models/animations per stage. ToppleStyleaccepts the topple direction names; if omitted, a random direction is chosen.
HeightDieUpdate¶
Added parameter:
TargetHeightIncludesWater = NoIf Yes, the target height check used to trigger the death also takes the water surface height into account, so the object dies relative to the water level rather than the terrain below it. Useful for projectiles/objects over water. Default = No
Die Modules - Water Depth Conditions¶
All Die modules (the shared DieMux conditions) now support restricting the death to a water depth range. This lets you trigger different death effects depending on how deep the water is (e.g. a normal death on land/shallow water, a sinking death in deep water).
MinWaterDepth = 0.0Minimum water depth required for this death module to trigger. Default = 0MaxWaterDepth = 0.0Maximum water depth allowed for this death module to trigger; 0 = no upper limit. Default = 0
BunkerBusterBehavior¶
Added parameter:
WorksOverWater = YesIf Yes (default), the bunker buster triggers its behavior even when it hits the water surface. Set to No to make it ignore targets over water.
Bridges¶
Bridge.ini / TerrainRoad (Bridge type)¶
BridgeHoleAreaPercentage = 100%Percentage of the bridge span that is removed/becomes impassable when the bridge is destroyed. Lets you tune how much of the bridge collapses.
BridgeBehavior¶
Added parameters to push objects on a bridge when it is repaired:
RepairPushDuration = 0Duration in ms over which objects standing on the bridge are pushed up when the bridge is repaired/restored.RepairPushForce = 0Acceleration applied to objects on the bridge while it is being repaired.
DrawBridgeUpdate (New) / DrawBridgeTowerUpdate New¶
New modules implementing an openable "draw bridge" that can be raised and lowered, triggered via a special power.
DrawBridgeUpdate (on the bridge object):
Behavior = DrawBridgeUpdate ModuleTag_DrawBridge
OpeningDuration = 0 ; time in ms to open (raise) the bridge
ClosingDuration = 0 ; time in ms to close (lower) the bridge
OpeningPushForce = 0 ; acceleration applied to objects when the bridge opens (pushes them off)
ClosingDamageTime = 0 ; time in ms during closing when objects underneath take damage
BridgeOpeningFX = <FXList> ; played when the bridge starts opening
BridgeOpenFX = <FXList> ; played once fully open
BridgeClosingFX = <FXList> ; played when the bridge starts closing
BridgeClosedFX = <FXList> ; played once fully closed
BridgeOpeningAudio = <AudioEvent> ; looping audio while opening
BridgeClosingAudio = <AudioEvent> ; looping audio while closing
End
DrawBridgeTowerUpdate (on the bridge tower/control object):
Behavior = DrawBridgeTowerUpdate ModuleTag_DrawBridgeTower
SpecialPowerTemplate = <SpecialPower entry> ; special power that triggers opening/closing
End
Jumpjet / Special Ability Modules¶
SpecialAbilityUpdate¶
Added parameters to control turning before an ability is used:
RequiresMoveToTurn = NoIf Yes, the unit must use its movement/locomotor to turn towards the target before the ability can fire, instead of snapping its facing.FacingAngleTolerance = 0Allowed facing angle error (in degrees) towards the target before the ability is considered "facing" the target.
JumpjetContain New¶
A contain module for a "jumpjet"-style carrier that launches and lands riders which fly using jumpjet missiles. Handles the flying/landing animation states and landing safety checks.
Behavior = JumpjetContain ModuleTag_Jumpjet
;<TransportContain parameters>
FlyingConditionFlag = <ModelCondition> ; condition flag set while flying
LandingConditionFlag = <ModelCondition> ; condition flag set while landing
LandingDistance = 0.0 ; distance from the ground at which landing begins
KillWhenLandingInWater = No ; kill the unit if it tries to land in water
KillWhenLandingInWaterSlop = 0.0 ; extra water-depth tolerance before the water kill triggers
KillWhenLandingOnCliff = No ; kill the unit if it tries to land on an (impassable) cliff
KillWhenLandingOnImpassable = No ; kill the unit if it tries to land on impassable terrain
End
JumpjetMissileAIUpdate New¶
AI update for the projectiles/riders launched by a jumpjet carrier.
Behavior = JumpjetMissileAIUpdate ModuleTag_JumpjetMissile
ScatterRadius = 0.0 ; random scatter radius around the target (default = 0)
MaxSearchRadius = 100.0 ; radius to search for targets (default = 100)
InitialPitchAngle = 0.0 ; initial launch pitch angle in degrees (default = 0)
End
Animation Blending¶
A set of features to smoothly blend between animations and trigger frame-accurate effects. (PRs #85, #86, #91, #93)
W3DModelDraw (module level)¶
KeepRecoilAcrossStates = NoIf Yes, weapon recoil offset is kept when the model switches condition states, instead of being reset. Avoids the gun "snapping back" when the firing state changes. Default = No
ConditionState parameters¶
-
AnimationBlendTime = 0Per ConditionState; number of animation frames to blend from the previous state's animation into this state's animation, for a smooth transition. Default = 0 = no blending -
AutoConditionState = <ConditionFlag1> <ConditionFlag2> ...Shorthand that auto-generates a combined condition state from the previously defined ConditionState by OR-ing in the listed condition flags. It copies the previous state's model/animation/overrides and creates a new state for each of the previous state's condition sets combined with the auto flags. It has no body.
Requirements/notes: - Must come after a regular ConditionState (it refers to the last defined one). - Requires at least one condition flag. - It is an asset error if it would produce a condition state that already exists. - Useful for animation blending, e.g. to duplicate a state for an additional flag without retyping the whole block.
FXEvent = <frame> <boneName> <FXList>Per ConditionState; plays the given FXList at the given bone when the animation playback crosses the given frame number. Can be added multiple times. Lets you trigger effects at exact animation frames, e.g. footstep dust or muzzle smoke.
AnimationSteeringUpdate New¶
A client update that drives steering/lean animations based on the unit's turning.
ClientUpdate = AnimationSteeringUpdate ModuleTag_AnimSteer
MinAngle = 0 ; minimum turn angle (degrees) before a steering animation is used
SkipCenteringAnims = No ; if Yes, do not play the "return to center" animations
End
W3DDecalDraw New¶
A draw module that renders a single ground decal for its object. Mainly used together with the Decal FX nugget to create temporary decals (e.g. scorch marks, footprints) via FXLists.
Draw = W3DDecalDraw ModuleTag_Decal
Texture = <texture name>
Style = SHADOW_ALPHA_DECAL ; SHADOW_DECAL, SHADOW_ALPHA_DECAL or SHADOW_ADDITIVE_DECAL
Color = R:255 G:255 B:255 A:255
Opacity = 100%
SizeX = 1.0 ; world-space size in X
SizeY = 1.0 ; world-space size in Y
FadeInTime = 0 ; ms to fade in
FadeOutTime = 0 ; ms to fade out (use with LifetimeUpdate)
RenderAboveWater = No ; Yes draws the decal on the water surface instead of the terrain below
End
Note
SHADOW_DECAL is no longer a valid Style for this module. Use SHADOW_ALPHA_DECAL or
SHADOW_ADDITIVE_DECAL.
Target Designator¶
SpecialPowerDesignatorUpdate New¶
Update module that lets a unit "designate" an area, enabling special powers that require a designator (see NeedsTargetDesignator on the SpecialPower). While active, it can show a radius decal and optionally apply a temporary status to objects in the area.
Behavior = SpecialPowerDesignatorUpdate ModuleTag_Designator
SpecialPowerTemplate = <SpecialPower entry> ; the power that this designator enables
DesignatorRadius = 0.0 ; radius of the designated area
AlwaysShowDecal = No ; always show the radius decal, even when the power is not ready
TriggerStatusType = <ObjectStatus> ; status applied to objects in the designated area
TriggerStatusTime = 0 ; how long (ms) the status stays on after leaving the area
TriggerFX = <FXList> ; FX played when the designator triggers
End
Crate / Salvage Upgrades¶
AutoHealBehavior¶
Added parameters so that auto-healing can also grant salvage upgrades / promotions (e.g. a repair bay that "salvages" or veterans up units while healing them):
GrantSalvageUpgrade = NoIf Yes, apply a salvage crate upgrade to the unit while it is being healed.GrantPromotion = NoIf Yes, give the unit a veterancy level-up while it is being healed.
CrateApplyUpgrade New¶
An upgrade module that applies "crate"-style effects (salvage weapon/armor upgrades or a veterancy level-up) when triggered, reusing the salvage-crate logic.
SalvageCrate = NoIf Yes, apply a salvage weapon/armor upgrade. Only affects units that areKINDOF_WEAPON_SALVAGER/KINDOF_ARMOR_SALVAGERand not already at the highest salvage tier.LevelUp = NoIf Yes, grant a veterancy level-up, up to HEROIC, if the unit is trainable.
Crate.ini (CrateData)¶
AllowWater = NoIf Yes, this salvage/pickup crate may be created on water. By default crates are only created on land. Default = No
Multiple Portable Structures (Overlord contain)¶
OverlordContain (and Overlord-style contain redirection) now allows holding multiple add-ons at once, as long as they are KINDOF_PORTABLE_STRUCTURE. Objects with this KindOf are always added directly to the Overlord's own contain list (rather than being redirected to a single passenger), so several portable structures can be mounted on the same carrier. See also MultiAddOnContain.
Water Genpower Support¶
Improvements to make existing generals-power superweapons work correctly over water. (PR #97)
SpectreGunshipUpdate¶
HitWaterSurface = NoIf Yes, the gunship's strafing shots detonate at the water surface instead of passing through / hitting the sea floor.GattlingStrafeFXParticleSystemWater = <ParticleSystem>Particle system used for strafe impacts that land on water, instead of the regular land FX.
ParticleUplinkCannonUpdate¶
HitWaterSurface = NoIf Yes, the uplink cannon beam detonates at the water surface over water.
See also OrbitalBeamUpdate HitWaterSurface and the DeliverPayload StrafingWeaponTargetsWater flag.
See also ParticleUplinkCannonUpdate TornadoObjectName.
Scorch Mark Selection¶
ParticleUplinkCannonUpdate¶
The particle beam used to burn a random scorch decal (SCORCH_1 to SCORCH_4) every time it marked the ground, which
a mod cannot change. Mods that replace the scorch art with crater-like decals end up with craters punched along the
beam path. This key picks which decals the beam is allowed to use, or turns them off entirely.
ScorchType = SCORCH_1 SCORCH_2 SCORCH_3 SCORCH_4The scorch types the beam may burn. One name always burns that type, several pick randomly among just those, andNONEburns no scorches at all. AcceptsSCORCH_1,SCORCH_2,SCORCH_3,SCORCH_4,SHADOW_SCORCHandNONE.
Example - a beam that only leaves the fourth scorch decal:
Behavior = ParticleUplinkCannonUpdate ModuleTag_12
TotalScorchMarks = 20
ScorchMarkScalar = 1.0
ScorchType = SCORCH_4 ; New
End
Omitting ScorchType reproduces the original random SCORCH_1 to SCORCH_4 behaviour exactly, so data that does not
mention it is unaffected.
Behaviour notes:
NONEonly suppresses the decal. The beam still counts its scorch marks, still fires itsGroundHitFXon the same rhythm and still reveals the shroud, so the timing of everything else is untouched.SHADOW_SCORCHwas never reachable before, because the old random pick stopped atSCORCH_4. It is only used if you name it.
Veterancy¶
Veterancy Object Parameters¶
With the two extra veterancy levels (LEVEL_FOUR, LEVEL_FIVE; see New Enum Definitions), the per-object veterancy parameters now support up to 6 levels:
MaxVeterancyLevel = HEROICThe highest veterancy level this object may ever reach. Default =HEROIC(vanilla behavior). Set toLEVEL_FOUR/LEVEL_FIVEto allow the extra levels.ExperienceRequired = <lvl0> <lvl1> ... <lvl5>XP required to reach each level. Accepts up to 6 values now.ExperienceValue = <lvl0> <lvl1> ... <lvl5>XP granted to the killer when this object is destroyed, per level. Up to 6 values.SkillPointValue = <lvl0> <lvl1> ... <lvl5>Skill points granted per level. Up to 6 values.
Notes
- Health bonuses for the new levels are set in GameData via
HealthBonus_Four/HealthBonus_Five. - The maximum level can also be raised at runtime via the
SetMaxVeterancyLevelupgrade.
RiderChangeContain¶
Extended from 8 to 16 rider slots. Additional slots Rider9 through Rider16 can now be defined, using the same syntax as Rider1-Rider8. Corresponding RIDER9-RIDER16 enums were added for ArmorSet/WeaponSet/ModelCondition/ObjectStatus (see New Enum Definitions).
On-Kill Modules¶
Two new behavior modules that trigger an effect when the object kills another object. Both share a common set of "kill condition" parameters (KillMux) that filter which kills count.
Shared Kill Conditions (KillMux)¶
These parameters are available on both On-Kill modules below:
KilledKindOf = <KindOf list>Only trigger when the killed victim matches these KindOfs.ForbiddenKilledKindOf = <KindOf list>Do not trigger if the victim matches any of these KindOfs.RequiresAllKindOfs = NoIf Yes, the victim must match allKilledKindOfentries instead of any.RequiredKilledStatus = <ObjectStatus list>Victim must have these status flags.ForbiddenKilledStatus = <ObjectStatus list>Victim must not have these status flags.KilledRelationship = <ALLIES | ENEMIES | NEUTRALS>Only count kills of victims with this relationship to the killer.DamageTypes = <DamageType flags>Only trigger if the killing blow used one of these damage types. NONE/ALL +X -Y notation.DeathTypes = <DeathType flags>Only trigger for these death types.TriggerChance = 100%Chance to trigger on a qualifying kill.CooldownTime = 0Minimum time (ms) between triggers.
CreateObjectOnKillBehavior New¶
Spawns an OCL when the object kills a qualifying victim.
Behavior = CreateObjectOnKillBehavior ModuleTag_CreateOnKill
StartsActive = Yes
; --- shared KillMux conditions (see above) ---
KilledKindOf = INFANTRY
; --- module params ---
CreationList = <OCL entry> ; OCL spawned at the victim's location
CreateAtKillerLocation = No ; if Yes, spawn at the killer's position instead of the victim's
CreateObjectForVictim = No ; if Yes, the created object is owned by the victim's player instead of the killer's
End
FireWeaponOnKillBehavior New¶
Fires a weapon at the victim when the object kills a qualifying target.
Behavior = FireWeaponOnKillBehavior ModuleTag_FireOnKill
StartsActive = Yes
; --- shared KillMux conditions (see above) ---
KilledKindOf = VEHICLE
; --- module params ---
KillWeapon = <Weapon entry> ; weapon fired at the victim on kill
End
Superweapon / Special Power Update Modules¶
OrbitalBeamUpdate New¶
A special power update module for an "orbital beam" style superweapon that charges up several beams and then fires a final beam/weapon. (PR #99)
Behavior = OrbitalBeamUpdate ModuleTag_OrbitalBeam
SpecialPowerTemplate = <SpecialPower entry> ; (via SpecialPowerModule params)
InitialDelay = 0 ; ms before the sequence starts
InitialSound = <AudioEvent>
InitialFX = <FXList> ; played when the sequence starts
InitialOCL = <OCL entry> ; created when the sequence starts
; --- Charge beams (multiple beams that converge before the final shot) ---
NumChargeBeams = 1
ChargeBeamName = <LaserName> ; laser template used for charge beams
ChargeBeamRadius = 0.0 ; radius the charge beams spread over
ChargeBeamHeight = 0.0
ChargeBeamRotation = 0 ; rotation angle (degrees)
ChargeBeamsStartCenter = No ; start beams from the center
ChargeBeamInterpolation = <InterpolationType> ; how the beams move in
RandomizeChargeBeamOrder = No
ChargeBeamStartFX = <FXList>
ChargeStartFX = <FXList> ; played once as charging begins
ChargeStartOCL = <OCL entry> ; created once as charging begins
ChargeSound = <AudioEvent>
ChargeWeapon = <Weapon entry> ; weapon(s) fired per charge beam (can repeat)
ChargeBeamParticleSystem = <ParticleSystem> ... ; particle systems for the charge beam
ChargeBeamParticleSystemLand = <ParticleSystem> ... ; used over land
ChargeBeamParticleSystemWater = <ParticleSystem> ... ; used over water
DelayBetweenChargeBeams = 0
DelayChargeToAnim = 0
BeamAnimationDuration = 0
DelayAnimationToFinal = 0
; --- Final beam / weapon ---
FinalBeamName = <LaserName>
FinalBeamDuration = 0
FinalWeapon = <Weapon entry>
FinalFX = <FXList>
FinalOCL = <OCL entry> ; created when the final beam fires
AreaDecalRadius = 0.0 ; radius of the area decal drawn at the target
HitWaterSurface = No ; if Yes, beam/effects detonate at the water surface over water
End
Note
many fields have a matching ...Frames internal name; all Delay/Duration values are in milliseconds. Refer to the field list for the full set.
ChronoSphereUpdate New¶
Special power update module implementing a Chronosphere-style teleport superweapon: teleports units from a source area to a target area after a delay. (PR #100)
Behavior = ChronoSphereUpdate ModuleTag_Chrono
SpecialPowerTemplate = <SpecialPower entry>
Radius = 0.0 ; radius of the source/target area
RequiredKindOf = <KindOf list> ; only these units are teleported
ForbiddenKindOf = <KindOf list> ; these units are never teleported
TeleportDelay = 0 ; ms between activation and the teleport happening
SourceFX = <FXList> ; FX at the source area
SourceOCL = <OCL> ; OCL at the source area
TargetFX = <FXList> ; FX at the target area
TargetOCL = <OCL> ; OCL at the target area
UnitSourceFX = <FXList> ; FX on each teleported unit at the source
UnitTargetFX = <FXList> ; FX on each teleported unit at the target
End
TeleportSelfSpecialPower New¶
Special power update module that teleports its own object to a clicked ground position. This is the activated-ability counterpart to TeleporterAIUpdate, which instead replaces all normal movement with teleporting; a unit with this module walks normally the rest of the time.
Pair it with a SpecialPowerModule (or SpecialAbility) that sets UpdateModuleStartsAttack = Yes, otherwise the power triggers itself and a rejected click still consumes the recharge. The SpecialPower entry needs BehaviorEnum = SPECIAL_JUMPJET, which supplies the position-only validation (no water, no cliffs).
Behavior = TeleportSelfSpecialPower ModuleTag_Teleport
SpecialPowerTemplate = <SpecialPower entry>
MaxTeleportRange = 0.0 ; furthest the object may teleport, 0 = unlimited
TeleportDelay = 0 ; ms between activation and the teleport happening
TeleportStartFX = <FXList> ; FX at the position we left
TeleportTargetFX = <FXList> ; FX at the position we arrived at
; Recovery is off entirely unless RecoverDuration is set
RecoverDuration = 0 ; ms the unit is immobilized after landing
TeleportRecoverEndFX = <FXList> ; FX when the recovery finishes
TeleportRecoverSoundAmbient = <AudioEvent> ; looped while recovering
TeleportRecoverTint = <TintStatus> ; color tint applied while recovering
TeleportRecoverCondition = <ModelCondition> ; e.g. TELEPORT_RECOVER
TeleportRecoverOpacityStart = 100% ; opacity when the recovery starts
TeleportRecoverOpacityEnd = 100% ; opacity when the recovery ends
End
Notes
- The destination is validated when the order is given and again when it fires, so a spot that becomes blocked during
TeleportDelaycancels the teleport rather than stranding the unit. - An unaffordable
Cost, a dead/garrisoned/disabled caster, or an invalid destination all refuse the order without consuming the recharge. RecoverDurationusesDISABLED_TELEPORT_RECOVER, which genuinely immobilizes the unit. Because any disable pauses special power countdowns, the effective cooldown becomesReloadTime+RecoverDuration.- Do not set
KINDOF_TELEPORTERon a unit using this module - that KindOf excludes units from group speed, leader selection and column formations, which would break normal squad movement.
MultiLocationSpecialPowerUpdate New¶
Special power update that can create objects/OCLs at multiple resolved map locations (e.g. edges relative to the source/target). Used together with the multi-target CommandButton fields.
Behavior = MultiLocationSpecialPowerUpdate ModuleTag_MultiLoc
SpecialPowerTemplate = <SpecialPower entry>
CreateLocation = CREATE_AT_EDGE_NEAR_SOURCE ; where the OCL/object is created
; valid values:
; CREATE_AT_EDGE_NEAR_SOURCE (default)
; CREATE_AT_EDGE_NEAR_TARGET
; CREATE_AT_EDGE_FARTHEST_FROM_TARGET
; CREATE_AT_LOCATION
InitialDelay = 0 ; ms before the first creation
Delay = 0 ; ms between creations at each location
OCL = <OCL entry> ; default OCL created at each location
UpgradeOCL = <Upgrade> <OCL> ; optional per-upgrade OCL override (can repeat)
WaitForAttackComplete = No ; advance only once the caster has stopped attacking
MaxWaitPerTarget = 0 ; ms; safety cap when WaitForAttackComplete is used
End
Multi-click artillery¶
If the OCL contains an Attack nugget, the caster attacks each point with one of its own weapon
slots. aiAttackPosition replaces the previous order rather than queueing behind it, so with a
fixed Delay the next point cuts the previous barrage short.
WaitForAttackComplete = Yesadvance to the next point only once the caster has actually stopped attacking, instead of after a fixed delay.MaxWaitPerTarget = 5000safety cap in ms. Without it, a point the caster cannot attack would stall the whole sequence.
Note
Delay is still used as the poll interval, so leave it at a small value when
WaitForAttackComplete is enabled.
PropagateUpgradeToContainedUpgrade New¶
Upgrade module that grants upgrades to everything currently contained inside the object when it triggers. Useful for a transport passing a bought upgrade down to its riders.
Behavior = PropagateUpgradeToContainedUpgrade ModuleTag_Propagate
TriggeredBy = <Upgrade entry>
UpgradeToPropagate = <Upgrade entry> ; granted to each contained object (can repeat)
End
GlobalLightingModifierUpdate New¶
Update module that tints the global map lighting while the object lives. Intended for effects like a superweapon darkening the sky.
Behavior = GlobalLightingModifierUpdate ModuleTag_Lighting
TargetColor = R:0 G:0 B:0 ; colour blended towards
BlendMode = DARKEN ; DARKEN | COLORIZE | BRIGHTEN
Intensity = 1.0 ; 0.0 - 1.0, strength of the blend
InitialDelay = 0 ; ms before the effect starts
Duration = 0 ; ms the effect is held at full intensity; 0 = while the object lives
FadeInTime = 0 ; ms to reach full intensity
FadeOutTime = 0 ; ms to fade back out
RequiredUpgrade = <Upgrade> ; optional; the modifier only applies once this upgrade is present
End
TornadoUpdate New¶
Applies a tornado effect around the object: nearby units are dragged toward it, lifted, spun, and damaged, and they fall when the effect fades. The strength follows a weak - strong - weak envelope, so the tornado builds up, holds, and dies away like the particle uplink cannon beam does.
The module never moves its own object, so a tornado that wanders needs a Locomotor and an AI
module on the object like any other unit. A stationary one can be spawned by a weapon through
ProjectileDetonationOCL or FireOCL with a CreateObject nugget.
Behavior = TornadoUpdate ModuleTag_Tornado
Radius = 120 ; (required; how far out units are grabbed)
RingRadius = 12 ; (distance from the axis victims orbit at; 0 = a tenth of Radius)
PullForce = 0.6 ; (inward speed toward the centre, in distance per frame)
LiftForce = 1.5 ; (climb speed toward MaxLiftHeight, in height per frame)
SpinForce = 6 ; (orbit speed around the centre; a negative value orbits the other way)
YawRate = 360 ; (how fast a victim spins about its own axis, in degrees per second)
MaxLiftHeight = 40 ; (above this height over the tornado ground, lift stops, so victims hover)
MaxVictimSpeed = 12 ; (speed cap on victims; 0 = uncapped, which lets them spiral away)
MassReference = 100 ; (victims heavier than this spin proportionally slower; 0 = no scaling)
ReleaseSpeed = 0 ; (horizontal speed kept when released; 0 drops them straight down)
RequiredKindOf = VEHICLE INFANTRY ; (optional; a victim must be at least one of these)
ForbiddenKindOf = AIRCRAFT ; (optional; a victim must be none of these)
AffectsTargets = ENEMIES NEUTRALS ; (default = ALLIES ENEMIES NEUTRALS)
AffectAirborne = No ; (default = No)
IgnoreVictimGeometry = No ; (default = No; Yes stops held victims shoving each other apart)
RampUpTime = 2000 ; (ms to reach full strength)
FullStrengthTime = 6000 ; (ms at full strength; 0 = until the object dies or a controller ends it)
RampDownTime = 2000 ; (ms to fade to nothing; victims fall once it reaches zero)
DamagePerSecond = 20 ; (damage rate at full strength)
DamageRadius = 0 ; (default = 0, which uses Radius)
DamagePulseDelay = 500 ; (ms between damage pulses; 0 disables damage)
DamageType = EXPLOSION ; (default = EXPLOSION)
DeathType = EXPLODED ; (default = EXPLODED)
KillObjectWhenDone = No ; (default = No; Yes destroys the object once the ramp down finishes)
End
- A victim needs a
PhysicsBehavior. Lift, pull and spin all ignoreMass, so every held unit rides at the same height and speed. The one per unit resistance isShockResistance, which scales the whole effect down and doubles as an immunity dial. - Structures, immobile objects and projectiles take damage but are never pulled. Units inside a transport are untouched; only the transport itself is grabbed.
- Airborne targets are skipped unless
AffectAirborne = Yes. Aircraft with a fixed flight height overwrite their own height every frame, so lifting them does not work well. - Falling damage on release is the victim's own, from
MinFallHeightForDamageandFallHeightDamageFactoron itsPhysicsBehavior. It only counts a steep descent, which is whyReleaseSpeed = 0is the reliable way to splat units. IgnoreVictimGeometrysuppresses collision push-apart between held victims. Because they are all steered onto the same ring they overlap constantly, and wide units can be shoved around faster than the orbit settles, which reads as juddering. It is restored on release.- The module does not end the object. Pair it with a
LifetimeUpdate, or the OCLMinLifetimeandMaxLifetimefields, or setKillObjectWhenDone. A tornado withFullStrengthTime = 0and none of these, and no controller such as the cannon, fades out by itself after 30 seconds.
ThermiteBehavior New¶
Goes on a projectile object. When the projectile detonates, the projectile itself stays alive as a
hidden burn instead of being destroyed. If the projectile hit an object, the burn sticks to that
object and follows it around. If the projectile detonated on the ground, the burn stays where it
landed. Every time Weapon is ready it fires at the stuck object, or at the ground spot, until the
lifetime runs out. Damage, radius, pulse rate and FX all come from that weapon.
The module is meant for an upgrade such as thermite shells, so the upgrade fields gate it. Without the trigger the projectile detonates and dies as usual.
Behavior = ThermiteBehavior ModuleTag_Thermite
Weapon = FlameTankThermiteBurn ; (required; fired on every pulse, its FireFX is the burn visual)
MinLifetime = 3000 ; (ms; shortest burn)
MaxLifetime = 5000 ; (ms; longest burn, picked once per projectile)
TriggeredBy = Upgrade_ChinaThermiteShells ; (optional; none = always on)
ConflictsWith = Upgrade_Something ; (optional)
RequiresAllTriggers = No ; (default = No)
End
- Works with
DumbProjectileBehavior,MissileAIUpdateandFreeFallProjectileBehavior. The normalProjectileDetonationFXand damage still happen first, and only then does the burn start. - The projectile is the burn, so
DetonateCallsKilland the projectile's own death FX are skipped when the thermite ignites. Weaponis fired from the projectile with the stuck object as the target, so it must have noMinimumAttackRange.DelayBetweenShotssets the pulse rate. On the ground it is fired at the burn position, so give it aPrimaryDamageRadius.- The stuck object is the one the projectile collided with, not the one it was aimed at. Mobile victims are followed at their center. Structures and the ground keep the impact point.
- A victim that dies or enters a transport or tunnel drops the burn to the ground under it, where it keeps burning for the rest of its lifetime.
- The upgrade check looks at the firing player, the launcher object and the projectile, so both
player upgrades and object upgrades on the launcher work as
TriggeredBy.
PoweredBehavior New¶
Controls what an object does while its owner is out of power. Without the module, a KINDOF_POWERED
object gets the underpowered disable and shuts down completely. With the module the object stays
active, and only the listed effects apply. The module replaces the KINDOF_POWERED disable on that
object, so abilities and command buttons keep working.
Behavior = PoweredBehavior ModuleTag_Powered
IsMobile = No ; (default = Yes; No = cannot move while out of power)
DisableWeapon = Yes ; (default = No; Yes = cannot attack while out of power)
MovePenalty = 50% ; (default = 0%; move speed lost while out of power)
LiftPenalty = 20% ; (default = 0%; lift lost while out of power, hovering units only)
Icon = LowPower ; (optional; name of an Animation block, shown while out of power)
End
MovePenaltyof 100% or more acts likeIsMobile = No.MovePenaltynever touches lift, so helicopters keep hovering.LiftPenaltylowers lift on its own. Once lift no longer beats gravity the unit sinks, so keep it small. 100% is ignored.Iconnames anAnimationblock fromanimation2d.ini, like the stockDisabledone. It sits above the health bar, beside the disabled icon when both show. See Animation2D.ini for the single-imageTextureform.- Losing power with
IsMobile = Nostops the current move order. Attack orders still work, so a turreted unit keeps firing from where it stands. - The effects follow the owner. A captured object takes the new owner's power state.
- No disabled tint is shown; use
Iconfor feedback.
ParticleUplinkCannonUpdate (Tornado)¶
TornadoObjectName = <object>Creates this object at the beam ground point when the orbital beam appears, drags it along with the beam, ramps it down when the beam starts decaying, and destroys it when the beam dies or the cannon is sold or destroyed.
The named object is expected to carry a TornadoUpdate. Give it
FullStrengthTime = 0 and a RampDownTime matching the cannon WidthGrowTime, so that the tornado
follows the beam for as long as it fires and then fades out with it.
Subdual Jamming¶
Jamming damage that accumulates on the body like subdual damage, interacts with armor, and disables the unit when the threshold is reached. Healing ticks remove the damage over time.
New Damage Types¶
Two new entries in DamageType:
SUBDUAL_JAMMINGjamming damage adjusted by armor coefficientsSUBDUAL_JAMMING_UNRESISTABLEbypasses armor entirely (used internally for healing ticks)
Neither type reduces health. Set these on a weapon's DamageType field.
Jam Effect¶
When jamming damage reaches the unit's max health, the unit gains UNSELECTABLE object status, drops
out of the player's selection, and its passengers are ordered to idle. The status clears once the
jamming damage heals below the threshold.
UNSELECTABLE on its own only blocks a new selection click. Dropping the unit from the current
selection is something jamming asks for specifically, so other sources of the status - a slaved drone,
a docked unit, a sold building - leave the selection alone.
Jamming is independent of the DISABLED_* states: it neither waits for them nor ends them, and a
disabled unit stays disabled through a jam. On unjam it only clears UNSELECTABLE if the jam was
what set it, so a docked, slaved, or status-held unit keeps that state.
ActiveBody Fields¶
Body = ActiveBody ModuleTag_Body
; ...existing ActiveBody fields...
JammingDamageCap = 100.0 ; max jamming damage this unit can accumulate (0 = immune)
JammingDamageHealRate = 500 ; milliseconds between each healing tick
JammingDamageHealAmount = 5.0 ; jamming damage removed per tick
End
A unit with JammingDamageCap = 0 ignores SUBDUAL_JAMMING damage entirely.
The unit becomes jammed when accumulated jamming damage reaches MaxHealth. Healing begins
automatically after the first hit.
Recovery timing¶
Every hit resets the heal countdown, so the first healing tick lands one full HealRate after
the last hit. Each tick then removes HealAmount until the stored damage reaches zero. The unit
unjams as soon as the stored damage drops below MaxHealth; the overlay only disappears once it
reaches zero. JammingDamageCap bounds the stored damage and therefore the longest recovery.
time to unjam = HealRate * ceil((stored - MaxHealth) / HealAmount)
time to clear overlay = HealRate * ceil(stored / HealAmount)
With the defaults in Subdual Damage Defaults
(cap MaxHealth * 2, heal MaxHealth / 16.25 every 500 ms) a fully capped unit unjams after
8.5 s and its overlay clears after 16.5 s. Subdual damage heals the same way, but its blue tint
is a flag rather than a level and clears on the first healing tick.
Any of these keys, and the SubdualDamage* trio, may be omitted. An omitted key takes its value
from the matching SubdualDamageDefaults block in GameData.ini, and is 0 if no block matches.
Cap and HealAmount keys accept MaxHealth * 2 or MaxHealth / 16.25 as well as a plain number,
evaluated against the unit's current max health. ActiveBody also accepts ChronoDamageHealRate
and ChronoDamageHealAmount in the same forms, which override the global chrono keys for that
unit. See Subdual Damage Defaults.
Armor¶
SUBDUAL_JAMMING interacts with armor normally. Define coefficients in Armor.ini:
Armor ChinaTankArmor
Armor = SUBDUAL_JAMMING 200% ; takes twice as long to jam
End
SUBDUAL_JAMMING_UNRESISTABLE bypasses armor (like UNRESISTABLE and SUBDUAL_UNRESISTABLE).
Overlay Texture¶
A scrolling texture can be drawn over units taking jamming damage. Its opacity is the stored
jamming damage divided by MaxHealth, clamped to 1, so it fades in as the unit is jammed, holds
full strength while damage sits above MaxHealth, and fades out as it heals (see
Recovery timing). Configured globally in GameData.ini:
JammingOverlayTexture = JammingFX ; texture name; omit or leave empty to disable
JammingOverlayScrollU = 0.5 ; horizontal scroll per second
JammingOverlayScrollV = 0.0 ; vertical scroll per second
JammingOverlayScale = 1.0 ; UV tiling; >1 repeats the texture more densely
JammingOverlayColor = R:255 G:255 B:255 ; tint multiplied into the texture
JammingOverlayAdditive = Yes ; Yes = additive glow, No = alpha blend
The effect is off by default. Yes suits an electrical shimmer; No suits an opaque layer
such as frost, and needs the texture to carry an alpha channel.
Note
a unit that is both jammed and stealth-detected shows the jamming overlay only. The engine carries one opacity value per render call, so the two effects cannot be layered with independent strengths. The frozen overlay stacks with this one and shares that single value.
Icon¶
A jammed unit shows its own icon beside the health bar, next to the disabled icon when both
apply. Define an Animation Jammed block in Animation2D.ini; the icon is not drawn until this
exists. The single-image Texture form is the natural fit — see
Animation2D.ini:
Animation Jammed
NumberImages = 1
Texture = jammer.tga
AnimationMode = ONCE
AnimationDelay = 0
End
Per-Unit Sounds¶
Units can define custom jam/unjam sounds via their UnitSpecificSounds block:
Object SomeUnit
UnitSpecificSounds
SoundJammed = JammedSoundEvent
SoundUnjammed = UnjammedSoundEvent
End
End
If no per-unit sound is defined, the unit falls back to the global jam sounds in
MiscAudio.ini, and is silent if those are unset too:
UnitJammed = JammedSoundEvent
UnitUnjammed = UnjammedSoundEvent
Jamming never borrows the building-disabled or vehicle-disabled sounds, so an EMP'd unit that is also jammed plays two distinct cues rather than a repeated one.
Example Weapon¶
Weapon JammerGun
PrimaryDamage = 50.0
PrimaryDamageRadius = 0.0
DamageType = SUBDUAL_JAMMING
DeathType = NORMAL
; ...other weapon fields...
End
Subdual Frozen¶
Frozen damage is a third subdual pool beside retail subdual and jamming. It accumulates on the body, interacts with armor, and disables the unit the way retail subdual does once it reaches the threshold. Healing ticks remove the damage over time. The three pools are independent: each has its own counter, cap, heal rate and effect, and a unit can be subdued, jammed and frozen at the same time.
New Damage Types¶
Two new entries in DamageType:
SUBDUAL_FROZENfrozen damage adjusted by armor coefficientsSUBDUAL_FROZEN_UNRESISTABLEbypasses armor entirely (used internally for healing ticks)
Neither type reduces health. Set these on a weapon's DamageType field.
Freeze Effect¶
When frozen damage reaches the unit's max health, the unit gains the DISABLED_FROZEN disabled
type and the FROZEN condition state, and its passengers are ordered to idle. Both clear once the
frozen damage heals below the threshold.
DISABLED_FROZEN is checked everywhere the game checks DISABLED_SUBDUED, so a frozen unit
behaves exactly like a subdued one: it cannot move, fire, animate, sell, evacuate or auto-target,
transports refuse to load or unload it, a frozen stinger site silences its soldiers, and its
command buttons grey out. A unit that is both frozen and EMP'd, subdued or hacked stays disabled
until the last of those clears.
The FROZEN condition state lets art react. A ConditionState = FROZEN block on a draw module can
swap the model or play an animation for as long as the unit is frozen.
A frozen unit does not take the dark-gray disabled tint that EMP and subdual apply, so the
frozen overlay and any FROZEN art carry the look on their own.
Projectiles take frozen damage but are never disabled by it; only the sound plays.
ActiveBody Fields¶
Body = ActiveBody ModuleTag_Body
; ...existing ActiveBody fields...
FrozenDamageCap = 100.0 ; max frozen damage this unit can accumulate (0 = immune)
FrozenDamageHealRate = 500 ; milliseconds between each healing tick
FrozenDamageHealAmount = 5.0 ; frozen damage removed per tick
End
A unit with FrozenDamageCap = 0 ignores SUBDUAL_FROZEN damage entirely. The unit freezes when
accumulated frozen damage reaches MaxHealth. Healing begins automatically after the first hit,
with the same recovery timing as jamming.
Any of these keys may be omitted. An omitted key takes its value from the matching
SubdualDamageDefaults block in GameData.ini, and is 0 if no block matches. Cap and HealAmount
keys accept MaxHealth * 2 or MaxHealth / 16.25 as well as a plain number. See
Subdual Damage Defaults.
Armor¶
SUBDUAL_FROZEN interacts with armor normally. Define coefficients in Armor.ini:
Armor ChinaTankArmor
Armor = SUBDUAL_FROZEN 200% ; takes twice as long to freeze
End
SUBDUAL_FROZEN_UNRESISTABLE bypasses armor (like UNRESISTABLE and SUBDUAL_UNRESISTABLE).
Overlay Texture¶
A texture can be drawn over units taking frozen damage, with the same fade rule as the jamming
overlay: opacity is the stored frozen damage divided by MaxHealth, clamped to 1. Configured
globally in GameData.ini with the same keys as the jamming overlay:
FrozenOverlayTexture = FrostFX.tga ; texture name; omit or leave empty to disable
FrozenOverlayScrollU = 0.0 ; horizontal scroll per second
FrozenOverlayScrollV = 0.0 ; vertical scroll per second
FrozenOverlayScale = 1.0 ; UV tiling; >1 repeats the texture more densely
FrozenOverlayColor = R:255 G:255 B:255 ; tint multiplied into the texture
FrozenOverlayAdditive = No ; Yes = additive glow, No = alpha blend
The effect is off by default. The defaults differ from jamming: no scroll and alpha blend, which suits a static frost layer with an alpha channel.
The jamming and frozen overlays stack, so a unit that is both jammed and frozen draws both textures. The engine carries one opacity value per render call, so both passes use the stronger of the two intensities and fade together. A unit that is also stealth-detected shows the subdual overlays only.
Icon¶
A frozen unit shows its own icon beside the health bar, after the disabled and jammed icons when
those apply. Define an Animation Frozen block in Animation2D.ini; the icon is not drawn until
this exists. See Animation2D.ini:
Animation Frozen
NumberImages = 1
Texture = frozen.tga
AnimationMode = ONCE
AnimationDelay = 0
End
Per-Unit Sounds¶
Units can define custom freeze/thaw sounds via their UnitSpecificSounds block:
Object SomeUnit
UnitSpecificSounds
SoundFrozen = FrozenSoundEvent
SoundUnfrozen = UnfrozenSoundEvent
End
End
If no per-unit sound is defined, the unit falls back to the global sounds in MiscAudio.ini,
and is silent if those are unset too:
UnitFrozen = FrozenSoundEvent
UnitUnfrozen = UnfrozenSoundEvent
Freezing never borrows the building-disabled or vehicle-disabled sounds.
Example Weapon¶
Weapon FreezeGun
PrimaryDamage = 50.0
PrimaryDamageRadius = 0.0
DamageType = SUBDUAL_FROZEN
DeathType = NORMAL
; ...other weapon fields...
End
Animation2D.ini¶
Texture (single image frames)¶
An Animation block can name a texture file directly for a frame instead of a MappedImage.
This is the simplest way to make a one-frame icon such as the low-power or jammed indicators:
Animation Jammed
NumberImages = 1
Texture = jammer.tga
AnimationMode = ONCE
AnimationDelay = 0
End
Syntax is Texture = <file> [width height]. The whole texture is used as the frame.
- Width and height are optional and default to
32 32. They set the size the frame is drawn at, so they should match the file's real pixel size or the image will be scaled. TextureandImagelines can be mixed in one block; each fills the next frame slot in order, soNumberImagesmust still count them all.- The file name doubles as the image name. Every animation that names the same file shares one
image, and a
MappedImagealready defined under that name is reused rather than replaced. - The file is resolved like any other texture, so a
.ddsof the same name anywhere in the archives takes priority over a loose.tga. Loose files go inArt\Textures\.
A static icon wants NumberImages = 1, AnimationMode = ONCE and AnimationDelay = 0, as above.
Misc Improvements¶
ObjectExtend¶
Allows to use inheritence in the parser. ObjectExtend is similar to ObjectReskin but inherit all modules and allow modifications. The parent object must be defined before the ObjectExtend.
Syntax: ObjectExtend NewObject ObjectToInheritFrom
Use RemoveModule ModuleTag_xx to remove a module inherited from the parent.
WeaponSet and ArmorSet are inherited, but if you define another one in the child, the inherited sets are removed.
If the parent has multiple WeaponSets all will be removed from the child if the child defines one.
Examples:
ObjectExtend ZExtendedTank Chem_GLAVehicleRadarVan
; *** ART Parameters ***
SelectPortrait = SNHacker2_L ;define other icons
ButtonImage = SNHacker2
RemoveModule ModuleTag_01 ; Remove the parent's draw
Draw = W3DTankDraw ModuleTag_1337 ; add a new draw
OkToChangeModelColor = Yes
DefaultConditionState
Model = NVInferno
Turret = Turret
TurretPitch = TurretEL01
WeaponFireFXBone = PRIMARY Muzzle
WeaponRecoilBone = PRIMARY Barrel
WeaponLaunchBone = PRIMARY Muzzle
HideSubObject = PARTSUP TurretEl02
ShowSubObject = TurretEL01 TURRETPARTS
End
ConditionState = RUBBLE REALLYDAMAGED
Model = NVInferno_D
End
TrackMarks = EXTnkTrack.tga
TreadAnimationRate = 2.0
End
Draw = W3DModelDraw ModuleTag_0123 ; add a second draw (tree on top)
DefaultConditionState
Model = PTOak01
End
End
Prerequisites ; change the prerequisites
Object = Tank_ChinaCommandCenter TEST_MODE
End
WeaponSet ; define new weaponset, all parent inherited weapons are cleared
Conditions = None
Weapon = PRIMARY Tank_InfernoCannonGun
End
RemoveModule ModuleTag_Stealth ; Remove the stealth update inherited from the parent
End
ObjectExtend ZExtendedTank2 ZExtendedTank ; inherit again
RemoveModule ModuleTag_0123 ; remove the tree draw
WeaponSet ; replaces all weaponset
Conditions = None
Weapon = PRIMARY MarauderTankGun
End
ArmorSet ; replaces all armor sets
Conditions = None
Armor = TruckArmorExtended
DamageFX = TankDamageFX
End
End