minecraft-source/src/net/minecraft/world/entity/npc/WanderingTrader.java

281 lines
11 KiB
Java

package net.minecraft.world.entity.npc;
import net.minecraft.core.Position;
import net.minecraft.world.phys.Vec3;
import java.util.EnumSet;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.item.Item;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.entity.Entity;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.InteractGoal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal;
import net.minecraft.world.entity.ai.goal.LookAtTradingPlayerGoal;
import net.minecraft.world.entity.ai.goal.PanicGoal;
import net.minecraft.world.entity.monster.Illusioner;
import net.minecraft.world.entity.monster.Pillager;
import net.minecraft.world.entity.monster.Vex;
import net.minecraft.world.entity.monster.Vindicator;
import net.minecraft.world.entity.monster.Evoker;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.ai.goal.TradeWithPlayerGoal;
import net.minecraft.world.entity.ai.goal.UseItemGoal;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.item.alchemy.PotionUtils;
import net.minecraft.world.item.alchemy.Potions;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
public class WanderingTrader extends AbstractVillager {
@Nullable
private BlockPos wanderTarget;
private int despawnDelay;
public WanderingTrader(final EntityType<? extends WanderingTrader> akr, final Level bjt) {
super(akr, bjt);
this.forcedLoading = true;
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(0, new UseItemGoal<>(this, PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.INVISIBILITY), SoundEvents.WANDERING_TRADER_DISAPPEARED, axz -> !this.level.isDay() && !axz.isInvisible()));
this.goalSelector.addGoal(0, new UseItemGoal<>(this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, axz -> this.level.isDay() && axz.isInvisible()));
this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this));
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Zombie.class, 8.0f, 0.5, 0.5));
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Evoker.class, 12.0f, 0.5, 0.5));
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Vindicator.class, 8.0f, 0.5, 0.5));
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Vex.class, 8.0f, 0.5, 0.5));
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Pillager.class, 15.0f, 0.5, 0.5));
this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Illusioner.class, 12.0f, 0.5, 0.5));
this.goalSelector.addGoal(1, new PanicGoal(this, 0.5));
this.goalSelector.addGoal(1, new LookAtTradingPlayerGoal(this));
this.goalSelector.addGoal(2, new WanderToPositionGoal(this, 2.0, 0.35));
this.goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 0.35));
this.goalSelector.addGoal(8, new WaterAvoidingRandomStrollGoal(this, 0.35));
this.goalSelector.addGoal(9, new InteractGoal(this, Player.class, 3.0f, 1.0f));
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0f));
}
@Nullable
@Override
public AgableMob getBreedOffspring(final AgableMob akl) {
return null;
}
@Override
public boolean showProgressBar() {
return false;
}
@Override
public boolean mobInteract(final Player ayg, final InteractionHand ajh) {
final ItemStack bek4 = ayg.getItemInHand(ajh);
final boolean boolean5 = bek4.getItem() == Items.NAME_TAG;
if (boolean5) {
bek4.interactEnemy(ayg, this, ajh);
return true;
}
if (bek4.getItem() == Items.VILLAGER_SPAWN_EGG || !this.isAlive() || this.isTrading() || this.isBaby()) {
return super.mobInteract(ayg, ajh);
}
if (ajh == InteractionHand.MAIN_HAND) {
ayg.awardStat(Stats.TALKED_TO_VILLAGER);
}
if (this.getOffers().isEmpty()) {
return super.mobInteract(ayg, ajh);
}
if (!this.level.isClientSide) {
this.setTradingPlayer(ayg);
this.openTradingScreen(ayg, this.getDisplayName(), 1);
}
return true;
}
@Override
protected void updateTrades() {
final VillagerTrades.ItemListing[] arr2 = (VillagerTrades.ItemListing[])VillagerTrades.WANDERING_TRADER_TRADES.get(1);
final VillagerTrades.ItemListing[] arr3 = (VillagerTrades.ItemListing[])VillagerTrades.WANDERING_TRADER_TRADES.get(2);
if (arr2 == null || arr3 == null) {
return;
}
final MerchantOffers bix4 = this.getOffers();
this.addOffersFromItemListings(bix4, arr2, 5);
final int integer5 = this.random.nextInt(arr3.length);
final VillagerTrades.ItemListing f6 = arr3[integer5];
final MerchantOffer biw7 = f6.getOffer(this, this.random);
if (biw7 != null) {
bix4.add(biw7);
}
}
@Override
public void addAdditionalSaveData(final CompoundTag jt) {
super.addAdditionalSaveData(jt);
jt.putInt("DespawnDelay", this.despawnDelay);
if (this.wanderTarget != null) {
jt.put("WanderTarget", NbtUtils.writeBlockPos(this.wanderTarget));
}
}
@Override
public void readAdditionalSaveData(final CompoundTag jt) {
super.readAdditionalSaveData(jt);
if (jt.contains("DespawnDelay", 99)) {
this.despawnDelay = jt.getInt("DespawnDelay");
}
if (jt.contains("WanderTarget")) {
this.wanderTarget = NbtUtils.readBlockPos(jt.getCompound("WanderTarget"));
}
this.setAge(Math.max(0, this.getAge()));
}
@Override
public boolean removeWhenFarAway(final double double1) {
return false;
}
@Override
protected void rewardTradeXp(final MerchantOffer biw) {
if (biw.shouldRewardExp()) {
final int integer3 = 3 + this.random.nextInt(4);
this.level.addFreshEntity(new ExperienceOrb(this.level, this.getX(), this.getY() + 0.5, this.getZ(), integer3));
}
}
@Override
protected SoundEvent getAmbientSound() {
if (this.isTrading()) {
return SoundEvents.WANDERING_TRADER_TRADE;
}
return SoundEvents.WANDERING_TRADER_AMBIENT;
}
@Override
protected SoundEvent getHurtSound(final DamageSource ajw) {
return SoundEvents.WANDERING_TRADER_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.WANDERING_TRADER_DEATH;
}
@Override
protected SoundEvent getDrinkingSound(final ItemStack bek) {
final Item bef3 = bek.getItem();
if (bef3 == Items.MILK_BUCKET) {
return SoundEvents.WANDERING_TRADER_DRINK_MILK;
}
return SoundEvents.WANDERING_TRADER_DRINK_POTION;
}
@Override
protected SoundEvent getTradeUpdatedSound(final boolean boolean1) {
return boolean1 ? SoundEvents.WANDERING_TRADER_YES : SoundEvents.WANDERING_TRADER_NO;
}
@Override
public SoundEvent getNotifyTradeSound() {
return SoundEvents.WANDERING_TRADER_YES;
}
public void setDespawnDelay(final int integer) {
this.despawnDelay = integer;
}
public int getDespawnDelay() {
return this.despawnDelay;
}
@Override
public void aiStep() {
super.aiStep();
if (!this.level.isClientSide) {
this.maybeDespawn();
}
}
private void maybeDespawn() {
if (this.despawnDelay > 0 && !this.isTrading() && --this.despawnDelay == 0) {
this.remove();
}
}
public void setWanderTarget(@Nullable final BlockPos fk) {
this.wanderTarget = fk;
}
@Nullable
private BlockPos getWanderTarget() {
return this.wanderTarget;
}
class WanderToPositionGoal extends Goal {
final WanderingTrader trader;
final double stopDistance;
final double speedModifier;
WanderToPositionGoal(final WanderingTrader axz2, final double double3, final double double4) {
this.trader = axz2;
this.stopDistance = double3;
this.speedModifier = double4;
this.setFlags(EnumSet.<Flag>of(Flag.MOVE));
}
@Override
public void stop() {
this.trader.setWanderTarget(null);
WanderingTrader.this.navigation.stop();
}
@Override
public boolean canUse() {
final BlockPos fk2 = this.trader.getWanderTarget();
return fk2 != null && this.isTooFarAway(fk2, this.stopDistance);
}
@Override
public void tick() {
final BlockPos fk2 = this.trader.getWanderTarget();
if (fk2 != null && WanderingTrader.this.navigation.isDone()) {
if (this.isTooFarAway(fk2, 10.0)) {
final Vec3 cvi3 = new Vec3(fk2.getX() - this.trader.getX(), fk2.getY() - this.trader.getY(), fk2.getZ() - this.trader.getZ()).normalize();
final Vec3 cvi4 = cvi3.scale(10.0).add(this.trader.getX(), this.trader.getY(), this.trader.getZ());
WanderingTrader.this.navigation.moveTo(cvi4.x, cvi4.y, cvi4.z, this.speedModifier);
}
else {
WanderingTrader.this.navigation.moveTo(fk2.getX(), fk2.getY(), fk2.getZ(), this.speedModifier);
}
}
}
private boolean isTooFarAway(final BlockPos fk, final double double2) {
return !fk.closerThan(this.trader.position(), double2);
}
}
}