mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 21:38:00 +01:00
Implement grogar's bell
This commit is contained in:
parent
b728416c17
commit
539f094582
5 changed files with 270 additions and 3 deletions
|
@ -38,6 +38,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
private static final TrackedData<NbtCompound> MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
|
||||
public static final TrackedData<Float> GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
private static final TrackedData<Integer> EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
private static final TrackedData<Boolean> DISCORDED = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
|
||||
public static void boostrap() {}
|
||||
|
||||
|
@ -52,11 +53,14 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
@Nullable
|
||||
private EatMuffinGoal eatMuffinGoal;
|
||||
|
||||
private boolean discordedChanged = true;
|
||||
|
||||
public Creature(LivingEntity entity) {
|
||||
super(entity, EFFECT);
|
||||
physics = new EntityPhysics<>(entity, GRAVITY);
|
||||
entity.getDataTracker().startTracking(MASTER, owner.toNBT());
|
||||
entity.getDataTracker().startTracking(EATING, 0);
|
||||
entity.getDataTracker().startTracking(DISCORDED, false);
|
||||
|
||||
addTicker(physics);
|
||||
addTicker(this::updateConsumption);
|
||||
|
@ -75,6 +79,15 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
return owner.getId().isPresent();
|
||||
}
|
||||
|
||||
public boolean isDiscorded() {
|
||||
return entity.getDataTracker().get(DISCORDED);
|
||||
}
|
||||
|
||||
public void setDiscorded(boolean discorded) {
|
||||
entity.getDataTracker().set(DISCORDED, discorded);
|
||||
discordedChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public LivingEntity getMaster() {
|
||||
|
@ -115,6 +128,10 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
initMinionAi(targets);
|
||||
}
|
||||
|
||||
if (isDiscorded()) {
|
||||
initDiscordedAi();
|
||||
}
|
||||
|
||||
if (entity instanceof CreeperEntity mob) {
|
||||
goals.add(1, new FleeEntityGoal<>(mob, LivingEntity.class, 10, 1.5, 1.9, AmuletSelectors.ALICORN_AMULET));
|
||||
}
|
||||
|
@ -131,12 +148,32 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
.isEmpty();
|
||||
});
|
||||
|
||||
targets.clear(g -> true);
|
||||
clearGoals(targets);
|
||||
targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, PlayerEntity.class, true, filter));
|
||||
targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, HostileEntity.class, true, filter));
|
||||
targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, SlimeEntity.class, true, filter));
|
||||
}
|
||||
|
||||
private void initDiscordedAi() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerAttributes(DefaultAttributeContainer.Builder builder) {
|
||||
builder.add(EntityAttributes.GENERIC_ATTACK_DAMAGE);
|
||||
builder.add(EntityAttributes.GENERIC_ATTACK_KNOCKBACK);
|
||||
|
@ -145,9 +182,17 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
|
||||
@Override
|
||||
public boolean beforeUpdate() {
|
||||
if (isDiscorded() && discordedChanged) {
|
||||
discordedChanged = false;
|
||||
initDiscordedAi();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void clearGoals(GoalSelector t) {
|
||||
t.clear(g -> true);
|
||||
}
|
||||
|
||||
private void updateConsumption() {
|
||||
if (isClient()) {
|
||||
eatTimer = entity.getDataTracker().get(EATING);
|
||||
|
@ -227,6 +272,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
});
|
||||
compound.put("master", owner.toNBT());
|
||||
physics.toNBT(compound);
|
||||
compound.putBoolean("discorded", isDiscorded());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -242,5 +288,6 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
}
|
||||
}
|
||||
physics.fromNBT(compound);
|
||||
setDiscorded(compound.getBoolean("discorded"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
@Nullable
|
||||
private Caster<?> attacker;
|
||||
|
||||
private Optional<Living<?>> target = Optional.empty();
|
||||
|
||||
private int invinsibilityTicks;
|
||||
|
||||
private final List<Tickable> tickers = new ArrayList<>();
|
||||
|
@ -135,6 +137,15 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
entity.getDataTracker().set(CARRIER_ID, Optional.ofNullable(carrier).map(Entity::getUuid));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Optional<Living<?>> getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(Living<?> target) {
|
||||
this.target = Optional.ofNullable(target);
|
||||
}
|
||||
|
||||
public boolean isBeingCarried() {
|
||||
Entity vehicle = entity.getVehicle();
|
||||
return vehicle != null && getCarrierId().filter(vehicle.getUuid()::equals).isPresent();
|
||||
|
|
|
@ -32,7 +32,6 @@ import net.minecraft.nbt.NbtCompound;
|
|||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.*;
|
||||
import net.minecraft.world.event.GameEvent;
|
||||
|
||||
|
|
210
src/main/java/com/minelittlepony/unicopia/item/BellItem.java
Normal file
210
src/main/java/com/minelittlepony/unicopia/item/BellItem.java
Normal file
|
@ -0,0 +1,210 @@
|
|||
package com.minelittlepony.unicopia.item;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.entity.Creature;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.mob.CreeperEntity;
|
||||
import net.minecraft.entity.mob.HostileEntity;
|
||||
import net.minecraft.entity.mob.IllagerEntity;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
import net.minecraft.util.UseAction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BellItem extends Item implements ChargeableItem {
|
||||
|
||||
public BellItem(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UseAction getUseAction(ItemStack stack) {
|
||||
return UseAction.BOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> list, TooltipContext tooltipContext) {
|
||||
list.add(Text.translatable(getTranslationKey() + ".charges", (int)Math.floor(ChargeableItem.getEnergy(stack)), getMaxCharge()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxUseTime(ItemStack stack) {
|
||||
return 3000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity target, Hand hand) {
|
||||
player.setCurrentHand(hand);
|
||||
Pony pony = Pony.of(player);
|
||||
pony.getCorruption().add(1);
|
||||
pony.playSound(SoundEvents.BLOCK_BELL_USE, 0.4F, 0.2F);
|
||||
Living<?> targetLiving = target instanceof HostileEntity || target instanceof PlayerEntity ? Living.getOrEmpty(target)
|
||||
.filter(living -> !(living instanceof Creature c && c.isDiscorded()))
|
||||
.orElse(null) : null;
|
||||
pony.setTarget(targetLiving);
|
||||
return targetLiving == null ? ActionResult.FAIL : ActionResult.CONSUME_PARTIAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
ItemStack offhandStack = AmuletItem.getForEntity(player);
|
||||
|
||||
if (!(offhandStack.getItem() instanceof ChargeableItem)) {
|
||||
offhandStack = player.getStackInHand(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND);
|
||||
}
|
||||
|
||||
Pony pony = Pony.of(player);
|
||||
|
||||
if (hasCharge(stack)) {
|
||||
pony.playSound(SoundEvents.BLOCK_BELL_RESONATE, 0.6F, 1);
|
||||
pony.getCorruption().add(1);
|
||||
if (offhandStack.getItem() instanceof ChargeableItem chargeable) {
|
||||
float maxChargeBy = chargeable.getMaxCharge() - ChargeableItem.getEnergy(offhandStack);
|
||||
float energyTransferred = Math.min(ChargeableItem.getEnergy(stack), maxChargeBy);
|
||||
chargeable.recharge(offhandStack, energyTransferred);
|
||||
ChargeableItem.consumeEnergy(stack, energyTransferred);
|
||||
} else {
|
||||
pony.getMagicalReserves().getMana().add(ChargeableItem.getEnergy(stack));
|
||||
ChargeableItem.setEnergy(stack, 0);
|
||||
}
|
||||
|
||||
pony.spawnParticles(pony.getPhysics().getHeadPosition().toCenterPos(), new Sphere(false, 0.5F), 7, p -> {
|
||||
pony.addParticle(new MagicParticleEffect(0xAAFFFF), p, Vec3d.ZERO);
|
||||
});
|
||||
|
||||
return TypedActionResult.consume(stack);
|
||||
}
|
||||
|
||||
pony.playSound(SoundEvents.BLOCK_BELL_USE, 0.01F, 0.9F);
|
||||
return TypedActionResult.consume(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void usageTick(World world, LivingEntity userEntity, ItemStack stack, int remainingUseTicks) {
|
||||
if (userEntity.age % 5 != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Living.getOrEmpty(userEntity).ifPresent(user -> {
|
||||
user.getTarget().ifPresent(living -> {
|
||||
float maxUseTime = getMaxUseTime(stack);
|
||||
float progress = (maxUseTime - remainingUseTicks) / maxUseTime;
|
||||
|
||||
if (tickDraining(user, living, stack, progress)) {
|
||||
onStoppedDraining(user, living, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void onStoppedDraining(Living<?> user, Living<?> target, boolean completed) {
|
||||
user.setTarget(null);
|
||||
user.playSound(SoundEvents.BLOCK_BELL_USE, 0.2F, 0.3F);
|
||||
if (target instanceof Creature creature && (completed || target.asEntity().getHealth() < (target.asEntity().getMaxHealth() * 0.5F) + 1)) {
|
||||
creature.setDiscorded(true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tickDraining(Living<?> user, Living<?> living, ItemStack stack, float progress) {
|
||||
if (living.getOrigin().getSquaredDistance(user.getOrigin()) > 25 || living.asEntity().isRemoved()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float amountDrawn;
|
||||
ParticleEffect particleType = ParticleTypes.COMPOSTER;
|
||||
|
||||
if (living instanceof Pony pony) {
|
||||
amountDrawn = pony.getMagicalReserves().getMana().get() * 0.2F;
|
||||
pony.getMagicalReserves().getMana().multiply(0.8F);
|
||||
if (pony.getActualSpecies() == Race.CHANGELING) {
|
||||
particleType = ParticleTypes.HEART;
|
||||
}
|
||||
} else {
|
||||
float damageAmount = Math.min(Math.max(1, living.asEntity().getMaxHealth() / 25F), living.asEntity().getHealth() - 1);
|
||||
living.asEntity().damage(MagicalDamageSource.EXHAUSTION, damageAmount);
|
||||
living.asEntity().setAttacker(user.asEntity());
|
||||
if (living.asEntity() instanceof MobEntity mob) {
|
||||
mob.setTarget(null);
|
||||
}
|
||||
if (living.asEntity() instanceof CreeperEntity creeper) {
|
||||
creeper.setFuseSpeed(0);
|
||||
}
|
||||
amountDrawn = Math.max(living.asEntity().getWidth(), living.asEntity().getHeight());
|
||||
if (living.asEntity() instanceof IllagerEntity) {
|
||||
particleType = ParticleTypes.ANGRY_VILLAGER;
|
||||
}
|
||||
|
||||
if (living.asEntity().getHealth() <= 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ChargeableItem.consumeEnergy(stack, -amountDrawn);
|
||||
|
||||
user.playSound(SoundEvents.ENTITY_GUARDIAN_ATTACK, 0.2F, progress);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
living.addParticle(
|
||||
new FollowingParticleEffect(UParticles.HEALTH_DRAIN, user.asEntity(), 0.4F)
|
||||
.withChild(particleType),
|
||||
living.getOriginVector().add(0, living.getPhysics().getGravitySignum() * living.asEntity().getHeight() / 2, 0)
|
||||
.add(VecHelper.supply(() -> user.asWorld().random.nextTriangular(0, 0.2))),
|
||||
Vec3d.ZERO
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack finishUsing(ItemStack stack, World world, LivingEntity user) {
|
||||
Living.getOrEmpty(user).ifPresent(living -> {
|
||||
living.getTarget().ifPresent(target -> {
|
||||
onStoppedDraining(living, target, true);
|
||||
});
|
||||
});
|
||||
return super.finishUsing(stack, world, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStoppedUsing(ItemStack stack, World world, LivingEntity user, int remainingUseTicks) {
|
||||
Living.getOrEmpty(user).ifPresent(living -> {
|
||||
living.getTarget().ifPresent(target -> {
|
||||
onStoppedDraining(living, target, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlint(ItemStack stack) {
|
||||
return stack.hasEnchantments() || ChargeableItem.getEnergy(stack) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxCharge() {
|
||||
return 1000;
|
||||
}
|
||||
}
|
|
@ -99,7 +99,7 @@ public interface UItems {
|
|||
Item GOLDEN_WING = register("golden_wing", new Item(new Item.Settings().rarity(Rarity.UNCOMMON)), ItemGroups.NATURAL);
|
||||
|
||||
Item DRAGON_BREATH_SCROLL = register("dragon_breath_scroll", new DragonBreathScrollItem(new Item.Settings().rarity(Rarity.UNCOMMON)), ItemGroups.TOOLS);
|
||||
Item GROGARS_BELL = register("grogars_bell", new Item(new Item.Settings().rarity(Rarity.RARE)), ItemGroups.TOOLS);
|
||||
Item GROGARS_BELL = register("grogars_bell", new BellItem(new Item.Settings().rarity(Rarity.RARE).maxCount(1)), ItemGroups.TOOLS);
|
||||
Item MEADOWBROOKS_STAFF = register("meadowbrooks_staff", new StaffItem(new Settings().rarity(Rarity.UNCOMMON).maxCount(1).maxDamage(120)), ItemGroups.TOOLS);
|
||||
Item MAGIC_STAFF = register("magic_staff", new EnchantedStaffItem(new Settings().rarity(Rarity.UNCOMMON).maxCount(1).maxDamage(120)), ItemGroups.TOOLS);
|
||||
|
||||
|
|
Loading…
Reference in a new issue