Complete guide to LuaJIT scripting for hero automation
Marvel Rivals Lua scripting allows you to create custom hero automation using LuaJIT with aggressive JIT optimization. Scripts run at 60-144+ FPS and have access to complete game state, actor information, and input control.
-- Default hero script -- This script is called every frame (60-144+ times per second) function on_game_tick(ctx, helpers, config) -- ctx: Game state (player info, enemies, abilities, etc.) -- helpers: Utility functions (UseAbility, CountEnemiesInFOV, etc.) -- config: Your script configuration values return true end
string.format(), string concatenation, and table allocations in hot loopsAll input functions (UseAbility, SendSkill) have a 50ms global cooldown to prevent spam. Use helpers.CanDoAction() to check if you can send an input.
The helpers table provides utility functions for game interaction and queries.
if helpers.CanDoAction() then helpers.UseAbility(helpers.PRIMARY_ATTACK) end
local target = helpers.GetAimbotTarget() if target and target.is_alive then helpers.PressKey(helpers.PRIMARY_ATTACK) else helpers.ReleaseKey(helpers.PRIMARY_ATTACK) end
if helpers.IsKeyHeld(0x58) then -- 'X' key -- Only execute combo when X is held helpers.UseAbility(helpers.ABILITY_1) end
if ctx.has_aimbot_target then local target = helpers.GetAimbotTarget() if target and helpers.CanDoAction() then helpers.UseAbility(helpers.PRIMARY_ATTACK) end end
local enemies_in_view = helpers.CountVisibleEnemiesInFOV(150, 20) if enemies_in_view >= 2 and helpers.CanDoAction() then helpers.UseAbility(helpers.ULTIMATE) end
local allies_near = helpers.CountVisibleAlliesInFOV(200, 15) if allies_near >= 3 then helpers.UseAbility(helpers.ABILITY_2) -- AoE heal end
local target = helpers.GetAimbotTarget() if target and helpers.IsLookingAt(target.actor_state, 10) then helpers.UseAbility(helpers.PRIMARY_ATTACK) end
The ctx parameter provides complete game state information updated every frame.
| Field | Type | Description |
|---|---|---|
| pawn | number | Player pawn pointer |
| controller | number | Player controller pointer |
| hero_id | number | Current hero ID |
| team_id | number | Team ID (0 or 1) |
| camera_location | FVector | Camera world position {X, Y, Z} |
| camera_rotation | FVector | Camera rotation {Pitch, Yaw, Roll} |
| camera_fov | number | Camera field of view |
| buffs | array | Active buffs/debuffs on player |
for _, buff in ipairs(ctx.local_player.buffs) do if buff.hash == 12345 then -- Player has specific buff helpers.UseAbility(helpers.ABILITY_1) end end
Array of all actors (enemies, allies, etc.) in the game. 1-indexed Lua array.
| Field | Type | Description |
|---|---|---|
| actor_state | number | Unique actor state ID |
| pawn | number | Pawn pointer |
| hero_id | number | Hero character ID |
| team_id | number | Team ID |
| is_alive | boolean | Is actor alive |
| is_same_team | boolean | Same team as player |
| is_visible | boolean | Is visible to player |
| current_health | number | Current HP |
| max_health | number | Maximum HP |
| health_percentage | number | Health % (0-100) |
| world_position | FVector | World position {X, Y, Z} |
| velocity | FVector | Velocity vector |
| distance_world | number | Distance in world units |
| distance_meters | number | Distance in meters |
| bone_head | FVector | Head bone screen position |
| bone_* | FVector | Various skeleton bones (screen/world space) |
| buffs | array | Active buffs on this actor |
| abilities | table | Actor's abilities (same structure as ctx.abilities) |
for _, actor in ipairs(ctx.actors) do if actor.is_alive and not actor.is_same_team then if actor.distance_meters < 15 and actor.health_percentage < 30 then -- Low health enemy nearby - execute! helpers.UseAbility(helpers.MELEE_ATTACK) end end end
Table of hero abilities indexed by bind ID. Each ability has an array of ability states (some binds can have multiple abilities).
| Field | Type | Description |
|---|---|---|
| can_activate | boolean | Can be activated now |
| can_preactivate | boolean | Can be pre-activated |
| is_activated | boolean | Currently activated |
| is_blocked | boolean | Blocked (stunned, etc.) |
| is_on_cooldown | boolean | On cooldown |
| energy_percent | number | Energy/charge percentage (0-100) |
-- Check if ability 1 (bind index 4) is ready if ctx.abilities[4] and ctx.abilities[4][1] then local ability = ctx.abilities[4][1] if ability.can_activate and not ability.is_blocked then helpers.UseAbility(helpers.ABILITY_1) end end
| Field | Type | Description |
|---|---|---|
| screen_width | number | Screen width in pixels |
| screen_height | number | Screen height in pixels |
| screen_center_x | number | Screen center X coordinate |
| screen_center_y | number | Screen center Y coordinate |
| aimbot_key_pressed | boolean | Is aimbot key pressed |
| trigger_key_pressed | boolean | Is trigger key pressed |
| has_aimbot_target | boolean | Does aimbot have a target |
| aimbot_target_actor_state | number | Aimbot target actor ID |
| aimbot_target_fov | number | Target FOV distance |
Used in ctx.local_player.buffs[] and actor.buffs[]
| Field | Type | Description |
|---|---|---|
| hash | number | Unique buff ID hash |
| name | string | Buff name (for debugging) |
| count | number | Stack count |
function on_game_tick(ctx, helpers, config) if ctx.has_aimbot_target then local target = helpers.GetAimbotTarget() if target and helpers.IsLookingAt(target.actor_state, 5) then if helpers.CanDoAction() then helpers.UseAbility(helpers.PRIMARY_ATTACK) end end end return true end
function on_game_tick(ctx, helpers, config) -- Count enemies in FOV within 20 meters local enemies = helpers.CountVisibleEnemiesInFOV(200, 20) -- Use ultimate if 3+ enemies nearby if enemies >= 3 and helpers.CanDoAction() then -- Check if ultimate is ready if ctx.abilities[7] and ctx.abilities[7][1] then local ult = ctx.abilities[7][1] if ult.can_activate and not ult.is_blocked then helpers.UseAbility(helpers.ULTIMATE) end end end return true end
function on_game_tick(ctx, helpers, config) -- Check if player has damage buff local has_damage_buff = false for _, buff in ipairs(ctx.local_player.buffs) do if buff.hash == 123456 then -- Replace with actual buff hash has_damage_buff = true break end end -- Hold primary attack while buffed if has_damage_buff then helpers.PressKey(helpers.PRIMARY_ATTACK) else helpers.ReleaseKey(helpers.PRIMARY_ATTACK) end return true end
function on_game_tick(ctx, helpers, config) if not helpers.CanDoAction() then return true end local target = helpers.GetClosestVisibleEnemy() if not target then return true end -- Combo conditions: -- 1. Enemy within 15 meters -- 2. Enemy health below 50% -- 3. Looking at enemy if target.distance_meters < 15 and target.health_percentage < 50 and helpers.IsLookingAt(target.actor_state, 10) then -- Execute combo: E -> Shift -> LMB helpers.UseAbility(helpers.ABILITY_1) end return true end
function on_game_tick(ctx, helpers, config) -- Find low health enemies in range local low_health_enemies = {} for _, actor in ipairs(ctx.actors) do if actor.is_alive and not actor.is_same_team and actor.is_visible and actor.distance_meters < 20 and actor.health_percentage < 30 then table.insert(low_health_enemies, actor) end end -- If we found low health targets, prioritize them if #low_health_enemies > 0 and helpers.CanDoAction() then helpers.UseAbility(helpers.MELEE_ATTACK) end return true end
Use these constants with helpers.UseAbility(), helpers.PressKey(), and helpers.ReleaseKey().
| Constant | Value | Description |
|---|---|---|
helpers.PRIMARY_ATTACK | 0 | Left mouse button / primary fire |
helpers.SECONDARY_ATTACK | 1 | Right mouse button / secondary fire |
helpers.RELOAD | 2 | Reload key |
helpers.MELEE_ATTACK | 3 | Melee attack key |
helpers.ABILITY_1 | 4 | Ability 1 (usually E) |
helpers.ABILITY_2 | 5 | Ability 2 (usually Shift) |
helpers.ABILITY_3 | 6 | Ability 3 (usually Q) |
helpers.ULTIMATE | 7 | Ultimate ability |
helpers.TEAMUP_ABILITY_1 | 8 | Team-up ability 1 |
helpers.TEAMUP_ABILITY_2 | 9 | Team-up ability 2 |
helpers.TEAMUP_ABILITY_3 | 10 | Team-up ability 3 |
| Key | VK Code (Hex) | VK Code (Dec) |
|---|---|---|
| A-Z Keys | 0x41-0x5A | 65-90 |
| 0-9 Keys | 0x30-0x39 | 48-57 |
| Space | 0x20 | 32 |
| Shift | 0x10 | 16 |
| Control | 0x11 | 17 |
| Alt | 0x12 | 18 |
| Left Mouse | 0x01 | 1 |
| Right Mouse | 0x02 | 2 |
| Middle Mouse | 0x04 | 4 |
-- FVector is a table with X, Y, Z components local pos = actor.world_position local x = pos.X local y = pos.Y local z = pos.Z