Unicopia/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java
2023-09-02 18:34:57 +01:00

230 lines
9.5 KiB
Java

package com.minelittlepony.unicopia.item;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import com.minelittlepony.unicopia.entity.mob.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;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.sound.SoundCategory;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class EnchantedStaffItem extends StaffItem implements EnchantableItem, ChargeableItem, MultiItem {
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) {
ENTITY_TYPE_TO_SPELL.put(entityType, spellType);
return spellType;
}
public static SpellType<?> getSpellType(Entity entity, boolean remove) {
if (entity instanceof CastSpellEntity cast) {
return cast.getSpellSlot().get(c -> !SpellPredicate.IS_PLACED.test(c), true).map(Spell::getType).orElse(SpellType.empty());
}
if (entity instanceof PlayerEntity player) {
if (remove) {
return Pony.of(player).getCharms().equipSpell(Hand.MAIN_HAND, SpellType.EMPTY_KEY.withTraits()).type();
}
return Pony.of(player).getCharms().getEquippedSpell(Hand.MAIN_HAND).type();
}
return ENTITY_TYPE_TO_SPELL.getOrDefault(entity.getType(), SpellType.empty());
}
static {
register(EntityType.DROWNED, SpellType.BUBBLE);
register(EntityType.DOLPHIN, SpellType.BUBBLE);
register(EntityType.BLAZE, SpellType.FIRE_BOLT);
register(EntityType.CHICKEN, SpellType.FEATHER_FALL);
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);
register(EntityType.GUARDIAN, SpellType.AWKWARD);
register(EntityType.ELDER_GUARDIAN, SpellType.AWKWARD);
register(EntityType.DRAGON_FIREBALL, SpellType.INFERNAL);
register(EntityType.CAVE_SPIDER, SpellType.REVEALING);
register(EntityType.ZOMBIE, SpellType.NECROMANCY);
register(EntityType.VEX, SpellType.NECROMANCY);
register(EntityType.SKELETON, SpellType.CATAPULT);
register(EntityType.WITHER_SKELETON, SpellType.CATAPULT);
register(EntityType.SKELETON_HORSE, SpellType.CATAPULT);
register(UEntities.TWITTERMITE, SpellType.LIGHT);
}
public EnchantedStaffItem(Settings settings) {
super(settings.maxDamage(500));
}
@Override
public List<ItemStack> getDefaultStacks() {
return Stream.concat(
Stream.of(getDefaultStack()),
ENTITY_TYPE_TO_SPELL.values().stream().distinct().map(type -> EnchantableItem.enchant(getDefaultStack(), type))
).toList();
}
@Override
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> lines, TooltipContext context) {
if (EnchantableItem.isEnchanted(stack)) {
SpellType<?> key = EnchantableItem.getSpellKey(stack);
lines.add(Text.translatable(key.getTranslationKey()).formatted(key.getAffinity().getColor()));
lines.add(Text.translatable(getTranslationKey(stack) + ".charges", (int)Math.floor(ChargeableItem.getEnergy(stack)), getMaxCharge()));
}
}
@Override
public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity target, Hand hand) {
if (EnchantableItem.isEnchanted(stack)) {
return ActionResult.PASS;
}
super.useOnEntity(stack, player, target, hand);
boolean remove = EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(target);
SpellType<?> type = getSpellType(target, remove);
if (!type.isEmpty()) {
if (remove) {
target.setHealth(1);
target.setFrozenTicks(9000);
}
player.setStackInHand(hand, recharge(EnchantableItem.enchant(stack, type)));
}
return ActionResult.SUCCESS;
}
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
ItemStack itemstack = player.getStackInHand(hand);
player.setCurrentHand(hand);
return TypedActionResult.consume(itemstack);
}
@Override
public void onStoppedUsing(ItemStack stack, World world, LivingEntity entity, int timeLeft) {
int i = getMaxUseTime(stack) - timeLeft;
if (EnchantableItem.isEnchanted(stack) && hasCharge(stack)) {
if (i > 20) {
Pony.of(entity).ifPresent(pony -> {
pony.subtractEnergyCost(4);
stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND));
getSpellEffect(stack).create().toThrowable().throwProjectile(pony);
pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10);
});
ChargeableItem.consumeEnergy(stack, 1);
} else if (i > 5) {
Pony.of(entity).ifPresent(pony -> {
pony.subtractEnergyCost(4);
stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND));
getSpellEffect(stack).create().toThrowable().throwProjectile(pony);
pony.setAnimation(Animation.ARMS_UP, Animation.Recipient.ANYONE, 10);
});
ChargeableItem.consumeEnergy(stack, 1);
}
}
}
@Override
protected boolean castContainedEffect(ItemStack stack, LivingEntity target, LivingEntity attacker) {
if (attacker.isSneaking() && hasCharge(stack)) {
stack.damage(50, attacker, p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND));
Caster.of(attacker).ifPresent(c -> c.subtractEnergyCost(4));
Caster.of(target).ifPresent(c -> getSpellEffect(stack).apply(c, CastingMethod.STAFF));
ChargeableItem.consumeEnergy(stack, 1);
return true;
}
return false;
}
@Override
public void usageTick(World world, LivingEntity entity, ItemStack stack, int ticksRemaining) {
if (entity instanceof LivingEntity) {
LivingEntity living = entity;
if (living.getActiveItem().getItem() == this) {
Vec3d eyes = entity.getCameraPosVec(1);
float i = getMaxUseTime(stack) - ticksRemaining;
world.addParticle(i > 150 ? ParticleTypes.LARGE_SMOKE : ParticleTypes.CLOUD, eyes.x, eyes.y, eyes.z,
(world.random.nextGaussian() - 0.5) / 10,
(world.random.nextGaussian() - 0.5) / 10,
(world.random.nextGaussian() - 0.5) / 10
);
world.playSound(null, entity.getBlockPos(), USounds.ITEM_MAGIC_STAFF_CHARGE, SoundCategory.PLAYERS, 1, i / 20);
if (i > 200) {
living.clearActiveItem();
living.damage(entity.getDamageSources().magic(), 1);
if (EnchantableItem.isEnchanted(stack) && hasCharge(stack)) {
Caster.of(entity).ifPresent(c -> getSpellEffect(stack).apply(c, CastingMethod.STAFF));
ChargeableItem.consumeEnergy(stack, 1);
}
}
}
}
}
@Override
public int getMaxUseTime(ItemStack stack) {
return 72000;
}
@Override
public int getMaxCharge() {
return 3;
}
@Override
public int getDefaultCharge() {
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) {
EnchantableItem.unenchant(stack);
}
}
}