Overview
This genre pack targets shooters in the Call of Duty / Halo / Apex / Counter-Strike mould: a character defined by weapon-handling attributes, an ammo economy (magazine plus reserve), a fire / reload / aim gunplay loop, and hit resolution that couples regenerating shields, hitzone multipliers (headshots), and range falloff.
Unlike the Platformer, Racing, and ARPG packs, the core specification ships no dedicated shooter
case study, so this pack is designed from first principles. It still leans entirely on core
constructs — the modifier Channel mechanism (core spec §5.3) for accuracy
aggregation, custom Executions for stateful reload and damage, and effect-granted tags for the
weapon-handling state machine.
The first-person shooter is the concrete seed, but the same pieces generalize to the wider shooter family — third-person, hero shooter, battle royale — which layer classes, loot, and objectives on top of this gunplay-and-loadout core.
Relationship to the core specification
This document is additive. It defines genre-specific Attributes, Tags, Abilities, and Effects on top of the core Universal Gameplay Ability System specification.
-
It MUST NOT redefine, override, or contradict any concept in the core spec.
-
All entities in
entities/validate against the sameschemas/*.jsonas the core. -
It reuses the core lifecycle tags (
State.Alive,State.Combat,State.Dead) by reference, and adds shooter-specific states (State.Aiming,State.Reloading, …). -
Weapon-handling state is mutated only through Effects (core spec §3.1) — abilities never write tags directly — and the accuracy stacking is the core modifier
Channelmechanism, not a new construct.
Genre Attributes
Defined in entities/attribute_set.yaml as the ShooterCombatSet set. The base values describe a
default automatic rifle, so the set is playable as shipped.
| Attribute | Category | Role |
|---|---|---|
|
Statistic / Resource |
|
|
Statistic / Resource |
Regenerating overshield; absorbs incoming damage before |
|
Statistic |
Ground movement speed; lowered while aiming down sights. |
|
Statistic |
Fully-aggregated per-shot damage read by |
|
Statistic |
Rounds per second; the per-shot cooldown is \(1 / \text{FireRate}\). |
|
Statistic |
Bullet-cone half-angle in degrees; tightened by the |
|
Statistic |
Damage multiplier applied on a |
|
Statistic |
Distance before damage falloff begins; extended by barrel attachments. |
|
Statistic |
Rounds per magazine; the upper clamp on |
|
Resource |
Loaded rounds; clamped to |
|
Resource |
Spare rounds drawn into the magazine on reload. |
|
Statistic |
Seconds to complete a reload; the |
|
Meta |
Live distance to the traced target; compared against |
|
Meta |
Output of the hit-resolution calc after hitzone and falloff; for telemetry. |
The gunplay loop (the core shooter mechanic)
A shooter lives or dies on gun feel, and in UGAS that feel is a small loop of abilities, each gated by tags and an ammo resource.
Fire — cost-gated and rate-paced
GA_Fire (entities/ability_fire.yaml) requires Weapon.Equipped and is blocked while
State.Reloading. On activation it traces under the crosshair (WaitTargetData) and applies
GE_BallisticDamage to the hit target. Two reusable effects make the cadence work:
-
Cost —
GE_FireCostsubtracts1fromAmmo. Because an ability cannot activate if it cannot pay its cost, this is exactly what stops the gun firing on an empty magazine — no explicit ammo-check tag is needed. -
Cooldown —
GE_FireCooldownruns for \(1 / \text{FireRate}\) seconds, pacing automatic fire.
Both are trivial (a flat resource cost and a cooldown tag); the pack references them by name rather than shipping a file for each, the same convention the Racing pack uses for its nitro cost/cooldown.
Reload — a state plus a stateful transfer
GA_Reload is blocked while already reloading. It applies GE_Reloading (which grants
State.Reloading, blocking fire and aim), waits the reload window, then applies GE_Reload. The
amount of ammo moved depends on the live Ammo, MagazineSize, and ReserveAmmo, so it cannot be
a static modifier — GE_Reload runs a custom Execution (ExecCalc_MagazineReload) that tops the
magazine up and decrements the reserve by the rounds loaded. The "only reload when not full and the
reserve is non-empty" check is activation logic, since attribute comparisons can’t be activation tags.
Aim down sights — accuracy traded for mobility
GA_Aim uses the same hold-then-WaitInputRelease shape as the platformer jump: it applies
GE_ADS on press and removes it on release. GE_ADS tightens the bullet cone and slows movement,
and grants State.Aiming.
Accuracy aggregation across channels
Spread is the showcase of the core Channel mechanism. Modifiers are additive within a channel
and multiplicative across channels, so aiming and attachments compose cleanly:
-
GE_ADSputs aMultiplyof-0.75in theAimchannel: \(1 - 0.75 = 0.25\). -
GE_AttachmentBarrelputs aMultiplyof-0.5in theAttachmentschannel: \(1 - 0.5 = 0.50\).
entities/gameplay_controller.yaml)A soldier aiming a rifle that has a barrel attachment fitted:
-
Spread: \(2.0 \times 0.25 \times 0.50 = 0.25\) (base ×Aim×Attachments) -
MoveSpeed: \(600 \times (1 - 0.3) = 420\) (theAimchannel) -
EffectiveRange: \(50 + 30 = 80\) (a flatAdd)
These are exactly the CurrentValue entries recorded for the example soldier.
Hit resolution
GE_BallisticDamage (entities/effect_ballistic_damage.yaml) is the payload GA_Fire applies to
the hit target. Shooter damage is not a single subtraction: it couples the source’s aggregated
WeaponDamage with range falloff (DistanceToTarget vs EffectiveRange), the hitzone
multiplier (× HeadshotMultiplier when the target is hit on Hitzone.Head), and shield-before-
health absorption. That can’t be a static modifier, so the effect delegates to a custom
Execution (ExecCalc_HitResolution) that honors Immunity.Ballistic targets and writes
EffectiveDamage (a Meta attribute) for telemetry and UI. This is the shooter analogue of the
Racing pack’s traction calculator — the seam where a genre’s signature math plugs into UGAS.
Genre Tags
Defined in entities/tag_registry.yaml (additive only):
-
Weapon-handling states —
State.Aiming,State.Reloading,State.Sprinting. -
Weapon loadout —
Weapon.Equipped,Weapon.Type.Rifle|Pistol|Shotgun|Sniper,Weapon.FireMode.Auto|SemiAuto|Burst,Weapon.Attachment.Barrel. -
Ability types —
Ability.Type.Fire|Reload|Aim|Movement. -
Damage & hitzones —
DamageType.Ballistic|Explosive,Hitzone.Head|Body|Limb. -
Teams & immunity —
Team.Friendly|Hostile,Immunity.Ballistic.
Genre Abilities
-
entities/ability_fire.yaml—GA_Fire: traces under the crosshair and appliesGE_BallisticDamage; costsAmmoand is paced by a per-shot cooldown. -
entities/ability_reload.yaml—GA_Reload: appliesGE_Reloading, waits, then runs theGE_Reloadmagazine transfer. -
entities/ability_aim.yaml—GA_Aim: holdsGE_ADSfor a tighter cone at the cost of movement.
Genre Effects
-
entities/effect_equip_rifle.yaml—GE_EquipRifle: infinite; grants the weapon-loadout tags. -
entities/effect_ads.yaml—GE_ADS: infinite-while-held;SpreadandMoveSpeedmultipliers in theAimchannel; grantsState.Aiming. -
entities/effect_attachment_barrel.yaml—GE_AttachmentBarrel: infinite;Spreadmultiplier in theAttachmentschannel and+30EffectiveRange; grantsWeapon.Attachment.Barrel. -
entities/effect_reloading.yaml—GE_Reloading:HasDuration; grantsState.Reloading. -
entities/effect_reload.yaml—GE_Reload: instant;ExecCalc_MagazineReloadtransfers reserve rounds into the magazine. -
entities/effect_ballistic_damage.yaml—GE_BallisticDamage: instant;ExecCalc_HitResolutionapplies shields, hitzone multiplier, and falloff.
Using this pack
-
Copy
genres/shooter/into your project (or loadentities/directly via theugas-schema-authorskill). -
Tune the rifle base values in
ShooterCombatSetfirst — they carry most of the gun feel — then add new weapons asGE_Equip*effects and new attachments asAttachments-channel effects. -
Implement the two
ExecCalc_*hooks (ExecCalc_MagazineReload,ExecCalc_HitResolution) in your engine; everything else is data. -
Add new states as
State.*tags granted by Effects (never mutate tags directly), and new weapons /abilities as Effects + Abilities. -
Validate with
python scripts/validate_schema_examples.pybefore committing.