diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java index 25be9d5b..8e26e627 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java @@ -7,13 +7,16 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.CastSpellEntity; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import com.minelittlepony.unicopia.util.MagicalDamageSource; import net.minecraft.entity.Entity; import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.Vec3d; -public class DisplacementSpell extends AbstractSpell implements HomingSpell, PlaceableSpell.PlacementDelegate { +public class DisplacementSpell extends AbstractSpell implements HomingSpell, PlaceableSpell.PlacementDelegate, ProjectileDelegate.EntityHitListener { private final EntityReference target = new EntityReference<>(); @@ -41,23 +44,29 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pla } if (ticks == 0) { - target.ifPresent(originator.asWorld(), target -> { - - Vec3d destinationPos = target.getPos(); - Vec3d destinationVel = target.getVelocity(); - - Vec3d sourcePos = originator.getOriginVector(); - Vec3d sourceVel = originator.asEntity().getVelocity(); - - teleport(target, sourcePos, sourceVel); - teleport(originator.asEntity(), destinationPos, destinationVel); - originator.subtractEnergyCost(destinationPos.distanceTo(sourcePos) / 20F); - }); + target.ifPresent(originator.asWorld(), target -> apply(originator, target)); } return ticks >= -10; } + @Override + public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { + Caster.of(projectile.getMaster()).ifPresent(originator -> apply(originator, hit.getEntity())); + } + + private void apply(Caster originator, Entity target) { + Vec3d destinationPos = target.getPos(); + Vec3d destinationVel = target.getVelocity(); + + Vec3d sourcePos = originator.getOriginVector(); + Vec3d sourceVel = originator.asEntity().getVelocity(); + + teleport(target, sourcePos, sourceVel); + teleport(originator.asEntity(), destinationPos, destinationVel); + originator.subtractEnergyCost(destinationPos.distanceTo(sourcePos) / 20F); + } + @Override public void onPlaced(Caster source, PlaceableSpell parent, CastSpellEntity entity) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index a2a36430..0dd8fa74 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -11,13 +11,15 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.FairyEntity; import com.minelittlepony.unicopia.entity.UEntities; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import com.minelittlepony.unicopia.util.VecHelper; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; -public class LightSpell extends AbstractSpell implements TimedSpell { +public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileDelegate.HitListener { public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() .with(Trait.LIFE, 10) .with(Trait.AIR, 0.3F) @@ -80,6 +82,11 @@ public class LightSpell extends AbstractSpell implements TimedSpell { return true; } + @Override + public void onImpact(MagicProjectileEntity projectile) { + Caster.of(projectile.getMaster()).ifPresent(getTypeAndTraits()::apply); + } + @Override public void onDestroyed(Caster caster) { if (caster.isClient()) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index 32567309..710ef0d9 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; import java.util.*; +import java.util.function.Predicate; import java.util.function.Supplier; import com.minelittlepony.unicopia.ability.magic.Caster; @@ -10,17 +11,25 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.Equine; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import com.minelittlepony.unicopia.util.Weighted; import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.*; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.passive.VillagerEntity; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; import net.minecraft.particle.ParticleTypes; import net.minecraft.sound.SoundEvents; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.Difficulty; @@ -29,7 +38,7 @@ import net.minecraft.world.WorldEvents; /** * An area-effect spell that summons the undead. */ -public class NecromancySpell extends AbstractAreaEffectSpell { +public class NecromancySpell extends AbstractAreaEffectSpell implements ProjectileDelegate.EntityHitListener, ProjectileDelegate.BlockHitListener { private final Supplier>> spawnPool = new Weighted.Builder>() .put(7, EntityType.ZOMBIE) .put(4, EntityType.HUSK) @@ -38,6 +47,23 @@ public class NecromancySpell extends AbstractAreaEffectSpell { .put(1, EntityType.ZOMBIE_VILLAGER) .build(); + static final Map, EntityType> NECROMANTIC_CONVERSIONS = Map.of( + match(EntityType.PIGLIN), EntityType.ZOMBIFIED_PIGLIN, + match(EntityType.HOGLIN), EntityType.ZOGLIN, + match(EntityType.HORSE), EntityType.ZOMBIE_HORSE, + match(EntityType.DONKEY), EntityType.SKELETON_HORSE, + match(EntityType.ZOMBIE), EntityType.HUSK, + match(EntityType.SKELETON), EntityType.WITHER_SKELETON, + match(EntityType.WANDERING_TRADER), EntityType.WITCH, + match(EntityType.WITHER), EntityType.WARDEN, + match(EntityType.WARDEN), EntityType.RABBIT, + (e -> e instanceof VillagerEntity), EntityType.ZOMBIE_VILLAGER + ); + + static Predicate match(EntityType type) { + return e -> e.getType() == type; + } + private final List> summonedEntities = new ArrayList<>(); private int spawnCountdown; @@ -172,4 +198,37 @@ public class NecromancySpell extends AbstractAreaEffectSpell { }); } } + + @Override + public void onImpact(MagicProjectileEntity source, BlockHitResult hit) { + + // source.asWorld().createExplosion(source, hit.getPos().x, hit.getPos().y, hit.getPos().z, 3, ExplosionSourceType.MOB); + + Shape affectRegion = new Sphere(false, 3); + + for (int i = 0; i < 10; i++) { + Vec3d pos = affectRegion.computePoint(source.asWorld().random).add(source.getOriginVector()); + + BlockPos loc = new BlockPos(pos); + + if (source.asWorld().isAir(loc.up()) && !source.asWorld().isAir(loc)) { + spawnPool.get().ifPresent(type -> { + spawnMonster(source, pos, type); + }); + } + } + + summonedEntities.clear(); + } + + @Override + public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { + NECROMANTIC_CONVERSIONS.entrySet().stream().filter(entry -> entry.getKey().test(hit.getEntity())).findFirst().ifPresent(entry -> { + MobEntity newEntity = ((MobEntity)hit.getEntity()).convertTo(entry.getValue(), true); + + if (newEntity != null) { + newEntity.addStatusEffect(new StatusEffectInstance(StatusEffects.NAUSEA, 200, 0)); + } + }); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java index 67ac4723..9244a542 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java @@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.CastSpellEntity; import com.minelittlepony.unicopia.entity.UEntities; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.item.group.MultiItem; import net.minecraft.client.item.TooltipContext; import net.minecraft.entity.Entity; @@ -32,7 +33,7 @@ import net.minecraft.util.TypedActionResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class EnchantedStaffItem extends StaffItem implements EnchantableItem, ChargeableItem { +public class EnchantedStaffItem extends StaffItem implements EnchantableItem, ChargeableItem, MultiItem { private static final Map, SpellType> ENTITY_TYPE_TO_SPELL = new HashMap<>(); public static SpellType register(EntityType entityType, SpellType spellType) { @@ -58,6 +59,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch register(EntityType.CREEPER, SpellType.CATAPULT); register(EntityType.HUSK, SpellType.HYDROPHOBIC); register(EntityType.SNOW_GOLEM, SpellType.FROST); + register(EntityType.POLAR_BEAR, SpellType.FROST); register(EntityType.FIREBALL, SpellType.FLAME); register(EntityType.SMALL_FIREBALL, SpellType.FLAME); register(EntityType.ENDER_DRAGON, SpellType.DISPLACEMENT); @@ -78,8 +80,8 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch } @Override - public ItemStack getDefaultStack() { - return EnchantableItem.enchant(super.getDefaultStack(), SpellType.FIRE_BOLT); + public List getDefaultStacks() { + return ENTITY_TYPE_TO_SPELL.values().stream().distinct().map(type -> EnchantableItem.enchant(getDefaultStack(), type)).toList(); } @Override @@ -197,6 +199,14 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch return 3; } + @Override + public Text getName(ItemStack stack) { + if (EnchantableItem.isEnchanted(stack) && hasCharge(stack)) { + return Text.translatable(this.getTranslationKey(stack) + ".enchanted", super.getName(stack), EnchantableItem.getSpellKey(stack).getName()); + } + return super.getName(stack); + } + @Override public void onDischarge(ItemStack stack) { if ((stack.hasNbt() && stack.getNbt().contains("energy") ? stack.getNbt().getFloat("energy") : 0) == 0) { diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index d07ce48b..c39c3547 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -97,6 +97,7 @@ "item.unicopia.grogars_bell": "Grogar's Bell", "item.unicopia.grogars_bell.charges": "Charges: %d / %d", "item.unicopia.magic_staff": "Magic Staff", + "item.unicopia.magic_staff.enchanted": "%s of %s", "item.unicopia.magic_staff.charges": "Charges: %d / %d", "item.unicopia.meadowbrooks_staff": "Meadowbrook's Staff", "item.unicopia.meadowbrooks_staff.lore": "A Heavy Stick",