API completed, Implementation required (#1)

New API, ready to go.
Implementations required.
This commit is contained in:
Paldiu 2023-07-18 18:00:33 -05:00 committed by GitHub
parent a84bbeea94
commit 0648b51c96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 1760 additions and 1111 deletions

19
LICENSE.MD Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2023 Simplex Development Group
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal with the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -19,6 +19,7 @@ repositories {
dependencies { dependencies {
compileOnly "org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT" compileOnly "org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT"
compileOnly "org.reflections:reflections:0.10.2"
} }
def targetJavaVersion = 17 def targetJavaVersion = 17

View File

@ -2,16 +2,15 @@ package app.simplexdev.arcanumocculta;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public final class ArcanumOcculta extends JavaPlugin { public class ArcanumOcculta extends JavaPlugin
{
@Override @Override
public void onEnable() { public void onEnable() {
// Plugin startup logic
} }
@Override public static ArcanumOcculta getInstance()
public void onDisable() { {
// Plugin shutdown logic return JavaPlugin.getPlugin(ArcanumOcculta.class);
} }
} }

View File

@ -1,32 +0,0 @@
package app.simplexdev.arcanumocculta.api.book;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public interface SpellBook {
String getBookName();
void setBookName(final String name);
String getBookDescription();
void setBookDescription(final String description);
ItemStack getBookItem();
void setBookItem(final ItemStack itemStack);
List<Spell> getSpells();
void addSpell(Spell spell);
void removeSpell(Spell spell);
Spell getSpell(final String name);
Spell getSpell(final int index);
int getSpellCount();
}

View File

@ -1,14 +0,0 @@
package app.simplexdev.arcanumocculta.api.book;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import org.bukkit.inventory.ItemStack;
public interface SpellTome {
String getTomeName();
String getTomeDescription();
ItemStack getTomeItem();
Spell getContainedSpell();
}

View File

@ -0,0 +1,137 @@
package app.simplexdev.arcanumocculta.api.caster;
import app.simplexdev.arcanumocculta.api.wand.Wand;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public abstract class AbstractCaster implements Caster
{
private final SpellBook spellBook;
private final UUID playerUUID;
private final String name;
private Wand wand;
private CasterLevel level;
private double currentExperience;
private double currentMana;
private double maxMana;
protected AbstractCaster(final Player player, final Wand wand, final SpellBook spellBook, final CasterLevel level)
{
this.spellBook = spellBook;
this.playerUUID = player.getUniqueId();
this.name = player.getName();
this.wand = wand;
this.level = level;
}
@Override
public Wand getWand()
{
return this.wand;
}
public void setWand(final Wand wand)
{
this.wand = wand;
}
@Override
public SpellBook getSpellBook()
{
return this.spellBook;
}
@Override
public UUID getUniqueId()
{
return this.playerUUID;
}
@Override
public String getName()
{
return this.name;
}
@Override
public CasterLevel getCurrentLevel()
{
return this.level;
}
public void setCurrentLevel(final CasterLevel level)
{
this.level = level;
}
@Override
public double getCurrentExperience()
{
return this.currentExperience;
}
public void setCurrentExperience(final double experience)
{
this.currentExperience = experience;
}
@Override
public double getCurrentMana()
{
return this.currentMana;
}
public void setCurrentMana(final double mana)
{
this.currentMana = mana;
}
@Override
public double getMaxMana()
{
return this.maxMana;
}
@Override
public void setMaxMana(final double mana)
{
this.maxMana = mana;
}
public void addExperience(final double experience)
{
this.currentExperience = this.currentExperience + experience;
}
public void removeExperience(final double experience)
{
this.currentExperience = this.currentExperience - experience;
}
public void addMana(final double mana)
{
this.currentMana = this.currentMana + mana;
}
public void removeMana(final double mana)
{
this.currentMana = this.currentMana - mana;
}
public void setManaToMax()
{
this.currentMana = this.maxMana;
}
public void setExperienceToZero()
{
this.currentExperience = 0;
}
@Override
public Player bukkit()
{
return Bukkit.getPlayer(this.playerUUID);
}
}

View File

@ -0,0 +1,97 @@
package app.simplexdev.arcanumocculta.api.caster;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.SplittableRandom;
import java.util.UUID;
public abstract class AbstractSpellBook implements SpellBook
{
private final List<Spell> spells = new ArrayList<>();
@Override
public boolean hasSpell(final Spell spell)
{
return getSpells().contains(spell);
}
@Override
public List<Spell> getSpells()
{
return this.spells;
}
@Override
public void addSpell(Spell spell)
{
this.spells.add(spell);
}
@Override
public void removeSpell(Spell spell)
{
this.spells.remove(spell);
}
@Override
public Spell getSpell(String id)
{
return getSpells().stream()
.filter(spell -> spell.getId().equalsIgnoreCase(id))
.findFirst()
.orElse(getSpells().get(0));
}
public Spell getSpell(UUID uuid)
{
return getSpells().stream()
.filter(spell -> spell.getUniqueId().equals(uuid))
.findFirst()
.orElse(getSpells().get(0));
}
@Override
public Spell getSpell(int index)
{
if (index < 0 || index > getSpells().size() - 1)
return getSpells().get(0);
return getSpells().get(index);
}
@Override
public int getSpellCount()
{
return getSpells().size();
}
@Override
public void setSpell(int index, Spell spell)
{
this.spells.set(index, spell);
}
@Override
public void setSpell(String name, Spell spell)
{
this.spells.set(getSpells().indexOf(getSpell(name)), spell);
}
@Override
public void clearSpells()
{
this.spells.clear();
}
public void addAll(Collection<? extends Spell> spells) {
this.spells.addAll(spells);
}
@Override
public Spell randomSpell()
{
final SplittableRandom random = new SplittableRandom();
return getSpells().get(random.nextInt(getSpells().size()));
}
}

View File

@ -0,0 +1,44 @@
package app.simplexdev.arcanumocculta.api.caster;
import app.simplexdev.arcanumocculta.api.wand.Wand;
import java.util.UUID;
import org.bukkit.entity.Player;
public interface Caster
{
Wand getWand();
void setWand(Wand wand);
SpellBook getSpellBook();
String getName();
UUID getUniqueId();
double getCurrentMana();
void setCurrentMana(double mana);
double getMaxMana();
void setMaxMana(double maxMana);
CasterLevel getCurrentLevel();
void setCurrentLevel(CasterLevel level);
double getCurrentExperience();
void setCurrentExperience(double experience);
void addMana(double mana);
void removeMana(double mana);
void addExperience(double experience);
void removeExperience(double experience);
Player bukkit();
}

View File

@ -0,0 +1,85 @@
package app.simplexdev.arcanumocculta.api.caster;
import java.text.MessageFormat;
import java.util.stream.Stream;
import org.bukkit.ChatColor;
public enum CasterLevel
{
APPRENTICE(1, 250D, "Apprentice", "an Apprentice", ChatColor.WHITE, "Lvl1"),
PRIMARY(2, 500D, "Primary", "a Primary", ChatColor.RED, "Lvl2"),
SCHOLAR(3, 750D, "Scholar", "a Scholar", ChatColor.AQUA, "Lvl3"),
PREFECT(4, 1000D, "Prefect", "a Prefect", ChatColor.BLUE, "Lvl4"),
GRADUATE(5, 1250D, "Graduate", "a Graduate", ChatColor.GRAY, "Lvl5"),
ADEPT(6, 1500D, "Adept", "an Adept", ChatColor.DARK_PURPLE, "Lvl6"),
MAGISTRATE(7, 1750D, "Magister", "a Magister", ChatColor.DARK_GREEN, "Lvl7"),
HEADMASTER(8, 2000D, "Headmaster", "a Headmaster", ChatColor.GOLD, "Lvl8"),
ARCH_MAGE(9, 4000D, "Arch-Mage", "an Arch-Mage", ChatColor.BLACK, "Lvl9");
private final int level;
private final double experienceMarker;
private final String name;
private final String plural;
private final ChatColor rankColor;
private final String suffix;
CasterLevel(final int level, final double experienceMarker, final String name, final String plural,
final ChatColor rankColor,
final String suffix)
{
this.experienceMarker = experienceMarker;
this.level = level;
this.name = name;
this.plural = plural;
this.rankColor = rankColor;
this.suffix = MessageFormat.format("{0}[{1}{2}{3}]{4}",
ChatColor.DARK_GRAY,
rankColor,
suffix,
ChatColor.DARK_GRAY,
ChatColor.RESET);
}
public static CasterLevel fromOrdinal(final int ordinal)
{
return Stream.of(CasterLevel.values())
.filter(lvl -> lvl.getLevel() == ordinal)
.findFirst()
.orElse(CasterLevel.APPRENTICE);
}
public int getLevel()
{
return this.level;
}
public String getName()
{
return this.name;
}
public String getPlural()
{
return this.plural;
}
public ChatColor getRankColor()
{
return this.rankColor;
}
public String getSuffix()
{
return this.suffix;
}
public double getExperienceMarker()
{
return this.experienceMarker;
}
public boolean isAtLeast(final CasterLevel level) {
return this.getLevel() >= level.getLevel();
}
}

View File

@ -0,0 +1,29 @@
package app.simplexdev.arcanumocculta.api.caster;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import java.util.List;
public interface SpellBook
{
List<Spell> getSpells();
void addSpell(Spell spell);
void removeSpell(Spell spell);
Spell getSpell(String name);
Spell getSpell(int index);
int getSpellCount();
void setSpell(int index, Spell spell);
void setSpell(String name, Spell spell);
void clearSpells();
Spell randomSpell();
boolean hasSpell(final Spell spell);
}

View File

@ -1,24 +0,0 @@
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 extends Display> {
T getDisplay();
Location getLocation();
World getWorld();
Caster getWhoCast();
Spell getCastSpell();
Particle[] getParticles();
void display(boolean force);
}

View File

@ -1,7 +0,0 @@
package app.simplexdev.arcanumocculta.api.effect;
import org.bukkit.potion.PotionEffectType;
public interface CompoundEffect extends Effect {
PotionEffectType[] getEffectTypes();
}

View File

@ -1,14 +0,0 @@
package app.simplexdev.arcanumocculta.api.effect;
import java.time.Duration;
public interface Effect
{
Duration getDuration();
float getAmplifier();
boolean isAmbient();
boolean forceDisplay();
}

View File

@ -1,5 +0,0 @@
package app.simplexdev.arcanumocculta.api.effect;
public interface EffectProvider<T extends Effect> {
T getEffect(Class<T> type);
}

View File

@ -1,12 +0,0 @@
package app.simplexdev.arcanumocculta.api.effect;
import app.simplexdev.arcanumocculta.api.player.Caster;
public interface PassiveEffect extends Effect
{
Caster getWandHolder();
void onTick();
PassiveEffects getPassiveEffect();
}

View File

@ -1,30 +0,0 @@
package app.simplexdev.arcanumocculta.api.effect;
import java.time.Duration;
public enum PassiveEffects {
MANA_REGEN(Duration.ofSeconds(10L), 2.0),
LIFE_STEAL(Duration.ofSeconds(5L), 1.0),
ABSORPTION(Duration.ofSeconds(30L), 4.0),
SPELL_SHIELD(Duration.ofSeconds(5L), 5.0),
IMMUNITY(Duration.ofSeconds(5L), 100.0),
WITHER(Duration.ofSeconds(5L), 2.0),
DAMAGE_BOOST(Duration.ofSeconds(5L), 2.75),
IMPROVED_ACCURACY(Duration.ofSeconds(5L), 5.0);
private final Duration duration;
private final double amount;
PassiveEffects(final Duration duration, final double amount) {
this.duration = duration;
this.amount = amount;
}
Duration getDuration() {
return this.duration;
}
double getAmount() {
return this.amount;
}
}

View File

@ -1,7 +0,0 @@
package app.simplexdev.arcanumocculta.api.effect;
import org.bukkit.entity.LivingEntity;
public interface SpecialEffect extends Effect {
void applyEffect(final LivingEntity target);
}

View File

@ -1,7 +0,0 @@
package app.simplexdev.arcanumocculta.api.effect;
import org.bukkit.potion.PotionEffectType;
public interface SpellEffect extends Effect {
PotionEffectType getEffectType();
}

View File

@ -1,96 +0,0 @@
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;
public interface Caster {
/**
* @return The {@link UUID} of the caster.
*/
UUID getCasterUUID();
/**
* @return The name of the 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.
*/
double getMaximumMana();
/**
* Sets the maximum amount of mana the caster is allowed to have.
*
* @param mana The amount of mana to set the maximum to.
*/
void setMaximumMana(final double mana);
/**
* @return The amount of mana the caster currently has.
*/
double getCurrentMana();
/**
* Adds mana to the caster.
*
* @param mana The amount of mana to add.
* @return The players updated {@link #getCurrentMana()}.
*/
double addMana(final double mana);
/**
* Increases the amount of maximum mana this caster is allowed to have.
*
* @param mana The amount of mana to increase the maximum by.
* @return The players updated {@link #getMaximumMana()}.
*/
double increaseMaximumMana(final double mana);
/**
* Removes mana from the caster.
*
* @param mana The amount of mana to remove.
* @return The players updated {@link #getCurrentMana()}.
*/
double removeMana(final double mana);
/**
* Decreases the amount of maximum mana this caster is allowed to have.
*
* @param mana The amount of mana to decrease the maximum by.
* @return The players updated {@link #getMaximumMana()}.
*/
double decreaseMaximumMana(final double mana);
/**
* Sets the amount of mana the caster currently has.
*
* @param mana The amount of mana to set the user's current mana to.
*/
void setMana(final double mana);
/**
* @return The {@link SpellBook} of the caster.
*/
SpellBook getSpellbook();
/**
* @return A list of {@link SpellResistance}s the caster has.
*/
List<SpellResistance> getSpellResistances();
void addSpellResistance(SpellResistance resistance);
void removeSpellResistance(SpellResistance resistance);
boolean hasResistance(int spellOrdinal);
}

View File

@ -1,9 +0,0 @@
package app.simplexdev.arcanumocculta.api.player;
public interface SpellResistance {
String getSpellName();
double getResistance();
int getOrdinal();
}

View File

@ -1,18 +0,0 @@
package app.simplexdev.arcanumocculta.api.player;
import app.simplexdev.arcanumocculta.api.effect.PassiveEffect;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public interface Wand {
String getWandName();
String getWandDescription();
ItemStack getWandItem();
double getManaPenalty();
List<PassiveEffect> getPassiveEffects();
}

View File

@ -0,0 +1,198 @@
package app.simplexdev.arcanumocculta.api.spell;
import app.simplexdev.arcanumocculta.api.caster.Caster;
import app.simplexdev.arcanumocculta.api.caster.CasterLevel;
import app.simplexdev.arcanumocculta.api.spell.enums.Damages;
import app.simplexdev.arcanumocculta.api.spell.enums.Durations;
import app.simplexdev.arcanumocculta.api.spell.enums.ManaCosts;
import app.simplexdev.arcanumocculta.util.SpellUtils;
import java.util.List;
import java.util.SplittableRandom;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public abstract class AbstractSpell implements Spell
{
private final String name;
private final String id;
private final String description;
private final CasterLevel levelRequirement;
private final Damages baseDamage;
private final Durations effectDuration;
private final ManaCosts manaCost;
private final long coolDown;
private final SplittableRandom random = new SplittableRandom();
protected AbstractSpell(final String name, final String id,
final String description, final CasterLevel levelRequirement,
final Damages baseDamage, final Durations effectDuration,
final ManaCosts manaCost, final long coolDown)
{
this.name = name;
this.id = id;
this.description = description;
this.levelRequirement = levelRequirement;
this.baseDamage = baseDamage;
this.effectDuration = effectDuration;
this.manaCost = manaCost;
this.coolDown = coolDown;
}
@Override
public String getName()
{
return name;
}
@Override
public String getId()
{
return this.id;
}
@Override
public String getDescription()
{
return description;
}
@Override
public CasterLevel getLevelRequirement()
{
return levelRequirement;
}
@Override
public Damages baseDamage()
{
return baseDamage;
}
@Override
public Durations effectDuration()
{
return effectDuration;
}
@Override
public ManaCosts manaCost()
{
return manaCost;
}
@Override
public long coolDown()
{
return coolDown;
}
@Override
public Spell dupe()
{
try
{
return this.getClass()
.getDeclaredConstructor()
.newInstance();
}
catch (ReflectiveOperationException e)
{
Bukkit.getLogger().severe(e.getMessage());
return null;
}
}
@Override
public boolean isUnlocked(Caster caster)
{
return caster.getSpellBook().hasSpell(this)
&& caster.getCurrentLevel().isAtLeast(this.getLevelRequirement());
}
protected SplittableRandom random()
{
return random;
}
/**
* Checks if the caster has enough mana to cast this spell.
*
* @param caster The caster who is casting the spell
* @return True if the caster has enough mana, false otherwise
*/
protected boolean checkManaCosts(final Caster caster)
{
boolean isValid = !manaCost().isMoreThan(caster.getCurrentMana());
if (!isValid)
caster.bukkit().sendMessage(ChatColor.RED + "You don't have enough mana to cast this spell!");
return isValid;
}
public void applyEffects(final List<Entity> targets, final Caster caster)
{
targets.stream()
.filter(LivingEntity.class::isInstance)
.map(LivingEntity.class::cast)
.forEach(entity -> applyEffectsIndividually(
getSpellEffects(),
entity,
caster));
}
public Entity prepareProjectile(final Caster caster, final Material visual)
{
final double expMod = getLevelRequirement().getExperienceMarker();
final Player player = caster.bukkit();
final Location location = player.getLocation().clone().add(0, player.getEyeHeight(), 0);
final Vector velocity = player.getLocation().getDirection().multiply(2);
final Entity projectile = createProjectile(visual, player.getWorld(), location,
velocity);
caster.removeMana(manaCost().getManaCost());
caster.addExperience(random().nextDouble(expMod * 0.25));
return projectile;
}
public void tracer(final World world, final Location location, final Particle particle)
{
world.spawnParticle(particle,
location,
0,
random().nextDouble(-2, 2),
random().nextDouble(-2, 2),
random().nextDouble(-2, 2));
}
private void applyEffectsIndividually(final SpellEffect[] effects, final LivingEntity target,
final Caster caster)
{
for (final SpellEffect effect : effects)
effect.apply(target, caster);
}
private static ItemDisplay createProjectile(final Material visual, final World world, final Location location,
final Vector velocity)
{
final ItemDisplay display = (ItemDisplay) world.spawnEntity(location, EntityType.ITEM_DISPLAY);
display.setItemStack(new ItemStack(visual));
display.setGravity(true);
display.setPersistent(false);
display.setSilent(true);
display.setShadowRadius(0);
display.setShadowStrength(0);
display.setVelocity(velocity);
return display;
}
}

View File

@ -1,23 +1,47 @@
package app.simplexdev.arcanumocculta.api.spell; package app.simplexdev.arcanumocculta.api.spell;
import app.simplexdev.arcanumocculta.api.effect.Effect; import app.simplexdev.arcanumocculta.api.caster.Caster;
import app.simplexdev.arcanumocculta.api.effect.EffectProvider; import app.simplexdev.arcanumocculta.api.caster.CasterLevel;
import org.bukkit.entity.Projectile; import app.simplexdev.arcanumocculta.api.spell.enums.Damages;
import app.simplexdev.arcanumocculta.api.spell.enums.Durations;
import app.simplexdev.arcanumocculta.api.spell.enums.ManaCosts;
import app.simplexdev.arcanumocculta.api.wand.Wand;
import java.util.UUID;
import java.time.Duration; public interface Spell
{
String getName();
public interface Spell<T extends Effect> { String getId();
String getSpellName();
String getSpellDescription(); default UUID getUniqueId()
{
double getManaCost(); return UUID.nameUUIDFromBytes(this.getName().getBytes());
}
Duration getCoolDown();
String getDescription();
int getSpellLevel();
CasterLevel getLevelRequirement();
SpellProjectile<? extends Projectile> getSpellProjectile();
Damages baseDamage();
T getEffect();
SpellEffect[] getSpellEffects();
Durations effectDuration();
ManaCosts manaCost();
long coolDown();
boolean isUnlocked(final Caster caster);
void cast(final Caster caster, final Wand wand);
/**
* Used to create a copy of the spell for player spell books.
* Should only ever be used by the primary list when initializing a player's spell book.
*
* @return a copy of the spell.
*/
Spell dupe();
} }

View File

@ -0,0 +1,10 @@
package app.simplexdev.arcanumocculta.api.spell;
import app.simplexdev.arcanumocculta.api.caster.Caster;
import org.bukkit.entity.LivingEntity;
@FunctionalInterface
public interface SpellEffect
{
void apply(final LivingEntity target, final Caster caster);
}

View File

@ -1,18 +0,0 @@
package app.simplexdev.arcanumocculta.api.spell;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import java.util.List;
public interface SpellProjectile<T extends Projectile> {
Class<T> getProjectileType();
List<Particle> getParticles();
void cast(final Location target);
void cast(final LivingEntity target);
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2023 Simplex Development Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* with the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package app.simplexdev.arcanumocculta.api.spell.enums;
public enum Damages
{
MINIMAL(0.5),
LIGHT(1.0),
NEUTRAL(1.5),
MODERATE(2.0),
INTERMEDIATE(2.5),
HEAVY(3.0),
MAJOR(3.5),
SEVERE(4.0),
EXTREME(4.5),
IMMENSE(5.0),
CRITICAL(6.5),
FATAL(10.0),
OVERKILL(20.0),
DEVASTATION(50.0);
private final double damage;
Damages(double damage)
{
this.damage = damage;
}
public double getDamage()
{
return damage;
}
public double multiply(double multiplier) {
return damage * multiplier;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2023 Simplex Development Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* with the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package app.simplexdev.arcanumocculta.api.spell.enums;
public enum Durations
{
INSTANT(1L),
SHORT(20L),
MEDIUM(20L * 5L),
LONG(20L * 30L),
VERY_LONG(20L * 60L),
AGES(20L * 60L * 5L);
private final long ticks;
Durations(final long ticks)
{
this.ticks = ticks;
}
public long getTicks()
{
return this.ticks;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 Simplex Development Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* with the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package app.simplexdev.arcanumocculta.api.spell.enums;
public enum ManaCosts
{
MINIMAL_CAST(5.0),
LIGHT_CAST(10.0),
MODERATE_CAST(20.0),
HEAVY_CAST(30.0),
MAJOR_CAST(50.0),
EXTREME_CAST(100.0),
IMMENSE_CAST(200.0),
MASTER_CAST(500.0);
private final double manaCost;
ManaCosts(final double manaCost) {
this.manaCost = manaCost;
}
public double getManaCost() {
return manaCost;
}
public boolean isMoreThan(final double manaCost) {
return this.manaCost > manaCost;
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2023 Simplex Development Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* with the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package app.simplexdev.arcanumocculta.api.spell.enums;
// Reference for implementation.
public enum SpellTypes
{
SOUL_PEBBLE, SOUL_SHARD, LARGE_SOUL_SHARD, SOUL_COMET_SHARD, SOUL_COMET, SOUL_SHARD_SPIRAL, SOUL_STARS,
SOUL_STAR_SHOWER, SOUL_ARC, SOUL_BARRAGE, SOUL_BURST, SOUL_CANNON, SOUL_HAMMER, SOUL_BLAST, SOUL_EXPLOSION,
SOUL_LAMP, SOUL_PHALANX, GREAT_SOUL_PHALANX, SOUL_MIST, ARS_NOVA, ARS_ENIGMA, ARS_ULTIMA,
FLAME_SLING, FLAME_BURST, CATCH_FLAME, FLAME_BARRAGE, FIREBALL, METEORITE, METEOR, FLAME_WHIP, FLAME_FAN,
FLAME_ORB, FLAME_PILLARS, FLAME_WHIRLWIND,
WITHER_BURST, WITHER_SHOT, WITHER_SHARD, WITHER_COMET, WITHER_METEORITE,
HEALING, GREATER_HEALING, HEAL_OTHER, HEALING_HANDS, HEALING_WAVE, GUARDIAN_PROTECTION, SAVIORS_BLESSING,
DIVING_BLESSING, DIVINE_GRACE, ULTIMATE_HEALING, DIVINE_INTERVENTION, DIVINE_RETRIBUTION,
LIGHTNING_BOLT, LIGHTNING_STORM, STAR_SHOWER, STORM_CALL, LIGHTNING_BARRAGE;
}

View File

@ -0,0 +1,69 @@
package app.simplexdev.arcanumocculta.api.wand;
import org.bukkit.inventory.ItemStack;
public abstract class AbstractWand implements Wand
{
private final ItemStack item;
private final CapType capType;
private final CoreType coreType;
private final GemType gemType;
private final String name;
private final String description;
protected AbstractWand(String name,
String description, ItemStack item, CapType capType,
CoreType coreType, GemType gemType)
{
this.name = name;
this.description = description;
this.item = item;
this.capType = capType;
this.coreType = coreType;
this.gemType = gemType;
}
@Override
public String getName()
{
return name;
}
@Override
public String getDescription()
{
return description;
}
@Override
public ItemStack getItem()
{
return item;
}
@Override
public double getSpellBonus()
{
return getCapType().getSpellBoost()
+ getCoreType().getSpellBoost()
+ getGemType().getSpellBoost();
}
@Override
public CapType getCapType()
{
return capType;
}
@Override
public CoreType getCoreType()
{
return coreType;
}
@Override
public GemType getGemType()
{
return gemType;
}
}

View File

@ -0,0 +1,28 @@
package app.simplexdev.arcanumocculta.api.wand;
import org.bukkit.Material;
public enum CapType
{
IRON(Material.IRON_NUGGET, 1.0),
GOLD(Material.GOLD_NUGGET, 2.5),
DIAMOND(Material.DIAMOND, 3.0),
OBSIDIAN(Material.OBSIDIAN, 4.5),
NETHERITE(Material.NETHERITE_INGOT, 6.0);
private final Material material;
private final double spellBoost;
CapType(final Material material, final double spellBoost) {
this.material = material;
this.spellBoost = spellBoost;
}
public final Material getMaterial() {
return this.material;
}
public final double getSpellBoost() {
return this.spellBoost;
}
}

View File

@ -0,0 +1,32 @@
package app.simplexdev.arcanumocculta.api.wand;
import org.bukkit.Material;
public enum CoreType
{
WOOD(Material.STICK, 1.0),
IRON(Material.IRON_INGOT, 1.25),
GOLD(Material.GOLD_INGOT, 1.5),
OBSIDIAN(Material.OBSIDIAN, 1.75),
BLAZE(Material.BLAZE_ROD, 2.0),
ENDER(Material.END_ROD, 2.5);
private final Material material;
private final double spellBoost;
CoreType(final Material material, final double spellBoost)
{
this.spellBoost = spellBoost;
this.material = material;
}
public Material getMaterial()
{
return this.material;
}
public double getSpellBoost()
{
return spellBoost;
}
}

View File

@ -0,0 +1,32 @@
package app.simplexdev.arcanumocculta.api.wand;
import org.bukkit.Material;
public enum GemType
{
NONE(Material.AIR, 1.0),
LAPIS(Material.LAPIS_LAZULI, 1.25),
REDSTONE(Material.REDSTONE, 1.5),
EMERALD(Material.EMERALD, 2.0),
DIAMOND(Material.DIAMOND, 3.0),
QUARTZ(Material.QUARTZ, 4.0);
private final Material material;
private final double spellBoost;
GemType(final Material material, final double spellBoost)
{
this.spellBoost = spellBoost;
this.material = material;
}
public Material getMaterial()
{
return this.material;
}
public double getSpellBoost()
{
return spellBoost;
}
}

View File

@ -0,0 +1,20 @@
package app.simplexdev.arcanumocculta.api.wand;
import org.bukkit.inventory.ItemStack;
public interface Wand
{
String getName();
String getDescription();
ItemStack getItem();
double getSpellBonus();
CapType getCapType();
CoreType getCoreType();
GemType getGemType();
}

View File

@ -0,0 +1,19 @@
package app.simplexdev.arcanumocculta.base;
import app.simplexdev.arcanumocculta.api.caster.AbstractCaster;
import app.simplexdev.arcanumocculta.api.caster.CasterLevel;
import app.simplexdev.arcanumocculta.api.caster.SpellBook;
import app.simplexdev.arcanumocculta.api.wand.Wand;
import org.bukkit.entity.Player;
public class SimpleCaster extends AbstractCaster
{
public SimpleCaster(Player player, Wand wand,
SpellBook spellBook,
CasterLevel level)
{
super(player, wand, spellBook, level);
}
}

View File

@ -0,0 +1,7 @@
package app.simplexdev.arcanumocculta.base;
import app.simplexdev.arcanumocculta.api.caster.AbstractSpellBook;
public class SimpleSpellBook extends AbstractSpellBook
{
}

View File

@ -0,0 +1,18 @@
package app.simplexdev.arcanumocculta.base;
import app.simplexdev.arcanumocculta.api.wand.AbstractWand;
import app.simplexdev.arcanumocculta.api.wand.CapType;
import app.simplexdev.arcanumocculta.api.wand.CoreType;
import app.simplexdev.arcanumocculta.api.wand.GemType;
import org.bukkit.inventory.ItemStack;
public class SimpleWand extends AbstractWand
{
public SimpleWand(String name, String description, ItemStack item,
CapType capType,
CoreType coreType,
GemType gemType)
{
super(name, description, item, capType, coreType, gemType);
}
}

View File

@ -1,99 +0,0 @@
package app.simplexdev.arcanumocculta.base.book;
import app.simplexdev.arcanumocculta.api.book.SpellBook;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractSpellBook implements SpellBook {
private final List<Spell> spellbook = new ArrayList<>();
private String name;
private String description;
private ItemStack itemStack;
protected AbstractSpellBook(final String name) {
this.name = name;
this.description = ChatColor.BLUE + "A simple spell book.";
final ItemStack stack = new ItemStack(Material.WRITTEN_BOOK, 1);
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
meta.setDisplayName(name);
meta.setLore(List.of(description));
stack.setItemMeta(meta);
}
this.itemStack = stack;
}
@Override
public String getBookName() {
return name;
}
@Override
public void setBookName(String name) {
this.name = name;
}
@Override
public String getBookDescription() {
return description;
}
@Override
public void setBookDescription(String description) {
this.description = description;
}
@Override
public ItemStack getBookItem() {
return itemStack;
}
@Override
public void setBookItem(final ItemStack stack) {
this.itemStack = stack;
}
@Override
public List<Spell> getSpells() {
return this.spellbook;
}
@Override
public void addSpell(Spell spell) {
this.spellbook.add(spell);
}
@Override
public void removeSpell(Spell spell) {
this.spellbook.remove(spell);
}
@Override
public Spell getSpell(String name) {
return getSpells()
.stream()
.filter(spell -> spell.getSpellName().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
}
@Override
public Spell getSpell(int index) {
return getSpells().get(index);
}
@Override
public int getSpellCount() {
return getSpells().size();
}
}

View File

@ -1,50 +0,0 @@
package app.simplexdev.arcanumocculta.base.book;
import app.simplexdev.arcanumocculta.api.book.SpellTome;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.List;
public abstract class AbstractSpellTome implements SpellTome {
private final Spell containedSpell;
private final String name;
private final String description;
private final ItemStack item;
protected AbstractSpellTome(final String name, final String description, final Spell containedSpell) {
this.containedSpell = containedSpell;
this.name = name;
this.description = description;
final ItemStack stack = new ItemStack(Material.BOOK, 1);
final ItemMeta meta = stack.getItemMeta();
if (meta != null) {
meta.setDisplayName(name);
meta.setLore(List.of(description));
stack.setItemMeta(meta);
}
this.item = stack;
}
@Override
public String getTomeName() {
return this.name;
}
@Override
public String getTomeDescription() {
return this.description;
}
@Override
public ItemStack getTomeItem() {
return this.item;
}
@Override
public Spell getContainedSpell() {
return this.containedSpell;
}
}

View File

@ -1,40 +0,0 @@
package app.simplexdev.arcanumocculta.base.effect;
import app.simplexdev.arcanumocculta.api.effect.CompoundEffect;
import org.bukkit.potion.PotionEffectType;
import java.time.Duration;
public abstract class AbstractCompoundEffect extends AbstractEffect implements CompoundEffect {
private final PotionEffectType[] effectTypes;
protected AbstractCompoundEffect(Duration duration, float amplifier, boolean ambient, boolean forceDisplay, PotionEffectType... effectTypes) {
super(duration, amplifier, ambient, forceDisplay);
this.effectTypes = effectTypes;
}
protected AbstractCompoundEffect(Duration duration, float amplifier, boolean forceDisplay, PotionEffectType... effectTypes) {
super(duration, amplifier, forceDisplay);
this.effectTypes = effectTypes;
}
protected AbstractCompoundEffect(Duration duration, float amplifier, PotionEffectType... effectTypes) {
super(duration, amplifier);
this.effectTypes = effectTypes;
}
protected AbstractCompoundEffect(Duration duration, PotionEffectType... effectTypes) {
super(duration);
this.effectTypes = effectTypes;
}
protected AbstractCompoundEffect(PotionEffectType... effectTypes) {
super();
this.effectTypes = effectTypes;
}
@Override
public PotionEffectType[] getEffectTypes() {
return new PotionEffectType[0];
}
}

View File

@ -1,55 +0,0 @@
package app.simplexdev.arcanumocculta.base.effect;
import app.simplexdev.arcanumocculta.api.effect.Effect;
import java.time.Duration;
public abstract class AbstractEffect implements Effect {
private final Duration duration;
private final float amplifier;
private final boolean ambient;
private final boolean forceDisplay;
protected AbstractEffect(Duration duration, float amplifier, boolean ambient, boolean forceDisplay) {
this.duration = duration;
this.amplifier = amplifier;
this.ambient = ambient;
this.forceDisplay = forceDisplay;
}
protected AbstractEffect(Duration duration, float amplifier, boolean forceDisplay) {
this(duration, amplifier, false, forceDisplay);
}
protected AbstractEffect(Duration duration, float amplifier) {
this(duration, amplifier, false, false);
}
protected AbstractEffect(Duration duration) {
this(duration, 1, false, false);
}
protected AbstractEffect() {
this(Duration.ofSeconds(5L), 1, false, false);
}
@Override
public Duration getDuration() {
return duration;
}
@Override
public float getAmplifier() {
return amplifier;
}
@Override
public boolean isAmbient() {
return ambient;
}
@Override
public boolean forceDisplay() {
return forceDisplay;
}
}

View File

@ -1,53 +0,0 @@
package app.simplexdev.arcanumocculta.base.effect;
import app.simplexdev.arcanumocculta.api.effect.PassiveEffect;
import app.simplexdev.arcanumocculta.api.effect.PassiveEffects;
import app.simplexdev.arcanumocculta.api.player.Caster;
import java.time.Duration;
public abstract class AbstractPassiveEffect extends AbstractEffect implements PassiveEffect {
private final Caster wandHolder;
private final 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;
}
public AbstractPassiveEffect(Duration duration, float amplifier, boolean forceDisplay, Caster wandHolder, PassiveEffects passiveEffect) {
super(duration, amplifier, forceDisplay);
this.wandHolder = wandHolder;
this.passiveEffect = passiveEffect;
}
protected AbstractPassiveEffect(Duration duration, float amplifier, Caster wandHolder, PassiveEffects passiveEffect) {
super(duration, amplifier);
this.wandHolder = wandHolder;
this.passiveEffect = passiveEffect;
}
protected AbstractPassiveEffect(Duration duration, Caster wandHolder, PassiveEffects passiveEffect) {
super(duration);
this.wandHolder = wandHolder;
this.passiveEffect = passiveEffect;
}
protected AbstractPassiveEffect(Caster wandHolder, PassiveEffects passiveEffect) {
super();
this.wandHolder = wandHolder;
this.passiveEffect = passiveEffect;
}
@Override
public Caster getWandHolder() {
return wandHolder;
}
@Override
public PassiveEffects getPassiveEffect() {
return passiveEffect;
}
}

View File

@ -1,40 +0,0 @@
package app.simplexdev.arcanumocculta.base.effect;
import app.simplexdev.arcanumocculta.api.effect.SpellEffect;
import org.bukkit.potion.PotionEffectType;
import java.time.Duration;
public abstract class AbstractSpellEffect extends AbstractEffect implements SpellEffect {
private final PotionEffectType effectType;
protected AbstractSpellEffect(Duration duration, float amplifier, boolean ambient, boolean forceDisplay, PotionEffectType effectType) {
super(duration, amplifier, ambient, forceDisplay);
this.effectType = effectType;
}
protected AbstractSpellEffect(Duration duration, float amplifier, boolean forceDisplay, PotionEffectType effectType) {
super(duration, amplifier, forceDisplay);
this.effectType = effectType;
}
protected AbstractSpellEffect(Duration duration, float amplifier, PotionEffectType effectType) {
super(duration, amplifier);
this.effectType = effectType;
}
protected AbstractSpellEffect(Duration duration, PotionEffectType effectType) {
super(duration);
this.effectType = effectType;
}
protected AbstractSpellEffect(PotionEffectType effectType) {
super();
this.effectType = effectType;
}
@Override
public PotionEffectType getEffectType() {
return effectType;
}
}

View File

@ -1,124 +0,0 @@
package app.simplexdev.arcanumocculta.base.player;
import app.simplexdev.arcanumocculta.api.book.SpellBook;
import app.simplexdev.arcanumocculta.api.player.Caster;
import app.simplexdev.arcanumocculta.api.player.SpellResistance;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public abstract class AbstractCaster implements Caster {
private final String name;
private final UUID uuid;
private final SpellBook spellBook;
private final List<SpellResistance> spellResistances = new ArrayList<>();
private double maximumMana;
private double currentMana;
protected AbstractCaster(final Player player, SpellBook spellBook) {
this.name = player.getName();
this.uuid = player.getUniqueId();
this.spellBook = spellBook;
this.maximumMana = 20;
this.currentMana = maximumMana;
}
@Override
public UUID getCasterUUID() {
return uuid;
}
@Override
public String getDisplayName() {
return name;
}
@Override
public double getMaximumMana() {
return maximumMana;
}
@Override
public void setMaximumMana(double mana) {
this.maximumMana = mana;
}
@Override
public double getCurrentMana() {
return currentMana;
}
@Override
public double addMana(double mana) {
this.currentMana += mana;
return getCurrentMana();
}
@Override
public double increaseMaximumMana(double mana) {
this.maximumMana += mana;
return getMaximumMana();
}
@Override
public double removeMana(double mana) {
final double newMana = currentMana - mana;
if (newMana < 0) {
currentMana = 0;
} else {
currentMana = newMana;
}
return getCurrentMana();
}
@Override
public double decreaseMaximumMana(double mana) {
final double newMana = maximumMana - mana;
if (newMana < 0) {
maximumMana = 0;
} else {
maximumMana = newMana;
}
return getMaximumMana();
}
@Override
public void setMana(double mana) {
if (mana > getMaximumMana()) {
currentMana = getMaximumMana();
} else if (mana < 0) {
currentMana = 0;
} else {
currentMana = mana;
}
}
@Override
public SpellBook getSpellbook() {
return spellBook;
}
@Override
public List<SpellResistance> getSpellResistances() {
return spellResistances;
}
@Override
public void addSpellResistance(SpellResistance resistance) {
this.spellResistances.add(resistance);
}
@Override
public void removeSpellResistance(SpellResistance resistance) {
this.spellResistances.remove(resistance);
}
@Override
public boolean hasResistance(int ordinal) {
return getSpellResistances().stream().anyMatch(resistance -> resistance.getOrdinal() == ordinal);
}
}

View File

@ -1,48 +0,0 @@
package app.simplexdev.arcanumocculta.base.player;
import app.simplexdev.arcanumocculta.api.effect.PassiveEffect;
import app.simplexdev.arcanumocculta.api.player.Wand;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractWand implements Wand {
private final List<PassiveEffect> passiveEffects = new ArrayList<>();
private String name;
private String description;
private ItemStack item;
private double manaPenalty;
protected AbstractWand(String name, String description, ItemStack item, double manaPenalty) {
this.name = name;
this.description = description;
this.item = item;
this.manaPenalty = manaPenalty;
}
@Override
public String getWandName() {
return name;
}
@Override
public String getWandDescription() {
return description;
}
@Override
public ItemStack getWandItem() {
return item;
}
@Override
public double getManaPenalty() {
return manaPenalty;
}
@Override
public List<PassiveEffect> getPassiveEffects() {
return passiveEffects;
}
}

View File

@ -1,30 +0,0 @@
package app.simplexdev.arcanumocculta.base.player;
import app.simplexdev.arcanumocculta.api.player.SpellResistance;
public class SimpleSpellResistance implements SpellResistance {
private final String name;
private final double resistance;
private final int ordinal;
public SimpleSpellResistance(String spellName, double resistance, int ordinal) {
this.name = spellName;
this.resistance = resistance;
this.ordinal = ordinal;
}
@Override
public String getSpellName() {
return name;
}
@Override
public double getResistance() {
return resistance;
}
@Override
public int getOrdinal() {
return ordinal;
}
}

View File

@ -1,68 +0,0 @@
package app.simplexdev.arcanumocculta.base.spell;
import app.simplexdev.arcanumocculta.api.effect.Effect;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import java.time.Duration;
public abstract class AbstractSpell<T extends Effect> implements Spell<T> {
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 name;
}
@Override
public String getSpellDescription() {
return description;
}
@Override
public double getManaCost() {
return manaCost;
}
@Override
public Duration getCoolDown() {
return coolDown;
}
@Override
public int getSpellLevel() {
return spellLevel;
}
@Override
public T getEffect() {
return spellEffect;
}
}

View File

@ -1,143 +0,0 @@
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<T extends Projectile> implements SpellProjectile<T> {
private static final List<EntityType> 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<T> projectile;
private final List<Particle> particles;
private final Caster caster;
private final Spell<?> spell;
protected AbstractSpellProjectile(final Spell<?> spell, final Caster caster, final Class<T> projectile, final Particle... particles) {
this.projectile = projectile;
this.particles = Arrays.asList(particles);
this.caster = caster;
this.spell = spell;
}
@Override
public Class<T> getProjectileType() {
return projectile;
}
@Override
public List<Particle> 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<PotionEffect> 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<PotionEffect> 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);
}
}
}

View File

@ -0,0 +1,45 @@
package app.simplexdev.arcanumocculta.cooldown;
import app.simplexdev.arcanumocculta.api.caster.Caster;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CooldownService
{
private final Map<Caster, List<CooldownStatus>> cooldowns = new HashMap<>();
public void tick()
{
cooldowns.forEach((c, sl) -> {
sl.removeIf(CooldownStatus::hasExpired);
if (sl.isEmpty()) cooldowns.remove(c);
});
}
public void include(final Caster caster, final CooldownStatus status)
{
List<CooldownStatus> statuses = cooldowns.get(caster);
if (status == null) statuses = new ArrayList<>();
statuses.add(status);
cooldowns.put(caster, statuses);
}
public void exclude(final CooldownStatus status)
{
cooldowns.forEach((c, sl) -> sl.removeIf(s -> s.getSpellUUID().equals(status.getSpellUUID())));
}
public boolean isOnCooldown(final Spell spell)
{
tick();
return cooldowns.values()
.stream()
.flatMap(List::stream)
.anyMatch(status -> status.getSpellUUID().equals(spell.getUniqueId()));
}
}

View File

@ -0,0 +1,31 @@
package app.simplexdev.arcanumocculta.cooldown;
import java.time.Duration;
import java.time.Instant;
import java.util.UUID;
public class CooldownStatus
{
private final Duration duration;
private final Instant currentTime;
private final Instant endTime;
private final UUID spellUUID;
public CooldownStatus(final UUID spellUUID, final Duration duration)
{
this.duration = duration;
this.currentTime = Instant.now();
this.endTime = this.currentTime.plus(duration);
this.spellUUID = spellUUID;
}
public UUID getSpellUUID()
{
return spellUUID;
}
public boolean hasExpired()
{
return Instant.now().isAfter(this.endTime);
}
}

View File

@ -1,23 +0,0 @@
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<FireballEffect> {
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);
}
}

View File

@ -1,12 +0,0 @@
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);
}
}

View File

@ -1,15 +0,0 @@
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<Fireball> {
public FireballProjectile(FireballSpell spell,
Caster caster) {
super(spell, caster, Fireball.class, Particle.FLAME, Particle.SMALL_FLAME, Particle.LAVA);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2023 Simplex Development Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* with the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package app.simplexdev.arcanumocculta.spells;
import app.simplexdev.arcanumocculta.api.caster.AbstractSpellBook;
import app.simplexdev.arcanumocculta.api.spell.AbstractSpell;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import app.simplexdev.arcanumocculta.util.SpellUtils;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
public class PrimarySpellList extends AbstractSpellBook
{
public PrimarySpellList()
{
Set<Class<? extends AbstractSpell>> spellClasses = m0().getSubTypesOf(AbstractSpell.class);
final Set<Spell> v0 = new HashSet<>();
spellClasses.forEach(spellClass ->
{
try
{
final Spell spell = spellClass.getDeclaredConstructor().newInstance();
v0.add(spell);
}
catch (ReflectiveOperationException e)
{
Bukkit.getLogger().severe(e.getMessage());
}
});
this.addAll(v0);
}
private Reflections m0()
{
final Reflections v0 = new Reflections(SpellUtils.SPELL_PACKAGE + ".flame",
Scanners.SubTypes);
final Reflections v1 = new Reflections(SpellUtils.SPELL_PACKAGE + ".soul",
Scanners.SubTypes);
final Reflections v2 = new Reflections(SpellUtils.SPELL_PACKAGE + ".wither", Scanners.SubTypes);
return v0.merge(v1).merge(v2);
}
}

View File

@ -0,0 +1,63 @@
package app.simplexdev.arcanumocculta.spells.soul;
import app.simplexdev.arcanumocculta.api.caster.Caster;
import app.simplexdev.arcanumocculta.api.caster.CasterLevel;
import app.simplexdev.arcanumocculta.api.spell.AbstractSpell;
import app.simplexdev.arcanumocculta.api.spell.SpellEffect;
import app.simplexdev.arcanumocculta.api.spell.enums.Damages;
import app.simplexdev.arcanumocculta.api.spell.enums.Durations;
import app.simplexdev.arcanumocculta.api.spell.enums.ManaCosts;
import app.simplexdev.arcanumocculta.api.wand.Wand;
import app.simplexdev.arcanumocculta.util.SpellUtils;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.entity.Entity;
public final class SoulPebble extends AbstractSpell
{
public SoulPebble()
{
super("Soul Pebble",
"soul_pebble",
"Fires a small soul pebble",
CasterLevel.APPRENTICE,
Damages.MINIMAL,
Durations.INSTANT,
ManaCosts.MINIMAL_CAST,
5L);
}
@Override
public SpellEffect[] getSpellEffects()
{
final SpellEffect[] effects = new SpellEffect[1];
effects[0] = SpellUtils.soulEffectBase(baseDamage());
return effects;
}
@Override
public void cast(Caster caster, Wand wand)
{
if (!this.checkManaCosts(caster))
{
return;
}
final Entity projectile = prepareProjectile(caster, Material.AIR);
while (!projectile.isOnGround() || !projectile.isDead())
{
tracer(projectile.getWorld(), projectile.getLocation(), Particle.SOUL);
if (!projectile.getNearbyEntities(1, 1, 1).isEmpty())
{
applyEffects(projectile.getNearbyEntities(1, 1, 1),
caster);
projectile.remove();
}
if (projectile.isOnGround())
projectile.remove();
}
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2023 Simplex Development Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* with the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package app.simplexdev.arcanumocculta.spells.soul;
import app.simplexdev.arcanumocculta.api.caster.Caster;
import app.simplexdev.arcanumocculta.api.caster.CasterLevel;
import app.simplexdev.arcanumocculta.api.spell.AbstractSpell;
import app.simplexdev.arcanumocculta.api.spell.enums.Damages;
import app.simplexdev.arcanumocculta.api.spell.enums.Durations;
import app.simplexdev.arcanumocculta.api.spell.SpellEffect;
import app.simplexdev.arcanumocculta.api.spell.enums.ManaCosts;
import app.simplexdev.arcanumocculta.api.wand.Wand;
import app.simplexdev.arcanumocculta.util.SpellUtils;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
public final class SoulShard extends AbstractSpell
{
public SoulShard()
{
super("Soul Shard",
"soul_shard",
"A larger version of soul pebble.",
CasterLevel.APPRENTICE, Damages.LIGHT,
Durations.INSTANT, ManaCosts.LIGHT_CAST,
5L);
}
@Override
public SpellEffect[] getSpellEffects()
{
final SpellEffect[] effects = new SpellEffect[1];
effects[0] = SpellUtils.soulEffectBase(baseDamage());
return effects;
}
@Override
public void cast(Caster caster, Wand wand)
{
if (!this.checkManaCosts(caster))
{
return;
}
final Entity projectile = prepareProjectile(caster, Material.AIR);
while (!projectile.isDead()) {
for (int i = 0; i < 3; i++) {
tracer(projectile.getWorld(), projectile.getLocation(), Particle.SOUL);
}
if (!projectile.getNearbyEntities(1, 1, 1).isEmpty())
{
applyEffects(projectile.getNearbyEntities(1, 1, 1),
caster);
projectile.remove();
}
if (projectile.isOnGround()) {
projectile.remove();
}
}
}
}

View File

@ -0,0 +1,95 @@
package app.simplexdev.arcanumocculta.storage.local;
import app.simplexdev.arcanumocculta.ArcanumOcculta;
import app.simplexdev.arcanumocculta.api.caster.Caster;
import app.simplexdev.arcanumocculta.api.caster.CasterLevel;
import app.simplexdev.arcanumocculta.api.caster.SpellBook;
import app.simplexdev.arcanumocculta.api.wand.CapType;
import app.simplexdev.arcanumocculta.api.wand.CoreType;
import app.simplexdev.arcanumocculta.api.wand.GemType;
import app.simplexdev.arcanumocculta.api.wand.Wand;
import app.simplexdev.arcanumocculta.base.SimpleCaster;
import app.simplexdev.arcanumocculta.base.SimpleSpellBook;
import app.simplexdev.arcanumocculta.base.SimpleWand;
import app.simplexdev.arcanumocculta.util.SpellUtils;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class PlayerYaml
{
private final YamlHolder yamlHolder;
public PlayerYaml(final ArcanumOcculta plugin, final String name)
{
this.yamlHolder = new YamlHolder(plugin, "player-default.yml", name, plugin.getDataFolder(), false);
}
public YamlHolder getYamlHolder()
{
return yamlHolder;
}
public Wand retrieveWand()
{
ConfigurationSection wandSection = yamlHolder.getConfigurationSection("wand");
String name = wandSection.getString("name");
String description = wandSection.getString("description");
Material material = Material.getMaterial(wandSection.getString("item"));
CoreType core = CoreType.valueOf(wandSection.getString("core"));
CapType cap = CapType.valueOf(wandSection.getString("cap"));
ItemStack item = new ItemStack(material, 1);
ItemMeta meta = item.getItemMeta();
if (meta != null)
{
meta.setDisplayName(name);
meta.setLore(List.of(description));
item.setItemMeta(meta);
}
GemType gem = GemType.valueOf(wandSection.getString("gem"));
return new SimpleWand(name, description, item, cap, core, gem);
}
public void saveWand(final Wand wand)
{
ConfigurationSection wandSection = yamlHolder.getConfigurationSection("wand");
wandSection.set("name", wand.getName());
wandSection.set("description", wand.getDescription());
wandSection.set("item", wand.getItem().getType().name());
wandSection.set("core", wand.getCoreType().name());
wandSection.set("cap", wand.getCapType().name());
wandSection.set("gem", wand.getGemType().name());
yamlHolder.save();
}
public Caster fetchCaster(final Player player)
{
ConfigurationSection caster = yamlHolder.getConfigurationSection("caster");
CasterLevel level = CasterLevel.fromOrdinal(caster.getInt("caster_rank"));
double xp = caster.getDouble("current_experience");
double currentMana = caster.getDouble("current_mana");
double maxMana = caster.getDouble("max_mana");
final Wand wand = retrieveWand();
final SpellBook spellBook = retrieveSpellBook();
Caster c = new SimpleCaster(player, wand, spellBook, level);
c.setCurrentExperience(xp);
c.setCurrentMana(currentMana);
c.setMaxMana(maxMana);
return c;
}
public SpellBook retrieveSpellBook()
{
final SpellBook book = new SimpleSpellBook();
List<String> spellBook = yamlHolder.getStringList("spellbook");
for (String spell : spellBook)
{
book.addSpell(SpellUtils.copyFromPrimaryList(spell));
}
return book;
}
}

View File

@ -0,0 +1,106 @@
package app.simplexdev.arcanumocculta.storage.local;
import app.simplexdev.arcanumocculta.ArcanumOcculta;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
public class YamlHolder
{
private final YamlConfiguration configuration;
private final ArcanumOcculta plugin;
public YamlHolder(final ArcanumOcculta plugin, final String resourceLocation, final String fileName,
final File parentFolder,
final boolean copyDefaults)
{
final File file = new File(parentFolder, fileName);
this.plugin = plugin;
try
{
if (file.createNewFile() || copyDefaults)
{
final String creatingFile = String.format("Creating %s...", fileName);
plugin.getLogger().info(creatingFile);
plugin.saveResource(resourceLocation, true);
}
}
catch (IOException ex)
{
plugin.getLogger().severe(ex.getMessage());
}
this.configuration = YamlConfiguration.loadConfiguration(file);
}
public String getString(final String path)
{
return this.configuration.getString(path);
}
public boolean getBoolean(final String path)
{
return this.configuration.getBoolean(path);
}
public int getInt(final String path)
{
return this.configuration.getInt(path);
}
public double getDouble(final String path)
{
return this.configuration.getDouble(path);
}
public ConfigurationSection getConfigurationSection(final String path)
{
return this.configuration.getConfigurationSection(path);
}
public List<String> getStringList(final String path)
{
return this.configuration.getStringList(path);
}
public void set(final String path, final Object value)
{
this.configuration.set(path, value);
}
public void save()
{
try
{
this.configuration.save(this.configuration.getCurrentPath());
}
catch (IOException ex)
{
final String message = MessageFormat.format("Failed to save {0}!", this.configuration.getCurrentPath());
plugin.getLogger().severe(message);
}
}
public void load()
{
try
{
this.configuration.load(this.configuration.getCurrentPath());
}
catch (IOException | org.bukkit.configuration.InvalidConfigurationException ex)
{
final String message = MessageFormat.format("Failed to load {0}!", this.configuration.getCurrentPath());
plugin.getLogger().severe(message);
}
}
public void reload()
{
this.save();
this.load();
}
}

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2023 Simplex Development Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* with the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package app.simplexdev.arcanumocculta.util;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import app.simplexdev.arcanumocculta.api.spell.SpellEffect;
import app.simplexdev.arcanumocculta.api.spell.enums.Damages;
import app.simplexdev.arcanumocculta.spells.PrimarySpellList;
import java.util.SplittableRandom;
import org.bukkit.Particle;
import org.bukkit.entity.Damageable;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
public final class SpellUtils
{
public static final String SPELL_PACKAGE = PrimarySpellList.class.getPackageName();
private static final PrimarySpellList primarySpellList = new PrimarySpellList();
private static final SplittableRandom RANDOM = new SplittableRandom();
private SpellUtils()
{
throw new AssertionError();
}
public static void damage(final Damageable target, final LivingEntity damager, final double damage)
{
if (target instanceof Player)
target.damage(damage % 20.0, damager);
else
target.damage(damage);
}
public static Spell copyFromPrimaryList(final String id)
{
return SpellUtils.primarySpellList.getSpell(id).dupe();
}
public static SpellEffect soulEffectBase(final Damages baseDamage)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
if (target instanceof Player player)
// Player is freezing when hit, as if they were in powdered snow for 1 minute.
player.setFreezeTicks(1200);
damage(target, caster.bukkit(), damage);
};
}
public static SpellEffect flameEffectBase(final Damages baseDamage)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
// Fire ticks for 15 seconds.
target.setFireTicks(300);
damage(target, caster.bukkit(), damage);
};
}
public static SpellEffect witherEffectBase(final Damages baseDamage)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
// Wither for 10 seconds.
target.addPotionEffect(PotionEffectType.WITHER.createEffect(200, 2));
damage(target, caster.bukkit(), damage);
};
}
public static SpellEffect lightningEffectBase(final Damages baseDamage)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
// Lightning on target
target.getWorld().strikeLightning(target.getLocation());
damage(target, caster.bukkit(), damage);
};
}
public static SpellEffect healEffectBase(final Damages baseDamage)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
// Heal target
target.setHealth(target.getHealth() + damage);
};
}
public static SpellEffect regenEffectBase(final Damages baseDamage)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
// Regen target
target.addPotionEffect(PotionEffectType.REGENERATION.createEffect(300, 3));
target.setHealth(target.getHealth() + ((target.getHealth() + damage) / 2));
};
}
public static SpellEffect meteorLikeEffectBase(final Damages baseDamage,
final Vector incomingVelocity,
final float size)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
// Meteor like effect
// TODO: Make a configuration option to enable/disable explosions destroying blocks.
target.getWorld().createExplosion(target.getLocation(), size, true, false);
target.setVelocity(incomingVelocity.normalize().multiply(2).multiply(-1));
damage(target, caster.bukkit(), damage);
};
}
public static SpellEffect arsLikeEffectBase(final Damages baseDamage)
{
return (target, caster) ->
{
final var damage = baseDamage.multiply(caster.getWand().getSpellBonus());
// Ars Magica like effect
target.setVelocity(caster.bukkit().getLocation().clone().getDirection().multiply(2));
if (target instanceof Player player)
player.setFreezeTicks(1200);
for (int i = 0; i < 50; i++)
{
target.getWorld().spawnParticle(Particle.SOUL_FIRE_FLAME,
target.getLocation(),
0,
RANDOM.nextDouble(-2, 2),
RANDOM.nextDouble(-2, 2),
RANDOM.nextDouble(-2, 2));
}
damage(target, caster.bukkit(), damage);
};
}
}

View File

@ -0,0 +1,18 @@
caster:
caster_rank: 1
current_experience: 0
current_mana: 100
max_mana: 100
spell_influence: 0
spell_points: 0
spellbook:
- FIREBALL
wand:
name: Basic Wand
description: A basic wand
item: STICK
core: WOOD
gem: NONE
cap: IRON

View File

@ -3,3 +3,5 @@ version: '${version}'
main: app.simplexdev.arcanumocculta.ArcanumOcculta main: app.simplexdev.arcanumocculta.ArcanumOcculta
api-version: '1.20' api-version: '1.20'
load: STARTUP load: STARTUP
libraries:
- org.reflections:reflections:0.10.2