220 lines
9.2 KiB
Java
220 lines
9.2 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.world.entity.monster;
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.tags.ItemTags;
|
|
import net.minecraft.tags.TagKey;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.util.SpecialDates;
|
|
import net.minecraft.world.Difficulty;
|
|
import net.minecraft.world.DifficultyInstance;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntitySpawnReason;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.EquipmentSlot;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.entity.PathfinderMob;
|
|
import net.minecraft.world.entity.SpawnGroupData;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
|
import net.minecraft.world.entity.ai.goal.FleeSunGoal;
|
|
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
|
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
|
|
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
|
import net.minecraft.world.entity.ai.goal.RangedBowAttackGoal;
|
|
import net.minecraft.world.entity.ai.goal.RestrictSunGoal;
|
|
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
|
|
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
|
|
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
|
import net.minecraft.world.entity.animal.IronGolem;
|
|
import net.minecraft.world.entity.animal.Turtle;
|
|
import net.minecraft.world.entity.animal.wolf.Wolf;
|
|
import net.minecraft.world.entity.monster.Monster;
|
|
import net.minecraft.world.entity.monster.RangedAttackMob;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.entity.projectile.AbstractArrow;
|
|
import net.minecraft.world.entity.projectile.Projectile;
|
|
import net.minecraft.world.entity.projectile.ProjectileUtil;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.item.ProjectileWeaponItem;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.ServerLevelAccessor;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.storage.ValueInput;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public abstract class AbstractSkeleton
|
|
extends Monster
|
|
implements RangedAttackMob {
|
|
private static final int HARD_ATTACK_INTERVAL = 20;
|
|
private static final int NORMAL_ATTACK_INTERVAL = 40;
|
|
protected static final int INCREASED_HARD_ATTACK_INTERVAL = 50;
|
|
protected static final int INCREASED_NORMAL_ATTACK_INTERVAL = 70;
|
|
private final RangedBowAttackGoal<AbstractSkeleton> bowGoal = new RangedBowAttackGoal<AbstractSkeleton>(this, 1.0, 20, 15.0f);
|
|
private final MeleeAttackGoal meleeGoal = new MeleeAttackGoal(this, 1.2, false){
|
|
|
|
@Override
|
|
public void stop() {
|
|
super.stop();
|
|
AbstractSkeleton.this.setAggressive(false);
|
|
}
|
|
|
|
@Override
|
|
public void start() {
|
|
super.start();
|
|
AbstractSkeleton.this.setAggressive(true);
|
|
}
|
|
};
|
|
|
|
protected AbstractSkeleton(EntityType<? extends AbstractSkeleton> type, Level level) {
|
|
super((EntityType<? extends Monster>)type, level);
|
|
this.reassessWeaponGoal();
|
|
}
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(2, new RestrictSunGoal(this));
|
|
this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0));
|
|
this.goalSelector.addGoal(3, new AvoidEntityGoal<Wolf>(this, Wolf.class, 6.0f, 1.0, 1.2));
|
|
this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0));
|
|
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0f));
|
|
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
|
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0]));
|
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<Player>((Mob)this, Player.class, true));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<IronGolem>((Mob)this, IronGolem.class, true));
|
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<Turtle>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.25);
|
|
}
|
|
|
|
@Override
|
|
protected void playStepSound(BlockPos pos, BlockState blockState) {
|
|
this.playSound(this.getStepSound(), 0.15f, 1.0f);
|
|
}
|
|
|
|
abstract SoundEvent getStepSound();
|
|
|
|
@Override
|
|
public void rideTick() {
|
|
super.rideTick();
|
|
Entity entity = this.getControlledVehicle();
|
|
if (entity instanceof PathfinderMob) {
|
|
PathfinderMob entity2 = (PathfinderMob)entity;
|
|
this.yBodyRot = entity2.yBodyRot;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void populateDefaultEquipmentSlots(RandomSource random, DifficultyInstance difficulty) {
|
|
super.populateDefaultEquipmentSlots(random, difficulty);
|
|
this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.BOW));
|
|
}
|
|
|
|
@Override
|
|
public @Nullable SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData groupData) {
|
|
groupData = super.finalizeSpawn(level, difficulty, spawnReason, groupData);
|
|
RandomSource random = level.getRandom();
|
|
this.populateDefaultEquipmentSlots(random, difficulty);
|
|
this.populateDefaultEquipmentEnchantments(level, random, difficulty);
|
|
this.reassessWeaponGoal();
|
|
this.setCanPickUpLoot(random.nextFloat() < 0.55f * difficulty.getSpecialMultiplier());
|
|
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && SpecialDates.isHalloween() && random.nextFloat() < 0.25f) {
|
|
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1f ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
|
this.setDropChance(EquipmentSlot.HEAD, 0.0f);
|
|
}
|
|
return groupData;
|
|
}
|
|
|
|
public void reassessWeaponGoal() {
|
|
if (this.level() == null || this.level().isClientSide()) {
|
|
return;
|
|
}
|
|
this.goalSelector.removeGoal(this.meleeGoal);
|
|
this.goalSelector.removeGoal(this.bowGoal);
|
|
ItemStack usedWeapon = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW));
|
|
if (usedWeapon.is(Items.BOW)) {
|
|
int minAttackInterval = this.getHardAttackInterval();
|
|
if (this.level().getDifficulty() != Difficulty.HARD) {
|
|
minAttackInterval = this.getAttackInterval();
|
|
}
|
|
this.bowGoal.setMinAttackInterval(minAttackInterval);
|
|
this.goalSelector.addGoal(4, this.bowGoal);
|
|
} else {
|
|
this.goalSelector.addGoal(4, this.meleeGoal);
|
|
}
|
|
}
|
|
|
|
protected int getHardAttackInterval() {
|
|
return 20;
|
|
}
|
|
|
|
protected int getAttackInterval() {
|
|
return 40;
|
|
}
|
|
|
|
@Override
|
|
public void performRangedAttack(LivingEntity target, float power) {
|
|
ItemStack bowItem = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW));
|
|
ItemStack projectile = this.getProjectile(bowItem);
|
|
AbstractArrow arrow = this.getArrow(projectile, power, bowItem);
|
|
double xd = target.getX() - this.getX();
|
|
double yd = target.getY(0.3333333333333333) - arrow.getY();
|
|
double zd = target.getZ() - this.getZ();
|
|
double distanceToTarget = Math.sqrt(xd * xd + zd * zd);
|
|
Level level = this.level();
|
|
if (level instanceof ServerLevel) {
|
|
ServerLevel serverLevel = (ServerLevel)level;
|
|
Projectile.spawnProjectileUsingShoot(arrow, serverLevel, projectile, xd, yd + distanceToTarget * (double)0.2f, zd, 1.6f, 14 - serverLevel.getDifficulty().getId() * 4);
|
|
}
|
|
this.playSound(SoundEvents.SKELETON_SHOOT, 1.0f, 1.0f / (this.getRandom().nextFloat() * 0.4f + 0.8f));
|
|
}
|
|
|
|
protected AbstractArrow getArrow(ItemStack projectile, float power, @Nullable ItemStack firingWeapon) {
|
|
return ProjectileUtil.getMobArrow(this, projectile, power, firingWeapon);
|
|
}
|
|
|
|
@Override
|
|
public boolean canFireProjectileWeapon(ProjectileWeaponItem item) {
|
|
return item == Items.BOW;
|
|
}
|
|
|
|
@Override
|
|
public TagKey<Item> getPreferredWeaponType() {
|
|
return ItemTags.SKELETON_PREFERRED_WEAPONS;
|
|
}
|
|
|
|
@Override
|
|
protected void readAdditionalSaveData(ValueInput input) {
|
|
super.readAdditionalSaveData(input);
|
|
this.reassessWeaponGoal();
|
|
}
|
|
|
|
@Override
|
|
public void onEquipItem(EquipmentSlot slot, ItemStack oldStack, ItemStack stack) {
|
|
super.onEquipItem(slot, oldStack, stack);
|
|
if (!this.level().isClientSide()) {
|
|
this.reassessWeaponGoal();
|
|
}
|
|
}
|
|
|
|
public boolean isShaking() {
|
|
return this.isFullyFrozen();
|
|
}
|
|
}
|
|
|