WE ARE BOOLING!!!!!!!!!!!!

This commit is contained in:
Paul Reilly 2023-07-18 13:02:58 -05:00
parent 6776c82149
commit 893ed446c4
12 changed files with 361 additions and 69 deletions

View File

@ -78,4 +78,8 @@ public enum CasterLevel
{
return this.experienceMarker;
}
public boolean isAtLeast(final CasterLevel level) {
return this.getLevel() >= level.getLevel();
}
}

View File

@ -1,6 +1,10 @@
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 java.util.SplittableRandom;
import org.bukkit.Bukkit;
@ -9,17 +13,17 @@ public abstract class AbstractSpell implements Spell
private final String name;
private final String id;
private final String description;
private final int levelRequirement;
private final double baseDamage;
private final long effectDuration;
private final double manaCost;
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 int levelRequirement,
final double baseDamage, final long effectDuration, final double manaCost,
final long coolDown)
final String description, final CasterLevel levelRequirement,
final Damages baseDamage, final Durations effectDuration,
final ManaCosts manaCost, final long coolDown)
{
this.name = name;
this.id = id;
@ -50,25 +54,25 @@ public abstract class AbstractSpell implements Spell
}
@Override
public int getLevelRequirement()
public CasterLevel getLevelRequirement()
{
return levelRequirement;
}
@Override
public double baseDamage()
public Damages baseDamage()
{
return baseDamage;
}
@Override
public long effectDuration()
public Durations effectDuration()
{
return effectDuration;
}
@Override
public double manaCost()
public ManaCosts manaCost()
{
return manaCost;
}
@ -99,7 +103,7 @@ public abstract class AbstractSpell implements Spell
public boolean isUnlocked(Caster caster)
{
return caster.getSpellBook().hasSpell(this)
&& caster.getCurrentLevel().getLevel() >= this.levelRequirement;
&& caster.getCurrentLevel().isAtLeast(this.getLevelRequirement());
}
protected SplittableRandom random()

View File

@ -1,6 +1,10 @@
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.api.wand.Wand;
import java.util.UUID;
@ -17,15 +21,15 @@ public interface Spell
String getDescription();
int getLevelRequirement();
CasterLevel getLevelRequirement();
double baseDamage();
Damages baseDamage();
SpellEffect[] getSpellEffects();
long effectDuration();
Durations effectDuration();
double manaCost();
ManaCosts manaCost();
long coolDown();

View File

@ -1,19 +0,0 @@
package app.simplexdev.arcanumocculta.api.spell;
// 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,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

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

View File

@ -1,15 +1,21 @@
package app.simplexdev.arcanumocculta.spells.soul;
import app.simplexdev.arcanumocculta.util.SpellUtils;
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.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.util.Vector;
public final class SoulPebble extends AbstractSpell
{
@ -18,10 +24,10 @@ public final class SoulPebble extends AbstractSpell
super("Soul Pebble",
"soul_pebble",
"Fires a small soul pebble",
1,
1.0,
1L,
10.0,
CasterLevel.APPRENTICE,
Damages.MINIMAL,
Durations.INSTANT,
ManaCosts.MINIMAL_CAST,
5L);
}
@ -32,7 +38,7 @@ public final class SoulPebble extends AbstractSpell
effects[0] = (target, caster) ->
{
final Wand wand = caster.getWand();
final double damage = wand.getSpellBonus() * this.baseDamage();
final double damage = baseDamage().multiply(wand.getSpellBonus());
SpellUtils.damage(target, caster.bukkit(), damage);
};
@ -42,34 +48,43 @@ public final class SoulPebble extends AbstractSpell
@Override
public void cast(Caster caster, Wand wand)
{
if (this.manaCost() > caster.getCurrentMana())
if (this.manaCost().isMoreThan(caster.getCurrentMana()))
{
caster.bukkit().sendMessage("You do not have enough mana to cast this spell!");
return;
}
final double expMod = this.getLevelRequirement().getExperienceMarker();
final Player player = caster.bukkit();
final double expMod = CasterLevel.fromOrdinal(this.getLevelRequirement()).getExperienceMarker();
final Projectile projectile = player.launchProjectile(Projectile.class);
projectile.setVelocity(player.getLocation().getDirection().multiply(2));
caster.removeMana(this.manaCost());
final Location location = player.getLocation().clone().add(0, player.getEyeHeight(), 0);
final Vector velocity = player.getLocation().getDirection().multiply(2);
final ItemDisplay projectile = SpellUtils.createProjectile(Material.AIR, player.getWorld(), location,
velocity);
caster.removeMana(this.manaCost().getManaCost());
caster.addExperience(random().nextDouble(expMod * 0.25));
while (!projectile.isOnGround() || !projectile.isDead())
{
projectile.getWorld().spawnParticle(Particle.SOUL, projectile.getLocation(), 10,
random().nextGaussian() * 0.8,
random().nextGaussian() * 0.8,
random().nextGaussian() * 0.8);
projectile.getWorld().spawnParticle(Particle.SOUL, projectile.getLocation(), 1,
random().nextGaussian() * 0.2,
random().nextGaussian() * 0.2,
random().nextGaussian() * 0.2);
if (!projectile.getNearbyEntities(1, 1, 1).isEmpty()) {
projectile.getNearbyEntities(1, 1, 1)
.stream()
.filter(LivingEntity.class::isInstance)
.map(LivingEntity.class::cast)
.forEach(entity -> SpellUtils.applyEffects(
this.getSpellEffects(),
entity,
caster));
projectile.remove();
break;
}
}
projectile.getNearbyEntities(1, 1, 1)
.stream()
.filter(LivingEntity.class::isInstance)
.map(LivingEntity.class::cast)
.forEach(entity -> SpellUtils.applyEffects(
this.getSpellEffects(),
entity,
caster));
if (projectile.isOnGround()) projectile.remove();
}
}

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.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;
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()
{
return new SpellEffect[0];
}
@Override
public void cast(Caster caster, Wand wand)
{
}
}

View File

@ -26,9 +26,16 @@ import app.simplexdev.arcanumocculta.api.caster.Caster;
import app.simplexdev.arcanumocculta.api.spell.Spell;
import app.simplexdev.arcanumocculta.api.spell.SpellEffect;
import app.simplexdev.arcanumocculta.spells.PrimarySpellList;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Damageable;
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 final class SpellUtils
{
@ -54,7 +61,22 @@ public final class SpellUtils
effect.apply(target, caster);
}
public static Spell copyFromPrimaryList(final String id) {
public static Spell copyFromPrimaryList(final String id)
{
return SpellUtils.primarySpellList.getSpell(id).dupe();
}
public 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;
}
}