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).
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:
WeaponManager::reset() (kernel/src/mgr/weaponmanager.cpp) callsWeaponManager::loadWeapon(WeaponType wt) once for every WeaponType.loadWeapon() opens ref/weapons.dat as a ConfigFile and constructs a new Weapon(wt, conf).Weapon constructor sets a number of hardcoded, per-type properties (see §4), then callsWeapon::initFromConfig(w_type, conf) to read the remaining fields from the file using the keyweapon.{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).
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.* |
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(). |
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.
ShotPropertyEnum / WeaponShotPropertyType bitmask referenceshot_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 |
Weapon vs WeaponInstanceWeapon 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_.
.dat and weaponmanager.cpp comments)weapon.7.range): comment notes the value was changed from 512 to 1152.weapon.9) and MediKit (weapon.10): their range value is "used only forrange has no gameplay effect forweapon.11): ammo.price=7500 is flagged uncertain ("what is real number forbomb.explosiondelay is "the time before the bomb explodes";reloadtime is repurposed as the delay before the tick sound effect.weapon.14.range=100): a comment notes "in real game it's 256" — a deliberateweaponmanager.cpp notes Bullfrog appears to have planned another weapon// TODO: calibrate weapon time for shot and reload, angle, accuracy marksreloadtime/shotangle/shotaccuracy values across weapons as not fully tuned.weapon.13): ammo-consumption pacing uses auto.fire_rateWeaponInstance::consumeAmmoForEnergyShield()). weapon.13.auto.fire_ratespe_Automatic flag, so unlike Uzi/Minigun/Flamer this key isn't aboutweapon.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).