From a84bbeea9491e3156f99169b844d6ea578e69541 Mon Sep 17 00:00:00 2001 From: Paul Reilly Date: Thu, 29 Jun 2023 11:26:31 -0500 Subject: [PATCH] Backend Finalization TODO: - Listener implementations - Spell tome, book, and wand items - Persistent data storage - Configurable values - Custom spells --- .../api/display/SpellDisplay.java | 24 +++ .../api/effect/EffectProvider.java | 5 + .../api/effect/SpecialEffect.java | 7 +- .../api/effect/SpellEffect.java | 4 +- .../arcanumocculta/api/player/Caster.java | 6 + .../api/spell/CompoundSpell.java | 8 - .../api/spell/SpecialSpell.java | 8 - .../arcanumocculta/api/spell/Spell.java | 10 +- .../api/spell/SpellProjectile.java | 2 +- .../api/spell/StandardSpell.java | 8 - .../base/effect/AbstractPassiveEffect.java | 12 +- .../base/spell/AbstractSpell.java | 54 +++++-- .../base/spell/AbstractSpellProjectile.java | 143 ++++++++++++++++++ .../arcanumocculta/spell/FireballSpell.java | 23 +++ .../spell/effect/FireballEffect.java | 12 ++ .../spell/projectile/FireballProjectile.java | 15 ++ 16 files changed, 283 insertions(+), 58 deletions(-) create mode 100644 src/main/java/app/simplexdev/arcanumocculta/api/display/SpellDisplay.java create mode 100644 src/main/java/app/simplexdev/arcanumocculta/api/effect/EffectProvider.java delete mode 100644 src/main/java/app/simplexdev/arcanumocculta/api/spell/CompoundSpell.java delete mode 100644 src/main/java/app/simplexdev/arcanumocculta/api/spell/SpecialSpell.java delete mode 100644 src/main/java/app/simplexdev/arcanumocculta/api/spell/StandardSpell.java create mode 100644 src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpellProjectile.java create mode 100644 src/main/java/app/simplexdev/arcanumocculta/spell/FireballSpell.java create mode 100644 src/main/java/app/simplexdev/arcanumocculta/spell/effect/FireballEffect.java create mode 100644 src/main/java/app/simplexdev/arcanumocculta/spell/projectile/FireballProjectile.java diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/display/SpellDisplay.java b/src/main/java/app/simplexdev/arcanumocculta/api/display/SpellDisplay.java new file mode 100644 index 0000000..2fa4b42 --- /dev/null +++ b/src/main/java/app/simplexdev/arcanumocculta/api/display/SpellDisplay.java @@ -0,0 +1,24 @@ +package app.simplexdev.arcanumocculta.api.display; + +import app.simplexdev.arcanumocculta.api.player.Caster; +import app.simplexdev.arcanumocculta.api.spell.Spell; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.World; +import org.bukkit.entity.Display; + +public interface SpellDisplay { + T getDisplay(); + + Location getLocation(); + + World getWorld(); + + Caster getWhoCast(); + + Spell getCastSpell(); + + Particle[] getParticles(); + + void display(boolean force); +} diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/effect/EffectProvider.java b/src/main/java/app/simplexdev/arcanumocculta/api/effect/EffectProvider.java new file mode 100644 index 0000000..ecf4908 --- /dev/null +++ b/src/main/java/app/simplexdev/arcanumocculta/api/effect/EffectProvider.java @@ -0,0 +1,5 @@ +package app.simplexdev.arcanumocculta.api.effect; + +public interface EffectProvider { + T getEffect(Class type); +} diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpecialEffect.java b/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpecialEffect.java index 1cf0ca4..49284be 100644 --- a/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpecialEffect.java +++ b/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpecialEffect.java @@ -1,8 +1,7 @@ package app.simplexdev.arcanumocculta.api.effect; -import org.bukkit.entity.Player; +import org.bukkit.entity.LivingEntity; -public interface SpecialEffect extends Effect -{ - void applyEffect(final Player player); +public interface SpecialEffect extends Effect { + void applyEffect(final LivingEntity target); } diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpellEffect.java b/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpellEffect.java index 7d0c7a1..02f6499 100644 --- a/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpellEffect.java +++ b/src/main/java/app/simplexdev/arcanumocculta/api/effect/SpellEffect.java @@ -1,9 +1,7 @@ package app.simplexdev.arcanumocculta.api.effect; -import java.time.Duration; import org.bukkit.potion.PotionEffectType; -public interface SpellEffect extends Effect -{ +public interface SpellEffect extends Effect { PotionEffectType getEffectType(); } diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/player/Caster.java b/src/main/java/app/simplexdev/arcanumocculta/api/player/Caster.java index 7de7d2c..1ec0d8c 100644 --- a/src/main/java/app/simplexdev/arcanumocculta/api/player/Caster.java +++ b/src/main/java/app/simplexdev/arcanumocculta/api/player/Caster.java @@ -1,6 +1,7 @@ package app.simplexdev.arcanumocculta.api.player; import app.simplexdev.arcanumocculta.api.book.SpellBook; +import org.bukkit.entity.Player; import java.util.List; import java.util.UUID; @@ -16,6 +17,11 @@ public interface Caster { */ String getDisplayName(); + /** + * @return The {@link Player} associated with this caster. + */ + Player bukkit(); + /** * @return The amount of maximum mana the caster is allowed to have. */ diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/spell/CompoundSpell.java b/src/main/java/app/simplexdev/arcanumocculta/api/spell/CompoundSpell.java deleted file mode 100644 index e71ba53..0000000 --- a/src/main/java/app/simplexdev/arcanumocculta/api/spell/CompoundSpell.java +++ /dev/null @@ -1,8 +0,0 @@ -package app.simplexdev.arcanumocculta.api.spell; - -import app.simplexdev.arcanumocculta.api.effect.CompoundEffect; - -public interface CompoundSpell extends Spell -{ - CompoundEffect getEffect(); -} diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/spell/SpecialSpell.java b/src/main/java/app/simplexdev/arcanumocculta/api/spell/SpecialSpell.java deleted file mode 100644 index 5aa0eb1..0000000 --- a/src/main/java/app/simplexdev/arcanumocculta/api/spell/SpecialSpell.java +++ /dev/null @@ -1,8 +0,0 @@ -package app.simplexdev.arcanumocculta.api.spell; - -import app.simplexdev.arcanumocculta.api.effect.SpecialEffect; - -public interface SpecialSpell extends Spell -{ - SpecialEffect getSpecialEffect(); -} diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/spell/Spell.java b/src/main/java/app/simplexdev/arcanumocculta/api/spell/Spell.java index 8475087..8415455 100644 --- a/src/main/java/app/simplexdev/arcanumocculta/api/spell/Spell.java +++ b/src/main/java/app/simplexdev/arcanumocculta/api/spell/Spell.java @@ -1,12 +1,12 @@ package app.simplexdev.arcanumocculta.api.spell; -import app.simplexdev.arcanumocculta.api.effect.SpellEffect; +import app.simplexdev.arcanumocculta.api.effect.Effect; +import app.simplexdev.arcanumocculta.api.effect.EffectProvider; import org.bukkit.entity.Projectile; import java.time.Duration; -public interface Spell -{ +public interface Spell { String getSpellName(); String getSpellDescription(); @@ -17,7 +17,7 @@ public interface Spell int getSpellLevel(); - boolean isOnCoolDown(); - SpellProjectile getSpellProjectile(); + + T getEffect(); } diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/spell/SpellProjectile.java b/src/main/java/app/simplexdev/arcanumocculta/api/spell/SpellProjectile.java index 8abf077..01ea8a7 100644 --- a/src/main/java/app/simplexdev/arcanumocculta/api/spell/SpellProjectile.java +++ b/src/main/java/app/simplexdev/arcanumocculta/api/spell/SpellProjectile.java @@ -8,7 +8,7 @@ import org.bukkit.entity.Projectile; import java.util.List; public interface SpellProjectile { - T getProjectile(); + Class getProjectileType(); List getParticles(); diff --git a/src/main/java/app/simplexdev/arcanumocculta/api/spell/StandardSpell.java b/src/main/java/app/simplexdev/arcanumocculta/api/spell/StandardSpell.java deleted file mode 100644 index d7e804d..0000000 --- a/src/main/java/app/simplexdev/arcanumocculta/api/spell/StandardSpell.java +++ /dev/null @@ -1,8 +0,0 @@ -package app.simplexdev.arcanumocculta.api.spell; - -import app.simplexdev.arcanumocculta.api.effect.SpellEffect; - -public interface StandardSpell extends Spell -{ - SpellEffect getSpellEffect(); -} diff --git a/src/main/java/app/simplexdev/arcanumocculta/base/effect/AbstractPassiveEffect.java b/src/main/java/app/simplexdev/arcanumocculta/base/effect/AbstractPassiveEffect.java index 1bb6de8..3beaf9c 100644 --- a/src/main/java/app/simplexdev/arcanumocculta/base/effect/AbstractPassiveEffect.java +++ b/src/main/java/app/simplexdev/arcanumocculta/base/effect/AbstractPassiveEffect.java @@ -11,7 +11,7 @@ public abstract class AbstractPassiveEffect extends AbstractEffect implements Pa private final Caster wandHolder; private final PassiveEffects passiveEffect; - public AbstractPassiveEffect(Duration duration, float amplifier, boolean ambient, boolean forceDisplay, Caster wandHolder, PassiveEffects passiveEffect) { + protected AbstractPassiveEffect(Duration duration, float amplifier, boolean ambient, boolean forceDisplay, Caster wandHolder, PassiveEffects passiveEffect) { super(duration, amplifier, ambient, forceDisplay); this.wandHolder = wandHolder; this.passiveEffect = passiveEffect; @@ -23,19 +23,19 @@ public abstract class AbstractPassiveEffect extends AbstractEffect implements Pa this.passiveEffect = passiveEffect; } - public AbstractPassiveEffect(Duration duration, float amplifier, Caster wandHolder, PassiveEffects passiveEffect) { + protected AbstractPassiveEffect(Duration duration, float amplifier, Caster wandHolder, PassiveEffects passiveEffect) { super(duration, amplifier); this.wandHolder = wandHolder; this.passiveEffect = passiveEffect; } - public AbstractPassiveEffect(Duration duration, Caster wandHolder, PassiveEffects passiveEffect) { + protected AbstractPassiveEffect(Duration duration, Caster wandHolder, PassiveEffects passiveEffect) { super(duration); this.wandHolder = wandHolder; this.passiveEffect = passiveEffect; } - public AbstractPassiveEffect(Caster wandHolder, PassiveEffects passiveEffect) { + protected AbstractPassiveEffect(Caster wandHolder, PassiveEffects passiveEffect) { super(); this.wandHolder = wandHolder; this.passiveEffect = passiveEffect; @@ -43,11 +43,11 @@ public abstract class AbstractPassiveEffect extends AbstractEffect implements Pa @Override public Caster getWandHolder() { - return null; + return wandHolder; } @Override public PassiveEffects getPassiveEffect() { - return null; + return passiveEffect; } } diff --git a/src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpell.java b/src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpell.java index 17c5c82..600e4c2 100644 --- a/src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpell.java +++ b/src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpell.java @@ -1,44 +1,68 @@ package app.simplexdev.arcanumocculta.base.spell; +import app.simplexdev.arcanumocculta.api.effect.Effect; import app.simplexdev.arcanumocculta.api.spell.Spell; -import app.simplexdev.arcanumocculta.api.spell.SpellProjectile; -import org.bukkit.entity.Projectile; import java.time.Duration; -public class AbstractSpell implements Spell { +public abstract class AbstractSpell implements Spell { + private final String name; + private final String description; + private final double manaCost; + private final Duration coolDown; + private final int spellLevel; + private final T spellEffect; + + private long coolDownEnd; + + protected AbstractSpell(String name, String description, double manaCost, Duration coolDown, int spellLevel, T effect) { + this.name = name; + this.description = description; + this.manaCost = manaCost; + this.coolDown = coolDown; + this.spellLevel = spellLevel; + this.spellEffect = effect; + } + + protected AbstractSpell(String name, String description, double manaCost, Duration coolDown, T effect) { + this(name, description, manaCost, coolDown, 1, effect); + } + + protected AbstractSpell(String name, String description, double manaCost, T effect) { + this(name, description, manaCost, Duration.ofSeconds(10L), effect); + } + + protected AbstractSpell(String name, String description, T effect) { + this(name, description, 5.0, effect); + } + @Override public String getSpellName() { - return null; + return name; } @Override public String getSpellDescription() { - return null; + return description; } @Override public double getManaCost() { - return 0; + return manaCost; } @Override public Duration getCoolDown() { - return null; + return coolDown; } @Override public int getSpellLevel() { - return 0; + return spellLevel; } @Override - public boolean isOnCoolDown() { - return false; - } - - @Override - public SpellProjectile getSpellProjectile() { - return null; + public T getEffect() { + return spellEffect; } } diff --git a/src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpellProjectile.java b/src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpellProjectile.java new file mode 100644 index 0000000..28536d1 --- /dev/null +++ b/src/main/java/app/simplexdev/arcanumocculta/base/spell/AbstractSpellProjectile.java @@ -0,0 +1,143 @@ +package app.simplexdev.arcanumocculta.base.spell; + +import app.simplexdev.arcanumocculta.api.effect.CompoundEffect; +import app.simplexdev.arcanumocculta.api.effect.Effect; +import app.simplexdev.arcanumocculta.api.effect.SpecialEffect; +import app.simplexdev.arcanumocculta.api.effect.SpellEffect; +import app.simplexdev.arcanumocculta.api.player.Caster; +import app.simplexdev.arcanumocculta.api.spell.Spell; +import app.simplexdev.arcanumocculta.api.spell.SpellProjectile; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.AreaEffectCloud; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Projectile; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public abstract class AbstractSpellProjectile implements SpellProjectile { + + private static final List accepted = List.of( + EntityType.ARROW, + EntityType.SPECTRAL_ARROW, + EntityType.FIREBALL, + EntityType.DRAGON_FIREBALL, + EntityType.SMALL_FIREBALL, + EntityType.WITHER_SKULL, + EntityType.ENDER_PEARL, + EntityType.SNOWBALL, + EntityType.EGG, + EntityType.TRIDENT, + EntityType.FIREWORK, + EntityType.LLAMA_SPIT, + EntityType.SHULKER_BULLET, + EntityType.FISHING_HOOK, + EntityType.SPLASH_POTION, + EntityType.THROWN_EXP_BOTTLE); + + private final Class projectile; + private final List particles; + private final Caster caster; + private final Spell spell; + + protected AbstractSpellProjectile(final Spell spell, final Caster caster, final Class projectile, final Particle... particles) { + this.projectile = projectile; + this.particles = Arrays.asList(particles); + this.caster = caster; + this.spell = spell; + } + + @Override + public Class getProjectileType() { + return projectile; + } + + @Override + public List getParticles() { + return particles; + } + + @Override + public void cast(Location target) { + final Vector velocity = caster.bukkit().getEyeLocation().getDirection().multiply(2); + final T launched = caster.bukkit().launchProjectile(getProjectileType(), velocity); + + while (!launched.isDead()) { + final double randomXOffset = Math.sin((Math.random() * 10 - 2) % Math.PI) * 5; + final double randomYOffset = ((Math.random() * 10 - 2) % Math.PI) * 5; + final double randomZOffset = Math.cos((Math.random() * 10 - 2) % (2 * Math.PI)) * 5; + particles.forEach(particle -> launched.getWorld().spawnParticle(particle, launched.getLocation(), 1, randomXOffset, randomYOffset, randomZOffset)); + + if (launched.isOnGround() + || launched.isDead() + || launched.getTicksLived() > 100 + || launched.getLocation().clone().equals(target)) { + break; + } + } + + final Effect effect = spell.getEffect(); + if (effect instanceof SpellEffect sp) { + PotionEffect e = sp.getEffectType().createEffect((int) sp.getDuration().getSeconds(), (int) sp.getAmplifier()); + AreaEffectCloud cloud = (AreaEffectCloud) target.getWorld().spawnEntity(target, EntityType.AREA_EFFECT_CLOUD); + cloud.addCustomEffect(e, true); + cloud.setRadius(2.5F); + cloud.setDuration((int) sp.getDuration().getSeconds()); + cloud.setSource(caster.bukkit()); + } else if (effect instanceof CompoundEffect sp) { + final List effects = new ArrayList<>(); + for (PotionEffectType type : sp.getEffectTypes()) { + PotionEffect e = type.createEffect((int) sp.getDuration().getSeconds(), (int) sp.getAmplifier()); + effects.add(e); + } + AreaEffectCloud cloud = (AreaEffectCloud) target.getWorld().spawnEntity(target, EntityType.AREA_EFFECT_CLOUD); + for (PotionEffect e : effects) { + cloud.addCustomEffect(e, true); + } + cloud.setRadius(2.5F); + cloud.setDuration((int) sp.getDuration().getSeconds()); + cloud.setSource(caster.bukkit()); + } + } + + @Override + public void cast(LivingEntity target) { + final Vector velocity = caster.bukkit().getEyeLocation().getDirection().multiply(2); + final T launched = caster.bukkit().launchProjectile(getProjectileType(), velocity); + + while (!launched.isDead()) { + final double randomXOffset = Math.sin((Math.random() * 10 - 2) % Math.PI) * 5; + final double randomYOffset = ((Math.random() * 10 - 2) % Math.PI) * 5; + final double randomZOffset = Math.cos((Math.random() * 10 - 2) % (2 * Math.PI)) * 5; + particles.forEach(particle -> launched.getWorld().spawnParticle(particle, launched.getLocation(), 1, randomXOffset, randomYOffset, randomZOffset)); + + if (launched.isOnGround() + || launched.isDead() + || launched.getTicksLived() > 100 + || launched.getLocation().clone().equals(target)) { + break; + } + } + + final Effect effect = spell.getEffect(); + if (effect instanceof SpellEffect sp) { + PotionEffect e = sp.getEffectType().createEffect((int) sp.getDuration().getSeconds(), (int) sp.getAmplifier()); + target.addPotionEffect(e); + } else if (effect instanceof CompoundEffect sp) { + final List effects = new ArrayList<>(); + for (PotionEffectType type : sp.getEffectTypes()) { + PotionEffect e = type.createEffect((int) sp.getDuration().getSeconds(), (int) sp.getAmplifier()); + effects.add(e); + } + target.addPotionEffects(effects); + } else if (effect instanceof SpecialEffect sp) { + sp.applyEffect(target); + } + } +} diff --git a/src/main/java/app/simplexdev/arcanumocculta/spell/FireballSpell.java b/src/main/java/app/simplexdev/arcanumocculta/spell/FireballSpell.java new file mode 100644 index 0000000..54a5d1d --- /dev/null +++ b/src/main/java/app/simplexdev/arcanumocculta/spell/FireballSpell.java @@ -0,0 +1,23 @@ +package app.simplexdev.arcanumocculta.spell; + +import app.simplexdev.arcanumocculta.api.effect.SpellEffect; +import app.simplexdev.arcanumocculta.api.player.Caster; +import app.simplexdev.arcanumocculta.base.spell.AbstractSpell; +import app.simplexdev.arcanumocculta.spell.effect.FireballEffect; +import app.simplexdev.arcanumocculta.spell.projectile.FireballProjectile; + +import java.time.Duration; + +public final class FireballSpell extends AbstractSpell { + private final Caster caster; + + public FireballSpell(final Caster caster) { + super("Fireball", "Fires a fireball in the direction you're facing.", new FireballEffect(Duration.ofSeconds(1), 1)); + this.caster = caster; + } + + @Override + public FireballProjectile getSpellProjectile() { + return new FireballProjectile(this, this.caster); + } +} diff --git a/src/main/java/app/simplexdev/arcanumocculta/spell/effect/FireballEffect.java b/src/main/java/app/simplexdev/arcanumocculta/spell/effect/FireballEffect.java new file mode 100644 index 0000000..f0eb174 --- /dev/null +++ b/src/main/java/app/simplexdev/arcanumocculta/spell/effect/FireballEffect.java @@ -0,0 +1,12 @@ +package app.simplexdev.arcanumocculta.spell.effect; + +import app.simplexdev.arcanumocculta.base.effect.AbstractSpellEffect; +import org.bukkit.potion.PotionEffectType; + +import java.time.Duration; + +public class FireballEffect extends AbstractSpellEffect { + public FireballEffect(Duration duration, float amplifier) { + super(duration, amplifier, PotionEffectType.HARM); + } +} diff --git a/src/main/java/app/simplexdev/arcanumocculta/spell/projectile/FireballProjectile.java b/src/main/java/app/simplexdev/arcanumocculta/spell/projectile/FireballProjectile.java new file mode 100644 index 0000000..6564564 --- /dev/null +++ b/src/main/java/app/simplexdev/arcanumocculta/spell/projectile/FireballProjectile.java @@ -0,0 +1,15 @@ +package app.simplexdev.arcanumocculta.spell.projectile; + +import app.simplexdev.arcanumocculta.api.player.Caster; +import app.simplexdev.arcanumocculta.api.spell.Spell; +import app.simplexdev.arcanumocculta.base.spell.AbstractSpellProjectile; +import app.simplexdev.arcanumocculta.spell.FireballSpell; +import org.bukkit.Particle; +import org.bukkit.entity.Fireball; + +public class FireballProjectile extends AbstractSpellProjectile { + public FireballProjectile(FireballSpell spell, + Caster caster) { + super(spell, caster, Fireball.class, Particle.FLAME, Particle.SMALL_FLAME, Particle.LAVA); + } +}