2021-02-14 16:52:56 +01:00
|
|
|
package com.minelittlepony.unicopia.entity;
|
|
|
|
|
2021-02-14 17:46:41 +01:00
|
|
|
import java.util.Optional;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
2022-01-01 21:08:50 +01:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2021-08-04 15:38:03 +02:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2021-02-14 16:52:56 +01:00
|
|
|
|
2021-12-29 16:18:26 +01:00
|
|
|
import com.minelittlepony.unicopia.Unicopia;
|
2021-02-14 16:52:56 +01:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
2021-03-05 18:22:27 +01:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
2021-12-22 15:43:06 +01:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
2021-12-26 10:13:32 +01:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
|
2021-11-05 14:18:32 +01:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
2022-09-18 01:23:29 +02:00
|
|
|
import com.minelittlepony.unicopia.block.data.DragonBreathStore;
|
2021-02-14 17:46:41 +01:00
|
|
|
import com.minelittlepony.unicopia.item.UItems;
|
2021-12-21 16:28:47 +01:00
|
|
|
import com.minelittlepony.unicopia.network.datasync.EffectSync;
|
2022-09-18 01:23:29 +02:00
|
|
|
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
2021-03-06 10:58:44 +01:00
|
|
|
import com.minelittlepony.unicopia.projectile.ProjectileImpactListener;
|
2021-03-06 13:27:52 +01:00
|
|
|
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
2022-09-18 01:23:29 +02:00
|
|
|
import com.minelittlepony.unicopia.util.VecHelper;
|
2021-02-14 16:52:56 +01:00
|
|
|
|
2022-09-18 01:23:29 +02:00
|
|
|
import net.minecraft.entity.*;
|
2021-02-14 16:52:56 +01:00
|
|
|
import net.minecraft.entity.damage.DamageSource;
|
|
|
|
import net.minecraft.entity.data.TrackedData;
|
2022-09-18 01:23:29 +02:00
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
2021-02-14 16:52:56 +01:00
|
|
|
import net.minecraft.entity.projectile.ProjectileEntity;
|
2021-02-14 17:46:41 +01:00
|
|
|
import net.minecraft.item.ItemStack;
|
2021-08-04 15:38:03 +02:00
|
|
|
import net.minecraft.nbt.NbtCompound;
|
2022-09-18 01:23:29 +02:00
|
|
|
import net.minecraft.particle.ParticleTypes;
|
|
|
|
import net.minecraft.sound.SoundEvents;
|
2021-02-14 17:46:41 +01:00
|
|
|
import net.minecraft.util.Hand;
|
2022-09-18 01:23:29 +02:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
|
|
|
import net.minecraft.util.math.Vec3d;
|
2021-02-14 16:52:56 +01:00
|
|
|
|
|
|
|
public abstract class Living<T extends LivingEntity> implements Equine<T>, Caster<T> {
|
|
|
|
|
|
|
|
protected final T entity;
|
|
|
|
|
|
|
|
private final EffectSync effectDelegate;
|
|
|
|
|
|
|
|
private boolean prevSneaking;
|
|
|
|
private boolean prevLanded;
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
private Runnable landEvent;
|
|
|
|
|
2021-03-06 13:27:52 +01:00
|
|
|
@Nullable
|
|
|
|
private Entity attacker;
|
|
|
|
|
2021-02-14 17:46:41 +01:00
|
|
|
private int invinsibilityTicks;
|
|
|
|
|
2021-02-16 12:39:39 +01:00
|
|
|
private final Enchantments enchants = new Enchantments(this);
|
|
|
|
|
2021-08-04 15:38:03 +02:00
|
|
|
protected Living(T entity, TrackedData<NbtCompound> effect) {
|
2021-02-14 16:52:56 +01:00
|
|
|
this.entity = entity;
|
|
|
|
this.effectDelegate = new EffectSync(this, effect);
|
|
|
|
|
2021-08-04 15:38:03 +02:00
|
|
|
entity.getDataTracker().startTracking(effect, new NbtCompound());
|
2021-02-14 16:52:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public void waitForFall(Runnable action) {
|
2021-03-01 08:42:51 +01:00
|
|
|
if (entity.isOnGround()) {
|
|
|
|
action.run();
|
|
|
|
} else {
|
|
|
|
landEvent = action;
|
|
|
|
}
|
2021-02-14 16:52:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean sneakingChanged() {
|
|
|
|
return entity.isSneaking() != prevSneaking;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean landedChanged() {
|
|
|
|
return entity.isOnGround() != prevLanded;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-03-05 18:22:27 +01:00
|
|
|
public SpellContainer getSpellSlot() {
|
2021-02-14 16:52:56 +01:00
|
|
|
return effectDelegate;
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:39:39 +01:00
|
|
|
public Enchantments getEnchants() {
|
|
|
|
return enchants;
|
|
|
|
}
|
|
|
|
|
2021-02-14 16:52:56 +01:00
|
|
|
@Override
|
|
|
|
public void setMaster(T owner) {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-01-01 21:08:50 +01:00
|
|
|
@NotNull
|
2021-02-14 16:52:56 +01:00
|
|
|
public T getMaster() {
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void tick() {
|
2021-12-29 16:18:26 +01:00
|
|
|
try {
|
|
|
|
getSpellSlot().forEach(spell -> Operation.ofBoolean(spell.tick(this, Situation.BODY)), true);
|
|
|
|
} catch (Exception e) {
|
|
|
|
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", getEntity(), e);
|
|
|
|
}
|
2021-02-14 16:52:56 +01:00
|
|
|
|
2021-02-14 17:46:41 +01:00
|
|
|
if (invinsibilityTicks > 0) {
|
|
|
|
invinsibilityTicks--;
|
|
|
|
}
|
|
|
|
|
2021-03-01 08:42:51 +01:00
|
|
|
if (landEvent != null && entity.isOnGround() && landedChanged()) {
|
|
|
|
landEvent.run();
|
|
|
|
landEvent = null;
|
|
|
|
}
|
2021-02-14 16:52:56 +01:00
|
|
|
|
2021-02-16 12:39:39 +01:00
|
|
|
enchants.tick();
|
2021-03-01 08:42:51 +01:00
|
|
|
|
|
|
|
prevSneaking = entity.isSneaking();
|
|
|
|
prevLanded = entity.isOnGround();
|
2022-09-18 01:23:29 +02:00
|
|
|
|
|
|
|
if (!entity.world.isClient && (entity instanceof PlayerEntity || entity.hasCustomName())) {
|
|
|
|
|
|
|
|
Vec3d targetPos = entity.getRotationVector().multiply(2).add(entity.getEyePos());
|
|
|
|
|
|
|
|
if (entity.getWorld().isAir(new BlockPos(targetPos))) {
|
|
|
|
DragonBreathStore store = DragonBreathStore.get(entity.world);
|
|
|
|
String name = entity.getDisplayName().getString();
|
|
|
|
store.popEntries(name).forEach(stack -> {
|
|
|
|
Vec3d randomPos = targetPos.add(VecHelper.supply(() -> entity.getRandom().nextTriangular(0.1, 0.5)));
|
|
|
|
|
|
|
|
if (!entity.getWorld().isAir(new BlockPos(randomPos))) {
|
|
|
|
store.put(name, stack.payload());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
ParticleUtils.spawnParticle(entity.world, ParticleTypes.FLAME, randomPos.add(
|
|
|
|
VecHelper.supply(() -> entity.getRandom().nextTriangular(0.1, 0.5))
|
|
|
|
), Vec3d.ZERO);
|
|
|
|
}
|
|
|
|
|
|
|
|
ItemEntity item = EntityType.ITEM.create(entity.world);
|
|
|
|
item.setStack(stack.payload());
|
|
|
|
item.setPosition(randomPos);
|
|
|
|
item.world.spawnEntity(item);
|
|
|
|
entity.world.playSoundFromEntity(null, entity, SoundEvents.ITEM_FIRECHARGE_USE, entity.getSoundCategory(), 1, 1);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2021-02-14 16:52:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onJump() {
|
|
|
|
if (getPhysics().isGravityNegative()) {
|
|
|
|
entity.setVelocity(entity.getVelocity().multiply(1, -1, 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-06 13:27:52 +01:00
|
|
|
@Nullable
|
|
|
|
@Override
|
|
|
|
public final Entity getAttacker() {
|
|
|
|
return attacker;
|
|
|
|
}
|
|
|
|
|
2021-02-14 17:46:41 +01:00
|
|
|
@Override
|
|
|
|
public Optional<Boolean> onDamage(DamageSource source, float amount) {
|
|
|
|
|
|
|
|
if (source == DamageSource.LIGHTNING_BOLT) {
|
|
|
|
if (invinsibilityTicks > 0 || tryCaptureLightning()) {
|
|
|
|
return Optional.of(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-06 13:27:52 +01:00
|
|
|
if (source instanceof MagicalDamageSource) {
|
|
|
|
Entity attacker = ((MagicalDamageSource)source).getSpell();
|
|
|
|
if (attacker != null) {
|
|
|
|
this.attacker = attacker;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 17:46:41 +01:00
|
|
|
return Optional.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean tryCaptureLightning() {
|
|
|
|
return getInventoryStacks().filter(stack -> !stack.isEmpty() && stack.getItem() == UItems.EMPTY_JAR).findFirst().map(stack -> {
|
|
|
|
invinsibilityTicks = 20;
|
|
|
|
stack.split(1);
|
|
|
|
giveBackItem(UItems.LIGHTNING_JAR.getDefaultStack());
|
|
|
|
return stack;
|
|
|
|
}).isPresent();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Stream<ItemStack> getInventoryStacks() {
|
|
|
|
return Stream.of(entity.getStackInHand(Hand.MAIN_HAND), entity.getStackInHand(Hand.OFF_HAND));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void giveBackItem(ItemStack stack) {
|
|
|
|
entity.dropStack(stack);
|
|
|
|
}
|
|
|
|
|
2021-02-14 16:52:56 +01:00
|
|
|
@Override
|
|
|
|
public boolean onProjectileImpact(ProjectileEntity projectile) {
|
2021-03-03 10:33:23 +01:00
|
|
|
return getSpellSlot().get(true)
|
2021-03-06 10:58:44 +01:00
|
|
|
.filter(effect -> !effect.isDead()
|
|
|
|
&& effect instanceof ProjectileImpactListener
|
|
|
|
&& ((ProjectileImpactListener)effect).onProjectileImpact(projectile))
|
2021-03-03 10:33:23 +01:00
|
|
|
.isPresent();
|
2021-02-14 16:52:56 +01:00
|
|
|
}
|
|
|
|
|
2021-08-04 15:38:03 +02:00
|
|
|
protected void handleFall(float distance, float damageMultiplier, DamageSource cause) {
|
2021-12-22 15:43:06 +01:00
|
|
|
getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> {
|
2021-08-04 15:38:03 +02:00
|
|
|
spell.getDisguise().onImpact(this, distance, damageMultiplier, cause);
|
2021-02-14 16:52:56 +01:00
|
|
|
});
|
|
|
|
}
|
2021-02-16 12:39:39 +01:00
|
|
|
|
|
|
|
@Override
|
2021-08-04 15:38:03 +02:00
|
|
|
public void toNBT(NbtCompound compound) {
|
2021-02-16 12:39:39 +01:00
|
|
|
enchants.toNBT(compound);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-08-04 15:38:03 +02:00
|
|
|
public void fromNBT(NbtCompound compound) {
|
2021-02-16 12:39:39 +01:00
|
|
|
enchants.fromNBT(compound);
|
|
|
|
}
|
2021-02-14 16:52:56 +01:00
|
|
|
}
|