Friendly fire is refused by the victim's client through damage groups
Status: Accepted (2026-10-31)
Context
A gamemode team with friendly fire off must protect its members from every kind of damage between them. Damage is applied by the victim's client at the moment of the hit, synchronously; neither Lua nor the server can take it back afterwards, and the server never corrects a living player's health (ADR 0045). So the refusal has to happen on the victim's client, and that client has to know who its teammates are.
This extends ADR 0029: refused damage produces no event and no killer.
Decision
- Teams live on the server: name, color and the friendly fire flag. Membership is a field of the player, so it leaves with the player on disconnect and id reuse.
- A player's damage group is its team id while that team's friendly fire is off, and 0 otherwise. Two different players with the same non-zero group are teammates. Teams, names and colors do not go on the wire; only the group does.
- The victim decides by what it knew at the time. The server stamps the relation "the sender is your teammate" with a global revision into every relayed frame (of a player and of a vehicle), shot, projectile and detonation, and into every server effect with a creator, separately for each recipient. A shot is judged by its own stamp; everything else by the stamp of the newest packet. A team change sends nothing by itself: frames carry it within a heartbeat. The rules are in Damage groups and relations.
- The client refuses teammate damage before it applies: no damage, no hit reaction, no report. The server does not credit a report between teammates (no
player_damage, no last damage), does not accept a stealth kill of a teammate, and never names a teammate as the killer, including for damage dealt before the two joined the same team. - A hit from an action accepted before a team change is judged by what the victim knew then: nothing but the server holding the health could close that one-way window. The victim may apply such a hit; the server discards its report.
Consequences
- Damage to a vehicle is not damage to a player, so a teammate may still wreck the vehicle. When its explosion has a credited killer (ADR 0034), that killer is the explosion's author on every client: the killer's teammates inside refuse its damage, the server neither counts them dead (ADR 0045) nor gives them that killer. An explosion with no credited killer has no author and kills everyone inside; a player who hurt them earlier may still be the killer through the last damage.
- The group is visible to everyone the player is shown to, because a client compares the groups of two remote players. Gamemodes with hidden roles must not use damage groups for them.
- A hostile client can still ignore the refusal or apply damage it should not; the server's health ledger (ADR 0045) handles that.
Alternatives considered
- Teams on the wire. A client needs neither the name, the color nor the membership list to refuse damage.
- Only a reliable broadcast of groups. A UDP shot overtakes it when a packet is lost (retransmission after 250 ms), and the victim loses health.
- A reliable relation packet in addition to the stamps. One packet per pair of players: changing a big team overflows the reliable lane (limit 512) and disconnects clients, while frames carry the change within a heartbeat anyway.
- Hold frames until the revision is applied. Every remote player would freeze on one lost reliable packet.
- Server-side rejection only. A teammate would lose health without the damage ever being credited.
- Correct the victim's health from the server. A different authority model; the server does not correct a living player's health.
