Unicopia/src/main/java/com/minelittlepony/unicopia/entity/SpellcastEntity.java

376 lines
11 KiB
Java
Raw Normal View History

package com.minelittlepony.unicopia.entity;
2020-01-16 12:35:46 +01:00
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race;
2020-04-22 20:23:54 +02:00
import com.minelittlepony.unicopia.ducks.PickedItemSupplier;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.magic.Affinity;
2020-04-15 18:12:00 +02:00
import com.minelittlepony.unicopia.magic.Castable;
import com.minelittlepony.unicopia.magic.Caster;
import com.minelittlepony.unicopia.magic.MagicEffect;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.network.EffectSync;
2020-01-16 12:35:46 +01:00
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
2020-04-15 12:37:14 +02:00
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityPose;
2020-01-16 12:35:46 +01:00
import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.mob.MobEntityWithAi;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion.DestructionType;
2020-04-22 20:23:54 +02:00
public class SpellcastEntity extends MobEntityWithAi implements IMagicals, Caster<LivingEntity>, InAnimate, PickedItemSupplier {
2020-01-16 12:35:46 +01:00
private static final TrackedData<Integer> LEVEL = DataTracker.registerData(SpellcastEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final TrackedData<Optional<UUID>> OWNER = DataTracker.registerData(SpellcastEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
private static final TrackedData<CompoundTag> EFFECT = DataTracker.registerData(SpellcastEntity.class, TrackedDataHandlerRegistry.TAG_COMPOUND);
private static final TrackedData<Integer> AFFINITY = DataTracker.registerData(SpellcastEntity.class, TrackedDataHandlerRegistry.INTEGER);
private LivingEntity owner = null;
public float hoverStart;
2020-01-16 12:35:46 +01:00
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
public SpellcastEntity(EntityType<SpellcastEntity> type, World w) {
super(type, w);
hoverStart = (float)(Math.random() * Math.PI * 2.0D);
setPersistent();
}
public GoalSelector getGoals() {
return goalSelector;
}
2020-04-15 12:37:14 +02:00
public GoalSelector getTargets() {
return targetSelector;
}
2020-01-16 12:35:46 +01:00
@Override
public boolean cannotDespawn() {
return true;
}
@Override
2020-04-22 16:28:20 +02:00
public boolean shouldRender(double distance) {
2020-01-16 12:35:46 +01:00
if (getCurrentLevel() > 0) {
distance /= getCurrentLevel();
}
if (distance > 0) {
distance--;
}
2020-04-22 16:28:20 +02:00
return super.shouldRender(distance);
2020-01-16 12:35:46 +01:00
}
@Override
public Affinity getAffinity() {
return Affinity.values()[dataTracker.get(AFFINITY)];
}
public void setAffinity(Affinity affinity) {
dataTracker.set(AFFINITY, affinity.ordinal());
}
@Override
2020-04-15 18:12:00 +02:00
public void setEffect(@Nullable MagicEffect effect) {
2020-01-16 12:35:46 +01:00
effectDelegate.set(effect);
if (effect != null) {
effect.onPlaced(this);
}
}
@Override
public boolean canInteract(Race race) {
return race.canCast();
}
@Nullable
@Override
2020-04-15 18:12:00 +02:00
public <T extends MagicEffect> T getEffect(@Nullable Class<T> type, boolean update) {
2020-01-16 12:35:46 +01:00
return effectDelegate.get(type, update);
}
@Override
public boolean hasEffect() {
return effectDelegate.has();
}
@Override
protected void initDataTracker() {
super.initDataTracker();
dataTracker.startTracking(LEVEL, 0);
dataTracker.startTracking(EFFECT, new CompoundTag());
dataTracker.startTracking(OWNER, Optional.empty());
dataTracker.startTracking(AFFINITY, Affinity.NEUTRAL.ordinal());
}
2020-04-22 20:23:54 +02:00
@Override
public ItemStack getPickedStack() {
2020-01-16 12:35:46 +01:00
return SpellRegistry.instance().enchantStack(new ItemStack(getItem()), getEffect().getName());
2020-04-22 20:23:54 +02:00
}
2020-01-16 12:35:46 +01:00
protected Item getItem() {
2020-04-24 15:23:36 +02:00
return getAffinity() == Affinity.BAD ? UItems.CORRUPTED_GEM : UItems.GEM;
2020-01-16 12:35:46 +01:00
}
@Override
public boolean isPushable() {
return false;
}
@Override
public boolean doesRenderOnFire() {
return false;
}
@Override
public void setOwner(LivingEntity owner) {
this.owner = owner;
setOwner(owner.getUuid());
}
protected void setOwner(UUID ownerId) {
dataTracker.set(OWNER, Optional.ofNullable(ownerId));
}
protected String getOwnerName() {
LivingEntity owner = getOwner();
if (owner != null) {
return owner.getEntityName();
}
return "";
}
@Nullable
@Override
public LivingEntity getOwner() {
if (owner == null) {
owner = dataTracker.get(OWNER).map(world::getPlayerByUuid).orElse(null);
}
return owner;
}
protected void displayTick() {
if (hasEffect()) {
getEffect().render(this);
}
}
@Override
public void tickMovement() {
super.mobTick();
if (world.isClient) {
displayTick();
}
if (!hasEffect()) {
remove();
} else {
2020-01-17 14:27:26 +01:00
if (getEffect().isDead()) {
2020-01-16 12:35:46 +01:00
remove();
onDeath();
} else {
getEffect().update(this);
}
if (getEffect().allowAI()) {
super.tickMovement();
}
}
if (overLevelCap()) {
if (world.random.nextInt(10) == 0) {
playSpawnEffects();
}
if (!world.isClient && hasEffect()) {
float exhaustionChance = getEffect().getExhaustion(this);
if (exhaustionChance == 0 || world.random.nextInt((int)(exhaustionChance / 500)) == 0) {
addLevels(-1);
} else if (world.random.nextInt((int)(exhaustionChance * 500)) == 0) {
setEffect(null);
} else if (world.random.nextInt((int)(exhaustionChance * 3500)) == 0) {
2020-04-22 16:28:20 +02:00
world.createExplosion(this, getX(), getY(), getZ(), getCurrentLevel()/2, DestructionType.BREAK);
2020-01-16 12:35:46 +01:00
remove();
}
}
}
if (getCurrentLevel() < 0) {
remove();
}
}
2020-04-15 12:37:14 +02:00
@Override
public EntityDimensions getDimensions(EntityPose pose) {
EntityDimensions dims = super.getDimensions(pose);
if (hasEffect() && getEffect().allowAI()) {
return EntityDimensions.changing(dims.width, 1.5F);
}
return dims;
}
2020-01-16 12:35:46 +01:00
public boolean overLevelCap() {
return getCurrentLevel() > getMaxLevel();
}
@Override
protected void fall(double y, boolean onGround, BlockState state, BlockPos pos) {
this.onGround = true;
}
@Override
public boolean damage(DamageSource source, float amount) {
if (!world.isClient) {
remove();
onDeath();
}
return false;
}
protected void onDeath() {
BlockSoundGroup sound = BlockSoundGroup.STONE;
2020-04-22 16:28:20 +02:00
world.playSound(getX(), getY(), getZ(), sound.getBreakSound(), SoundCategory.NEUTRAL, sound.getVolume(), sound.getPitch(), true);
2020-01-16 12:35:46 +01:00
if (world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)) {
int level = getCurrentLevel();
ItemStack stack = new ItemStack(getItem(), level + 1);
if (hasEffect()) {
SpellRegistry.instance().enchantStack(stack, getEffect().getName());
}
dropStack(stack, 0);
}
}
@Override
public void remove() {
if (hasEffect()) {
getEffect().setDead();
}
super.remove();
}
@Override
public ActionResult interactAt(PlayerEntity player, Vec3d vec, Hand hand) {
2020-01-17 14:27:26 +01:00
if (EquinePredicates.MAGI.test(player)) {
2020-01-16 12:35:46 +01:00
ItemStack currentItem = player.getStackInHand(Hand.MAIN_HAND);
if (currentItem != null
2020-04-15 18:12:00 +02:00
&& currentItem.getItem() instanceof Castable
&& ((Castable)currentItem.getItem()).canFeed(this, currentItem)
2020-01-16 12:35:46 +01:00
&& tryLevelUp(currentItem)) {
if (!player.abilities.creativeMode) {
currentItem.decrement(1);
if (currentItem.isEmpty()) {
player.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND);
}
}
return ActionResult.SUCCESS;
}
}
return ActionResult.FAIL;
}
public boolean tryLevelUp(ItemStack stack) {
if (hasEffect() && SpellRegistry.stackHasEnchantment(stack)) {
if (!getEffect().getName().contentEquals(SpellRegistry.getKeyFromStack(stack))) {
return false;
}
addLevels(1);
playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1);
return true;
}
return false;
}
@Override
public int getMaxLevel() {
return hasEffect() ? getEffect().getMaxLevelCutOff(this) : 0;
}
@Override
public int getCurrentLevel() {
return dataTracker.get(LEVEL);
}
@Override
public void setCurrentLevel(int level) {
dataTracker.set(LEVEL, Math.max(level, 0));
}
@Override
public Entity getEntity() {
return this;
}
@Override
public void readCustomDataFromTag(CompoundTag compound) {
super.readCustomDataFromTag(compound);
2020-04-22 16:28:20 +02:00
if (compound.contains("affinity")) {
2020-01-16 12:35:46 +01:00
setAffinity(Affinity.of(compound.getString("affinity")));
}
setOwner(compound.getUuid("owner"));
setCurrentLevel(compound.getInt("level"));
2020-04-22 16:28:20 +02:00
if (compound.contains("effect")) {
2020-01-16 12:35:46 +01:00
setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect")));
}
}
@Override
public void writeCustomDataToTag(CompoundTag compound) {
super.writeCustomDataToTag(compound);
compound.putString("affinity", getAffinity().name());
compound.putString("owner", getOwnerName());
compound.putInt("level", getCurrentLevel());
if (hasEffect()) {
compound.put("effect", SpellRegistry.instance().serializeEffectToNBT(getEffect()));
}
}
}