Ranged combat
Use combat.fire for observed entities and combat.projectile.fire for observed
blocks. Both require combat. Add world.entities.read or world.blocks.read
for your target observations. These actions hold position while aiming.
Fire once
local observed = hexis.world.entities.find({
area = {kind = "radius", radius = 32.0},
selector = {type_ids = {"minecraft:enderman"}, exclude_self = true},
limit = 16,
})
local target = observed.entities[1]
if not target then return end
local result = hexis.await(hexis.combat.fire({
target = {ref = target.ref},
held = {name_patterns = {"Shortbow"}},
profile = "hypixel_shortbow",
timing = {reaction_ms = 120, dwell_ms = 80, cooldown_ms = 250},
}), {timeout = 5})
Success means a firing input was submitted and the result reports outcome = "fired". It does not prove a hit or kill. physical_input_kind distinguishes
a consumed attack/use key from a use-key release; release alone does not prove
that vanilla spawned a projectile. profile selects the registered
weapon behavior and must match the held item:
| Profile | Weapon behavior |
|---|---|
vanilla_bow | Draw for 20 use ticks, then release |
hypixel_shortbow | Instant use-key arrow |
jax_shortbow | Instant attack-key arrow |
frozen_scythe, glacial_scythe | Ice bolt |
spirit_sceptre | Visible target within 8 blocks; guide for up to 20 ticks |
soul_whip, flaming_flay | Directional ability toward a visible target within 8 blocks |
These replace projectile = "direct" and projectile = "arrow". Targets must
be visible. model_evidence reports the model's evidence level; custom ability
profiles still need live acceptance and do not promise an impact. A drawn bow
needs a hotbar slot containing a different item type or an empty slot so
cancellation can stop the draw without firing.
Cancellation leaves that safe slot selected.
The shortbow model checks Terminator’s primary arrow; its side arrows are not modeled.
Ballistic shots require a clear nominal trajectory to the target. For consumed
shots, spread_clear says whether the modeled arrow spread also clears the
surroundings. false means spread could hit cover or another body, including
blocks beside a Jax lamp. It does not prevent a nominally clear shot. A volley
reports true only when every consumed shot had a clear spread corridor.
Directional and guided abilities omit this field.
For an observed block, use combat.projectile.fire with an observed
target = {position = ..., block_id = ..., properties = ...}, held,
profile and timing. It accepts the three arrow profiles above. Arbitrary
speed, gravity, drag and draw-time overrides are no longer accepted. Jax's
settings select a profile and timing; its default is jax_shortbow.
Choose between several targets
Prefer visible targets near the current view direction. A script can combine view angle, distance and a workload-specific priority:
local function score_of(entity)
return math.cos(math.rad(entity.view_angle)) * 15
- entity.distance * 0.15
+ (is_special(entity) and 1000 or 0)
end
Skip observations without visible. Define is_special for your workload;
the example gives those targets priority over ordinary distance and angle.
Request a bounded volley
combat.fire reports that a shot was submitted, not that anything died.
For a known workload, request a bounded volley in one call:
local result = hexis.await(hexis.combat.fire({
target = {ref = target.ref},
held = weapon,
profile = "frozen_scythe",
shots = 3,
timing = {reaction_ms = 180, dwell_ms = 80, cooldown_ms = 280, aim_speed = 3.5},
}), {timeout = 12})
recently_shot[target.ref.id] = hexis.time.monotonic().seconds + 5
One volley holds movement, camera and use for the action and applies
reaction_ms once. Each shot rechecks the target and firing conditions.
Use fresh observations when deciding whether another action is needed.
shots_fired counts consumed firing inputs. Fewer than you asked for
can reflect a target disappearing during the volley; it does not independently
prove a kill.
aim_speed is an optional per-action setting from 0.5 through 8. Omit it
to inherit your saved rotation preferences. Larger values request faster aim.
Expose it in your config schema if the script needs its own speed control.
Use recently_shot to lower a target's priority. Keep it eligible when no
unshot target is available, since a submitted volley can miss or leave it alive.
The observation's alive field excludes living entities at zero health,
including bodies the server keeps briefly after death.