@FunctionalInterface
public interface ImpactEffect {
/**
* @return {@code true} si le projectile doit perdre son effet, {@code false} si le projectile doit garder son effet.
*/
// L'accès d'une méthode est forcément `public` dans les interfaces, donc le mot-clef est redondant.
boolean onHit(ProjectileHitEvent e);
/**
* Téléporte le joueur à l'endroit du projectile si celui-ci a percuté un bloc.
*/
// @FunctionalInterface nous permet de directement définir l'unique méthode de l'interface via une lambda.
// De la même façon, l'accès d'un champ est forcément `public static final`, donc les mots-clefs sont redondants.
ImpactEffect TELEPORT = e -> {
Block block = e.getHitBlock();
BlockFace face = e.getHitBlockFace();
if(e.getEntity().getShooter() instanceof Entity shooter && block != null) {
return shooter.teleport(block.getRelative(face != null ? face : BlockFace.UP).getLocation());
}
else {
return false;
}
};
/**
* Créer une explosion à l'endroit du projectile.
*/
// Idem, l'accès d'une classe interne d'une interface est forcément `public static`.
final class Explode implements ImpactEffect {
/**
* La puissance de l'explosion, où {@code 4} correspond à une TNT.
*/
public final float power;
public final boolean setFire, breakBlocks;
public Explode(float power, boolean setFire, boolean breakBlocks) {
this.power = power;
this.setFire = setFire;
this.breakBlocks = breakBlocks;
}
/**
* Créer une explosion détruisant les blocs.
*/
public Explode(float power, boolean setFire) {
this(power, setFire, true);
}
/**
* Créer une explosion détruisant les blocs, mais ne mettant pas le feu.
*/
public Explode(float power) {
this(power, false);
}
@Override
public boolean onHit(ProjectileHitEvent e) {
Projectile projectile = e.getEntity();
ProjectileSource shooter = projectile.getShooter();
Location origin = projectile.getLocation();
Entity source = (shooter instanceof Entity) ? (Entity) shooter : null;
return projectile.getWorld().createExplosion(origin.getX(), origin.getY(), origin.getZ(), this.power, this.setFire, this.breakBlocks, source);
}
}
/**
* N'effectue aucune action à l'impact.
*/
ImpactEffect NONE = e -> true;
/**
* Combine plusieurs {@linkplain ImpactEffect}.
*/
final class Combine implements ImpactEffect {
private final ImpactEffect[] effects;
public Combine(ImpactEffect[] effects) {
this.effects = effects;
}
public Combine(Iterable<ImpactEffect> effects) {
this(Iterables.toArray(effects, ImpactEffect.class));
}
@Override
public boolean onHit(ProjectileHitEvent e) {
boolean loseEffect = false;
for(ImpactEffect effect : this.effects) {
loseEffect |= effect.onHit(e);
}
return loseEffect;
}
}
}