The Ignominious Bulb now grows from a sprout when first summoned and will no longer lose its arms

This commit is contained in:
Sollace 2024-01-15 20:25:07 +00:00
parent d9bebf0b0f
commit 144f00c207
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
6 changed files with 224 additions and 29 deletions

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);

View file

@ -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();
}

View file

@ -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));
}
}

View file

@ -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