mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-30 16:28:00 +01:00
Further work on spell traits and clean up how projectile spells are handled
This commit is contained in:
parent
33476f2ed8
commit
2890bc3e07
22 changed files with 204 additions and 150 deletions
|
@ -8,8 +8,8 @@ import com.google.common.collect.Streams;
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.item.AmuletItem;
|
import com.minelittlepony.unicopia.item.AmuletItem;
|
||||||
import com.minelittlepony.unicopia.item.GemstoneItem;
|
import com.minelittlepony.unicopia.item.GemstoneItem;
|
||||||
|
@ -109,13 +109,13 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TypedActionResult<SpellType<?>> newSpell = getNewSpell(player);
|
TypedActionResult<CustomisedSpellType<?>> newSpell = getNewSpell(player);
|
||||||
|
|
||||||
if (newSpell.getResult() != ActionResult.FAIL) {
|
if (newSpell.getResult() != ActionResult.FAIL) {
|
||||||
SpellType<?> spell = newSpell.getValue();
|
CustomisedSpellType<?> spell = newSpell.getValue();
|
||||||
|
|
||||||
player.subtractEnergyCost(spell.isEmpty() ? 2 : 4);
|
player.subtractEnergyCost(spell.isEmpty() ? 2 : 4);
|
||||||
spell.apply(player, SpellTraits.EMPTY);
|
spell.apply(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,13 +135,13 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
||||||
return TypedActionResult.pass(stack);
|
return TypedActionResult.pass(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypedActionResult<SpellType<?>> getNewSpell(Pony player) {
|
private TypedActionResult<CustomisedSpellType<?>> getNewSpell(Pony player) {
|
||||||
final SpellType<?> current = player.getSpellSlot().get(true).map(Spell::getType).orElse(SpellType.empty());
|
final SpellType<?> current = player.getSpellSlot().get(true).map(Spell::getType).orElse(SpellType.empty());
|
||||||
return Streams.stream(player.getMaster().getItemsHand())
|
return Streams.stream(player.getMaster().getItemsHand())
|
||||||
.filter(GemstoneItem::isEnchanted)
|
.filter(GemstoneItem::isEnchanted)
|
||||||
.map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), current, null))
|
.map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), current, null))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(TypedActionResult.<SpellType<?>>pass(current == SpellType.EMPTY_KEY ? SpellType.SHIELD : SpellType.EMPTY_KEY));
|
.orElse(TypedActionResult.<CustomisedSpellType<?>>pass((current == SpellType.EMPTY_KEY ? SpellType.SHIELD : SpellType.EMPTY_KEY).withTraits()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,9 +5,8 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.item.GemstoneItem;
|
import com.minelittlepony.unicopia.item.GemstoneItem;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
|
@ -63,27 +62,27 @@ public class UnicornProjectileAbility implements Ability<Hit> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Pony player, Hit data) {
|
public void apply(Pony player, Hit data) {
|
||||||
TypedActionResult<SpellType<?>> thrown = getNewSpell(player);
|
TypedActionResult<CustomisedSpellType<?>> thrown = getNewSpell(player);
|
||||||
|
|
||||||
if (thrown.getResult() != ActionResult.FAIL) {
|
if (thrown.getResult() != ActionResult.FAIL) {
|
||||||
@Nullable
|
@Nullable
|
||||||
SpellType<?> spell = thrown.getValue();
|
CustomisedSpellType<?> spell = thrown.getValue();
|
||||||
|
|
||||||
if (spell == null) {
|
if (spell == null) {
|
||||||
spell = SpellType.VORTEX;
|
spell = SpellType.VORTEX.withTraits();
|
||||||
}
|
}
|
||||||
|
|
||||||
player.subtractEnergyCost(getCostEstimate(player));
|
player.subtractEnergyCost(getCostEstimate(player));
|
||||||
((ProjectileCapable)spell.create(SpellTraits.EMPTY)).toss(player);
|
spell.create().toThrowable().throwProjectile(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypedActionResult<SpellType<?>> getNewSpell(Pony player) {
|
private TypedActionResult<CustomisedSpellType<?>> getNewSpell(Pony player) {
|
||||||
return Streams.stream(player.getMaster().getItemsHand())
|
return Streams.stream(player.getMaster().getItemsHand())
|
||||||
.filter(GemstoneItem::isEnchanted)
|
.filter(GemstoneItem::isEnchanted)
|
||||||
.map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), null, null))
|
.map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), null, null))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(TypedActionResult.<SpellType<?>>pass(null));
|
.orElse(TypedActionResult.<CustomisedSpellType<?>>pass(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,11 +2,11 @@ package com.minelittlepony.unicopia.ability.magic;
|
||||||
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
|
|
||||||
public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
|
public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
|
||||||
SpellPredicate<ProjectileCapable> IS_THROWN = s -> s instanceof ProjectileCapable;
|
SpellPredicate<ProjectileSpell> IS_THROWN = s -> s instanceof ProjectileSpell;
|
||||||
SpellPredicate<Suppressable> IS_SUPPRESSABLE = s -> s instanceof Suppressable;
|
SpellPredicate<Suppressable> IS_SUPPRESSABLE = s -> s instanceof Suppressable;
|
||||||
|
|
||||||
default boolean isOn(Caster<?> caster) {
|
default boolean isOn(Caster<?> caster) {
|
||||||
|
|
|
@ -10,13 +10,14 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||||
|
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
public abstract class AbstractDelegatingSpell implements Spell, ProjectileCapable {
|
public abstract class AbstractDelegatingSpell implements ProjectileSpell {
|
||||||
|
|
||||||
private boolean isDirty;
|
private boolean isDirty;
|
||||||
|
|
||||||
|
@ -76,27 +77,30 @@ public abstract class AbstractDelegatingSpell implements Spell, ProjectileCapabl
|
||||||
getDelegates().forEach(spell -> spell.onDestroyed(caster));
|
getDelegates().forEach(spell -> spell.onDestroyed(caster));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tick(Caster<?> source, Situation situation) {
|
||||||
|
return execute(getDelegates().stream(), spell -> spell.tick(source, situation));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) {
|
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) {
|
||||||
getDelegates().stream().filter(a -> a instanceof ProjectileCapable).forEach(a -> {
|
getDelegates().stream().filter(a -> a instanceof ProjectileDelegate).forEach(a -> {
|
||||||
((ProjectileCapable)a).onImpact(projectile, pos, state);
|
((ProjectileDelegate)a).onImpact(projectile, pos, state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onImpact(MagicProjectileEntity projectile, Entity entity) {
|
public void onImpact(MagicProjectileEntity projectile, Entity entity) {
|
||||||
getDelegates().stream().filter(a -> a instanceof ProjectileCapable).forEach(a -> {
|
getDelegates().stream().filter(a -> a instanceof ProjectileDelegate).forEach(a -> {
|
||||||
((ProjectileCapable)a).onImpact(projectile, entity);
|
((ProjectileDelegate)a).onImpact(projectile, entity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tick(Caster<?> source, Situation situation) {
|
public void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) {
|
||||||
return execute(getDelegates().stream(), spell -> spell.tick(source, situation));
|
getDelegates().stream().filter(a -> a instanceof ProjectileSpell).forEach(a -> {
|
||||||
}
|
((ProjectileSpell)a).configureProjectile(projectile, caster);
|
||||||
|
});
|
||||||
private boolean execute(Stream<Spell> spells, Function<Spell, Boolean> action) {
|
|
||||||
return spells.reduce(false, (u, a) -> action.apply(a), (a, b) -> a || b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -111,4 +115,8 @@ public abstract class AbstractDelegatingSpell implements Spell, ProjectileCapabl
|
||||||
uuid = compound.getUuid("uuid");
|
uuid = compound.getUuid("uuid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean execute(Stream<Spell> spells, Function<Spell, Boolean> action) {
|
||||||
|
return spells.reduce(false, (u, a) -> action.apply(a), (a, b) -> a || b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ public class CompoundSpell extends AbstractDelegatingSpell {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Spell combineWith(Spell other) {
|
public Spell combineWith(Spell other) {
|
||||||
if (other instanceof CompoundSpell) {
|
if (other instanceof AbstractDelegatingSpell) {
|
||||||
spells.addAll(((CompoundSpell)other).spells);
|
spells.addAll(((AbstractDelegatingSpell)other).getDelegates());
|
||||||
} else {
|
} else {
|
||||||
spells.add(other);
|
spells.add(other);
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
||||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
||||||
}).ifPresent(p -> {
|
}).ifPresent(p -> {
|
||||||
p.attach(source);
|
p.attach(source);
|
||||||
p.setAttribute(1, getType().getColor());
|
p.setAttribute(1, spell.getType().getColor());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.ability.magic.spell;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
|
||||||
import com.minelittlepony.unicopia.item.GemstoneItem;
|
|
||||||
import com.minelittlepony.unicopia.item.UItems;
|
|
||||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
|
||||||
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.LivingEntity;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.sound.SoundCategory;
|
|
||||||
import net.minecraft.sound.SoundEvent;
|
|
||||||
import net.minecraft.sound.SoundEvents;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Magic effects that can be thrown.
|
|
||||||
*/
|
|
||||||
public interface ProjectileCapable extends Spell, ProjectileDelegate {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
default void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) {
|
|
||||||
if (!projectile.isClient()) {
|
|
||||||
tick(projectile, Situation.PROJECTILE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
default void onImpact(MagicProjectileEntity projectile, Entity entity) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of damage to be dealt when the projectile collides with an entity.
|
|
||||||
*/
|
|
||||||
default int getThrowDamage(Caster<?> stack) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The sound made when thrown.
|
|
||||||
*/
|
|
||||||
default SoundEvent getThrowSound(Caster<?> caster) {
|
|
||||||
return SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the appearance to be used when projecting this spell.
|
|
||||||
*/
|
|
||||||
default ItemStack getCastAppearance(Caster<?> caster) {
|
|
||||||
return GemstoneItem.enchanted(UItems.GEMSTONE.getDefaultStack(), getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Projects this spell.
|
|
||||||
*
|
|
||||||
* Returns the resulting projectile entity for customization (or null if on the client).
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
default MagicProjectileEntity toss(Caster<?> caster) {
|
|
||||||
World world = caster.getWorld();
|
|
||||||
|
|
||||||
LivingEntity entity = caster.getMaster();
|
|
||||||
|
|
||||||
world.playSound(null, entity.getX(), entity.getY(), entity.getZ(), getThrowSound(caster), SoundCategory.NEUTRAL, 0.7F, 0.4F / (world.random.nextFloat() * 0.4F + 0.8F));
|
|
||||||
|
|
||||||
if (!caster.isClient()) {
|
|
||||||
MagicProjectileEntity projectile = new MagicProjectileEntity(world, entity);
|
|
||||||
|
|
||||||
projectile.setItem(getCastAppearance(caster));
|
|
||||||
projectile.setThrowDamage(getThrowDamage(caster));
|
|
||||||
projectile.setSpell(this);
|
|
||||||
projectile.setHydrophobic();
|
|
||||||
projectile.setProperties(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, 1);
|
|
||||||
|
|
||||||
world.spawnEntity(projectile);
|
|
||||||
|
|
||||||
return projectile;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||||
|
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic effects that can be thrown.
|
||||||
|
*/
|
||||||
|
public interface ProjectileSpell extends Spell, ProjectileDelegate {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) {
|
||||||
|
if (!projectile.isClient()) {
|
||||||
|
tick(projectile, Situation.PROJECTILE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) { }
|
||||||
|
}
|
|
@ -75,4 +75,12 @@ public interface Spell extends NbtSerialisable, Affine {
|
||||||
default PlaceableSpell toPlaceable() {
|
default PlaceableSpell toPlaceable() {
|
||||||
return SpellType.PLACED_SPELL.create(SpellTraits.EMPTY).setSpell(this);
|
return SpellType.PLACED_SPELL.create(SpellTraits.EMPTY).setSpell(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this spell into a throwable spell.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
default ThrowableSpell toThrowable() {
|
||||||
|
return SpellType.THROWN_SPELL.create(SpellTraits.EMPTY).setSpell(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
|
import com.minelittlepony.unicopia.item.GemstoneItem;
|
||||||
|
import com.minelittlepony.unicopia.item.UItems;
|
||||||
|
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||||
|
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class ThrowableSpell extends AbstractDelegatingSpell {
|
||||||
|
|
||||||
|
private Spell spell;
|
||||||
|
|
||||||
|
public ThrowableSpell(SpellType<?> type, SpellTraits traits) {
|
||||||
|
super(type, traits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThrowableSpell setSpell(Spell spell) {
|
||||||
|
this.spell = spell;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Collection<Spell> getDelegates() {
|
||||||
|
return List.of(spell);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projects this spell.
|
||||||
|
*
|
||||||
|
* Returns the resulting projectile entity for customization (or null if on the client).
|
||||||
|
*/
|
||||||
|
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster) {
|
||||||
|
World world = caster.getWorld();
|
||||||
|
|
||||||
|
LivingEntity entity = caster.getMaster();
|
||||||
|
|
||||||
|
world.playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT, SoundCategory.NEUTRAL, 0.7F, 0.4F / (world.random.nextFloat() * 0.4F + 0.8F));
|
||||||
|
|
||||||
|
if (!caster.isClient()) {
|
||||||
|
MagicProjectileEntity projectile = new MagicProjectileEntity(world, entity);
|
||||||
|
|
||||||
|
projectile.setItem(GemstoneItem.enchanted(UItems.GEMSTONE.getDefaultStack(), spell.getType()));
|
||||||
|
projectile.setSpell(this);
|
||||||
|
projectile.setProperties(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, 1);
|
||||||
|
projectile.setHydrophobic();
|
||||||
|
configureProjectile(projectile, caster);
|
||||||
|
world.spawnEntity(projectile);
|
||||||
|
|
||||||
|
return Optional.of(projectile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThrowableSpell toThrowable() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import java.util.List;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.registry.Registry;
|
import net.minecraft.util.registry.Registry;
|
||||||
|
|
||||||
public class AwkwardSpell extends AbstractSpell implements ProjectileCapable {
|
public class AwkwardSpell extends AbstractSpell {
|
||||||
|
|
||||||
protected AwkwardSpell(SpellType<?> type, SpellTraits traits) {
|
protected AwkwardSpell(SpellType<?> type, SpellTraits traits) {
|
||||||
super(type, traits);
|
super(type, traits);
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
|
|
||||||
|
public class CustomisedSpellType<T extends Spell> {
|
||||||
|
|
||||||
|
private final SpellType<T> type;
|
||||||
|
private final SpellTraits traits;
|
||||||
|
|
||||||
|
public CustomisedSpellType(SpellType<T> type, SpellTraits traits) {
|
||||||
|
this.type = type;
|
||||||
|
this.traits = traits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return type.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T create() {
|
||||||
|
return type.create(traits);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public T apply(Caster<?> caster) {
|
||||||
|
return type.apply(caster, traits);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||||
import com.minelittlepony.unicopia.EquinePredicates;
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.block.state.StateMaps;
|
import com.minelittlepony.unicopia.block.state.StateMaps;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||||
|
@ -35,7 +35,7 @@ import net.minecraft.world.explosion.Explosion.DestructionType;
|
||||||
/**
|
/**
|
||||||
* Simple fire spell that triggers an effect when used on a block.
|
* Simple fire spell that triggers an effect when used on a block.
|
||||||
*/
|
*/
|
||||||
public class FireSpell extends AbstractSpell implements ProjectileCapable {
|
public class FireSpell extends AbstractSpell implements ProjectileSpell {
|
||||||
|
|
||||||
private static final Shape EFFECT_RANGE = new Sphere(false, 4);
|
private static final Shape EFFECT_RANGE = new Sphere(false, 4);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.block.state.StateMaps;
|
import com.minelittlepony.unicopia.block.state.StateMaps;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||||
|
@ -27,7 +26,7 @@ import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class IceSpell extends AbstractSpell implements ProjectileCapable {
|
public class IceSpell extends AbstractSpell {
|
||||||
|
|
||||||
private final int rad = 3;
|
private final int rad = 3;
|
||||||
private final Shape effect_range = new Sphere(false, rad);
|
private final Shape effect_range = new Sphere(false, rad);
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
import com.minelittlepony.unicopia.util.shape.Shape;
|
import com.minelittlepony.unicopia.util.shape.Shape;
|
||||||
|
@ -16,7 +15,7 @@ import net.minecraft.util.math.Vec3d;
|
||||||
/**
|
/**
|
||||||
* A spell for revealing changelings.
|
* A spell for revealing changelings.
|
||||||
*/
|
*/
|
||||||
public class RevealingSpell extends AbstractSpell implements ProjectileCapable {
|
public class RevealingSpell extends AbstractSpell {
|
||||||
private static final Shape AREA = new Sphere(false, 15);
|
private static final Shape AREA = new Sphere(false, 15);
|
||||||
|
|
||||||
protected RevealingSpell(SpellType<?> type, SpellTraits traits) {
|
protected RevealingSpell(SpellType<?> type, SpellTraits traits) {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
|
@ -42,14 +40,7 @@ public class ScorchSpell extends FireSpell {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
public void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) {
|
||||||
public MagicProjectileEntity toss(Caster<?> caster) {
|
|
||||||
MagicProjectileEntity projectile = super.toss(caster);
|
|
||||||
|
|
||||||
if (projectile != null) {
|
|
||||||
projectile.setNoGravity(true);
|
projectile.setNoGravity(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
|
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
|
||||||
|
@ -35,7 +35,7 @@ import net.minecraft.entity.vehicle.BoatEntity;
|
||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
public class ShieldSpell extends AbstractSpell implements ProjectileCapable {
|
public class ShieldSpell extends AbstractSpell implements ProjectileSpell {
|
||||||
|
|
||||||
private final ParticleHandle particlEffect = new ParticleHandle();
|
private final ParticleHandle particlEffect = new ParticleHandle();
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.JoustingSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.JoustingSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.util.Registries;
|
import com.minelittlepony.unicopia.util.Registries;
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
||||||
|
|
||||||
public static final SpellType<CompoundSpell> COMPOUND_SPELL = register("compound", Affinity.NEUTRAL, 0, false, CompoundSpell::new);
|
public static final SpellType<CompoundSpell> COMPOUND_SPELL = register("compound", Affinity.NEUTRAL, 0, false, CompoundSpell::new);
|
||||||
public static final SpellType<PlaceableSpell> PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, PlaceableSpell::new);
|
public static final SpellType<PlaceableSpell> PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, PlaceableSpell::new);
|
||||||
|
public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, ThrowableSpell::new);
|
||||||
|
|
||||||
public static final SpellType<DisguiseSpell> DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, DisguiseSpell::new);
|
public static final SpellType<DisguiseSpell> DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, DisguiseSpell::new);
|
||||||
public static final SpellType<JoustingSpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, JoustingSpell::new);
|
public static final SpellType<JoustingSpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, JoustingSpell::new);
|
||||||
|
@ -66,12 +68,15 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
||||||
@Nullable
|
@Nullable
|
||||||
private String translationKey;
|
private String translationKey;
|
||||||
|
|
||||||
|
private final CustomisedSpellType<T> traited;
|
||||||
|
|
||||||
private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
|
private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.affinity = affinity;
|
this.affinity = affinity;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.obtainable = obtainable;
|
this.obtainable = obtainable;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
|
traited = new CustomisedSpellType<>(this, SpellTraits.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isObtainable() {
|
public boolean isObtainable() {
|
||||||
|
@ -105,6 +110,14 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
||||||
return new TranslatableText(getTranslationKey());
|
return new TranslatableText(getTranslationKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CustomisedSpellType<T> withTraits() {
|
||||||
|
return traited;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomisedSpellType<T> withTraits(SpellTraits traits) {
|
||||||
|
return traits.isEmpty() ? withTraits() : new CustomisedSpellType<>(this, traits);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public T create(SpellTraits traits) {
|
public T create(SpellTraits traits) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import java.util.Set;
|
||||||
import com.minelittlepony.unicopia.UTags;
|
import com.minelittlepony.unicopia.UTags;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileCapable;
|
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.entity.UEntities;
|
import com.minelittlepony.unicopia.entity.UEntities;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||||
|
@ -22,7 +22,7 @@ import net.minecraft.particle.ParticleTypes;
|
||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.util.Util;
|
import net.minecraft.util.Util;
|
||||||
|
|
||||||
public class TransformationSpell extends AbstractSpell implements ProjectileCapable {
|
public class TransformationSpell extends AbstractSpell implements ProjectileSpell {
|
||||||
|
|
||||||
protected TransformationSpell(SpellType<?> type, SpellTraits traits) {
|
protected TransformationSpell(SpellType<?> type, SpellTraits traits) {
|
||||||
super(type, traits);
|
super(type, traits);
|
||||||
|
|
|
@ -43,19 +43,19 @@ public final class SpellTraits {
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<SpellTraits> of(Collection<ItemStack> stacks) {
|
public static Optional<SpellTraits> of(Collection<ItemStack> stacks) {
|
||||||
return fromEntries(stacks.stream().flatMap(a -> of(a).entries().stream()));
|
return fromEntries(stacks.stream().flatMap(a -> of(a).entries().stream()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellTraits of(ItemStack stack) {
|
public static SpellTraits of(ItemStack stack) {
|
||||||
return getEmbeddedTraits(stack).orElseGet(() -> of(stack.getItem()));
|
return getEmbeddedTraits(stack).orElseGet(() -> of(stack.getItem()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellTraits of(Item item) {
|
public static SpellTraits of(Item item) {
|
||||||
return TraitLoader.INSTANCE.values.getOrDefault(Registry.ITEM.getId(item), null);
|
return TraitLoader.INSTANCE.values.getOrDefault(Registry.ITEM.getId(item), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellTraits of(Block block) {
|
public static SpellTraits of(Block block) {
|
||||||
return of(block.asItem());
|
return of(block.asItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import com.minelittlepony.unicopia.Affinity;
|
import com.minelittlepony.unicopia.Affinity;
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
|
|
||||||
import net.minecraft.client.item.TooltipContext;
|
import net.minecraft.client.item.TooltipContext;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
@ -79,19 +81,20 @@ public class GemstoneItem extends Item {
|
||||||
return super.getName();
|
return super.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypedActionResult<SpellType<?>> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable SpellType<?> exclude, @Nullable Predicate<SpellType<?>> test) {
|
public static TypedActionResult<CustomisedSpellType<?>> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable SpellType<?> exclude, @Nullable Predicate<SpellType<?>> test) {
|
||||||
|
|
||||||
if (!isEnchanted(stack)) {
|
if (!isEnchanted(stack)) {
|
||||||
return TypedActionResult.pass(null);
|
return TypedActionResult.pass(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellType<Spell> key = getSpellKey(stack);
|
SpellType<Spell> key = getSpellKey(stack);
|
||||||
|
SpellTraits traits = SpellTraits.of(stack);
|
||||||
|
|
||||||
if (Objects.equals(key, exclude)) {
|
if (Objects.equals(key, exclude)) {
|
||||||
return TypedActionResult.fail(null);
|
return TypedActionResult.fail(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == SpellType.EMPTY_KEY || (test == null || !test.test(key))) {
|
if (key.isEmpty() || (test == null || !test.test(key))) {
|
||||||
return TypedActionResult.fail(null);
|
return TypedActionResult.fail(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +108,7 @@ public class GemstoneItem extends Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypedActionResult.consume(key);
|
return TypedActionResult.consume(key.withTraits(traits));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEnchanted(ItemStack stack) {
|
public static boolean isEnchanted(ItemStack stack) {
|
||||||
|
|
|
@ -8,10 +8,10 @@ public interface ProjectileDelegate {
|
||||||
/**
|
/**
|
||||||
* Called once the projectile lands either hitting the ground or an entity.
|
* Called once the projectile lands either hitting the ground or an entity.
|
||||||
*/
|
*/
|
||||||
void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state);
|
default void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called once the projectile lands either hitting the ground or an entity.
|
* Called once the projectile lands either hitting the ground or an entity.
|
||||||
*/
|
*/
|
||||||
void onImpact(MagicProjectileEntity projectile, Entity entity);
|
default void onImpact(MagicProjectileEntity projectile, Entity entity) {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue