Menu ▾ ▴

Configuration

benblan

Weapon configuration reference (data/ref/weapons.dat)

This document describes the parameters read from data/ref/weapons.dat and how each one is used
by the Weapon and WeaponInstance classes
(kernel/include/fs-kernel/model/weapon.h, kernel/src/model/weapon.cpp).

1. Overview

weapons.dat is a plain-text, INI-style file parsed by the generic ConfigFile class
(utils/include/fs-utils/io/configfile.h): key=value pairs, # for comments, blank lines
allowed. Each weapon type has its own block of keys prefixed weapon.<N>., where N is the
integer value of the Weapon::WeaponType enum.

Loading path:

  1. WeaponManager::reset() (kernel/src/mgr/weaponmanager.cpp) calls
    WeaponManager::loadWeapon(WeaponType wt) once for every WeaponType.
  2. loadWeapon() opens ref/weapons.dat as a ConfigFile and constructs a new Weapon(wt, conf).
    Note: the file is re-opened and re-parsed for every weapon type rather than parsed once and
    reused.
  3. The Weapon constructor sets a number of hardcoded, per-type properties (see §4), then calls
    Weapon::initFromConfig(w_type, conf) to read the remaining fields from the file using the key
    pattern weapon.{type}.{field} (WEAPON_PROPERTY_PATTERN).

A Weapon instance represents a weapon type/class, shared by all WeaponInstance objects of
that type. A WeaponInstance (created via WeaponInstance::createInstance()) wraps a pointer to
its Weapon plus per-object runtime state (ammo remaining, owner, timers — see §6).

2. Weapon type index

WeaponType value Name .dat prefix
1 Pistol weapon.1.*
2 GaussGun weapon.2.*
3 Shotgun weapon.3.*
4 Uzi weapon.4.*
5 Minigun weapon.5.*
6 Laser weapon.6.*
7 Flamer weapon.7.*
8 LongRange weapon.8.*
9 Scanner weapon.9.*
10 MediKit weapon.10.*
11 TimeBomb weapon.11.*
12 AccessCard weapon.12.*
13 EnergyShield weapon.13.*
14 Persuadatron weapon.14.*

3. Parameter reference

Fields are read in Weapon::initFromConfig() (kernel/src/model/weapon.cpp, lines ~205-246).
"Default" is the value used when ConfigFile::read<T>() is called with a fallback; keys with no
default listed throw (and are logged via FSERR) if missing from the file.

.dat key suffix Type Member Default Meaning / units
name std::string name_ — (required) Message-table id (e.g. WEAPON_PISTOL) resolved through g_Ctx.getMessage() to get the localized display name.
icon.small int small_icon_ — (required) Icon id shown in the weapon-select menu.
icon.big int big_icon_ — (required) Larger icon id shown in the equip/inventory screen.
cost int cost_ — (required) Purchase price of the weapon.
ammo.nb int ammoCapacity_ 0 Max ammo the weapon can carry. Weapons that don't use ammo have 0.
ammo.price int ammo_cost_ 0 Price per unit to reload; used by calculateReloadingCost() = (ammoCapacity_ - remainingAmmo) * ammo_cost_.
range int range_ — (required) Weapon range in world/map distance units. 256 units = 1 map tile (see MapObject::setPosition, which divides world coordinates by 256).
rank int rank_ -1 Used to order shooting weapons by value (e.g. in select menus / AI weapon preference).
anim int anim_ — (required) Animation id played when the weapon lies on the ground on the map (onGroundAnimationId()).
ammopershot int ammo_per_shot_ 0 Ammo units consumed per shot fired.
bomb.explosiondelay uint32_t explosionDelay_ 0 Time (milliseconds) before a TimeBomb explodes. Only meaningful for TimeBomb (weapon.11) — seeds WeaponInstance::bombExplosionTimer; unused (stays 0) for every other weapon type.
reloadtime int time_reload_ 0 Time (milliseconds) before the weapon is ready to fire again. For TimeBomb, repurposed to delay the ticking sound effect.
damagerange int range_dmg_ 0 Radius of splash/range damage (same distance units as range), for weapons that damage an area on impact.
shotangle double shot_angle_ 0.0 Half-angle (degrees) of the shot's spread cone; wider for shotgun-type weapons.
shotaccuracy double shot_accuracy_ 0.0 Accuracy factor (0.0–1.0). The shooting agent's own accuracy stat is later applied on top of shot_angle_.
shotspeed int shot_speed_ 0 Projectile travel speed. Only set (non-zero) for weapons that fire an actual projectile (GaussGun, Flamer).
dmg_per_shot int dmg_per_shot_ 0 Damage points inflicted per shot (health is capped around 0-255, see ShootableMapObject::setHealth).
ammo.impactNb int impactsPerAmmo_ 0 Number of impacts caused when one ammo unit is consumed (e.g. Minigun/GaussGun spread multiple impacts per shot).
weight int weight_ — (required) Abstract weight value; influences the carrying agent's movement speed.
auto.fire_rate int fireRate_ 0 Time (milliseconds) between two shots. Paces AutomaticShootAction's firing for automatic weapons (spe_Automatic, see §5) — Uzi, Minigun, Flamer — and also paces EnergyShield's (weapon.13) ammo consumption via WeaponInstance::consumeAmmoForEnergyShield().

4. Fields NOT in the config file

The following Weapon members are not read from weapons.dat. They are hardcoded per
WeaponType in the Weapon constructor's switch statement (weapon.cpp, before the call to
initFromConfig()):

Member Type Purpose
idx_ WeaponAnimIndex Index into the weapon-carrying ped's animation set (Pistol_Anim, Uzi_Anim, …).
sample_ fs_eng::InGameSample Sound effect played when firing (engine/include/fs-engine/sound/sound.h).
dmg_type_ DamageType Damage category (kDmgTypeBullet, kDmgTypeLaser, kDmgTypeBurn, kDmgTypeExplosion, kDmgTypeCollision, kDmgTypePersuasion — see kernel/include/fs-kernel/model/damage.h).
shot_property_ uint32_t (WeaponShotPropertyType) Bitmask describing shooting behavior — see §5.
impactAnims_ ImpactAnims Set of SFXObject::SfxType ids used for ground-hit / object-hit / trace animations, plus rd_anim for range-damage visuals.

Editing weapons.dat alone will not change these — they require a code change in the constructor
switch.

5. ShotPropertyEnum / WeaponShotPropertyType bitmask reference

shot_property_ is a bitmask combining flags from Weapon::ShotPropertyEnum:

Flag Value Meaning
spe_None 0x0 No special property.
spe_Owner 0x0001 Can only target its own owner (self-use weapons: Scanner, MediKit, AccessCard, EnergyShield).
spe_PointToPoint 0x0002 Fires a single shot toward one target point.
spe_PointToManyPoints 0x0004 Fires toward multiple points (e.g. shotgun pellets, minigun spread).
spe_TargetReachInstant 0x0008 Shot reaches its target instantly (hitscan).
spe_TargetReachNeedTime / spe_CreatesProjectile 0x0010 Shot travels over time as a projectile (GaussGun, Flamer).
spe_RangeDamageOnReach 0x0020 Deals area damage on impact.
spe_ShootsWhileNoTarget 0x0040 Can fire without a target and ignores accuracy (TimeBomb).
spe_UsesAmmo 0x0080 Consumes ammo when used.
spe_ChangeAttribute 0x0100 Alters an attribute rather than dealing damage (Scanner, AccessCard, EnergyShield).
spe_SelfDestruction 0x0200 Weapon destroys itself on use (TimeBomb).
spe_TargetPedOnly 0x0400 Can only target peds.
spe_CanShoot 0x0800 Weapon can be fired at all (canShoot()).
spe_Automatic 0x1000 Can fire continuously while the mouse is held (isAutomatic()).

Per-type combinations (WeaponShotPropertyType), from weapon.h:

Weapon type Flags combined
Persuadatron spe_None
Pistol PointToPoint \| TargetReachInstant \| UsesAmmo \| CanShoot
GaussGun PointToPoint \| TargetReachNeedTime \| UsesAmmo \| RangeDamageOnReach \| CanShoot
Shotgun PointToManyPoints \| TargetReachInstant \| UsesAmmo \| CanShoot
Uzi PointToPoint \| TargetReachInstant \| UsesAmmo \| CanShoot \| Automatic
Minigun PointToManyPoints \| TargetReachInstant \| UsesAmmo \| CanShoot \| Automatic
Laser PointToPoint \| TargetReachInstant \| RangeDamageOnReach \| UsesAmmo \| CanShoot
Flamer PointToPoint \| TargetReachNeedTime \| UsesAmmo \| CanShoot \| Automatic
LongRange PointToPoint \| TargetReachInstant \| UsesAmmo \| CanShoot
Scanner Owner \| ChangeAttribute
MediKit Owner \| UsesAmmo
TimeBomb ShootsWhileNoTarget \| TargetReachInstant \| RangeDamageOnReach \| SelfDestruction
AccessCard Owner \| ChangeAttribute
EnergyShield Owner \| ChangeAttribute \| UsesAmmo

6. Weapon vs WeaponInstance

Weapon holds the shared, type-level data loaded from weapons.dat (one object per
WeaponType, owned by WeaponManager). WeaponInstance holds per-object runtime state for an
actual weapon on the map or in an agent's inventory:

Member Type Purpose
pWeaponClass_ Weapon * Pointer to the shared weapon-type definition.
pOwner_ PedInstance * The ped currently carrying/owning this weapon instance, if any.
ammo_remaining_ int Current ammo count for this instance (starts at ammoCapacity() unless constructed with an explicit value).
bombSoundTimer fs_utl::Timer Timer for the TimeBomb ticking sound effect (initialized from reloadTime()).
bombExplosionTimer fs_utl::Timer Timer counting down to bomb explosion (initialized from explosionDelay()).
flamerTimer_ fs_utl::Timer Timer used to rotate the flame direction while firing.
shieldTimer_ fs_utl::Timer Timer pacing ammo consumption while an EnergyShield is active (initialized from fireRate(), reset in activate()).
activated_ bool Whether a TimeBomb/EnergyShield has been activated.
onGroundAnim_ uint16_t Runtime animation handle created from pWeaponClass_->onGroundAnimationId().

Most WeaponInstance accessors (range(), ammoCapacity(), rank(), getWeight(),
shotProperty(), dmgType(), …) simply delegate to pWeaponClass_.

7. Per-weapon quirks (from .dat and weaponmanager.cpp comments)

  • Flamer (weapon.7.range): comment notes the value was changed from 512 to 1152.
  • Scanner (weapon.9) and MediKit (weapon.10): their range value is "used only for
    display in select menu" — neither weapon actually shoots, so range has no gameplay effect for
    them beyond UI presentation.
  • TimeBomb (weapon.11): ammo.price=7500 is flagged uncertain ("what is real number for
    'shot'? for now = 7500"); bomb.explosiondelay is "the time before the bomb explodes";
    reloadtime is repurposed as the delay before the tick sound effect.
  • Persuadatron (weapon.14.range=100): a comment notes "in real game it's 256" — a deliberate
    deviation from the original Syndicate value.
  • Unused icon id 27: weaponmanager.cpp notes Bullfrog appears to have planned another weapon
    that got scrapped, leaving a gap in icon ids.
  • An existing // TODO: calibrate weapon time for shot and reload, angle, accuracy marks
    reloadtime/shotangle/shotaccuracy values across weapons as not fully tuned.
  • EnergyShield (weapon.13): ammo-consumption pacing uses auto.fire_rate
    (see WeaponInstance::consumeAmmoForEnergyShield()). weapon.13.auto.fire_rate
    must be set — it has no spe_Automatic flag, so unlike Uzi/Minigun/Flamer this key isn't about
    firing animation, it's about the shield's ammo drain rate.

8. Worked example: Pistol (weapon.1.*)

weapon.1.name=WEAPON_PISTOL      # -> name_ via message table
weapon.1.icon.small=15           # -> small_icon_
weapon.1.icon.big=65             # -> big_icon_
weapon.1.cost=0                  # -> cost_ (free starter weapon)
weapon.1.ammo.nb=13              # -> ammoCapacity_
weapon.1.ammo.price=0            # -> ammo_cost_ (free reload)
weapon.1.range=1280              # -> range_ (1280 / 256 = 5 map tiles)
weapon.1.rank=1                  # -> rank_
weapon.1.anim=368                # -> anim_ (on-ground sprite)
weapon.1.ammopershot=1           # -> ammo_per_shot_
weapon.1.reloadtime=600          # -> time_reload_ (600 ms before ready again)
weapon.1.damagerange=0           # -> range_dmg_ (no splash damage)
weapon.1.shotangle=5.0           # -> shot_angle_ (narrow, precise weapon)
weapon.1.shotaccuracy=0.9        # -> shot_accuracy_
weapon.1.shotspeed=0             # -> shot_speed_ (hitscan, no projectile)
weapon.1.dmg_per_shot=2          # -> dmg_per_shot_
weapon.1.ammo.impactNb=1         # -> impactsPerAmmo_
weapon.1.weight=1                # -> weight_ (light)

The Pistol has no auto.fire_rate entry, so fireRate_ falls back to its default of 0 — matching
wspt_Pistol, which does not include the spe_Automatic flag (see §5).