Skip to content

Features

Two gases#

There are two balloons, and they do opposite things to the voice.

BalloonGasVoice
helium_balloonHeliumPitched up, squeaky
sf6_balloonSulfur hexafluoridePitched down, deep

Both work exactly the same way, only the voice differs. A single tank refills both. A third gas can be added with one line in Gases (id, balloon item, pitch), it then uses the red balloon visuals unless you give it its own model in shared/internal.lua.

Balloon in hand#

Using a balloon item does not instantly inhale it. The balloon is taken into the player's hand and a key hint box appears on the right side of the screen.

KeyAction
ETake a breath, consumes gas and starts the voice effect
GLift the balloon to your mouth or lower it back to your hand
XPut the balloon away
RLet the balloon go. The knot slips, it shoots off in spirals while it deflates with a real escaping air sound, and the item is gone

The box also shows which gas is in the balloon, how much is left, and how long the voice effect still has to run. Using the item again while holding puts the balloon away, and using the other balloon swaps what is in your hand. While standing next to a placed tank, E and G are reserved for the tank so a refill cannot accidentally trigger a breath.

The balloon is dropped automatically when the player dies, blacks out, or when the item leaves their inventory.

The two poses use separate offsets, so the balloon hangs naturally in the hand and sits correctly at the mouth. Both poses are visible to every other player.

Balloon gas#

Every balloon carries its own gas amount in item metadata. The amount survives dropping, trading and server restarts.

  • Each breath consumes Balloon.gasPerInhale (default 25), so a full balloon is good for 4 breaths
  • The balloon visibly deflates as the gas drops: its model carries a baked inflation animation and the script freezes it on the frame that matches the gas, sliding along it during refills and breaths
  • Every other player sees the exact same shape, the value is synced with a state bag
  • One refill always tops the balloon up to 100%, only the missing amount is taken from the tank
  • Inventories show the gas as the quality/durability bar and in the item description

Gas tank#

The tank is a real object placed in the world, not a static prop. There is only one tank item and it refills whichever balloon the player is holding, so a helium balloon comes back full of helium and an SF6 balloon full of SF6.

Placing

Using the tank item opens a placement mode. A semi transparent tank follows where you look:

KeyAction
ENTERPlace the tank here
XCancel
Mouse wheelRotate

The tank cannot be placed further than about 4 meters away, the hint box turns red when you aim too far.

Interacting

Once placed, everyone nearby gets target options on the tank:

OptionWho can use it
Refill balloon from tankEveryone
Take the tankOnly the player who placed it, unless Tank.pickupAnyone is on
Check the tankEveryone, shows the remaining gas percentage

Without ox_target or qb-target the script falls back to key based interaction: E to refill, H to pick up.

Tank gas

The tank has its own supply (Tank.capacity, default 1000 units = 10 empty balloons). It drains with every refill and is removed when empty. Only one player can use a tank at a time, so two people cannot drain the same unit twice.

Placed tanks live only in memory. A resource or server restart removes every tank that is on the ground, so players should pick theirs back up before a restart.

Overdose system#

Every breath adds dose. Dose decays over time, so spacing breaths out keeps the player fine while chain inhaling gets dangerous.

StageDefault thresholdEffect
Dizzy30Light screen effect, camera sway, slightly drunk walk
Heavy60Strong screen effect, motion blur, very drunk walk, random stumbles to the ground
Blackout90Screen fades out, the player ragdolls on the ground, loses health, drops the balloon

After waking up the dose is lowered to 45 so players cannot chain blackouts.

Dose is tracked server side. The client only plays the effects, so it cannot be faked.

Voice effect#

Two systems, picked automatically per player.

Real pitch shift (default)

While the effect is active the player's microphone is captured inside the FiveM NUI browser, pitch shifted with a phase vocoder and streamed to nearby players in 3D. This is a genuine pitch shift, the same thing a pitch shifter plugin does in a DAW, and it works in both directions: helium shifts up, SF6 shifts down.

  • Nothing has to be installed, everything runs inside the resource
  • FiveM asks the player once to allow microphone access, the answer is remembered per server
  • By default (Voice.requireMic) a balloon can only be used after the microphone was allowed, so everyone on the server is heard with the real pitch shift
  • Audio is only sent while the player is actually talking, push to talk and voice activation both work
  • The pitch follows the dose, a first breath is light and a near blackout is the full effect

Built in effect (fallback)

Only used when Voice.requireMic is turned off: players who deny the microphone prompt then get the game's own RadioFx submix effect applied to their voice instead. It is not a real pitch shift but it still sounds altered.

The Voice System page explains how it works in detail.

Framework and inventory support#

Everything is detected automatically, no configuration needed.

LayerSupported
FrameworkQBCore, QBox, ESX
Inventoryox_inventory, qb-inventory and all qb forks (ps, lj, aj), qs-inventory, codem-inventory, tgiann-inventory, core_inventory, origen_inventory
Targetox_target, qb-target, or a built in key fallback
UIox_lib, with a built in drawn box as fallback
LanguagesArabic, German, English, Spanish, French, Italian, Portuguese, Russian, Turkish

Performance#

StateCost
Idle, nobody using anything~0.01 ms
Holding a balloon~0.05 ms
Placing a tank~0.08 ms

Player scanning is event driven through state bags instead of polling loops, and the placement preview only updates the ghost object when it actually moves.

Exports#

Server

lua
exports['frkn-helium']:giveHeliumVoice(source, 30000)          -- timed effect in ms, nil uses the config value
exports['frkn-helium']:giveHeliumVoice(source, 30000, 'sf6')   -- same but with the deep voice, gas id from FRKN.Gases
exports['frkn-helium']:setHeliumVoice(source, true)            -- permanent on, false turns it off
exports['frkn-helium']:setHeliumVoice(source, true, 'sf6')     -- permanent deep voice
exports['frkn-helium']:getDose(source)                         -- current dose, 0 to 100
exports['frkn-helium']:addDose(source, 34)                     -- add dose, returns true if it caused a blackout

The third argument is the gas id. Leaving it out uses the first gas in FRKN.Gases, which is helium.

Client

lua
exports['frkn-helium']:getDose() -- local player dose, 0 to 100

Use the exports to hook the helium voice into other scripts, for example a drug script, a party event or an admin menu.