2020-09-22 15:11:20 +02:00
|
|
|
package com.minelittlepony.unicopia.entity;
|
2020-04-15 14:22:03 +02:00
|
|
|
|
2021-12-29 23:59:17 +01:00
|
|
|
import java.util.Optional;
|
|
|
|
import java.util.function.Predicate;
|
|
|
|
|
2022-01-01 21:08:50 +01:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2021-12-29 23:59:17 +01:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
|
2020-09-23 17:19:28 +02:00
|
|
|
import com.minelittlepony.unicopia.Affinity;
|
2020-04-15 14:22:03 +02:00
|
|
|
import com.minelittlepony.unicopia.Race;
|
2023-05-05 22:12:21 +02:00
|
|
|
import com.minelittlepony.unicopia.Unicopia;
|
2022-01-01 21:08:50 +01:00
|
|
|
import com.minelittlepony.unicopia.WeaklyOwned;
|
2022-09-01 22:57:19 +02:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.*;
|
2021-12-29 17:11:32 +01:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
2021-12-29 23:59:17 +01:00
|
|
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.TargetSelecter;
|
2021-02-18 21:30:43 +01:00
|
|
|
import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal;
|
2021-02-20 00:34:30 +01:00
|
|
|
import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal;
|
2022-03-27 17:47:52 +02:00
|
|
|
import com.minelittlepony.unicopia.entity.ai.EatMuffinGoal;
|
2021-02-16 12:39:39 +01:00
|
|
|
import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal;
|
|
|
|
|
2023-05-05 22:12:21 +02:00
|
|
|
import net.minecraft.entity.EntityType;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.entity.LivingEntity;
|
2021-02-18 21:30:43 +01:00
|
|
|
import net.minecraft.entity.SpawnGroup;
|
2022-10-17 18:01:55 +02:00
|
|
|
import net.minecraft.entity.ai.goal.*;
|
2021-02-16 12:39:39 +01:00
|
|
|
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
|
|
|
import net.minecraft.entity.attribute.EntityAttributes;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.entity.data.DataTracker;
|
|
|
|
import net.minecraft.entity.data.TrackedData;
|
|
|
|
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
2022-10-17 18:01:55 +02:00
|
|
|
import net.minecraft.entity.mob.*;
|
|
|
|
import net.minecraft.entity.passive.*;
|
2021-12-29 23:59:17 +01:00
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
2021-08-04 15:38:03 +02:00
|
|
|
import net.minecraft.nbt.NbtCompound;
|
2021-12-29 23:59:17 +01:00
|
|
|
import net.minecraft.nbt.NbtElement;
|
2022-03-27 17:47:52 +02:00
|
|
|
import net.minecraft.util.math.MathHelper;
|
2020-01-16 12:35:46 +01:00
|
|
|
|
2022-12-19 20:45:02 +01:00
|
|
|
public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutable<LivingEntity> {
|
2022-03-26 20:34:15 +01:00
|
|
|
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
|
|
|
|
private static final TrackedData<NbtCompound> MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
|
2021-02-22 14:54:24 +01:00
|
|
|
public static final TrackedData<Float> GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
2022-03-27 17:47:52 +02:00
|
|
|
private static final TrackedData<Integer> EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
2023-03-05 02:28:43 +01:00
|
|
|
private static final TrackedData<Boolean> DISCORDED = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
2020-01-16 12:35:46 +01:00
|
|
|
|
|
|
|
public static void boostrap() {}
|
|
|
|
|
2021-03-04 21:35:49 +01:00
|
|
|
private final EntityPhysics<LivingEntity> physics;
|
2020-05-10 17:18:45 +02:00
|
|
|
|
2022-12-19 17:27:24 +01:00
|
|
|
private final EntityReference<LivingEntity> owner = new EntityReference<>();
|
2021-12-29 23:59:17 +01:00
|
|
|
|
2022-12-25 23:21:34 +01:00
|
|
|
private Optional<GoalSelector> goals = Optional.empty();
|
|
|
|
private Optional<GoalSelector> targets = Optional.empty();
|
2021-12-29 23:59:17 +01:00
|
|
|
|
2022-03-27 17:47:52 +02:00
|
|
|
private int eatTimer;
|
|
|
|
@Nullable
|
|
|
|
private EatMuffinGoal eatMuffinGoal;
|
|
|
|
|
2023-03-05 02:28:43 +01:00
|
|
|
private boolean discordedChanged = true;
|
|
|
|
|
2023-08-06 19:28:30 +02:00
|
|
|
private final Predicate<LivingEntity> targetPredicate = TargetSelecter.<LivingEntity>notOwnerOrFriend(() -> getOriginatingCaster().getAffinity(), this).and(e -> {
|
2023-08-05 18:39:56 +02:00
|
|
|
return Equine.of(e)
|
|
|
|
.filter(eq -> eq instanceof Creature)
|
2023-08-06 19:28:30 +02:00
|
|
|
.filter(eq -> isDiscorded() != ((Creature)eq).hasCommonOwner(this))
|
2023-08-05 18:39:56 +02:00
|
|
|
.isEmpty();
|
|
|
|
});
|
|
|
|
|
2020-05-10 17:18:45 +02:00
|
|
|
public Creature(LivingEntity entity) {
|
2021-02-14 16:52:56 +01:00
|
|
|
super(entity, EFFECT);
|
2021-03-04 21:35:49 +01:00
|
|
|
physics = new EntityPhysics<>(entity, GRAVITY);
|
2022-12-19 17:27:24 +01:00
|
|
|
entity.getDataTracker().startTracking(MASTER, owner.toNBT());
|
2022-03-27 17:47:52 +02:00
|
|
|
entity.getDataTracker().startTracking(EATING, 0);
|
2023-03-05 02:28:43 +01:00
|
|
|
entity.getDataTracker().startTracking(DISCORDED, false);
|
2022-12-25 23:21:34 +01:00
|
|
|
|
|
|
|
addTicker(physics);
|
|
|
|
addTicker(this::updateConsumption);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
2021-12-29 23:59:17 +01:00
|
|
|
@Override
|
|
|
|
public void setMaster(LivingEntity owner) {
|
2022-12-19 17:27:24 +01:00
|
|
|
this.owner.set(owner);
|
|
|
|
entity.getDataTracker().set(MASTER, this.owner.toNBT());
|
2022-12-25 23:21:34 +01:00
|
|
|
if (owner != null) {
|
|
|
|
targets.ifPresent(this::initMinionAi);
|
2021-12-29 23:59:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-30 21:44:46 +01:00
|
|
|
public boolean isMinion() {
|
2023-08-05 18:39:56 +02:00
|
|
|
return getMasterReference().isSet();
|
2021-12-30 21:44:46 +01:00
|
|
|
}
|
|
|
|
|
2023-03-05 02:28:43 +01:00
|
|
|
public boolean isDiscorded() {
|
|
|
|
return entity.getDataTracker().get(DISCORDED);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setDiscorded(boolean discorded) {
|
|
|
|
entity.getDataTracker().set(DISCORDED, discorded);
|
|
|
|
discordedChanged = true;
|
|
|
|
}
|
|
|
|
|
2022-01-01 21:08:50 +01:00
|
|
|
@Override
|
|
|
|
@NotNull
|
2021-12-29 23:59:17 +01:00
|
|
|
public LivingEntity getMaster() {
|
2023-08-05 18:39:56 +02:00
|
|
|
return getMasterReference().getOrEmpty(asWorld()).orElse(entity);
|
2021-12-29 23:59:17 +01:00
|
|
|
}
|
|
|
|
|
2022-01-01 21:08:50 +01:00
|
|
|
@Override
|
|
|
|
public EntityReference<LivingEntity> getMasterReference() {
|
2023-08-05 18:39:56 +02:00
|
|
|
if (entity.getDataTracker().containsKey(MASTER)) {
|
|
|
|
NbtCompound data = entity.getDataTracker().get(MASTER);
|
|
|
|
owner.fromNBT(data);
|
|
|
|
}
|
2022-12-19 17:27:24 +01:00
|
|
|
return owner;
|
2022-01-01 21:08:50 +01:00
|
|
|
}
|
|
|
|
|
2021-12-29 23:59:17 +01:00
|
|
|
public Optional<GoalSelector> getTargets() {
|
2022-12-25 23:21:34 +01:00
|
|
|
return targets;
|
2021-12-29 23:59:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public Optional<GoalSelector> getGoals() {
|
2022-12-25 23:21:34 +01:00
|
|
|
return goals;
|
2021-12-29 23:59:17 +01:00
|
|
|
}
|
|
|
|
|
2021-02-16 12:39:39 +01:00
|
|
|
public void initAi(GoalSelector goals, GoalSelector targets) {
|
2022-12-25 23:21:34 +01:00
|
|
|
this.goals = Optional.of(goals);
|
|
|
|
this.targets = Optional.of(targets);
|
2021-12-29 23:59:17 +01:00
|
|
|
|
2021-02-20 00:34:30 +01:00
|
|
|
DynamicTargetGoal targetter = new DynamicTargetGoal((MobEntity)entity);
|
|
|
|
targets.add(1, targetter);
|
2023-05-05 22:12:21 +02:00
|
|
|
if (!Unicopia.getConfig().wantItNeedItEntityExcludelist.get().contains(EntityType.getId(entity.getType()).toString())) {
|
|
|
|
goals.add(1, new WantItTakeItGoal((MobEntity)entity, targetter));
|
|
|
|
}
|
2021-02-18 21:30:43 +01:00
|
|
|
if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) {
|
2021-02-20 00:34:30 +01:00
|
|
|
goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter));
|
2021-02-18 21:30:43 +01:00
|
|
|
}
|
2022-10-17 18:01:55 +02:00
|
|
|
if (entity instanceof PigEntity pig) {
|
|
|
|
eatMuffinGoal = new EatMuffinGoal(pig, targetter);
|
2022-03-27 17:47:52 +02:00
|
|
|
goals.add(3, eatMuffinGoal);
|
|
|
|
}
|
2021-12-29 23:59:17 +01:00
|
|
|
|
2023-08-05 18:39:56 +02:00
|
|
|
if (getMasterReference().isSet()) {
|
2022-12-25 23:21:34 +01:00
|
|
|
initMinionAi(targets);
|
2021-12-29 23:59:17 +01:00
|
|
|
}
|
2022-10-17 18:01:55 +02:00
|
|
|
|
2023-03-05 02:28:43 +01:00
|
|
|
if (isDiscorded()) {
|
|
|
|
initDiscordedAi();
|
|
|
|
}
|
|
|
|
|
2022-10-17 18:01:55 +02:00
|
|
|
if (entity instanceof CreeperEntity mob) {
|
|
|
|
goals.add(1, new FleeEntityGoal<>(mob, LivingEntity.class, 10, 1.5, 1.9, AmuletSelectors.ALICORN_AMULET));
|
|
|
|
}
|
|
|
|
if (entity instanceof PassiveEntity mob) {
|
2022-12-09 22:19:45 +01:00
|
|
|
goals.add(1, new FleeEntityGoal<>(mob, LivingEntity.class, 10, 1.1, 1.7, AmuletSelectors.ALICORN_AMULET_AFTER_1_DAYS));
|
2022-10-17 18:01:55 +02:00
|
|
|
}
|
2021-12-29 23:59:17 +01:00
|
|
|
}
|
|
|
|
|
2023-08-05 18:39:56 +02:00
|
|
|
private void initMinionAi(GoalSelector targets) {
|
2023-03-05 02:28:43 +01:00
|
|
|
clearGoals(targets);
|
2023-08-05 18:39:56 +02:00
|
|
|
targets.add(2, new ActiveEnemyGoal<>(PlayerEntity.class));
|
|
|
|
targets.add(2, new ActiveEnemyGoal<>(HostileEntity.class));
|
|
|
|
targets.add(2, new ActiveEnemyGoal<>(SlimeEntity.class));
|
2021-02-16 12:39:39 +01:00
|
|
|
}
|
|
|
|
|
2023-03-05 02:28:43 +01:00
|
|
|
private void initDiscordedAi() {
|
2023-08-06 19:28:30 +02:00
|
|
|
if (getMasterReference().isSet()) {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-05 02:28:43 +01:00
|
|
|
targets.ifPresent(this::clearGoals);
|
|
|
|
// the brain drain
|
|
|
|
entity.getBrain().clear();
|
|
|
|
if (entity instanceof MobEntity mob) {
|
|
|
|
mob.setTarget(null);
|
|
|
|
goals.ifPresent(goalSelector -> {
|
|
|
|
clearGoals(goalSelector);
|
|
|
|
goalSelector.add(1, new SwimGoal(mob));
|
|
|
|
if (mob instanceof PathAwareEntity pae) {
|
|
|
|
goalSelector.add(5, new WanderAroundFarGoal(pae, 0.8));
|
|
|
|
}
|
|
|
|
goalSelector.add(6, new LookAtEntityGoal(mob, PlayerEntity.class, 8.0f));
|
|
|
|
goalSelector.add(6, new LookAroundGoal(mob));
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
goals.ifPresent(this::clearGoals);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:39:39 +01:00
|
|
|
public static void registerAttributes(DefaultAttributeContainer.Builder builder) {
|
|
|
|
builder.add(EntityAttributes.GENERIC_ATTACK_DAMAGE);
|
|
|
|
builder.add(EntityAttributes.GENERIC_ATTACK_KNOCKBACK);
|
2023-08-07 17:42:51 +02:00
|
|
|
builder.add(UEntityAttributes.ENTITY_GRAVITY_MODIFIER);
|
2021-02-16 12:39:39 +01:00
|
|
|
}
|
|
|
|
|
2022-12-25 16:01:12 +01:00
|
|
|
@Override
|
|
|
|
public boolean beforeUpdate() {
|
2023-03-05 02:28:43 +01:00
|
|
|
if (isDiscorded() && discordedChanged) {
|
|
|
|
discordedChanged = false;
|
|
|
|
initDiscordedAi();
|
|
|
|
}
|
2023-08-05 18:39:56 +02:00
|
|
|
|
2023-08-11 19:51:35 +02:00
|
|
|
return super.beforeUpdate();
|
2022-12-25 16:01:12 +01:00
|
|
|
}
|
|
|
|
|
2023-03-05 02:28:43 +01:00
|
|
|
private void clearGoals(GoalSelector t) {
|
|
|
|
t.clear(g -> true);
|
|
|
|
}
|
|
|
|
|
2022-12-25 23:21:34 +01:00
|
|
|
private void updateConsumption() {
|
2022-03-27 17:47:52 +02:00
|
|
|
if (isClient()) {
|
|
|
|
eatTimer = entity.getDataTracker().get(EATING);
|
|
|
|
} else if (eatMuffinGoal != null) {
|
|
|
|
eatTimer = eatMuffinGoal.getTimer();
|
|
|
|
entity.getDataTracker().set(EATING, eatTimer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public float getNeckAngle(float delta) {
|
|
|
|
if (eatTimer <= 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (eatTimer >= 4 && eatTimer <= 36) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (eatTimer < 4) {
|
|
|
|
return (eatTimer - delta) / 4F;
|
|
|
|
}
|
|
|
|
return -(eatTimer - 40 - delta) / 4F;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float getHeadAngle(float delta) {
|
|
|
|
if (eatTimer > 4 && eatTimer <= 36) {
|
|
|
|
float f = (eatTimer - 4 - delta) / 32F;
|
|
|
|
return 0.62831855f + 0.21991149f * MathHelper.sin(f * 28.7F);
|
|
|
|
}
|
|
|
|
if (eatTimer > 0) {
|
|
|
|
return 0.62831855f;
|
|
|
|
}
|
|
|
|
return entity.getPitch() * ((float)Math.PI / 180);
|
2021-02-23 18:02:23 +01:00
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
@Override
|
|
|
|
public Race getSpecies() {
|
|
|
|
return Race.HUMAN;
|
|
|
|
}
|
|
|
|
|
2020-05-10 17:18:45 +02:00
|
|
|
@Override
|
|
|
|
public Physics getPhysics() {
|
|
|
|
return physics;
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
@Override
|
|
|
|
public void setSpecies(Race race) {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-10-02 09:39:00 +02:00
|
|
|
public LevelStore getLevel() {
|
2022-09-17 22:11:24 +02:00
|
|
|
return Levelled.EMPTY;
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
2022-09-01 22:57:19 +02:00
|
|
|
@Override
|
|
|
|
public LevelStore getCorruption() {
|
2022-09-17 22:11:24 +02:00
|
|
|
return Levelled.EMPTY;
|
2022-09-01 22:57:19 +02:00
|
|
|
}
|
|
|
|
|
2021-03-06 11:26:54 +01:00
|
|
|
@Override
|
|
|
|
public boolean subtractEnergyCost(double amount) {
|
2023-06-02 21:20:30 +02:00
|
|
|
getMaster().damage(asEntity().getDamageSources().magic(), (int)amount/2);
|
2021-03-06 11:26:54 +01:00
|
|
|
return getMaster().getHealth() > 0;
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
@Override
|
|
|
|
public Affinity getAffinity() {
|
2020-10-08 19:22:20 +02:00
|
|
|
if (getMaster() instanceof Affine) {
|
2023-08-06 19:28:30 +02:00
|
|
|
Affinity affinity = ((Affine)getMaster()).getAffinity();
|
|
|
|
if (isDiscorded()) {
|
|
|
|
return affinity == Affinity.BAD ? Affinity.GOOD : affinity == Affinity.GOOD ? Affinity.BAD : affinity;
|
|
|
|
}
|
|
|
|
return affinity;
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
return Affinity.NEUTRAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-08-04 15:38:03 +02:00
|
|
|
public void toNBT(NbtCompound compound) {
|
2021-02-16 12:39:39 +01:00
|
|
|
super.toNBT(compound);
|
2021-03-03 10:33:23 +01:00
|
|
|
getSpellSlot().get(true).ifPresent(effect -> {
|
2021-12-29 17:11:32 +01:00
|
|
|
compound.put("effect", Spell.writeNbt(effect));
|
2021-03-03 10:33:23 +01:00
|
|
|
});
|
2023-08-05 18:39:56 +02:00
|
|
|
compound.put("master", getMasterReference().toNBT());
|
2020-05-10 17:18:45 +02:00
|
|
|
physics.toNBT(compound);
|
2023-03-05 02:28:43 +01:00
|
|
|
compound.putBoolean("discorded", isDiscorded());
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-08-04 15:38:03 +02:00
|
|
|
public void fromNBT(NbtCompound compound) {
|
2021-02-16 12:39:39 +01:00
|
|
|
super.fromNBT(compound);
|
2020-04-22 16:28:20 +02:00
|
|
|
if (compound.contains("effect")) {
|
2021-12-29 17:11:32 +01:00
|
|
|
getSpellSlot().put(Spell.readNbt(compound.getCompound("effect")));
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
2021-12-29 23:59:17 +01:00
|
|
|
if (compound.contains("master", NbtElement.COMPOUND_TYPE)) {
|
2022-12-19 17:27:24 +01:00
|
|
|
owner.fromNBT(compound.getCompound("master"));
|
2023-08-05 18:39:56 +02:00
|
|
|
if (entity.getDataTracker().containsKey(MASTER)) {
|
|
|
|
entity.getDataTracker().set(MASTER, owner.toNBT());
|
|
|
|
}
|
|
|
|
if (owner.isSet()) {
|
2022-12-25 23:21:34 +01:00
|
|
|
targets.ifPresent(this::initMinionAi);
|
2021-12-29 23:59:17 +01:00
|
|
|
}
|
|
|
|
}
|
2020-05-10 17:18:45 +02:00
|
|
|
physics.fromNBT(compound);
|
2023-03-05 02:28:43 +01:00
|
|
|
setDiscorded(compound.getBoolean("discorded"));
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
2023-08-05 18:39:56 +02:00
|
|
|
|
|
|
|
private class ActiveEnemyGoal<T extends LivingEntity> extends ActiveTargetGoal<T> {
|
|
|
|
public ActiveEnemyGoal(Class<T> targetClass) {
|
|
|
|
super((MobEntity)entity, targetClass, true, Creature.this.targetPredicate);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean shouldContinue() {
|
|
|
|
LivingEntity target = this.mob.getTarget();
|
|
|
|
return target != null && targetPredicate.test(mob, target) && super.shouldContinue();
|
|
|
|
}
|
|
|
|
}
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|