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 | Notes |
|---|
kind | string | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
radius | number | Rayon de la zone (sphere, dome, cylinder, cone) |
height | number | Hauteur du cylindre |
origin | location | Emplacement central (par défaut l'emplacement du boss si omis) |
destination | location | Point final pour les rayons et les cônes |
x, y, z | number | Demi-extensions du cuboïde |
length | number | Longueur pour les cônes et les rayons |
thickness / point_radius | number | Épaisseur du rayon |
border_radius | number | Largeur de la bordure (par défaut 1) |
x_border, y_border, z_border | number | Largeurs de bordure du cuboïde (par défaut 1) |
animation_duration | int | Durée de l'animation en ticks pour les rayons animés |
pitch_pre_rotation, yaw_pre_rotation | number | Angles de pré-rotation (rayon rotatif) |
pitch_rotation, yaw_rotation | number | Angles de rotation par tick (rayon rotatif) |
origin_end, destination_end | location | Positions finales pour le rayon en translation |
ignores_solid_blocks | boolean | Si les rayons traversent les blocs solides (par défaut true) |
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 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. Ils utilisent les mêmes noms de champs que les Zones EliteScript et les Cibles EliteScript pour une plus grande familiarité -- les noms d'enum (comme "NEARBY_PLAYERS", "SPHERE", "ZONE_FULL") sont identiques pour que les auteurs déjà à l'aise avec EliteScript puissent transférer ces connaissances directement.
context.script est une API Lua native. Ce n'est pas un pont vers YAML ou vers le runtime EliteScript. Il réutilise simplement les mêmes conventions de nommage pour que vous n'ayez pas à apprendre un second ensemble de noms d'enum.
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é | Notes |
|---|
targetType | "SELF", "DIRECT_TARGET", "NEARBY_PLAYERS", "NEARBY_MOBS", "NEARBY_ELITES", "ZONE_FULL", "ZONE_BORDER", "ALL_PLAYERS", "WORLD_PLAYERS", "SELF_SPAWN", "LOCATION" |
range | Portée pour les types de cible à proximité |
coverage | 0.0 à 1.0 pour les cibles de zone |
offset | Chaîne "x,y,z" ou table { x = n, y = n, z = n } |
track | Indique s'il faut ré-résoudre les cibles en mouvement |
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é | Notes |
|---|
shape | "SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY" |
radius | Rayon de la zone |
height | Hauteur du cylindre |
x, y, z | Demi-extensions du cuboïde |
borderRadius | Largeur de la bordure |
pointRadius | Épaisseur du rayon |
animationDuration | Durée de l'animation en ticks pour les rayons animés |
Target | Spécification de cible centrale (table) -- utilise le même format de spécification de cible |
Target2 | Second point pour les rayons et les cônes |
filter | Filtre d'entité |
ignoresSolidBlocks | boolean |
pitchPreRotation, yawPreRotation | Angles de pré-rotation |
pitchRotation, yawRotation | Angles de rotation par tick |
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
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.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
}
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
}
Les spécifications de particules peuvent être une chaîne, une table unique ou un tableau de tables :
| Clé | Notes |
|---|
particle | Nom de la particule (ex. "FLAME", "DUST", "SMOKE") |
amount | Nombre de particules |
x, y, z | Valeurs d'offset/dispersion |
speed | Vitesse des particules |
red, green, blue | Couleur pour DUST / DUST_COLOR_TRANSITION (0-255) |
toRed, toGreen, toBlue | Couleur cible de transition pour DUST_COLOR_TRANSITION |
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.state pour une utilisation dans un appel de hook ultérieur.
watch() de zone retourne un ID de tâche que vous pouvez annuler avec context.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) |
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