> For the complete documentation index, see [llms.txt](https://scripter-sm.gitbook.io/elite-zone/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://scripter-sm.gitbook.io/elite-zone/ai-prompt.md).

# AI prompt

One prompt that teaches any AI the whole API, so it can write Luas for you.

Let an AI write your Lua.

{% stepper %}
{% step %}

### Copy

Click the **copy** button in the top-right corner of the box below.
{% endstep %}

{% step %}

### Paste

Paste it into ChatGPT, Claude, or any other AI.
{% endstep %}

{% step %}

### Ask

Under the last heading, `My request`, write what you want, e.g. *"a planner that uses UE Killer against gun users and OOB Baiting against melee users"*.
{% endstep %}
{% endstepper %}

```
You are writing a Lua script for Elite Zone, a Roblox script for the game Rivals. Elite Zone exposes a global table called `api`. The script runs in a Roblox executor, so normal Roblox APIs and executor functions (getgenv, hookfunction, Drawing, readfile, etc.) are also available.

Write one complete Luau script for my request at the end. Reply with only the code.

# Rules

- The first line must be: local lua = api.register("Name", "type")
- The type is "ragebot planner" (changes ragebot behaviour), "misc" (aimbot / flickbot / silent aim / triggerbot targets, or anything else), or "both".
- The last line must be: lua:override()
- Connect signals with lua:connect(signal, fn), never signal:Connect(fn). It is disconnected automatically when the script unloads.
- Build UI with lua:tab(...), lua:box(...) or lua:tabbox(...) so it is removed on unload. Start your own setting names with the script's name, like "my_lua_enabled".
- Only take a tab of your own when the script needs one. To put settings inside a part of the menu that already exists, use api.ui.box and api.ui.tabbox, and remove what you added in lua.on_unload, because containers you did not build are not cleaned up for you.
- Hooks run every frame. Keep them fast and never yield (no task.wait) inside them.
- If a hook errors, the whole script is unloaded, so check values for nil.
- Only use the functions and ragebot setting names listed below. To find any other menu setting, look it up at runtime with api.ui.tree() or api.ui.list() instead of guessing its name.
- Scripts can be saved in the user's config and loaded at startup, so don't assume a round is already running when the script starts.
- The handle only has the fields and methods listed below. name, kind and alive are read only.

# The handle

api.register returns a handle, called lua here.

- lua.name, lua.kind: what you registered with.
- lua.alive: false once unloaded.
- lua.on_unload: a function you can set; it runs when the script is unloaded.
- lua:override(): makes the script active and unloads the previous script in the same slot.
- lua:unload(): removes the script.
- lua:connect(signal, fn): like signal:Connect, but cleaned up on unload.
- lua:on_changed(idx, fn): calls fn(value) when the menu setting idx changes.
- lua:tab(name, before): adds a menu tab and returns it. before is optional: the name of an existing tab to place it in front of; otherwise it goes at the end.
- lua:box(tab, side, name): adds a groupbox to any tab, including existing ones like "main" or "world". tab is a tab name or tab object, side is "left" or "right".
- lua:tabbox(tab, side): adds a tabbox to any tab, for settings split across tabs instead of one long list. tab is a tab name or tab object, side is "left" or "right" and defaults to left. Each tab you add to it is a groupbox, so you add settings to it directly.
- lua:add_method(kind, name, fn): ragebot planners only. Adds a custom "strafe" or "shooting" option to the ragebot, and returns a settings box that is only visible while that option is selected.
- lua:allow_manual(true or false): ragebot planners only. Controls whether the user can still see and change the ragebot settings (see below).

# Building UI

local box = lua:tab("my lua"):AddLeftGroupbox("settings")
local enabled = box:AddToggle("my_lua_enabled", { Text = "enabled", Default = true })
local range = box:AddSlider("my_lua_range", { Text = "range", Default = 50, Min = 0, Max = 100, Rounding = 0 })
local mode = box:AddDropdown("my_lua_mode", { Text = "mode", Values = { "a", "b" }, Default = "a" })
local label = box:AddLabel("status", true)
box:AddButton("reset", function() end)
box:AddDivider()

Read a value with enabled.Value and change a label with label:SetText("..."). AddRightGroupbox and AddInput also exist.

To split settings across tabs instead of one long list, add a tabbox. Every tab you add to it is a groupbox, so the same Add methods work on it:

local tab = lua:tab("my lua")
local tabbox = lua:tabbox(tab, "right")
tabbox:AddTab("general"):AddToggle("my_lua_enabled", { Text = "enabled", Default = true })
tabbox:AddTab("advanced"):AddSlider("my_lua_depth", { Text = "depth", Default = 3, Min = 1, Max = 10, Rounding = 0 })

To put settings inside a group or tab Elite Zone already has, instead of building a tab of your own, look it up with api.ui. Both return nil if it isn't there, and tab can be a name or a tab object. Elite Zone's own tabboxes have no name:

- api.ui.box(tab, name): the groupbox with that name on that tab.
- api.ui.tabbox(tab, name): the tabbox on that tab. name defaults to "".

What you get back is a normal groupbox, so AddToggle, AddSlider, AddDependencyBox and the rest all work on it. These containers belong to someone else, so nothing you add to them is removed on unload. Keep the reference and remove it yourself in lua.on_unload, which works on a groupbox and on a tab you added to a tabbox:

local mine = api.ui.tabbox("main"):AddTab("my lua")
mine:AddToggle("my_lua_enabled", { Text = "enabled", Default = true })

lua.on_unload = function()
    mine:Remove()
end

Removing a tab shows whichever tab is left, so the buttons resize. Note the names of removed settings stay registered with the menu, so read them with api.ui.element(idx) instead of caching at load time.

To show settings only when another setting has a value, use a dependency box. It works with your settings and Elite Zone's (get theirs with api.ui.element(idx)). List several pairs to show it when any of them match:

local extra = box:AddDependencyBox()
extra:AddSlider("my_lua_depth", { Text = "depth", Default = 3, Min = 1, Max = 10, Rounding = 0 })
extra:SetupDependencies({ { mode, "b" } })

# Ragebot menu while a planner is loaded

By default, when a ragebot planner is active, the ragebot box only shows the enabled toggle and a label saying "ragebot is controlled by ragebot planner". All other ragebot settings are hidden from the user (they still work, and the script can still change them with api.ui.set and presets).

- If the script takes full control of the ragebot, leave this as it is.
- If the script only adds something the user picks themselves (a preset, a strafe or a shooting method), call lua:allow_manual(true) right after api.register. Settings boxes from lua:add_method are inside the ragebot box, so they also need this to be visible.

# Ragebot hooks

Only ragebot planners can use these. Set them as fields on the handle.

A ragebot target is a table: { player = Player, head = BasePart, root = BasePart }.

lua.step = function(dt, duel, status)
Runs every ragebot frame in every round state. status is "Voting", "RoundStarting", "RoundStarted" or "RoundFinished". duel can be nil. Return nothing to carry on normally, "void" to dodge without shooting this frame, or "stop" to make the ragebot do nothing this frame. The string is "void", not "evade". This is the place to switch presets depending on the enemy.

lua.target = function(duel, item)
Replaces how the ragebot picks who to aim at. Return a target or nil. Build a target with api.ragebot.make_target(player), or get Elite Zone's normal pick with api.ragebot.acquire(). Use duel:GetDueler(player) to check the player is in your duel.

lua.can_shoot = function(target, item)
Return false to hold fire this frame. The ragebot keeps moving.

lua.anti_aim = function(dt, cframe, target)
Full control of anti aim. Runs every ragebot frame once status is "RoundStarted", after the ragebot picked where to put you and before it shoots, even if the anti aim toggle is off. cframe is where you'll be for the server this frame with the menu's anti aim already applied, or nil if the anti aim toggle is off. Return a CFrame to put yourself there instead, or nil to keep cframe. It isn't called for the "underground" strafe.

# Desync (put yourself anywhere for the server)

- api.ragebot.desync(cframe): from now on the server sees you at cframe every ragebot frame (your own screen doesn't move). It overrides strafe, voiding and anti aim in every round state, and shots are fired from there. Pass nil to go back to normal. It is cleared when the script unloads.
- api.ragebot.desynced(): the current desync CFrame, or nil.
- api.ragebot.client_cframe(): your real, visible position, or nil if the ragebot isn't running.

# Healing

- api.ragebot.heal(mode): heal with the medkit as soon as possible, even if the medkit heal toggle is off. mode is "quick heal" (+25) or "long heal" (+70); nil uses ragebot_medkit_mode. It only goes through during a live round with a medkit in the inventory that is off cooldown and health below max; otherwise the request is dropped.
- api.ragebot.healing(): true while the ragebot is in the void equipping or using the medkit. While healing it doesn't target or shoot, and lua.target / lua.can_shoot aren't called.

# Custom ragebot methods

lua:add_method adds a new option to the ragebot's strafe or shooting dropdown and returns a settings box for it. Select it with api.ui.set("ragebot_strafe", name) or api.ui.set("ragebot_shooting", name).

A strafe method returns the CFrame to be at this frame for the server, or nil to dodge. Anti aim is applied on top and shooting uses this position:

local radius
local box = lua:add_method("strafe", "tight orbit", function(target, root_part, client_cf, duel)
    local head = target.head.Position
    local angle = os.clock() * 6
    local pos = head + Vector3.new(math.cos(angle) * radius.Value, 0, math.sin(angle) * radius.Value)
    return CFrame.lookAt(pos, head)
end)
radius = box:AddSlider("tight_orbit_radius", { Text = "radius", Default = 5, Min = 1, Max = 20, Rounding = 1 })

A shooting method runs every frame while there is a target. It gets (target, item, cframe, dt) where item is the weapon and cframe is your server position this frame. It fires the game's UseItem remote itself with api.game.use_item(...) using whatever arguments the user asked for, and returns the camera angles to send with it as { pitch = degrees, yaw = degrees }, or nil. Limit the rate yourself with os.clock().

# Aim targets (misc Luas)

Only misc Luas ("misc" or "both") can use these hooks. They control who aimbot, flickbot, silent aim and triggerbot target. feature is "aimbot", "flickbot", "silentaim" or "triggerbot". Return the same thing for every feature to override the shared target, or check feature to override one of them.

An aim target is a table: { player = Player, character = Model, part = BasePart, position = Vector3, distance = number }. Build one with api.targeting.make(player, part), where part is a part name like "HitboxHead" or "HitboxBody" (default head) or a BasePart.

lua.aim_select = function(feature)
Replaces how the target is chosen; Elite Zone's own selection only runs if you return nil. Return a target, false for no target, or nil.

lua.aim_target = function(feature, target)
Runs after selection with the chosen target (nil if none). Return a different target, false for no target, or nil to keep it.

api.targeting.target(feature): the last target that feature picked, or nil.

# api.ui (the menu)

Every menu setting has a name called its idx, like "ragebot_strafe".

- api.ui.tree(): the whole menu as tree[tab][section] = list of entries.
- api.ui.list(prefix): flat list of entries, optionally only names starting with prefix.
- api.ui.where(idx): returns the tab and section the setting is in.
- api.ui.tabs(): list of tab names.
- api.ui.get(idx): current value.
- api.ui.set(idx, value): changes the value like a click in the menu.
- api.ui.remove(idx): removes the setting from the menu.
- api.ui.element(idx): the raw menu element (has .Value, .Values, :SetValue, :OnChanged).
- api.ui.box(tab, name): the groupbox with that name on that tab, or nil.
- api.ui.tabbox(tab, name): the tabbox on that tab, or nil. name defaults to "".
- api.ui.window: the window; api.ui.window.Tabs[name] is an existing tab.

Each entry has: idx, type ("Toggle", "Slider", "Dropdown", "Input", "ColorPicker" or "KeyPicker"), value, values (dropdown choices), tab and section.

# api.ragebot

- api.ragebot.target(): the current target, or nil.
- api.ragebot.acquire(): Elite Zone's normal pick (lowest health, then closest; skips allies, protected and deflecting players), or nil.
- api.ragebot.make_target(player): builds a target, or nil if the character isn't loaded.
- api.ragebot.desync, desynced, client_cframe, heal, healing: see above.
- api.ragebot.presets(): list of preset names, including presets from the user's config.
- api.ragebot.get_preset(name): a preset's settings table.
- api.ragebot.capture(): the current ragebot settings as a table.
- api.ragebot.apply_preset(name): applies a preset. Returns false if it doesn't exist.
- api.ragebot.save_preset(name, data): saves data (or the current settings if data is nil). "Default", "UE Killer", "Honest" and "OOB Baiting" can't be overwritten.

Built-in presets: "Default" is good against simple ragebots. "Honest" is good with weapons that kill before you reload (shotguns, infinite ammo) and good against advanced ragebots. "UE Killer" beats UE knife and gun users. "OOB Baiting" beats UE melee users and some other scripts.

# api.game

- api.game.players(): list of all players. Don't modify it.
- api.game.status(): the round status, or nil.
- api.game.weapon(player): the equipped weapon's name and item object.
- api.game.is_deflecting(player): true while they are deflecting.
- api.game.is_alive(player): true if they have health.
- api.game.is_ally(player): true if they are your teammate.
- api.game.use_item(...): fires the game's UseItem remote with exactly these arguments.
- api.active(slot): the script in the "ragebot" or "misc" slot, or nil.

# Ragebot settings

Use these with api.ui.get, api.ui.set and in preset tables. Numbers are allowed ranges.

General:
- ragebot_enabled: true or false
- ragebot_weapon: "primary" (slot 1), "secondary" (slot 2) or "melee" (slot 3). Melee attacks with the mode set in ragebot_melee_mode (see Melee below).
- fake_pos: true or false

Weapon resolver (only when ragebot_weapon is "primary" or "secondary"):
- ragebot_resolver: "switch if no ammo" (swap guns as soon as the gun is empty), "switch if no reserve" (reload, swap only when completely out) or "don't switch" (keep the chosen gun and just reload)
- ragebot_last_weapon: "none" or "melee". When the guns are completely out, "none" dodges; "melee" switches to your melee and keeps attacking.

Voiding: there is no setting. When there is no target to attack, or nothing worth shooting at, the ragebot drops you at a random point far out in the void and holds there until it has somewhere to go.

Strafe (guns only; melee uses its own logic):
- ragebot_strafe: "default", "glue flicker", "orbital", "spiral in", "spiral out", "oob baiting", "smart oob baiting", "underground", "adaptive", "wall break", or a custom method name. "default" sits on the enemy and shoots. "wall break" holds cover behind a wall near the enemy until they can see you, and is meant to be paired with the "manipulate" shooting method.
- ragebot_default_void_spam: true or false; ragebot_default_void_time and ragebot_default_attack_time: 0.01 to 1 (for "orbital" and the spirals only). Off, they just stay on the enemy and shoot. On, it loops: goes to the enemy and waits out your ping, shoots for attack time, then voids for void time.
- ragebot_flicker_glue: 0.01 to 1, ragebot_flicker_window: 0.01 to 1 (for "glue flicker"). It switches between default for flicker_glue seconds and a plain drop for flicker_window seconds.
- ragebot_orbit_radius: 2 to 40, ragebot_orbit_speed: 0.1 to 250 (for "orbital")
- ragebot_spiral_radius: 2 to 40, ragebot_spiral_speed: 0.1 to 250, ragebot_spiral_rate: 0.05 to 50 (for the spirals)
- ragebot_oob_position: "top", "down", "left" or "right"; ragebot_oob_position_offset: -10 to 10; ragebot_oob_hold: 0.001 to 0.5 (for "oob baiting"). It sits 3 studs past the chosen edge of the nearest out-of-bounds part, the offset moves it back toward the part (down with offset 2 = 1 stud below), and hold is how long each random spot on that edge is kept.
- ragebot_smart_oob_prebait: true or false; ragebot_smart_oob_distance: 0.1 to 50; ragebot_smart_oob_release: 0.1 to 5; ragebot_smart_oob_patience: 0.1 to 20; ragebot_smart_oob_void_time: 0.1 to 20 (for "smart oob baiting")
- ragebot_adaptive_on: 1 to 10, ragebot_adaptive_period: 2 to 12 (for "adaptive"). Each cycle of adaptive_period frames spends adaptive_on frames on the enemy and the rest in the void; it only shoots on a map frame that follows another map frame, so keep adaptive_on at 2 or more. While the enemy is in the void it holds still at your real position without shooting.
- ragebot_wall_break_interval: 0.05 to 2 (for "wall break"). Not how long you hold cover; it is how often it looks for a new wall when the map has none usable.

Shooting (guns only):
- ragebot_shooting: "hitscan" (works with any strafe), "beam" (pairs well with "default"), "force above", "vector resolver" (works with any strafe, tuned for "orbital"), "vector resolver v2", "manipulate" (the method for "wall break"), "none", or a custom method name
- ragebot_shoot_frames: 1 to 7 (for "hitscan", "beam", "force above" and "manipulate")
- ragebot_shot_interval: 0 to 500 ms (for "vector resolver" and "vector resolver v2")
- ragebot_los_check: true or false. "manipulate" and "vector resolver v2" ignore it, so leave it off when you use them.

Medkit, riot shield and anti knife (work with every strafe and weapon):
- ragebot_medkit: true or false. Heals in the void with the medkit when health drops.
- ragebot_medkit_mode: "quick heal" (+25) or "long heal" (+70)
- ragebot_medkit_health: 1 to 99 (%). Heals below this share of max health.
- ragebot_riot_shield: true or false. With a riot shield in the inventory, turns your back (where the shield sits) toward the target.
- ragebot_anti_knife: true or false. Protects you against enemy knife backstabs.

Anti aim (rotates your character for the server once the round has started, works with every weapon):
- ragebot_anti_aim: true or false
- ragebot_anti_aim_yaw: "none", "jitter", "spinbot" or "random"
- ragebot_anti_aim_pitch: "none", "jitter", "spinbot" or "random"
- ragebot_anti_aim_angle: "none", "tilt 45", "tilt 90", "upside down" or "custom"
- ragebot_anti_aim_custom_angle: 0 to 360
- ragebot_anti_aim_min_speed: 1 to 50, ragebot_anti_aim_max_speed: 1 to 100
- ragebot_anti_aim_min_angle: 1 to 180, ragebot_anti_aim_max_angle: 1 to 180
- ragebot_anti_aim_random_angle: true or false
- ragebot_anti_aim_underground: true or false. Keeps you 2 studs under the floor.

Melee (when ragebot_weapon is "melee", or last weapon is "melee"). It voids while the melee is on cooldown and attacks when it's ready:
- ragebot_melee_mode: "normal", "knife backstab" or "knife backstab v2". The knife modes do the knife's heavy attack (the backstab). "knife backstab v2" is the improved, much better backstab.
- ragebot_melee_void_spam: true or false ("normal" mode only). Loops: void for void time, then attack with the set number of attempts during attack time.
- ragebot_melee_void_time: 0.01 to 1
- ragebot_melee_attack_time: 0.01 to 1
- ragebot_melee_attempts: 1 to 3

# Example

local lua = api.register("Anti Deflect", "ragebot planner")

lua.can_shoot = function(target)
    return not api.game.is_deflecting(target.player)
end

lua:override()

# My request

```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://scripter-sm.gitbook.io/elite-zone/ai-prompt.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
