mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 23:27:59 +01:00
Add arcane protection spell
This commit is contained in:
parent
d38005c5bf
commit
3225c7924f
7 changed files with 132 additions and 10 deletions
|
@ -52,6 +52,9 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Hit tryActivate(Pony player) {
|
public Hit tryActivate(Pony player) {
|
||||||
|
if (!player.canCast()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return Hit.of(player.getMagicalReserves().getMana().get() >= getCostEstimate(player));
|
return Hit.of(player.getMagicalReserves().getMana().get() >= getCostEstimate(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +80,10 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Pony player, Hit data) {
|
public void apply(Pony player, Hit data) {
|
||||||
|
if (!player.canCast()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TypedActionResult<ItemStack> amulet = getAmulet(player);
|
TypedActionResult<ItemStack> amulet = getAmulet(player);
|
||||||
|
|
||||||
if (amulet.getResult().isAccepted()) {
|
if (amulet.getResult().isAccepted()) {
|
||||||
|
|
|
@ -66,6 +66,11 @@ public class UnicornTeleportAbility implements Ability<Pos> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pos tryActivate(Pony player) {
|
public Pos tryActivate(Pony player) {
|
||||||
|
|
||||||
|
if (!player.canCast()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
int maxDistance = player.getMaster().isCreative() ? 1000 : 100;
|
int maxDistance = player.getMaster().isCreative() ? 1000 : 100;
|
||||||
HitResult ray = RayTraceHelper.doTrace(player.getMaster(), maxDistance, 1, EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR).getResult();
|
HitResult ray = RayTraceHelper.doTrace(player.getMaster(), maxDistance, 1, EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR).getResult();
|
||||||
|
|
||||||
|
@ -130,6 +135,10 @@ public class UnicornTeleportAbility implements Ability<Pos> {
|
||||||
|
|
||||||
protected void teleport(Pony teleporter, Caster<?> teleportee, Pos destination) {
|
protected void teleport(Pony teleporter, Caster<?> teleportee, Pos destination) {
|
||||||
|
|
||||||
|
if (!teleporter.canCast()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LivingEntity player = teleportee.getMaster();
|
LivingEntity player = teleportee.getMaster();
|
||||||
|
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EquinePredicates;
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
import com.minelittlepony.unicopia.Owned;
|
import com.minelittlepony.unicopia.Owned;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.entity.Physics;
|
import com.minelittlepony.unicopia.entity.Physics;
|
||||||
import com.minelittlepony.unicopia.entity.PonyContainer;
|
import com.minelittlepony.unicopia.entity.PonyContainer;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleSource;
|
import com.minelittlepony.unicopia.particle.ParticleSource;
|
||||||
|
@ -18,6 +19,7 @@ import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.sound.SoundEvent;
|
import net.minecraft.sound.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.GameRules;
|
import net.minecraft.world.GameRules;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
@ -61,6 +63,11 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean canModifyAt(BlockPos pos) {
|
default boolean canModifyAt(BlockPos pos) {
|
||||||
|
|
||||||
|
if (!canCastAt(Vec3d.ofCenter(pos))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (getMaster() instanceof PlayerEntity) {
|
if (getMaster() instanceof PlayerEntity) {
|
||||||
return getReferenceWorld().canPlayerModifyAt((PlayerEntity)getMaster(), pos);
|
return getReferenceWorld().canPlayerModifyAt((PlayerEntity)getMaster(), pos);
|
||||||
}
|
}
|
||||||
|
@ -94,6 +101,18 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
|
||||||
return findAllEntitiesInRange(radius, null);
|
return findAllEntitiesInRange(radius, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default boolean canCast() {
|
||||||
|
return canCastAt(getOriginVector());
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean canCastAt(Vec3d pos) {
|
||||||
|
return findAllSpellsInRange(500, SpellType.ARCANE_PROTECTION::isOn).noneMatch(caster -> caster
|
||||||
|
.getSpellSlot().get(SpellType.ARCANE_PROTECTION, false)
|
||||||
|
.filter(spell -> spell.blocksMagicFor(caster, this, pos))
|
||||||
|
.isPresent()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static Stream<Caster<?>> stream(Stream<Entity> entities) {
|
static Stream<Caster<?>> stream(Stream<Entity> entities) {
|
||||||
return entities.map(Caster::of).flatMap(Optional::stream);
|
return entities.map(Caster::of).flatMap(Optional::stream);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
|
||||||
|
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.Trait;
|
||||||
|
import com.minelittlepony.unicopia.entity.UEntities;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
|
||||||
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
|
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
public class AreaProtectionSpell extends AbstractAreaEffectSpell {
|
||||||
|
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
||||||
|
.with(Trait.FOCUS, 50)
|
||||||
|
.with(Trait.STRENGTH, 30)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
protected AreaProtectionSpell(CustomisedSpellType<?> type) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tick(Caster<?> source, Situation situation) {
|
||||||
|
|
||||||
|
if (situation == Situation.PROJECTILE || situation == Situation.BODY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float radius = (float)getDrawDropOffRange(source);
|
||||||
|
|
||||||
|
if (source.isClient()) {
|
||||||
|
Vec3d origin = source.getOriginVector();
|
||||||
|
|
||||||
|
source.spawnParticles(origin, new Sphere(true, radius), (int)(radius * 6), pos -> {
|
||||||
|
if (!source.getReferenceWorld().isAir(new BlockPos(pos))) {
|
||||||
|
source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
source.findAllSpellsInRange(radius, e -> isValidTarget(source, e)).filter(caster -> !caster.hasCommonOwner(source)).forEach(caster -> {
|
||||||
|
caster.getEntity().kill();
|
||||||
|
});
|
||||||
|
|
||||||
|
return !isDead();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the maximum radius of the shield. aka The area of effect.
|
||||||
|
*/
|
||||||
|
public double getDrawDropOffRange(Caster<?> source) {
|
||||||
|
float multiplier = source instanceof Pony pony && pony.getMaster().isSneaking() ? 1 : 2;
|
||||||
|
float min = 4 + getTraits().get(Trait.POWER);
|
||||||
|
double range = (min + (source.getLevel().getScaled(4) * 2)) / multiplier;
|
||||||
|
if (source instanceof Pony && range > 2) {
|
||||||
|
range = Math.sqrt(range);
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean blocksMagicFor(Caster<?> source, Caster<?> other, Vec3d position) {
|
||||||
|
return !FriendshipBraceletItem.isComrade(other, other.getEntity())
|
||||||
|
&& source.getOriginVector().distanceTo(position) <= getDrawDropOffRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isValidTarget(Caster<?> source, Entity entity) {
|
||||||
|
return entity.getType() == UEntities.MAGIC_BEAM;
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,13 +50,14 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
||||||
public static final SpellType<FireSpell> FLAME = register("flame", Affinity.GOOD, 0xFFBB99, true, FireSpell.DEFAULT_TRAITS, FireSpell::new);
|
public static final SpellType<FireSpell> FLAME = register("flame", Affinity.GOOD, 0xFFBB99, true, FireSpell.DEFAULT_TRAITS, FireSpell::new);
|
||||||
public static final SpellType<InfernoSpell> INFERNAL = register("infernal", Affinity.BAD, 0xFFAA00, true, InfernoSpell.DEFAULT_TRAITS, InfernoSpell::new);
|
public static final SpellType<InfernoSpell> INFERNAL = register("infernal", Affinity.BAD, 0xFFAA00, true, InfernoSpell.DEFAULT_TRAITS, InfernoSpell::new);
|
||||||
public static final SpellType<ShieldSpell> SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, ShieldSpell.DEFAULT_TRAITS, ShieldSpell::new);
|
public static final SpellType<ShieldSpell> SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, ShieldSpell.DEFAULT_TRAITS, ShieldSpell::new);
|
||||||
|
public static final SpellType<AreaProtectionSpell> ARCANE_PROTECTION = register("arcane_protection", Affinity.BAD, 0x99CDAA, true, AreaProtectionSpell.DEFAULT_TRAITS, AreaProtectionSpell::new);
|
||||||
public static final SpellType<AttractiveSpell> VORTEX = register("vortex", Affinity.NEUTRAL, 0xFFEA88, true, AttractiveSpell.DEFAULT_TRAITS, AttractiveSpell::new);
|
public static final SpellType<AttractiveSpell> VORTEX = register("vortex", Affinity.NEUTRAL, 0xFFEA88, true, AttractiveSpell.DEFAULT_TRAITS, AttractiveSpell::new);
|
||||||
public static final SpellType<DarkVortexSpell> DARK_VORTEX = register("dark_vortex", Affinity.BAD, 0xA33333, true, DarkVortexSpell.DEFAULT_TRAITS, DarkVortexSpell::new);
|
public static final SpellType<DarkVortexSpell> DARK_VORTEX = register("dark_vortex", Affinity.BAD, 0xA33333, true, DarkVortexSpell.DEFAULT_TRAITS, DarkVortexSpell::new);
|
||||||
public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", Affinity.BAD, 0xFA3A3A, true, NecromancySpell::new);
|
public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", Affinity.BAD, 0xFA3A3A, true, SpellTraits.EMPTY, NecromancySpell::new);
|
||||||
public static final SpellType<SiphoningSpell> SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xFFA3AA, true, SiphoningSpell::new);
|
public static final SpellType<SiphoningSpell> SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xFFA3AA, true, SpellTraits.EMPTY, SiphoningSpell::new);
|
||||||
public static final SpellType<DisperseIllusionSpell> REVEALING = register("reveal", Affinity.GOOD, 0xFFFFAF, true, DisperseIllusionSpell::new);
|
public static final SpellType<DisperseIllusionSpell> REVEALING = register("reveal", Affinity.GOOD, 0xFFFFAF, true, SpellTraits.EMPTY, DisperseIllusionSpell::new);
|
||||||
public static final SpellType<AwkwardSpell> AWKWARD = register("awkward", Affinity.GOOD, 0x3A59FF, true, AwkwardSpell::new);
|
public static final SpellType<AwkwardSpell> AWKWARD = register("awkward", Affinity.GOOD, 0x3A59FF, true, SpellTraits.EMPTY, AwkwardSpell::new);
|
||||||
public static final SpellType<TransformationSpell> TRANSFORMATION = register("transformation", Affinity.GOOD, 0x19E48E, true, TransformationSpell::new);
|
public static final SpellType<TransformationSpell> TRANSFORMATION = register("transformation", Affinity.GOOD, 0x19E48E, true, SpellTraits.EMPTY, TransformationSpell::new);
|
||||||
public static final SpellType<FeatherFallSpell> FEATHER_FALL = register("feather_fall", Affinity.GOOD, 0x00EEFF, true, FeatherFallSpell.DEFAULT_TRAITS, FeatherFallSpell::new);
|
public static final SpellType<FeatherFallSpell> FEATHER_FALL = register("feather_fall", Affinity.GOOD, 0x00EEFF, true, FeatherFallSpell.DEFAULT_TRAITS, FeatherFallSpell::new);
|
||||||
public static final SpellType<CatapultSpell> CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new);
|
public static final SpellType<CatapultSpell> CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new);
|
||||||
public static final SpellType<FireBoltSpell> FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new);
|
public static final SpellType<FireBoltSpell> FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new);
|
||||||
|
@ -159,11 +160,6 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
||||||
return "SpellType[" + getTranslationKey() + "]";
|
return "SpellType[" + getTranslationKey() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated(forRemoval = true)
|
|
||||||
public static <T extends Spell> SpellType<T> register(String name, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
|
|
||||||
return register(name, affinity, color, obtainable, SpellTraits.EMPTY, factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends Spell> SpellType<T> register(String name, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory<T> factory) {
|
public static <T extends Spell> SpellType<T> register(String name, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory<T> factory) {
|
||||||
return register(Unicopia.id(name), affinity, color, obtainable, traits, factory);
|
return register(Unicopia.id(name), affinity, color, obtainable, traits, factory);
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,8 @@
|
||||||
"spell.unicopia.fire_bolt.lore": "Produces several burning projectiles",
|
"spell.unicopia.fire_bolt.lore": "Produces several burning projectiles",
|
||||||
"spell.unicopia.shield": "Protection",
|
"spell.unicopia.shield": "Protection",
|
||||||
"spell.unicopia.shield.lore": "Casts a protective shield around the user",
|
"spell.unicopia.shield.lore": "Casts a protective shield around the user",
|
||||||
|
"spell.unicopia.arcane_protection": "Arcane Protections",
|
||||||
|
"spell.unicopia.arcane_protection.lore": "Creates a protective shroud over an area in which no other spells can be cast",
|
||||||
"spell.unicopia.vortex": "Arcane Attraction",
|
"spell.unicopia.vortex": "Arcane Attraction",
|
||||||
"spell.unicopia.vortex.lore": "Creates a magnetic force that pulls in other targets",
|
"spell.unicopia.vortex.lore": "Creates a magnetic force that pulls in other targets",
|
||||||
"spell.unicopia.dark_vortex": "Dark Vortex",
|
"spell.unicopia.dark_vortex": "Dark Vortex",
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"type": "unicopia:spellbook/crafting",
|
||||||
|
"material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
|
||||||
|
"traits": {
|
||||||
|
"strength": 10, "knowledge": 18
|
||||||
|
},
|
||||||
|
"ingredients": [
|
||||||
|
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
|
||||||
|
],
|
||||||
|
"result": {
|
||||||
|
"item": "unicopia:gemstone",
|
||||||
|
"spell": "unicopia:arcane_protection"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue