Script Lua : Zones et ciblage
Les fonctions Lua d'EliteMobs offrent deux approches complémentaires pour définir des zones spatiales et résoudre des cibles :
- Zones natives (
context.zones) -- simples et directes. Vous construisez une définition de zone sous forme de table Lua simple et l'interrogez pour obtenir des entités ou des emplacements. Idéal pour les vérifications simples de type « y a-t-il quelque chose dans cette zone ? ». - Utilitaires de script (
context.script) -- ciblage plus riche, handles de zone avec les méthodes watch/contains/entities, génération de particules, dégâts et actions de poussée. Utilise les mêmes noms de champs que les Zones EliteScript et les Cibles EliteScript pour une plus grande familiarité.
Les deux approches sont des API Lua natives. Choisissez celle qui correspond à la complexité de votre pouvoir.
Zones natives : context.zones
Les zones natives vous permettent de définir des zones sous forme de tables Lua simples et de les interroger directement. Pas de handles, pas d'abstraction supplémentaire -- juste une table décrivant une forme et un appel de méthode pour l'interroger.
Méthodes
| Méthode | Notes |
|---|---|
zones:get_entities_in_zone(zoneDef, options) | Retourne un tableau de wrappers d'entité à l'intérieur de la zone |
zones:get_locations_in_zone(zoneDef, options) | Retourne un tableau de tables d'emplacement à l'intérieur de la zone |
zones:zone_contains(zoneDef, location[, "full"|"border"]) | Retourne true si l'emplacement est à l'intérieur de la zone |
zones:watch_zone(zoneDef, callbacks, options) | Enregistre un observateur de zone persistant qui se déclenche à chaque tick |
Champs de définition de zone
| Champ | Type | Défaut | Notes |
|---|---|---|---|
kind (ou type) | string | — | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
radius | number | 0 | Rayon de la zone (sphere, dome, cylinder, cone) |
height | number | 0 | Hauteur du cylindre |
origin | location | emplacement du boss | Emplacement central |
destination | location | emplacement du boss | Point final pour les rayons et les cônes |
x, y, z | number | 0 | Demi-extensions du cuboïde |
thickness / point_radius / pointRadius | number | 0.5 | Épaisseur du rayon |
border_radius / borderRadius | number | 1 | Largeur de la bordure |
x_border, y_border, z_border | number | 1 | Largeurs de bordure du cuboïde |
animation_duration | int | 0 | Durée de l'animation en ticks pour les rayons animés |
pitch_pre_rotation, yaw_pre_rotation | number | 0 | Angles de pré-rotation (rayon rotatif) |
pitch_rotation, yaw_rotation | number | 0 | Angles de rotation par tick (rayon rotatif) |
origin_end, destination_end | location | emplacement du boss | Positions finales pour le rayon en translation |
ignores_solid_blocks | boolean | true | Si les rayons traversent les blocs solides |
length | number | 0 | Lu uniquement lorsque destination est omis ; voir ci-dessous. |
Chaque champ composé accepte également le camelCase (borderRadius, xBorder, animationDuration, pitchPreRotation, ignoresSolidBlocks, ...) : une spécification copiée depuis un bloc Zone: EliteScript fonctionne donc en grande partie telle quelle.
kind est sensible à la casseContrairement à presque toutes les autres chaînes de l'API Lua, kind est comparé exactement et doit être en minuscules. "SPHERE" ou "Sphere" ne correspondent à rien, et la zone se résout silencieusement à rien — les requêtes renvoient simplement une liste vide, sans avertissement en console.
destination expliciteorigin et destination retombent tous deux sur l'emplacement du boss lorsqu'ils sont omis. Pour un cône ou un rayon, cela produit une forme de longueur nulle plutôt qu'une erreur. Définissez toujours destination sur cone, static_ray, rotating_ray et translating_ray. Il n'existe pas de raccourci length — définissez un emplacement de destination explicite.
destination ou lengthSi origin est omis, la position du boss est utilisée. Si destination est omis, origin est projeté de length blocs selon la direction enregistrée dans la table de position origin.
Vous pouvez donc définir un cône ou un rayon de deux façons :
-- Explicit endpoint
local explicit_ray = { kind = "static_ray", origin = context.boss:get_eye_location(),
destination = context.player:get_eye_location() }
-- Or a length along the origin's own facing
local forward_ray = { kind = "static_ray", origin = context.boss:get_eye_location(), length = 15 }
La forme abrégée avec length n’est correctement orientée que si origin contient yaw/pitch. Les positions renvoyées par l’API (get_location(), get_eye_location(), current_location) les contiennent. Une table écrite à la main { x = .., y = .., z = .. } ne les contient pas, pas plus que em.create_location(x, y, z) sans ses arguments facultatifs yaw et pitch.
Si les deux sont omis, length vaut 0 par défaut : la forme a une longueur nulle et toutes les requêtes renvoient un résultat vide sans avertissement.
Options de requête
| Clé | Notes |
|---|---|
filter | "player" / "players", "elite" / "elites", "mob" / "mobs", "living" (par défaut) |
mode | "full" (par défaut) ou "border" |
coverage | 0.0 à 1.0 -- fraction des emplacements à échantillonner (par défaut 1.0) |
Callbacks d'observation
| Clé | Notes |
|---|---|
on_enter | function(entity) -- appelée quand une entité entre dans la zone |
on_leave | function(entity) -- appelée quand une entité quitte la zone |
Exemple : requête de sphère basique
Exemple
return {
api_version = 1,
on_spawn = function(context)
-- Store a zone definition for reuse
context.state.danger_zone = {
kind = "sphere",
origin = context.boss:get_location(),
radius = 10
}
end,
on_boss_damaged_by_player = function(context)
-- Update the origin to the boss's current position
context.state.danger_zone.origin = context.boss:get_location()
local players = context.zones:get_entities_in_zone(
context.state.danger_zone,
{ filter = "players" }
)
for _, player in ipairs(players) do
player:send_message("&cYou are in the danger zone!")
end
end
}
Exemple : observation de zone avec entrée/sortie
Exemple
return {
api_version = 1,
on_spawn = function(context)
context.zones:watch_zone(
{
kind = "sphere",
origin = context.boss:get_location(),
radius = 8
},
{
on_enter = function(entity)
entity:apply_potion_effect("SLOWNESS", 40, 1)
entity:send_message("&7You feel sluggish near the boss...")
end,
on_leave = function(entity)
entity:send_message("&aYou escape the slowing aura.")
end
},
{ filter = "players", mode = "full" }
)
end
}
Notes sur les observateurs :
- Les callbacks d'observateurs reçoivent directement un seul wrapper d'entité, pas via
context.event - Les observateurs appellent leurs propres callbacks
on_enter/on_leave; ils n'invoquent pas les hooks de premier niveauon_zone_enter/on_zone_leavedu pouvoir - Les observateurs sont nettoyés automatiquement lorsque le boss est supprimé
- Chaque observateur s'exécute à chaque tick, donc gardez la logique du callback légère
- L'entité du boss elle-même est exclue des requêtes de zone
Utilitaires de script : context.script
Les utilitaires de script fournissent la résolution de cibles, les handles de zone, les vecteurs relatifs, la génération de particules et les actions de combat.
context.script exécute le moteur EliteScriptcontext.script n'est pas un simple « nommage à la sauce EliteScript » — la table de spécification que vous transmettez est convertie en une map Java brute et remise directement aux mêmes classes de cibles, de zones, de vecteurs relatifs et de particules qui font fonctionner les EliteScripts YAML. Il n'existe pas d'implémentation distincte.
Ce que cela signifie en pratique :
- Tous les champs documentés dans Cibles EliteScript, Zones EliteScript et Vecteurs relatifs EliteScript fonctionnent dans ces tables de spécification, y compris ceux que cette page ne liste pas.
- Les valeurs d'enum sont en UPPER_SNAKE_CASE exact (
"NEARBY_PLAYERS","SPHERE","ZONE_FULL"), comme en YAML. - Les noms de champs sont les noms YAML :
TargetetTarget2portent donc une majuscule, tandis quetargetTypeetborderRadiussont en camelCase. - Le comportement de chargement YAML s'applique aussi : une valeur non analysable journalise un avertissement EliteScript et vide le champ au lieu de retomber sur sa valeur par défaut.
C'est l'inverse de context.zones, qui est une implémentation légère véritablement distincte utilisant des noms de kind en minuscules.
Méthodes
| Méthode | Notes |
|---|---|
script:target(spec) | Crée un handle de cible à partir d'une table de spécification de cible |
script:zone(spec) | Crée un handle de zone à partir d'une table de spécification de zone |
script:relative_vector(spec[, actionLocation][, zoneHandle]) | Crée un handle de vecteur relatif |
script:damage(targetHandle, amount[, multiplier]) | Inflige des dégâts aux cibles résolues |
script:push(targetHandle, vectorOrHandle[, additive]) | Pousse les cibles résolues |
script:set_facing(targetHandle, vectorOrHandle) | Définit la direction d'orientation des cibles |
script:spawn_particles(targetHandle, particleSpec) | Génère des particules aux emplacements des cibles résolues |
Méthodes du handle de cible
| Méthode | Notes |
|---|---|
handle:entities() | Retourne un tableau de wrappers d'entité |
handle:locations() | Retourne un tableau de tables d'emplacement |
handle:first_entity() | Retourne la première entité ou nil |
handle:first_location() | Retourne le premier emplacement ou nil |
Clés de spécification de cible
| Clé | Défaut | Notes |
|---|---|---|
targetType | "SELF" | Tout type de cible EliteScript |
range | 20 | Portée pour les types de cible à proximité |
coverage | 1.0 | 0.0 à 1.0. Honoré uniquement pour les types de cible de zone ; sur tout autre type il est remis à 1.0 avec un avertissement en console |
offset | 0,0,0 | Chaîne "x,y,z" ou table { x = n, y = n, z = n } |
relativeOffset | aucun | Une table de spécification de vecteur relatif, pour un décalage relatif à l'orientation du boss |
location | aucun | Emplacement unique, pour "LOCATION" |
locations | aucun | Liste d'emplacements, pour "LOCATIONS" |
track | true | Indique s'il faut ré-résoudre les cibles en mouvement |
Les 17 types de cible EliteScript sont acceptés, pas seulement les plus courants : SELF, SELF_SPAWN, DIRECT_TARGET, NEARBY_PLAYERS, NEARBY_MOBS, NEARBY_ELITES, WORLD_PLAYERS, ALL_PLAYERS, LOCATION, LOCATIONS, ZONE_FULL, ZONE_BORDER, LANDING_LOCATION, ACTION_TARGET, INHERIT_SCRIPT_TARGET, INHERIT_SCRIPT_ZONE_FULL, INHERIT_SCRIPT_ZONE_BORDER. Les types ACTION_TARGET et INHERIT_* ne se résolvent à quelque chose que si le contexte EliteScript environnant existe ; ils sont donc de peu d'utilité depuis Lua.
Exemple : créer et utiliser une cible
Exemple
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if not context.cooldowns:check_local("roar", 200) then return end
-- Find all players within 20 blocks
local nearby = context.script:target({
targetType = "NEARBY_PLAYERS",
range = 20
})
for _, player in ipairs(nearby:entities()) do
player:send_message("&eThe boss roars in fury!")
end
-- Single-entity access
local closest = nearby:first_entity()
if closest then
closest:show_title("&cRUN!", "&7The boss is targeting you")
end
end
}
Méthodes du handle de zone
| Méthode | Notes |
|---|---|
handle:full_target([coverage]) | Retourne un handle de cible pour le volume complet de la zone |
handle:border_target([coverage]) | Retourne un handle de cible pour la bordure de la zone |
handle:full_locations([coverage]) | Retourne les emplacements dans le volume complet de la zone |
handle:border_locations([coverage]) | Retourne les emplacements sur la bordure de la zone |
handle:full_entities() | Retourne les entités dans le volume complet de la zone |
handle:border_entities() | Retourne les entités sur la bordure de la zone |
handle:contains(location[, "full"|"border"]) | Retourne true si l'emplacement est à l'intérieur de la zone |
handle:watch(callbacks[, mode]) | Surveille la zone pour les événements d'entrée/sortie, retourne un ID de tâche |
Clés de spécification de zone
| Clé | Défaut | Notes |
|---|---|---|
shape | "CYLINDER" | "SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY" |
radius | 5 | Sphère, dôme, cylindre, cône |
height | 1 | Cylindre uniquement |
x, y, z | 0 | Demi-extensions du cuboïde |
xBorder, yBorder, zBorder | 0 | Largeurs de bordure du cuboïde |
borderRadius | 1 | Largeur de bordure pour sphère / dôme / cylindre / cône |
pointRadius | 0.5 | Épaisseur du rayon |
animationDuration | 0 | Durée de l'animation en ticks pour les rayons animés |
Target | {targetType = "SELF"} | Spécification de cible centrale (table) -- utilise le même format de spécification de cible |
Target2 | aucun | Second point. Requis pour les cônes et toutes les formes de rayon |
FinalTarget, FinalTarget2 | aucun | Positions finales, rayon en translation uniquement |
filter | "PLAYER" | "PLAYER", "ELITE", "LIVING" — notez qu'ils sont en MAJUSCULES ici, contrairement à context.zones |
ignoresSolidBlocks | true | Rayons uniquement |
pitchPreRotation, yawPreRotation | 0 | Rayon rotatif uniquement |
pitchRotation, yawRotation | 0 | Rayon rotatif uniquement |
Les clés qui ne s'appliquent pas à la shape choisie sont lues sans protestation puis ignorées — un height sur une sphère ne fait rien.
Exemple : zone avec dégâts et particules
Exemple
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a sphere zone centered on the boss
if context.state.zone_task_id ~= nil then return end
local zone = context.script:zone({
shape = "SPHERE",
radius = 6,
Target = { targetType = "SELF" }
})
-- Spawn warning particles on the zone border
context.script:spawn_particles(
zone:border_target(0.3),
{ particle = "FLAME", amount = 1, speed = 0.02 }
)
-- Damage all players inside the zone
local targets = zone:full_target()
context.script:damage(targets, 5.0)
-- Repeat every 20 ticks
context.state.zone_task_id = context.scheduler:run_every(20, function(ctx)
local z = ctx.script:zone({
shape = "SPHERE",
radius = 6,
Target = { targetType = "SELF" }
})
ctx.script:spawn_particles(
z:border_target(0.3),
{ particle = "FLAME", amount = 1, speed = 0.02 }
)
ctx.script:damage(z:full_target(), 5.0)
end)
end,
on_exit_combat = function(context)
if context.state.zone_task_id ~= nil then
context.scheduler:cancel_task(context.state.zone_task_id)
context.state.zone_task_id = nil
end
end
}
Clés de spécification de vecteur relatif
| Clé | Notes |
|---|---|
SourceTarget | Spécification de la cible source (table) |
DestinationTarget | Spécification de la cible de destination (table) |
normalize | boolean -- indique s'il faut normaliser le vecteur résultant |
multiplier | Facteur d'échelle appliqué après la normalisation |
offset | Chaîne "x,y,z" ou table { x = n, y = n, z = n } |
Méthodes du handle de vecteur relatif
| Méthode | Notes |
|---|---|
handle:resolve() | Retourne la table du vecteur calculé |
Exemple : pousser des cibles avec un vecteur relatif
Exemple
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if not context.cooldowns:check_local("knockback", 100) then return end
-- Build a vector from the boss toward the attacker
local vec = context.script:relative_vector({
SourceTarget = { targetType = "SELF" },
DestinationTarget = { targetType = "DIRECT_TARGET" },
normalize = true,
multiplier = 2.5
})
-- Push the attacker away
local target = context.script:target({
targetType = "DIRECT_TARGET"
})
context.script:push(target, vec)
end
}
Format de spécification des particules
Les spécifications de particules peuvent être une chaîne, une table unique ou un tableau de tables. Comme ce chemin exécute le moteur de particules d'EliteScript, les clés sont celles d'EliteScript documentées sous SPAWN_PARTICLE :
| Clé | Défaut | Notes |
|---|---|---|
particle | "FLAME" | Nom de la particule (ex. "FLAME", "DUST", "SMOKE") |
amount | 1 | Nombre de particules. 0 transforme x/y/z en vecteur de vélocité |
x, y, z | 0.01 | Valeurs d'offset/dispersion, ou vélocité lorsque amount vaut 0 |
speed | 0.01 | Vitesse des particules |
red, green, blue | 255 | Couleur pour DUST, DUST_COLOR_TRANSITION, WITCH et les autres particules à données de couleur (0-255) |
toRed, toGreen, toBlue | 255 | Couleur cible de transition pour DUST_COLOR_TRANSITION |
material | "STONE" | Bloc ou objet affiché par les particules portant des données de bloc/objet (BLOCK, ITEM, FALLING_DUST, ...) |
relativeVector | aucun | Une spécification de vecteur relatif. La définir force amount à 0 et écrase x/y/z par la direction résolue |
Ces clés EliteScript ne sont pas les mêmes que celles acceptées par context.world:spawn_particle_at_location(loc, spec). La table world possède son propre lecteur plus réduit, avec des valeurs par défaut différentes (amount 1, x/y/z/speed 0), sans material ni relativeVector, et il accepte en plus to_red / to_green / to_blue en snake_case. Voir Monde et Environnement.
Pour la liste complète des noms de particules, consultez la Référence des enums.
Avertissements importants
- Les handles des utilitaires de script sont liés au contexte d'événement dans lequel ils ont été créés. Ne les stockez pas dans
context.statepour une utilisation dans un appel de hook ultérieur. watch()de zone retourne un ID de tâche que vous pouvez annuler aveccontext.scheduler:cancel_task().- Les valeurs de coverage ne s'appliquent qu'à la résolution basée sur les emplacements, pas aux requêtes d'entités.
- Toutes les valeurs de chaîne utilisent les mêmes noms d'enum en UPPER_SNAKE_CASE que le YAML EliteScript (ex.
"SELF","NEARBY_PLAYERS","SPHERE").
Espace de noms auxiliaire em
L'espace de noms em est disponible globalement dans tous les fichiers de pouvoir Lua. Il fournit des constructeurs pratiques pour les emplacements, les vecteurs et les définitions de zone.
Constructeurs d'emplacement et de vecteur
| Fonction | Notes |
|---|---|
em.create_location(x, y, z[, world][, yaw][, pitch]) | Retourne une table d'emplacement avec une méthode add(dx, dy, dz) |
em.create_vector(x, y, z) | Retourne une table de vecteur |
Helpers de constructeur de zones
La sous-table em.zone fournit des fonctions constructrices qui retournent des tables de définition de zone compatibles avec context.zones. Chaque constructeur retourne une table avec des méthodes de mutation chaînables.
| Fonction | Paramètres | Mutateurs |
|---|---|---|
em.zone.create_sphere_zone(radius) | radius | :set_center(location) |
em.zone.create_dome_zone(radius) | radius | :set_center(location) |
em.zone.create_cylinder_zone(radius, height) | radius, height | :set_center(location) |
em.zone.create_cuboid_zone(x, y, z) | x, y, z (demi-extensions) | :set_center(location) |
em.zone.create_cone_zone(length, radius) | length, radius | :set_origin(location), :set_destination(location) |
em.zone.create_static_ray_zone(length, thickness) | length, thickness | :set_origin(location), :set_destination(location) |
em.zone.create_rotating_ray_zone(length, point_radius, animation_duration) | length, point_radius, animation_duration | :set_origin(location), :set_destination(location) |
em.zone.create_translating_ray_zone(length, point_radius, animation_duration) | length, point_radius, animation_duration | :set_origin(location), :set_destination(location) |
length n'est pas utiliséLes constructeurs de cônes et de rayons stockent length dans la table de spécification, mais context.zones ne le lit jamais — la forme va d'origin à destination. Chaînez toujours :set_origin(...) et :set_destination(...) sur ces constructeurs ; sinon les deux retombent sur l'emplacement du boss et la forme a une longueur nulle.
Exemple
Exemple
return {
api_version = 1,
on_spawn = function(context)
-- Create a location offset from the boss
local boss_loc = context.boss:get_location()
local above = em.create_location(boss_loc.x, boss_loc.y + 5, boss_loc.z)
-- Create a sphere zone using the builder
local zone = em.zone.create_sphere_zone(10):set_center(boss_loc)
-- Use with native zone queries
local players = context.zones:get_entities_in_zone(zone, { filter = "players" })
for _, p in ipairs(players) do
p:send_message("&cYou are within the boss's aura!")
end
-- Create a directional vector
local push_vec = em.create_vector(0, 1.5, 0)
context.boss:set_velocity_vector(push_vec)
end
}
L'espace de noms em n'est pas spécifique à une instance -- toutes les instances de pouvoir Lua partagent les mêmes fonctions auxiliaires em. Les fonctions sont des constructeurs purs et ne maintiennent aucun état.
Zones natives vs. Utilitaires de script
Les deux systèmes fonctionnent avec la même géométrie de zone sous-jacente. Voici quand utiliser chacun :
| Cas d'utilisation | Approche recommandée |
|---|---|
| Vérification simple « y a-t-il quelque chose dans cette zone ? » | Zones natives (context.zones) |
| Requête rapide d'entités avec une forme | Zones natives |
NEARBY_PLAYERS, ZONE_FULL avec coverage | Utilitaires de script (context.script) |
| Zones animées (rayons rotatifs/en translation) | Les deux -- les zones natives supportent aussi ces formes |
Handles de zone avec méthodes watch/contains/entities | Utilitaires de script |
| Génération de particules aux emplacements de zone | Utilitaires de script (spawn_particles) |
| Actions de dégâts et de poussée liées au ciblage | Utilitaires de script (damage, push) |
| Vecteurs relatifs pour effets directionnels | Utilitaires de script (relative_vector) |
| Combiner le flux de contrôle Lua avec un ciblage avancé | Utilitaires de script |
En pratique, beaucoup de pouvoirs utilisent les deux. Les zones natives sont idéales pour la vérification initiale « des joueurs sont-ils à proximité ? » dans un garde de cooldown, tandis que les utilitaires de script gèrent la logique d'attaque complexe qui suit.
Prochaines étapes
- Exemples et modèles -- pouvoirs fonctionnels complets que vous pouvez étudier et adapter
- Référence API -- la référence complète des méthodes
context.* - Référence des enums -- valeurs valides pour Particle, Sound, Material et autres constantes de chaîne
