starlit

rage

Tune the ragebot while you play: hit chance, minimum damage, the fire gate, which enemies it aims at, double precision and the stops.

rage lets a script improve the ragebot for the situation it sees. Lower the hit chance in the air, raise the minimum damage when the enemy is far away, hold a shot back until the player has slowed down, skip an enemy, switch double precision off for one tick, pick the stop style. The ragebot keeps doing the aiming and the shooting. The script gives it better numbers and better timing.

Everything a script sets through rage is a live value. It lasts 500 ms after the script's last call, then the ragebot is back on the user's own settings. Nothing is written into the config and the menu rows do not move.

What you can tune

callwhat it changes
rage.override_hitchancethe hit chance the ragebot asks for, 1 to 100
rage.override_min_damagethe minimum damage, 1 to 110
rage.hold_fireholds the ragebot's shot back while you keep calling
rage.excludetakes one enemy off the ragebot's target list
rage.override_double_precisionswitches double precision off, or caps its chain
rage.override_auto_stopswitches the auto stop off, picks its style and its in-air condition
rage.override_quick_stopskips the quick stop for a tick
rage.override_air_stopskips the standalone air stop for a tick

The resolver, which feeds the ragebot a yaw hint for an enemy and reads the shot results, has its own page: resolver.

How the calls behave

Return values. Every function answers true when the call was taken and false when the value was refused. A refused call changes nothing and does not refresh an earlier value. The functions never return a value of the ragebot: the script knows what it asked for, not what the ragebot did with it.

Errors. A missing argument is an ordinary Lua error with a fixed text. A wrong value, such as a string where a number is expected, NaN, infinity or an option name that does not exist, is answered with false.

Lifetime. Call the function every frame, in events.on_paint, for as long as you want the value. Repeating the same value costs nothing. A value goes back to the user's settings when the script stops calling, is unloaded, stops with an error, when the level changes, and, for rage.exclude, when the enemy dies or leaves.

Change numbers with intent. A number that changes every frame makes the auto stop start its plan again every tick. Use whole steps, for example 5 or 10, and change them at a moment that matters, such as the player leaving the ground.

The menu. The user's switches stay the user's. The hit chance number applies while the hit chance is switched on in the menu, and double precision and the stops are the ones the user has enabled. The minimum damage number switches the minimum damage on while the script asks for it. A key the user holds, a bind on the hit chance, the minimum damage, the stop style or the stop conditions, wins over the script's number for as long as it is held. Holds and off calls always apply while the script calls them.

Several scripts. For numbers (hit chance, minimum damage, stop style, in-air condition) the script that changed the value last wins, and a script that only repeats its value does not take over. Holds and off calls add up, so one script is enough. The double precision chain cap is the smallest of all. Excluded enemies are the union of every script. nil and false release only what the calling script set.

Cost. 20 instructions per call, 30 for rage.override_double_precision and rage.override_auto_stop. A script may make 128 rage calls per frame, accepted or not.

Functions

rage.override_hitchance

rage.override_hitchance(v) -> boolean
argumenttypemeaning
vnumber or nilthe hit chance to ask for. It is rounded to a whole number and kept between 1 and 100. nil gives the user's number back.

Returns true when taken, false for a value that is not a number or not finite. The number applies while the hit chance is switched on in the menu.

events.on_paint(function()
  local me = game.local_player()
  if me and me.alive and math.abs(me.vz) > 10 then
    rage.override_hitchance(40)
  end
end)

rage.override_min_damage

rage.override_min_damage(v) -> boolean
argumenttypemeaning
vnumber or nilthe minimum damage, rounded and kept between 1 and 110. The values 101 to 110 mean the target's health plus 1 to 10. nil gives the user's number back.

Returns true when taken, false for a value that is not a finite number.

events.on_paint(function()
  rage.override_min_damage(90)
end)

rage.hold_fire

rage.hold_fire(b) -> boolean
argumenttypemeaning
bbooleantrue holds the ragebot's shot back for as long as you keep calling. false releases the hold.

The fire gate. While the hold is on, the ragebot does not take its shot. The player's own click is not touched, so a shot you fire by hand still goes out.

local gate = ui.keybind("hold fire", "hold")
events.on_paint(function()
  if gate:get() then rage.hold_fire(true) end
end)

rage.exclude

rage.exclude(slot, b) -> boolean
argumenttypemeaning
slotintegerthe enemy's slot, 1 to 64. It is the index of an entry of game.players(), and ent:index() gives the same number.
bbooleantrue takes the enemy off the target list, false puts the enemy back.

Returns true when taken. It returns false when the slot is not an enemy that is alive in this frame. The exclusion ends by itself when the enemy dies, leaves or changes sides.

events.on_paint(function()
  local me = entity.local_player()
  if not me then return end
  local mx, my, mz = me:origin()
  for _, ent in ipairs(entity.players(true)) do
    local x, y, z = ent:origin()
    if x and mx then
      local far = math.sqrt((x - mx) ^ 2 + (y - my) ^ 2 + (z - mz) ^ 2) > 1500
      rage.exclude(ent:index(), far)
    end
  end
end)

rage.override_double_precision

rage.override_double_precision(off [, chain_cap]) -> boolean
argumenttypemeaning
offbooleantrue: no held commands this tick. false: no change from the script.
chain_capinteger 1 to 3at most this many commands are held in a row. Leave it out to give the cap back.

One call sets both parts. The value only matters while the user has double precision switched on. A cap lowered in the middle of a chain simply ends the chain.

events.on_paint(function()
  local me = game.local_player()
  rage.override_double_precision(me ~= nil and me.alive and math.abs(me.vz) > 10)
end)

rage.override_auto_stop

rage.override_auto_stop(off [, mode [, in_air]]) -> boolean
argumenttypemeaning
offbooleantrue: no auto stop this tick.
mode"full", "slide" or nilthe stop style. nil or a missing argument gives the part back.
in_air"on", "off" or nilthe auto stop's in-air condition. nil or a missing argument gives the part back.

One call sets all three parts. A string that is not exactly one of the listed names is answered with false. A key the user holds on the stop style or the stop conditions wins for as long as it is held.

events.on_paint(function()
  -- stop by sliding, and let the auto stop work in the air
  rage.override_auto_stop(false, "slide", "on")
end)

rage.override_quick_stop

rage.override_quick_stop(off) -> boolean

off = true skips the quick stop for this tick. false and nil leave it to the user's setting. The quick stop runs only when the user has it enabled.

rage.override_air_stop

rage.override_air_stop(off) -> boolean

off = true skips the standalone air stop for this tick. false and nil leave it to the user's setting.

Example: air peek helper

Relax the hit chance in the air, stop by sliding, and drop the held commands of double precision while the player is airborne.

local relaxed = ui.slider("Hit chance in the air", 1, 100, 40)

events.on_paint(function()
  local me = game.local_player()
  if not me or not me.alive then return end

  local airborne = math.abs(me.vz) > 10
  rage.override_hitchance(airborne and relaxed:get() or nil)
  rage.override_auto_stop(false, "slide", airborne and "on" or nil)
  rage.override_double_precision(airborne)
end)

Example: fire gate on speed

Hold the ragebot's shot while the player is faster than a speed you choose. The player's own click is not held. The slider is in units per second.

local grp = ui.group("fire gate")
local on = grp:checkbox("hold fire while moving", true)
local limit = grp:slider("speed limit", 5, 250, 40)

events.on_paint(function()
  if not on:get() then return end
  local me = entity.local_player()
  if not me or not me:is_alive() then return end
  if (me:get("speed") or 0) > limit:get() then
    rage.hold_fire(true)
  end
end)

previous: menu · next: resolver