Add projectile actions to the displacement, light, and necro spells so they can be used with staffs

This commit is contained in:
Sollace 2023-04-30 14:35:55 +01:00
parent 9ebe391a2b
commit 77bf8aa1de
5 changed files with 104 additions and 18 deletions

View file

@ -7,13 +7,16 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.CastSpellEntity; import com.minelittlepony.unicopia.entity.CastSpellEntity;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; 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 com.minelittlepony.unicopia.util.MagicalDamageSource;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.Vec3d; 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<Entity> target = new EntityReference<>(); private final EntityReference<Entity> target = new EntityReference<>();
@ -41,23 +44,29 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pla
} }
if (ticks == 0) { if (ticks == 0) {
target.ifPresent(originator.asWorld(), target -> { target.ifPresent(originator.asWorld(), target -> apply(originator, 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);
});
} }
return ticks >= -10; 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 @Override
public void onPlaced(Caster<?> source, PlaceableSpell parent, CastSpellEntity entity) { public void onPlaced(Caster<?> source, PlaceableSpell parent, CastSpellEntity entity) {

View file

@ -11,13 +11,15 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.FairyEntity; import com.minelittlepony.unicopia.entity.FairyEntity;
import com.minelittlepony.unicopia.entity.UEntities; 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 com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList; 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() public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.LIFE, 10) .with(Trait.LIFE, 10)
.with(Trait.AIR, 0.3F) .with(Trait.AIR, 0.3F)
@ -80,6 +82,11 @@ public class LightSpell extends AbstractSpell implements TimedSpell {
return true; return true;
} }
@Override
public void onImpact(MagicProjectileEntity projectile) {
Caster.of(projectile.getMaster()).ifPresent(getTypeAndTraits()::apply);
}
@Override @Override
public void onDestroyed(Caster<?> caster) { public void onDestroyed(Caster<?> caster) {
if (caster.isClient()) { if (caster.isClient()) {

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.*; import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.Creature;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.Equine; 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.Weighted;
import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Shape;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.entity.*; 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.item.Items;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList; import net.minecraft.nbt.NbtList;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundEvents; 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.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Difficulty; import net.minecraft.world.Difficulty;
@ -29,7 +38,7 @@ import net.minecraft.world.WorldEvents;
/** /**
* An area-effect spell that summons the undead. * 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<Optional<EntityType<? extends LivingEntity>>> spawnPool = new Weighted.Builder<EntityType<? extends LivingEntity>>() private final Supplier<Optional<EntityType<? extends LivingEntity>>> spawnPool = new Weighted.Builder<EntityType<? extends LivingEntity>>()
.put(7, EntityType.ZOMBIE) .put(7, EntityType.ZOMBIE)
.put(4, EntityType.HUSK) .put(4, EntityType.HUSK)
@ -38,6 +47,23 @@ public class NecromancySpell extends AbstractAreaEffectSpell {
.put(1, EntityType.ZOMBIE_VILLAGER) .put(1, EntityType.ZOMBIE_VILLAGER)
.build(); .build();
static final Map<Predicate<Entity>, EntityType<? extends MobEntity>> 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<Entity> match(EntityType<?> type) {
return e -> e.getType() == type;
}
private final List<EntityReference<LivingEntity>> summonedEntities = new ArrayList<>(); private final List<EntityReference<LivingEntity>> summonedEntities = new ArrayList<>();
private int spawnCountdown; 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));
}
});
}
} }

View file

@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.CastSpellEntity; import com.minelittlepony.unicopia.entity.CastSpellEntity;
import com.minelittlepony.unicopia.entity.UEntities; import com.minelittlepony.unicopia.entity.UEntities;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.group.MultiItem;
import net.minecraft.client.item.TooltipContext; import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@ -32,7 +33,7 @@ import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; 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<EntityType<?>, SpellType<?>> ENTITY_TYPE_TO_SPELL = new HashMap<>(); private static final Map<EntityType<?>, SpellType<?>> ENTITY_TYPE_TO_SPELL = new HashMap<>();
public static <T extends Spell> SpellType<T> register(EntityType<?> entityType, SpellType<T> spellType) { public static <T extends Spell> SpellType<T> register(EntityType<?> entityType, SpellType<T> spellType) {
@ -58,6 +59,7 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch
register(EntityType.CREEPER, SpellType.CATAPULT); register(EntityType.CREEPER, SpellType.CATAPULT);
register(EntityType.HUSK, SpellType.HYDROPHOBIC); register(EntityType.HUSK, SpellType.HYDROPHOBIC);
register(EntityType.SNOW_GOLEM, SpellType.FROST); register(EntityType.SNOW_GOLEM, SpellType.FROST);
register(EntityType.POLAR_BEAR, SpellType.FROST);
register(EntityType.FIREBALL, SpellType.FLAME); register(EntityType.FIREBALL, SpellType.FLAME);
register(EntityType.SMALL_FIREBALL, SpellType.FLAME); register(EntityType.SMALL_FIREBALL, SpellType.FLAME);
register(EntityType.ENDER_DRAGON, SpellType.DISPLACEMENT); register(EntityType.ENDER_DRAGON, SpellType.DISPLACEMENT);
@ -78,8 +80,8 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch
} }
@Override @Override
public ItemStack getDefaultStack() { public List<ItemStack> getDefaultStacks() {
return EnchantableItem.enchant(super.getDefaultStack(), SpellType.FIRE_BOLT); return ENTITY_TYPE_TO_SPELL.values().stream().distinct().map(type -> EnchantableItem.enchant(getDefaultStack(), type)).toList();
} }
@Override @Override
@ -197,6 +199,14 @@ public class EnchantedStaffItem extends StaffItem implements EnchantableItem, Ch
return 3; 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 @Override
public void onDischarge(ItemStack stack) { public void onDischarge(ItemStack stack) {
if ((stack.hasNbt() && stack.getNbt().contains("energy") ? stack.getNbt().getFloat("energy") : 0) == 0) { if ((stack.hasNbt() && stack.getNbt().contains("energy") ? stack.getNbt().getFloat("energy") : 0) == 0) {

View file

@ -97,6 +97,7 @@
"item.unicopia.grogars_bell": "Grogar's Bell", "item.unicopia.grogars_bell": "Grogar's Bell",
"item.unicopia.grogars_bell.charges": "Charges: %d / %d", "item.unicopia.grogars_bell.charges": "Charges: %d / %d",
"item.unicopia.magic_staff": "Magic Staff", "item.unicopia.magic_staff": "Magic Staff",
"item.unicopia.magic_staff.enchanted": "%s of %s",
"item.unicopia.magic_staff.charges": "Charges: %d / %d", "item.unicopia.magic_staff.charges": "Charges: %d / %d",
"item.unicopia.meadowbrooks_staff": "Meadowbrook's Staff", "item.unicopia.meadowbrooks_staff": "Meadowbrook's Staff",
"item.unicopia.meadowbrooks_staff.lore": "A Heavy Stick", "item.unicopia.meadowbrooks_staff.lore": "A Heavy Stick",