240 lines
8.4 KiB
Java
240 lines
8.4 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.world.entity.monster;
|
|
|
|
import java.util.EnumSet;
|
|
import java.util.function.IntFunction;
|
|
import net.minecraft.core.particles.ColorParticleOption;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
|
import net.minecraft.network.syncher.SynchedEntityData;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.util.ByIdMap;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.ai.goal.Goal;
|
|
import net.minecraft.world.entity.monster.AbstractIllager;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.storage.ValueInput;
|
|
import net.minecraft.world.level.storage.ValueOutput;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public abstract class SpellcasterIllager
|
|
extends AbstractIllager {
|
|
private static final EntityDataAccessor<Byte> DATA_SPELL_CASTING_ID = SynchedEntityData.defineId(SpellcasterIllager.class, EntityDataSerializers.BYTE);
|
|
private static final int DEFAULT_SPELLCASTING_TICKS = 0;
|
|
protected int spellCastingTickCount = 0;
|
|
private IllagerSpell currentSpell = IllagerSpell.NONE;
|
|
|
|
protected SpellcasterIllager(EntityType<? extends SpellcasterIllager> type, Level level) {
|
|
super((EntityType<? extends AbstractIllager>)type, level);
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder entityData) {
|
|
super.defineSynchedData(entityData);
|
|
entityData.define(DATA_SPELL_CASTING_ID, (byte)0);
|
|
}
|
|
|
|
@Override
|
|
protected void readAdditionalSaveData(ValueInput input) {
|
|
super.readAdditionalSaveData(input);
|
|
this.spellCastingTickCount = input.getIntOr("SpellTicks", 0);
|
|
}
|
|
|
|
@Override
|
|
protected void addAdditionalSaveData(ValueOutput output) {
|
|
super.addAdditionalSaveData(output);
|
|
output.putInt("SpellTicks", this.spellCastingTickCount);
|
|
}
|
|
|
|
@Override
|
|
public AbstractIllager.IllagerArmPose getArmPose() {
|
|
if (this.isCastingSpell()) {
|
|
return AbstractIllager.IllagerArmPose.SPELLCASTING;
|
|
}
|
|
if (this.isCelebrating()) {
|
|
return AbstractIllager.IllagerArmPose.CELEBRATING;
|
|
}
|
|
return AbstractIllager.IllagerArmPose.CROSSED;
|
|
}
|
|
|
|
public boolean isCastingSpell() {
|
|
if (this.level().isClientSide()) {
|
|
return this.entityData.get(DATA_SPELL_CASTING_ID) > 0;
|
|
}
|
|
return this.spellCastingTickCount > 0;
|
|
}
|
|
|
|
public void setIsCastingSpell(IllagerSpell spell) {
|
|
this.currentSpell = spell;
|
|
this.entityData.set(DATA_SPELL_CASTING_ID, (byte)spell.id);
|
|
}
|
|
|
|
protected IllagerSpell getCurrentSpell() {
|
|
if (!this.level().isClientSide()) {
|
|
return this.currentSpell;
|
|
}
|
|
return IllagerSpell.byId(this.entityData.get(DATA_SPELL_CASTING_ID).byteValue());
|
|
}
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel level) {
|
|
super.customServerAiStep(level);
|
|
if (this.spellCastingTickCount > 0) {
|
|
--this.spellCastingTickCount;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
if (this.level().isClientSide() && this.isCastingSpell()) {
|
|
IllagerSpell spell = this.getCurrentSpell();
|
|
float red = (float)spell.spellColor[0];
|
|
float green = (float)spell.spellColor[1];
|
|
float blue = (float)spell.spellColor[2];
|
|
float bodyAngle = this.yBodyRot * ((float)Math.PI / 180) + Mth.cos((float)this.tickCount * 0.6662f) * 0.25f;
|
|
float cos = Mth.cos(bodyAngle);
|
|
float sin = Mth.sin(bodyAngle);
|
|
double handDistance = 0.6 * (double)this.getScale();
|
|
double handHeight = 1.8 * (double)this.getScale();
|
|
this.level().addParticle(ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, red, green, blue), this.getX() + (double)cos * handDistance, this.getY() + handHeight, this.getZ() + (double)sin * handDistance, 0.0, 0.0, 0.0);
|
|
this.level().addParticle(ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, red, green, blue), this.getX() - (double)cos * handDistance, this.getY() + handHeight, this.getZ() - (double)sin * handDistance, 0.0, 0.0, 0.0);
|
|
}
|
|
}
|
|
|
|
protected int getSpellCastingTime() {
|
|
return this.spellCastingTickCount;
|
|
}
|
|
|
|
protected abstract SoundEvent getCastingSoundEvent();
|
|
|
|
protected static enum IllagerSpell {
|
|
NONE(0, 0.0, 0.0, 0.0),
|
|
SUMMON_VEX(1, 0.7, 0.7, 0.8),
|
|
FANGS(2, 0.4, 0.3, 0.35),
|
|
WOLOLO(3, 0.7, 0.5, 0.2),
|
|
DISAPPEAR(4, 0.3, 0.3, 0.8),
|
|
BLINDNESS(5, 0.1, 0.1, 0.2);
|
|
|
|
private static final IntFunction<IllagerSpell> BY_ID;
|
|
private final int id;
|
|
private final double[] spellColor;
|
|
|
|
private IllagerSpell(int id, double red, double green, double blue) {
|
|
this.id = id;
|
|
this.spellColor = new double[]{red, green, blue};
|
|
}
|
|
|
|
public static IllagerSpell byId(int id) {
|
|
return BY_ID.apply(id);
|
|
}
|
|
|
|
static {
|
|
BY_ID = ByIdMap.continuous(e -> e.id, IllagerSpell.values(), ByIdMap.OutOfBoundsStrategy.ZERO);
|
|
}
|
|
}
|
|
|
|
protected abstract class SpellcasterUseSpellGoal
|
|
extends Goal {
|
|
protected int attackWarmupDelay;
|
|
protected int nextAttackTickCount;
|
|
|
|
protected SpellcasterUseSpellGoal() {
|
|
}
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
LivingEntity target = SpellcasterIllager.this.getTarget();
|
|
if (target == null || !target.isAlive()) {
|
|
return false;
|
|
}
|
|
if (SpellcasterIllager.this.isCastingSpell()) {
|
|
return false;
|
|
}
|
|
return SpellcasterIllager.this.tickCount >= this.nextAttackTickCount;
|
|
}
|
|
|
|
@Override
|
|
public boolean canContinueToUse() {
|
|
LivingEntity target = SpellcasterIllager.this.getTarget();
|
|
return target != null && target.isAlive() && this.attackWarmupDelay > 0;
|
|
}
|
|
|
|
@Override
|
|
public void start() {
|
|
this.attackWarmupDelay = this.adjustedTickDelay(this.getCastWarmupTime());
|
|
SpellcasterIllager.this.spellCastingTickCount = this.getCastingTime();
|
|
this.nextAttackTickCount = SpellcasterIllager.this.tickCount + this.getCastingInterval();
|
|
SoundEvent spellPrepareSound = this.getSpellPrepareSound();
|
|
if (spellPrepareSound != null) {
|
|
SpellcasterIllager.this.playSound(spellPrepareSound, 1.0f, 1.0f);
|
|
}
|
|
SpellcasterIllager.this.setIsCastingSpell(this.getSpell());
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
--this.attackWarmupDelay;
|
|
if (this.attackWarmupDelay == 0) {
|
|
this.performSpellCasting();
|
|
SpellcasterIllager.this.playSound(SpellcasterIllager.this.getCastingSoundEvent(), 1.0f, 1.0f);
|
|
}
|
|
}
|
|
|
|
protected abstract void performSpellCasting();
|
|
|
|
protected int getCastWarmupTime() {
|
|
return 20;
|
|
}
|
|
|
|
protected abstract int getCastingTime();
|
|
|
|
protected abstract int getCastingInterval();
|
|
|
|
protected abstract @Nullable SoundEvent getSpellPrepareSound();
|
|
|
|
protected abstract IllagerSpell getSpell();
|
|
}
|
|
|
|
protected class SpellcasterCastingSpellGoal
|
|
extends Goal {
|
|
public SpellcasterCastingSpellGoal() {
|
|
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
|
|
}
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
return SpellcasterIllager.this.getSpellCastingTime() > 0;
|
|
}
|
|
|
|
@Override
|
|
public void start() {
|
|
super.start();
|
|
SpellcasterIllager.this.navigation.stop();
|
|
}
|
|
|
|
@Override
|
|
public void stop() {
|
|
super.stop();
|
|
SpellcasterIllager.this.setIsCastingSpell(IllagerSpell.NONE);
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
if (SpellcasterIllager.this.getTarget() != null) {
|
|
SpellcasterIllager.this.getLookControl().setLookAt(SpellcasterIllager.this.getTarget(), SpellcasterIllager.this.getMaxHeadYRot(), SpellcasterIllager.this.getMaxHeadXRot());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|