mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-17 10:24:23 +01:00
The Ignominious Bulb now grows from a sprout when first summoned and will no longer lose its arms
This commit is contained in:
parent
d9bebf0b0f
commit
144f00c207
6 changed files with 224 additions and 29 deletions
|
@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.block;
|
|||
|
||||
import com.minelittlepony.unicopia.ability.EarthPonyGrowAbility.Growable;
|
||||
import com.minelittlepony.unicopia.entity.mob.IgnominiousBulbEntity;
|
||||
import com.minelittlepony.unicopia.entity.mob.TentacleEntity;
|
||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
|
@ -33,21 +32,16 @@ public class CuringJokeBlock extends FlowerBlock implements Growable {
|
|||
.map(BlockPos::toImmutable)
|
||||
.toList();
|
||||
|
||||
if (otherFlowers.size() >= 8) {
|
||||
IgnominiousBulbEntity bulb = new IgnominiousBulbEntity(world);
|
||||
bulb.updatePositionAndAngles(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0);
|
||||
IgnominiousBulbEntity bulb = new IgnominiousBulbEntity(world);
|
||||
bulb.setBaby(true);
|
||||
bulb.updatePositionAndAngles(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0);
|
||||
|
||||
if (Dismounting.canPlaceEntityAt(world, bulb, bulb.getBoundingBox())) {
|
||||
otherFlowers.forEach(p -> world.removeBlock(p, false));
|
||||
world.spawnEntity(bulb);
|
||||
return true;
|
||||
}
|
||||
if (Dismounting.canPlaceEntityAt(world, bulb, bulb.getBoundingBox())) {
|
||||
otherFlowers.forEach(p -> world.breakBlock(p, false));
|
||||
world.spawnEntity(bulb);
|
||||
return true;
|
||||
}
|
||||
|
||||
world.removeBlock(pos, false);
|
||||
TentacleEntity tentacle = new TentacleEntity(world, pos);
|
||||
tentacle.updatePositionAndAngles(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0);
|
||||
world.spawnEntity(tentacle);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,13 @@ public class IgnominiousBulbEntityModel extends EntityModel<IgnominiousBulbEntit
|
|||
public void setAngles(IgnominiousBulbEntity entity, float limbSwing, float limbSwingAmount, float tickDelta, float yaw, float pitch) {
|
||||
|
||||
float age = entity.age + tickDelta;
|
||||
float scale = entity.getScale(tickDelta);
|
||||
|
||||
part.xScale = scale;
|
||||
part.yScale = scale;
|
||||
part.zScale = scale;
|
||||
part.pivotY = (1 - scale) * 24;
|
||||
part.yaw = yaw * MathHelper.RADIANS_PER_DEGREE;
|
||||
|
||||
head.yScale = 1 - MathHelper.sin(age * 0.05F) * 0.02F;
|
||||
|
||||
|
@ -65,9 +72,10 @@ public class IgnominiousBulbEntityModel extends EntityModel<IgnominiousBulbEntit
|
|||
head.zScale = hScale;
|
||||
|
||||
head.pitch = MathHelper.sin(age * 0.02F) * 0.02F;
|
||||
head.yaw = MathHelper.cos(age * 0.02F) * 0.02F;
|
||||
head.yaw = (MathHelper.cos(age * 0.02F) * 0.02F);
|
||||
|
||||
leaves.yScale = 1 + MathHelper.sin(age * 0.05F) * 0.12F;
|
||||
leaves.yaw = -part.yaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,7 +26,7 @@ public class IgnominiousBulbEntityRenderer extends EntityRenderer<IgnominiousBul
|
|||
matrices.scale(-1, -1, 1);
|
||||
matrices.translate(0, -1.5F, 0);
|
||||
|
||||
model.setAngles(entity, 0, 0, tickDelta, entity.getYaw(tickDelta), entity.getPitch(tickDelta));
|
||||
model.setAngles(entity, 0, 0, tickDelta, 180 + yaw, entity.getPitch(tickDelta));
|
||||
model.render(matrices, vertices.getBuffer(model.getLayer(getTexture(entity))), light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||
matrices.pop();
|
||||
super.render(entity, yaw, tickDelta, matrices, vertices, light);
|
||||
|
|
|
@ -27,6 +27,7 @@ import net.minecraft.registry.Registries;
|
|||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.SynchronousResourceReloader;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Colors;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Box;
|
||||
|
@ -109,7 +110,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader
|
|||
int left = (int)caster.asEntity().getWidth() * 64;
|
||||
|
||||
for (Text line : debugLines) {
|
||||
client.textRenderer.draw(line, left += 1, top += spacing, 0xFFFFFFFF, false, matrices.peek().getPositionMatrix(), vertices, TextLayerType.NORMAL, j, light);
|
||||
client.textRenderer.draw(line, left += 1, top += spacing, Colors.WHITE, false, matrices.peek().getPositionMatrix(), vertices, TextLayerType.NORMAL, j, light);
|
||||
}
|
||||
matrices.pop();
|
||||
}
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
package com.minelittlepony.unicopia.entity.mob;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.EntityDimensions;
|
||||
import net.minecraft.entity.EntityPose;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.MovementType;
|
||||
|
@ -20,17 +25,32 @@ import net.minecraft.entity.data.DataTracker;
|
|||
import net.minecraft.entity.data.TrackedData;
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.passive.PassiveEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.nbt.NbtList;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.minecraft.predicate.entity.EntityPredicates;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
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.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldEvents;
|
||||
|
||||
public class IgnominiousBulbEntity extends MobEntity {
|
||||
private static final TrackedData<Boolean> ANGRY = DataTracker.registerData(IgnominiousBulbEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<Integer> AGE = DataTracker.registerData(IgnominiousBulbEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
private static final int BABY_AGE = PassiveEntity.BABY_AGE;
|
||||
private static final int HAPPY_TICKS = 40;
|
||||
private static final List<BlockPos> TENTACLE_OFFSETS = List.of(
|
||||
new BlockPos(-3, 0, -3), new BlockPos(0, 0, -4), new BlockPos(3, 0, -3),
|
||||
new BlockPos(-4, 0, 0), new BlockPos(4, 0, 0),
|
||||
|
@ -40,6 +60,10 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
@Nullable
|
||||
private Map<BlockPos, TentacleEntity> tentacles;
|
||||
|
||||
private int prevAge;
|
||||
private int happyTicks;
|
||||
private int angryTicks;
|
||||
|
||||
public IgnominiousBulbEntity(EntityType<? extends IgnominiousBulbEntity> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
@ -52,6 +76,29 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
protected void initDataTracker() {
|
||||
super.initDataTracker();
|
||||
dataTracker.startTracking(ANGRY, false);
|
||||
dataTracker.startTracking(AGE, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBaby() {
|
||||
return getAge() < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaby(boolean baby) {
|
||||
setAge(BABY_AGE);
|
||||
}
|
||||
|
||||
protected int getAge() {
|
||||
return dataTracker.get(AGE);
|
||||
}
|
||||
|
||||
protected void setAge(int age) {
|
||||
dataTracker.set(AGE, age);
|
||||
}
|
||||
|
||||
public float getScale(float tickDelta) {
|
||||
return Math.max(0.2F, 1 - (MathHelper.clamp(MathHelper.lerp(tickDelta, prevAge, getAge()), BABY_AGE, 0F) / BABY_AGE));
|
||||
}
|
||||
|
||||
public boolean isAngry() {
|
||||
|
@ -59,7 +106,56 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
}
|
||||
|
||||
public void setAngry(boolean angry) {
|
||||
dataTracker.set(ANGRY, angry);
|
||||
if (angry != isAngry()) {
|
||||
dataTracker.set(ANGRY, angry);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAngryFor(int angryTicks) {
|
||||
this.angryTicks = angryTicks;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionResult interactMob(PlayerEntity player, Hand hand) {
|
||||
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
if (isBaby() && stack.isOf(Items.BONE_MEAL)) {
|
||||
if (!player.isCreative()) {
|
||||
stack.decrement(1);
|
||||
}
|
||||
growUp(10);
|
||||
if (!getWorld().isClient) {
|
||||
getWorld().syncWorldEvent(WorldEvents.BONE_MEAL_USED, getBlockPos(), 0);
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerSpawnedChild(PlayerEntity player, MobEntity child) {
|
||||
Vec3d center = getPos();
|
||||
Supplier<Vec3d> offset = VecHelper.supplier(() -> (getWorld().random.nextBoolean() ? 1 : -1) * 3);
|
||||
setPosition(center.add(offset.get().multiply(1, 0, 1)));
|
||||
child.setPosition(center.add(offset.get().multiply(1, 0, 1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(double x, double y, double z) {
|
||||
Vec3d change = new Vec3d(x, y, z).subtract(getPos());
|
||||
super.setPosition(x, y, z);
|
||||
getTentacles().values().forEach(tentacle -> {
|
||||
tentacle.setPosition(tentacle.getPos().add(change));
|
||||
});
|
||||
}
|
||||
|
||||
public void growUp(int age) {
|
||||
int currentAge = getAge();
|
||||
if (currentAge < 0) {
|
||||
setAge((age * 20) + currentAge);
|
||||
happyTicks = HAPPY_TICKS;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,20 +164,27 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
var center = new BlockPos.Mutable();
|
||||
var tentacles = getTentacles();
|
||||
|
||||
TENTACLE_OFFSETS.forEach(offset -> {
|
||||
tentacles.compute(adjustForTerrain(center, offset), this::updateTentacle);
|
||||
});
|
||||
if (!isBaby() && !firstUpdate) {
|
||||
TENTACLE_OFFSETS.forEach(offset -> {
|
||||
tentacles.compute(adjustForTerrain(center, offset), this::updateTentacle);
|
||||
});
|
||||
}
|
||||
|
||||
if (getWorld().random.nextInt(isAngry() ? 12 : 1200) == 0) {
|
||||
for (TentacleEntity tentacle : tentacles.values()) {
|
||||
for (TentacleEntity tentacle : tentacles.values()) {
|
||||
if (getWorld().random.nextInt(isAngry() ? 12 : 1200) == 0) {
|
||||
tentacle.addActiveTicks(120);
|
||||
}
|
||||
}
|
||||
LivingEntity target = getAttacker();
|
||||
|
||||
setAngry(target != null);
|
||||
if (angryTicks > 0) {
|
||||
angryTicks--;
|
||||
}
|
||||
|
||||
if (isAngry() && getWorld().random.nextInt(30) == 0) {
|
||||
setAngry(!isBaby() && (angryTicks > 0 || target != null));
|
||||
|
||||
float healthPercentage = getHealth() / getMaxHealth();
|
||||
if (isAngry() && target != null && getWorld().random.nextInt(1 + (int)(healthPercentage * 30)) == 0) {
|
||||
if (target instanceof PlayerEntity player) {
|
||||
Pony.of(player).getMagicalReserves().getEnergy().add(6);
|
||||
}
|
||||
|
@ -94,16 +197,41 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
tentacle.setTarget(target);
|
||||
});
|
||||
}
|
||||
|
||||
if (target != null) {
|
||||
lookAtEntity(target, 10, 10);
|
||||
}
|
||||
}
|
||||
|
||||
super.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickMovement() {
|
||||
super.tickMovement();
|
||||
prevAge = getAge();
|
||||
|
||||
if (getWorld().isClient) {
|
||||
if (happyTicks > 0 && --happyTicks % 4 == 0) {
|
||||
getWorld().addParticle(ParticleTypes.HAPPY_VILLAGER, getParticleX(1), getRandomBodyY() + 0.5, getParticleZ(1), 0, 0, 0);
|
||||
}
|
||||
} else {
|
||||
if (prevAge < 0) {
|
||||
setAge(prevAge + 1);
|
||||
} else if (prevAge > 0) {
|
||||
setAge(prevAge - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<BlockPos, TentacleEntity> getTentacles() {
|
||||
if (tentacles == null) {
|
||||
tentacles = getWorld().getEntitiesByClass(TentacleEntity.class, this.getBoundingBox().expand(5, 0, 5), EntityPredicates.VALID_ENTITY)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(TentacleEntity::getBlockPos, Function.identity()));
|
||||
.collect(Collectors.toMap(TentacleEntity::getBlockPos, tentacle -> {
|
||||
tentacle.setBulb(this);
|
||||
return tentacle;
|
||||
}));
|
||||
}
|
||||
return tentacles;
|
||||
}
|
||||
|
@ -112,7 +240,11 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
if (tentacle == null || tentacle.isRemoved()) {
|
||||
tentacle = new TentacleEntity(getWorld(), pos);
|
||||
tentacle.updatePositionAndAngles(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, getWorld().random.nextFloat() * 360, 0);
|
||||
getWorld().spawnEntity(tentacle);
|
||||
tentacle.setBulb(this);
|
||||
|
||||
if (getWorld().isTopSolid(pos.down(), this)) {
|
||||
getWorld().spawnEntity(tentacle);
|
||||
}
|
||||
}
|
||||
return tentacle;
|
||||
}
|
||||
|
@ -157,6 +289,9 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
@Override
|
||||
@Nullable
|
||||
protected SoundEvent getHurtSound(DamageSource source) {
|
||||
if (isBaby()) {
|
||||
return SoundEvents.ENTITY_HORSE_BREATHE;
|
||||
}
|
||||
return USounds.ENTITY_IGNIMEOUS_BULB_HURT;
|
||||
}
|
||||
|
||||
|
@ -166,15 +301,60 @@ public class IgnominiousBulbEntity extends MobEntity {
|
|||
return USounds.ENTITY_IGNIMEOUS_BULB_DEATH;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected SoundEvent getAmbientSound() {
|
||||
if (!isBaby() && getWorld().random.nextInt(2) == 0) {
|
||||
return SoundEvents.ENTITY_CAMEL_AMBIENT;
|
||||
}
|
||||
return SoundEvents.ITEM_BONE_MEAL_USE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCustomDataToNbt(NbtCompound nbt) {
|
||||
super.writeCustomDataToNbt(nbt);
|
||||
nbt.putBoolean("angry", isAngry());
|
||||
nbt.putInt("age", getAge());
|
||||
NbtList tentacles = new NbtList();
|
||||
getTentacles().forEach((pos, tentacle) -> {
|
||||
var compound = new NbtCompound();
|
||||
compound.put("pos", NbtSerialisable.BLOCK_POS.write(pos));
|
||||
compound.putUuid("uuid", tentacle.getUuid());
|
||||
tentacles.add(compound);
|
||||
});
|
||||
nbt.put("tentacles", tentacles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readCustomDataFromNbt(NbtCompound nbt) {
|
||||
super.readCustomDataFromNbt(nbt);
|
||||
setAngry(nbt.getBoolean("angry"));
|
||||
setAge(nbt.getInt("age"));
|
||||
if (!getWorld().isClient) {
|
||||
if (nbt.contains("tentacles", NbtElement.LIST_TYPE)) {
|
||||
var tentacles = new HashMap<BlockPos, TentacleEntity>();
|
||||
nbt.getList("tentacles", NbtElement.COMPOUND_TYPE).forEach(tag -> {
|
||||
var compound = (NbtCompound)tag;
|
||||
if (((ServerWorld)getWorld()).getEntity(compound.getUuid("uuid")) instanceof TentacleEntity tentacle) {
|
||||
tentacle.setBulb(this);
|
||||
tentacles.put(NbtSerialisable.BLOCK_POS.read(compound.getCompound("pos")), tentacle);
|
||||
}
|
||||
});
|
||||
this.tentacles = tentacles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackedDataSet(TrackedData<?> data) {
|
||||
if (AGE.equals(data)) {
|
||||
calculateDimensions();
|
||||
}
|
||||
super.onTrackedDataSet(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDimensions(EntityPose pose) {
|
||||
return EntityDimensions.changing(3, 2).scaled(getScale(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.entity.player.Pony;
|
|||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
||||
import net.minecraft.command.argument.EntityAnchorArgumentType.EntityAnchor;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
|
@ -55,6 +56,9 @@ public class TentacleEntity extends AbstractDecorationEntity {
|
|||
private LivingEntity target;
|
||||
private final Comparator<LivingEntity> targetSorting = Comparator.comparing(this::distanceTo);
|
||||
|
||||
@Nullable
|
||||
private IgnominiousBulbEntity bulb;
|
||||
|
||||
public TentacleEntity(EntityType<? extends TentacleEntity> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
@ -70,6 +74,10 @@ public class TentacleEntity extends AbstractDecorationEntity {
|
|||
dataTracker.startTracking(MOTION_OFFSET, 0);
|
||||
}
|
||||
|
||||
public void setBulb(IgnominiousBulbEntity bulb) {
|
||||
this.bulb = bulb;
|
||||
}
|
||||
|
||||
public void attack(BlockPos pos) {
|
||||
var offset = pos.toCenterPos().subtract(getBlockPos().toCenterPos());
|
||||
|
||||
|
@ -82,6 +90,10 @@ public class TentacleEntity extends AbstractDecorationEntity {
|
|||
setYaw(MathHelper.wrapDegrees((float)(MathHelper.atan2(dZ, dX) * MathHelper.DEGREES_PER_RADIAN) - 90));
|
||||
getWorld().sendEntityStatus(this, ATTACK_STATUS);
|
||||
attackingTicks = 30;
|
||||
if (bulb != null) {
|
||||
bulb.setAngryFor(10);
|
||||
bulb.lookAt(EntityAnchor.FEET, pos.toCenterPos());
|
||||
}
|
||||
}
|
||||
|
||||
public float getAttackProgress(float tickDelta) {
|
||||
|
@ -144,7 +156,7 @@ public class TentacleEntity extends AbstractDecorationEntity {
|
|||
}
|
||||
|
||||
public void addActiveTicks(int ticks) {
|
||||
ticksActive += ticks;
|
||||
ticksActive = Math.min(200, ticksActive + ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue