package playasmob;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.Level;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Item;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.monster.Creeper;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.AreaEffectCloud;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.util.Mth;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.EntityTypeTags;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.chat.Component;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.Holder;
import net.minecraft.client.renderer.entity.state.EntityRenderState;
import net.minecraft.client.renderer.entity.state.CreeperRenderState;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.CreeperRenderer;
import java.util.Optional;
import java.util.List;
import java.util.Collection;
public class CreeperInfo extends MonsterInfo {
public static final Synched swellDir = Synched.SwellDir;
public static final Synched swell = Synched.Swell;
public static final Synched powered = Synched.Powered;
public static final Synched ignited = Synched.Ignited;
public int oldSwell;
public int maxSwell = 30;
public int explosionRadius = 3;
public int droppedSkulls;
public CreeperInfo(Player player, CompoundTag compound) {
super(EntityType.CREEPER, Creeper.class, player, compound);
}
public CreeperInfo(Player player) {
this(player, null);
}
public CreeperInfo() {
this(null);
}
// Custom Code
@Override
public void delayedInit() {
super.delayedInit();
this.setSwellDir(-1);
}
@Override
public void reset() {
super.reset();
this.reset(swellDir);
this.reset(swell);
this.reset(powered);
this.reset(ignited);
this.oldSwell = 0;
this.maxSwell = 30;
this.explosionRadius = 3;
this.droppedSkulls = 0;
}
@Override
public EntityRenderer getRenderer() {
return new CreeperRenderer(Utils.getContext());
}
@Override
public EntityRenderState createState() {
return new CreeperRenderState();
}
@Override
public void modifyState(EntityRenderState state) {
super.modifyState(state);
if (state instanceof CreeperRenderState creeperState) {
creeperState.swelling = this.getSwelling(state.partialTick);
creeperState.isPowered = this.isPowered();
}
}
@Override
public void press(int key, boolean pressed, int time) {
if (key == 1)
this.setSwellDir(this.canSwell() && pressed ? 1 : -1);
}
@Override
public List<HudIcon> getIcons(float partialTick) {
if(this.isSpectator())
return super.getIcons(partialTick);
float swellPercent = Math.min(this.getSwelling(partialTick) * 100, 100);
int tntIndex = Math.round((swellPercent / 100) * 17);
String tntTexture = "playasmob:textures/screens/tnt" + (tntIndex < 17 ? "_" + tntIndex : "") + ".png";
HudIcon swellAbility = new HudIcon("playasmob:textures/screens/creeper" + (this.player.tickCount % 30 < 20 ? ".png" : "_flash.png")).key(Keybinds.Key1).useable(this.canSwell());
HudIcon swellIndicator = new HudIcon(tntTexture).text(Component.literal((int) swellPercent + "%")).iconWidth(20).iconHeight(20);
List<HudIcon> creeperIcons = this.canSwell() ? List.of(swellAbility, swellIndicator.offsetX(swellAbility, true)) : List.of(swellAbility);
return Utils.merge(super.getIcons(partialTick), creeperIcons);
}
public boolean canSwell() {
return !this.isSpectator() && this.isAlive() && (this.isIgnited() || (this.canUseHands(HandUse.Blocked) && !this.isSprinting()));
}
@Override
public boolean canSprint(boolean original) {
return super.canSprint(original) && this.<Integer>get(swell) == 0;
}
@Override
public boolean handUseageBlocked() {
return super.handUseageBlocked() || this.<Integer>get(swell) != 0;
}
@Override
public void respawn() {
super.respawn();
this.set(shouldRender, true);
}
@Override
public Diet getDiet() {
Diet diet = new Diet();
diet.allowNormalFood = true;
diet.addFood(Items.GUNPOWDER, true, FoodFactory.createFoodData(1, 0.3f));
return diet;
}
// Creeper.class Code
@Override
public int getMaxFallDistance(int original) {
return this.getTarget() == null ? original : original + (int) (this.getHealth() - 1);
}
@Override
public boolean causeFallDamage(boolean original, float distance, float multiplier, DamageSource source) {
if (this.getMaxFallDistance() < distance) {
this.set(swell, this.<Integer>get(swell) + (int) (distance * 1.5f));
if (this.<Integer>get(swell) > this.maxSwell - 5)
this.set(swell, this.maxSwell - 5);
}
return super.causeFallDamage(original, distance, multiplier, source);
}
@Override
public CompoundTag saveData() {
CompoundTag compound = super.saveData();
if (this.get(powered))
compound.putBoolean("powered", true);
compound.putShort("Fuse", (short) this.maxSwell);
compound.putByte("ExplosionRadius", (byte) this.explosionRadius);
compound.putBoolean("ignited", this.isIgnited());
return compound;
}
@Override
public void loadData(CompoundTag compound) {
super.loadData(compound);
this.set(powered, compound.getBoolean("powered"));
if (compound.contains("Fuse", 99))
this.maxSwell = compound.getShort("Fuse");
if (compound.contains("ExplosionRadius", 99))
this.explosionRadius = compound.getByte("ExplosionRadius");
if (compound.getBoolean("ignited"))
this.ignite();
}
@Override
public void preTick() {
if (this.isAlive()) {
this.oldSwell = this.<Integer>get(swell);
if (this.isIgnited())
this.setSwellDir(1);
int i = this.getSwellDir();
if (i == 1 && !this.canSwell())
i = -1;
if (i > 0 && this.<Integer>get(swell) == 0) {
this.playSound(SoundEvents.CREEPER_PRIMED, 1, 0.5f);
this.gameEvent(GameEvent.PRIME_FUSE);
}
this.set(swell, this.<Integer>get(swell) + i);
if (this.<Integer>get(swell) < 0)
this.set(swell, 0);
if (this.<Integer>get(swell) >= this.maxSwell) {
this.set(swell, this.maxSwell);
this.explodeCreeper();
}
}
super.preTick();
}
@Override
public SoundEvent getHurtSound(SoundEvent original, DamageSource source) {
return SoundEvents.CREEPER_HURT;
}
@Override
public SoundEvent getDeathSound(SoundEvent original) {
return SoundEvents.CREEPER_DEATH;
}
@Override
public boolean dropCustomDeathLoot(Object object, ServerLevel server, DamageSource source, boolean booleanValue) {
if (!super.dropCustomDeathLoot(null, server, source, booleanValue))
return false;
Entity entity = source.getEntity();
if (entity != this.getEntity() && entity instanceof Creeper creeper && creeper.canDropMobsSkull()) {
creeper.increaseDroppedSkulls();
this.spawnAtLocation(server, Items.CREEPER_HEAD);
} else if (entity != this.getEntity() && entity instanceof InfoHolder holder && holder.getInfo() instanceof CreeperInfo creeper && creeper.canDropMobsSkull()) {
creeper.increaseDroppedSkulls();
this.spawnAtLocation(server, Items.CREEPER_HEAD);
}
if (entity instanceof LivingEntity && entity.getType().is(EntityTypeTags.SKELETONS))
this.spawnAtLocation(server, randomDisc());
return true;
}
public ItemStack randomDisc() {
Optional<Holder<Item>> disc = BuiltInRegistries.ITEM.getRandomElementOf(ItemTags.CREEPER_DROP_MUSIC_DISCS, this.random);
return disc.isEmpty() ? ItemStack.EMPTY : new ItemStack(disc.get().value());
}
public boolean isPowered() {
return this.get(powered);
}
public float getSwelling(float partialTick) {
int currentSwell = this.get(swell);
return Mth.lerp(partialTick, (float) this.oldSwell, (float) currentSwell) / (float) (this.maxSwell - 2);
}
public int getSwellDir() {
return this.get(swellDir);
}
public void setSwellDir(int direction) {
this.set(swellDir, direction);
}
@Override
public boolean thunderHit(Object object, ServerLevel server, LightningBolt bolt) {
if (!super.thunderHit(null, server, bolt))
return false;
this.set(powered, true);
return true;
}
public void explodeCreeper() {
if (this.level() instanceof ServerLevel server) {
this.set(shouldRender, false);
float f = this.isPowered() ? 2 : 1;
server.explode(this.getEntity(), this.getX(), this.getY(), this.getZ(), (float) this.explosionRadius * f, Level.ExplosionInteraction.MOB);
this.setHealth(0);
if (this.getEntity() instanceof LivingEntity self)
self.die(server.damageSources().explosion(self, self));
this.set(swell, 0);
this.setSwellDir(-1);
this.spawnLingeringCloud();
}
}
public void spawnLingeringCloud() {
Collection<MobEffectInstance> effects = this.getActiveEffects();
if (!effects.isEmpty()) {
AreaEffectCloud cloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
cloud.setRadius(2.5f);
cloud.setRadiusOnUse(-0.5f);
cloud.setWaitTime(10);
cloud.setDuration(cloud.getDuration() / 2);
cloud.setRadiusPerTick(-cloud.getRadius() / (float) cloud.getDuration());
effects.forEach((effect) -> cloud.addEffect(new MobEffectInstance(effect)));
this.level().addFreshEntity(cloud);
}
}
public boolean isIgnited() {
return this.get(ignited);
}
public void ignite() {
this.set(ignited, true);
}
public boolean canDropMobsSkull() {
return this.isPowered() && this.droppedSkulls < 1;
}
public void increaseDroppedSkulls() {
this.droppedSkulls++;
}
}