2018-09-13 12:03:28 -04:00
|
|
|
package noppes.npcs.entity;
|
|
|
|
|
|
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
2021-11-22 23:34:02 -06:00
|
|
|
import java.util.*;
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
import net.minecraft.block.Block;
|
|
|
|
|
import net.minecraft.command.ICommandSender;
|
|
|
|
|
import net.minecraft.command.IEntitySelector;
|
2021-07-10 00:48:03 -04:00
|
|
|
import net.minecraft.entity.*;
|
2021-06-13 16:22:06 -04:00
|
|
|
import net.minecraft.entity.ai.*;
|
2018-09-13 12:03:28 -04:00
|
|
|
import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry;
|
|
|
|
|
import net.minecraft.entity.boss.IBossDisplayData;
|
|
|
|
|
import net.minecraft.entity.item.EntityItem;
|
|
|
|
|
import net.minecraft.entity.monster.EntityMob;
|
|
|
|
|
import net.minecraft.entity.monster.EntityZombie;
|
|
|
|
|
import net.minecraft.entity.passive.EntityBat;
|
|
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
|
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
|
|
|
import net.minecraft.entity.projectile.EntityArrow;
|
|
|
|
|
import net.minecraft.entity.projectile.EntityThrowable;
|
|
|
|
|
import net.minecraft.item.Item;
|
2021-09-24 16:50:28 -04:00
|
|
|
import net.minecraft.item.ItemBow;
|
2018-09-13 12:03:28 -04:00
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
|
import net.minecraft.nbt.NBTTagCompound;
|
2021-12-06 00:10:10 -06:00
|
|
|
import net.minecraft.pathfinding.PathNavigate;
|
2018-09-13 12:03:28 -04:00
|
|
|
import net.minecraft.potion.Potion;
|
|
|
|
|
import net.minecraft.potion.PotionEffect;
|
|
|
|
|
import net.minecraft.util.AxisAlignedBB;
|
|
|
|
|
import net.minecraft.util.ChatComponentTranslation;
|
|
|
|
|
import net.minecraft.util.ChunkCoordinates;
|
|
|
|
|
import net.minecraft.util.DamageSource;
|
|
|
|
|
import net.minecraft.util.IChatComponent;
|
|
|
|
|
import net.minecraft.util.IIcon;
|
|
|
|
|
import net.minecraft.util.MathHelper;
|
|
|
|
|
import net.minecraft.util.ResourceLocation;
|
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
import net.minecraft.world.WorldServer;
|
|
|
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
|
|
|
import net.minecraftforge.common.util.FakePlayer;
|
|
|
|
|
import net.minecraftforge.event.ServerChatEvent;
|
2022-03-23 03:54:06 -05:00
|
|
|
import noppes.npcs.*;
|
2021-06-13 16:22:06 -04:00
|
|
|
import noppes.npcs.ai.*;
|
2018-09-13 12:03:28 -04:00
|
|
|
import noppes.npcs.ai.EntityAIMoveIndoors;
|
|
|
|
|
import noppes.npcs.ai.EntityAIPanic;
|
|
|
|
|
import noppes.npcs.ai.EntityAIWander;
|
|
|
|
|
import noppes.npcs.ai.EntityAIWatchClosest;
|
2021-12-07 03:57:57 -06:00
|
|
|
import noppes.npcs.ai.pathfinder.FlyingMoveHelper;
|
2021-12-06 00:10:10 -06:00
|
|
|
import noppes.npcs.ai.pathfinder.PathNavigateFlying;
|
2018-09-13 12:03:28 -04:00
|
|
|
import noppes.npcs.ai.selector.NPCAttackSelector;
|
|
|
|
|
import noppes.npcs.ai.target.EntityAIClearTarget;
|
|
|
|
|
import noppes.npcs.ai.target.EntityAIClosestTarget;
|
|
|
|
|
import noppes.npcs.ai.target.EntityAIOwnerHurtByTarget;
|
|
|
|
|
import noppes.npcs.ai.target.EntityAIOwnerHurtTarget;
|
|
|
|
|
import noppes.npcs.client.EntityUtil;
|
|
|
|
|
import noppes.npcs.constants.EnumAnimation;
|
|
|
|
|
import noppes.npcs.constants.EnumJobType;
|
|
|
|
|
import noppes.npcs.constants.EnumMovingType;
|
|
|
|
|
import noppes.npcs.constants.EnumNavType;
|
|
|
|
|
import noppes.npcs.constants.EnumPacketClient;
|
|
|
|
|
import noppes.npcs.constants.EnumPotionType;
|
|
|
|
|
import noppes.npcs.constants.EnumRoleType;
|
|
|
|
|
import noppes.npcs.constants.EnumStandingType;
|
2022-05-29 16:01:05 -05:00
|
|
|
import noppes.npcs.controllers.data.*;
|
2018-09-13 12:03:28 -04:00
|
|
|
import noppes.npcs.controllers.FactionController;
|
|
|
|
|
import noppes.npcs.controllers.LinkedNpcController;
|
|
|
|
|
import noppes.npcs.controllers.LinkedNpcController.LinkedData;
|
|
|
|
|
import noppes.npcs.controllers.PlayerDataController;
|
2021-10-20 23:04:52 -05:00
|
|
|
import noppes.npcs.entity.data.DataTimers;
|
2022-06-12 01:26:23 -05:00
|
|
|
import noppes.npcs.roles.*;
|
2021-10-18 06:33:39 -05:00
|
|
|
import noppes.npcs.scripted.entity.ScriptNpc;
|
2022-06-10 17:25:58 -05:00
|
|
|
import noppes.npcs.scripted.event.*;
|
2022-05-11 16:43:14 -05:00
|
|
|
import noppes.npcs.scripted.interfaces.entity.ICustomNpc;
|
2022-06-10 17:25:58 -05:00
|
|
|
import noppes.npcs.scripted.interfaces.item.IItemStack;
|
2018-09-13 12:03:28 -04:00
|
|
|
import noppes.npcs.util.GameProfileAlt;
|
|
|
|
|
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
|
|
|
|
|
|
|
|
|
|
public abstract class EntityNPCInterface extends EntityCreature implements IEntityAdditionalSpawnData, ICommandSender, IRangedAttackMob, IBossDisplayData{
|
2021-09-30 21:44:30 -05:00
|
|
|
public ICustomNpc wrappedNPC;
|
2018-09-13 12:03:28 -04:00
|
|
|
|
2021-10-19 19:49:43 -05:00
|
|
|
public static final GameProfileAlt chateventProfile = new GameProfileAlt();
|
2021-10-11 06:49:30 -05:00
|
|
|
public static FakePlayer chateventPlayer;
|
2021-10-19 19:49:43 -05:00
|
|
|
public static FakePlayer CommandPlayer;
|
2018-09-13 12:03:28 -04:00
|
|
|
public DataDisplay display;
|
|
|
|
|
public DataStats stats;
|
|
|
|
|
public DataAI ai;
|
|
|
|
|
public DataAdvanced advanced;
|
|
|
|
|
public DataInventory inventory;
|
|
|
|
|
public DataScript script;
|
2022-05-24 01:08:23 -05:00
|
|
|
public DataTransform transform;
|
2021-10-20 23:04:52 -05:00
|
|
|
public DataTimers timers;
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
public String linkedName = "";
|
|
|
|
|
public long linkedLast = 0;
|
|
|
|
|
public LinkedData linkedData;
|
|
|
|
|
|
|
|
|
|
public float baseHeight = 1.8f;
|
|
|
|
|
public float scaleX, scaleY, scaleZ;
|
|
|
|
|
private boolean wasKilled = false;
|
|
|
|
|
public RoleInterface roleInterface;
|
|
|
|
|
public JobInterface jobInterface;
|
|
|
|
|
public HashMap<Integer, DialogOption> dialogs;
|
|
|
|
|
public boolean hasDied = false;
|
|
|
|
|
public long killedtime = 0;
|
|
|
|
|
public long totalTicksAlive = 0;
|
|
|
|
|
private int taskCount = 1;
|
|
|
|
|
public int lastInteract = 0;
|
2022-06-12 01:26:23 -05:00
|
|
|
public int itemGiverId = 0;
|
2021-04-29 20:42:52 -04:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public Faction faction; //should only be used server side
|
|
|
|
|
|
|
|
|
|
private EntityAIRangedAttack aiRange;
|
|
|
|
|
private EntityAIBase aiResponse, aiLeap, aiSprint, aiAttackTarget;
|
|
|
|
|
|
|
|
|
|
public List<EntityLivingBase> interactingEntities = new ArrayList<EntityLivingBase>();
|
|
|
|
|
|
|
|
|
|
public ResourceLocation textureLocation = null;
|
|
|
|
|
public ResourceLocation textureCloakLocation = null;
|
|
|
|
|
|
|
|
|
|
public EnumAnimation currentAnimation = EnumAnimation.NONE;
|
|
|
|
|
|
|
|
|
|
public int npcVersion = VersionCompatibility.ModRev;
|
|
|
|
|
public IChatMessages messages;
|
|
|
|
|
|
|
|
|
|
public boolean updateClient = false;
|
|
|
|
|
public boolean updateAI = false;
|
2022-05-24 03:06:16 -05:00
|
|
|
|
2021-12-07 03:57:57 -06:00
|
|
|
public FlyingMoveHelper flyMoveHelper = new FlyingMoveHelper(this);
|
|
|
|
|
public PathNavigate flyNavigator = new PathNavigateFlying(this, worldObj);
|
2021-06-13 16:22:06 -04:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public EntityNPCInterface(World world) {
|
|
|
|
|
super(world);
|
|
|
|
|
try{
|
2021-12-07 03:57:57 -06:00
|
|
|
if (canFly()) {
|
|
|
|
|
this.getNavigator().setCanSwim(true);
|
|
|
|
|
this.tasks.addTask(0, new EntityAISwimming(this));
|
|
|
|
|
} else {
|
|
|
|
|
this.tasks.addTask(0, new EntityAIWaterNav(this));
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
dialogs = new HashMap<Integer, DialogOption>();
|
|
|
|
|
if(!CustomNpcs.DefaultInteractLine.isEmpty())
|
|
|
|
|
advanced.interactLines.lines.put(0, new Line(CustomNpcs.DefaultInteractLine));
|
|
|
|
|
|
|
|
|
|
experienceValue = 0;
|
|
|
|
|
scaleX = scaleY = scaleZ = 0.9375f;
|
|
|
|
|
|
|
|
|
|
faction = getFaction();
|
|
|
|
|
setFaction(faction.id);
|
|
|
|
|
setSize(1, 1);
|
|
|
|
|
this.updateTasks();
|
2021-09-30 21:44:30 -05:00
|
|
|
|
2022-05-11 22:55:26 -05:00
|
|
|
if (!this.isRemote() && this.wrappedNPC == null) {
|
2022-05-11 22:08:31 -05:00
|
|
|
this.wrappedNPC = new ScriptNpc<>(this);
|
2021-09-30 21:44:30 -05:00
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
catch(Exception e){
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void applyEntityAttributes(){
|
|
|
|
|
super.applyEntityAttributes();
|
|
|
|
|
|
|
|
|
|
display = new DataDisplay(this);
|
|
|
|
|
stats = new DataStats(this);
|
|
|
|
|
ai = new DataAI(this);
|
|
|
|
|
advanced = new DataAdvanced(this);
|
|
|
|
|
inventory = new DataInventory(this);
|
2022-05-24 01:08:23 -05:00
|
|
|
transform = new DataTransform(this);
|
2018-09-13 12:03:28 -04:00
|
|
|
script = new DataScript(this);
|
2021-10-20 23:04:52 -05:00
|
|
|
timers = new DataTimers(this);
|
2018-09-13 12:03:28 -04:00
|
|
|
this.getAttributeMap().registerAttribute(SharedMonsterAttributes.attackDamage);
|
|
|
|
|
|
|
|
|
|
this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(stats.maxHealth);
|
|
|
|
|
this.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(CustomNpcs.NpcNavRange);
|
2021-12-03 00:49:10 -06:00
|
|
|
this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(this.getSpeed());
|
2018-09-13 12:03:28 -04:00
|
|
|
this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setBaseValue(stats.getAttackStrength());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void entityInit() {
|
|
|
|
|
super.entityInit();
|
|
|
|
|
this.dataWatcher.addObject(13, String.valueOf(""));//faction
|
|
|
|
|
this.dataWatcher.addObject(14, Integer.valueOf(0)); // Animation
|
|
|
|
|
this.dataWatcher.addObject(15, Integer.valueOf(0)); // isWalking
|
|
|
|
|
this.dataWatcher.addObject(16, String.valueOf("")); // Role
|
|
|
|
|
}
|
|
|
|
|
protected boolean isAIEnabled(){
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean getLeashed(){
|
|
|
|
|
return false; //Prevents npcs from being leashed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isEntityAlive(){
|
|
|
|
|
return super.isEntityAlive() && !isKilled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onUpdate(){
|
|
|
|
|
super.onUpdate();
|
2022-06-10 17:25:58 -05:00
|
|
|
if (!isRemote()) {
|
|
|
|
|
if (this.ticksExisted % 10 == 0) {
|
|
|
|
|
EventHooks.onNPCUpdate(this);
|
|
|
|
|
}
|
|
|
|
|
this.timers.update();
|
2022-03-23 03:54:06 -05:00
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setWorld(World world){
|
|
|
|
|
super.setWorld(world);
|
|
|
|
|
script.setWorld(world);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-18 03:34:20 -06:00
|
|
|
public int getMaxSafePointTries()
|
|
|
|
|
{
|
2022-11-10 00:31:14 -06:00
|
|
|
return 3;
|
2022-02-18 03:34:20 -06:00
|
|
|
}
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
@Override
|
|
|
|
|
public boolean attackEntityAsMob(Entity par1Entity){
|
|
|
|
|
float f = stats.getAttackStrength();
|
|
|
|
|
|
|
|
|
|
if (stats.attackSpeed < 10){
|
|
|
|
|
par1Entity.hurtResistantTime = 0;
|
|
|
|
|
}
|
2022-06-10 17:25:58 -05:00
|
|
|
if(par1Entity instanceof EntityLivingBase && !isRemote()){
|
2022-06-10 18:32:42 -05:00
|
|
|
NpcEvent.MeleeAttackEvent event = new NpcEvent.MeleeAttackEvent(wrappedNPC, f, (EntityLivingBase)par1Entity);
|
|
|
|
|
if(EventHooks.onNPCMeleeAttack(this, event))
|
2018-09-13 12:03:28 -04:00
|
|
|
return false;
|
|
|
|
|
f = event.getDamage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean var4 = par1Entity.attackEntityFrom(new NpcDamageSource("mob", this), f);
|
|
|
|
|
|
|
|
|
|
if (var4){
|
|
|
|
|
if(getOwner() instanceof EntityPlayer)
|
|
|
|
|
NPCEntityHelper.setRecentlyHit((EntityLivingBase)par1Entity);
|
|
|
|
|
if (stats.knockback > 0){
|
|
|
|
|
par1Entity.addVelocity((double)(-MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F) * (float)stats.knockback * 0.5F), 0.1D, (double)(MathHelper.cos(this.rotationYaw * (float)Math.PI / 180.0F) * (float)stats.knockback * 0.5F));
|
|
|
|
|
this.motionX *= 0.6D;
|
|
|
|
|
this.motionZ *= 0.6D;
|
|
|
|
|
}
|
|
|
|
|
if(advanced.role == EnumRoleType.Companion){
|
|
|
|
|
((RoleCompanion)roleInterface).attackedEntity(par1Entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stats.potionType != EnumPotionType.None){
|
|
|
|
|
if (stats.potionType != EnumPotionType.Fire)
|
|
|
|
|
((EntityLivingBase)par1Entity).addPotionEffect(new PotionEffect(this.getPotionEffect(stats.potionType), stats.potionDuration * 20, stats.potionAmp));
|
|
|
|
|
else
|
|
|
|
|
par1Entity.setFire(stats.potionDuration);
|
|
|
|
|
}
|
|
|
|
|
return var4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onLivingUpdate(){
|
|
|
|
|
if(CustomNpcs.FreezeNPCs)
|
|
|
|
|
return;
|
|
|
|
|
totalTicksAlive++;
|
|
|
|
|
this.updateArmSwingProgress();
|
|
|
|
|
if(this.ticksExisted % 20 == 0)
|
|
|
|
|
faction = getFaction();
|
|
|
|
|
if(!worldObj.isRemote){
|
|
|
|
|
if(!isKilled() && this.ticksExisted % 20 == 0){
|
|
|
|
|
if(this.getHealth() < this.getMaxHealth()){
|
|
|
|
|
if(stats.healthRegen > 0 && !isAttacking())
|
|
|
|
|
heal(stats.healthRegen);
|
|
|
|
|
if(stats.combatRegen > 0 && isAttacking())
|
|
|
|
|
heal(stats.combatRegen);
|
|
|
|
|
}
|
|
|
|
|
if(faction.getsAttacked && !isAttacking()){
|
|
|
|
|
List<EntityMob> list = this.worldObj.getEntitiesWithinAABB(EntityMob.class, this.boundingBox.expand(16, 16, 16));
|
|
|
|
|
for(EntityMob mob : list){
|
|
|
|
|
if(mob.getAttackTarget() == null && this.canSee(mob)){
|
|
|
|
|
if(mob instanceof EntityZombie && !mob.getEntityData().hasKey("AttackNpcs")){
|
|
|
|
|
mob.tasks.addTask(2, new EntityAIAttackOnCollide(mob, EntityLivingBase.class, 1.0D, false));
|
|
|
|
|
mob.getEntityData().setBoolean("AttackNpcs", true);
|
|
|
|
|
}
|
|
|
|
|
mob.setAttackTarget(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(linkedData != null && linkedData.time > linkedLast){
|
|
|
|
|
LinkedNpcController.Instance.loadNpcData(this);
|
|
|
|
|
}
|
|
|
|
|
if(updateClient){
|
2022-01-03 21:30:38 -06:00
|
|
|
this.updateClient();
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
if(updateAI){
|
|
|
|
|
updateTasks();
|
|
|
|
|
updateAI = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(getHealth() <= 0){
|
|
|
|
|
clearActivePotions();
|
|
|
|
|
setBoolFlag(true, 8);
|
|
|
|
|
}
|
|
|
|
|
setBoolFlag(this.getAttackTarget() != null, 4);
|
|
|
|
|
setBoolFlag(!getNavigator().noPath(), 1);
|
|
|
|
|
setBoolFlag(isInteracting(), 2);
|
|
|
|
|
|
|
|
|
|
onCollide();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(wasKilled != isKilled() && wasKilled){
|
|
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wasKilled = isKilled();
|
|
|
|
|
|
|
|
|
|
if (this.worldObj.isDaytime() && !this.worldObj.isRemote && this.stats.burnInSun){
|
|
|
|
|
float f = this.getBrightness(1.0F);
|
|
|
|
|
|
|
|
|
|
if (f > 0.5F && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ))){
|
|
|
|
|
this.setFire(8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
super.onLivingUpdate();
|
|
|
|
|
|
|
|
|
|
if (worldObj.isRemote){
|
|
|
|
|
if(roleInterface != null){
|
|
|
|
|
roleInterface.clientUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!display.cloakTexture.isEmpty())
|
|
|
|
|
cloakUpdate();
|
|
|
|
|
if(currentAnimation.ordinal() != dataWatcher.getWatchableObjectInt(14)){
|
|
|
|
|
currentAnimation = EnumAnimation.values()[dataWatcher.getWatchableObjectInt(14)];
|
|
|
|
|
updateHitbox();
|
|
|
|
|
}
|
|
|
|
|
if(advanced.job == EnumJobType.Bard)
|
|
|
|
|
((JobBard)jobInterface).onLivingUpdate();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-03 21:30:38 -06:00
|
|
|
|
|
|
|
|
public void updateClient() {
|
|
|
|
|
NBTTagCompound compound = writeSpawnData();
|
|
|
|
|
compound.setInteger("EntityId", getEntityId());
|
|
|
|
|
Server.sendAssociatedData(this, EnumPacketClient.UPDATE_NPC, compound);
|
|
|
|
|
updateClient = false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean interact(EntityPlayer player) {
|
|
|
|
|
if(worldObj.isRemote)
|
|
|
|
|
return false;
|
|
|
|
|
ItemStack currentItem = player.inventory.getCurrentItem();
|
|
|
|
|
if (currentItem != null) {
|
|
|
|
|
Item item = currentItem.getItem();
|
|
|
|
|
if (item == CustomItems.cloner || item == CustomItems.wand || item == CustomItems.mount || item == CustomItems.scripter) {
|
|
|
|
|
setAttackTarget(null);
|
|
|
|
|
setRevengeTarget(null);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (item == CustomItems.moving) {
|
|
|
|
|
setAttackTarget(null);
|
|
|
|
|
if(currentItem.stackTagCompound == null)
|
|
|
|
|
currentItem.stackTagCompound = new NBTTagCompound();
|
|
|
|
|
|
|
|
|
|
currentItem.stackTagCompound.setInteger("NPCID",this.getEntityId());
|
|
|
|
|
player.addChatMessage(new ChatComponentTranslation("Registered " + this.getCommandSenderName() + " to your NPC Pather"));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-23 03:54:06 -05:00
|
|
|
|
|
|
|
|
if(EventHooks.onNPCInteract(this, player) || isAttacking() || isKilled() || faction.isAggressiveToPlayer(player))
|
2018-09-13 12:03:28 -04:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
addInteract(player);
|
|
|
|
|
|
|
|
|
|
Dialog dialog = getDialog(player);
|
|
|
|
|
PlayerQuestData playerdata = PlayerDataController.instance.getPlayerData(player).questData;
|
|
|
|
|
QuestData data = playerdata.getQuestCompletion(player, this);
|
|
|
|
|
if (data != null){
|
2022-06-13 04:08:36 -05:00
|
|
|
NoppesUtilPlayer.questCompletion((EntityPlayerMP) player, data.quest.id);
|
2018-09-13 12:03:28 -04:00
|
|
|
Server.sendData((EntityPlayerMP)player, EnumPacketClient.QUEST_COMPLETION, data.quest.writeToNBT(new NBTTagCompound()));
|
|
|
|
|
}
|
|
|
|
|
else if (dialog != null){
|
2022-04-09 00:17:16 -05:00
|
|
|
NoppesUtilServer.openDialog(player, this, dialog, 0);
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
else if(roleInterface != null)
|
|
|
|
|
roleInterface.interact(player);
|
|
|
|
|
else
|
|
|
|
|
say(player, advanced.getInteractLine());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-12-07 03:57:57 -06:00
|
|
|
|
2022-08-26 15:50:58 -04:00
|
|
|
@Override
|
2021-12-07 03:57:57 -06:00
|
|
|
public PathNavigate getNavigator() {
|
2021-12-08 04:00:28 -06:00
|
|
|
if(canFly())
|
2021-12-07 03:57:57 -06:00
|
|
|
return this.flyNavigator;
|
|
|
|
|
else {
|
|
|
|
|
return super.getNavigator();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-26 15:50:58 -04:00
|
|
|
@Override
|
2021-12-07 03:57:57 -06:00
|
|
|
public EntityMoveHelper getMoveHelper() {
|
2021-12-08 04:00:28 -06:00
|
|
|
if(canFly())
|
2021-12-07 03:57:57 -06:00
|
|
|
return this.flyMoveHelper;
|
|
|
|
|
else {
|
|
|
|
|
return super.getMoveHelper();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-26 15:50:58 -04:00
|
|
|
@Override
|
2021-12-07 03:57:57 -06:00
|
|
|
protected void updateAITasks()
|
|
|
|
|
{
|
2022-06-29 14:36:17 -05:00
|
|
|
if (this.isInWater() || this.stats.drowningType != 2) {
|
2022-06-29 12:21:30 -05:00
|
|
|
this.getNavigator().onUpdateNavigation();
|
|
|
|
|
this.getMoveHelper().onUpdateMoveHelper();
|
|
|
|
|
try {
|
|
|
|
|
super.updateAITasks();
|
|
|
|
|
} catch (ConcurrentModificationException ignored){}
|
|
|
|
|
} else {
|
|
|
|
|
this.setAir(this.decreaseAirSupply(this.getAir()));
|
2022-05-04 03:06:40 -05:00
|
|
|
|
2022-06-29 12:21:30 -05:00
|
|
|
if (this.getAir() <= -20) {
|
|
|
|
|
this.setAir(0);
|
|
|
|
|
this.attackEntityFrom(DamageSource.drown, 2.0F);
|
|
|
|
|
}
|
2022-01-31 23:01:52 -06:00
|
|
|
}
|
2021-12-07 03:57:57 -06:00
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
public void addInteract(EntityLivingBase entity){
|
|
|
|
|
if( !ai.stopAndInteract || isAttacking() || !entity.isEntityAlive())
|
|
|
|
|
return;
|
|
|
|
|
if((ticksExisted - lastInteract) < 180)
|
|
|
|
|
interactingEntities.clear();
|
|
|
|
|
getNavigator().clearPathEntity();
|
|
|
|
|
lastInteract = ticksExisted;
|
|
|
|
|
if(!interactingEntities.contains(entity))
|
|
|
|
|
interactingEntities.add(entity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isInteracting(){
|
|
|
|
|
if((ticksExisted - lastInteract) < 40 || isRemote() && getBoolFlag(2))
|
|
|
|
|
return true;
|
|
|
|
|
return ai.stopAndInteract && !interactingEntities.isEmpty() && (ticksExisted - lastInteract) < 180;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Dialog getDialog(EntityPlayer player) {
|
|
|
|
|
for (DialogOption option : dialogs.values()) {
|
|
|
|
|
if (option == null)
|
|
|
|
|
continue;
|
|
|
|
|
if (!option.hasDialog())
|
|
|
|
|
continue;
|
|
|
|
|
Dialog dialog = option.getDialog();
|
|
|
|
|
if (dialog.availability.isAvailable(player)){
|
|
|
|
|
return dialog;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean attackEntityFrom(DamageSource damagesource, float i) {
|
2022-01-22 22:50:01 -06:00
|
|
|
if (this.worldObj.isRemote || CustomNpcs.FreezeNPCs || (damagesource.damageType != null && damagesource.damageType.equals("inWall"))){
|
2018-09-13 12:03:28 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-01-22 22:50:01 -06:00
|
|
|
if(damagesource.damageType != null && damagesource.damageType.equals("outOfWorld") && isKilled()){
|
2018-09-13 12:03:28 -04:00
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
i = stats.resistances.applyResistance(damagesource, i);
|
|
|
|
|
if((float)this.hurtResistantTime > (float)this.maxHurtResistantTime / 2.0F && i <= this.lastDamage)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
Entity entity = damagesource.getEntity();
|
|
|
|
|
|
|
|
|
|
EntityLivingBase attackingEntity = null;
|
|
|
|
|
|
|
|
|
|
if (entity instanceof EntityLivingBase)
|
|
|
|
|
attackingEntity = (EntityLivingBase) entity;
|
|
|
|
|
|
|
|
|
|
if ((entity instanceof EntityArrow) && ((EntityArrow) entity).shootingEntity instanceof EntityLivingBase)
|
|
|
|
|
attackingEntity = (EntityLivingBase) ((EntityArrow) entity).shootingEntity;
|
|
|
|
|
else if ((entity instanceof EntityThrowable))
|
|
|
|
|
attackingEntity = ((EntityThrowable) entity).getThrower();
|
|
|
|
|
|
|
|
|
|
if(attackingEntity != null && attackingEntity == getOwner())
|
|
|
|
|
return false;
|
|
|
|
|
else if (attackingEntity instanceof EntityNPCInterface){
|
|
|
|
|
EntityNPCInterface npc = (EntityNPCInterface) attackingEntity;
|
|
|
|
|
if(npc.faction.id == faction.id)
|
|
|
|
|
return false;
|
|
|
|
|
if(npc.getOwner() instanceof EntityPlayer)
|
|
|
|
|
this.recentlyHit = 100;
|
|
|
|
|
}
|
|
|
|
|
else if (attackingEntity instanceof EntityPlayer && faction.isFriendlyToPlayer((EntityPlayer) attackingEntity))
|
|
|
|
|
return false;
|
2022-06-10 18:32:42 -05:00
|
|
|
NpcEvent.DamagedEvent event = new NpcEvent.DamagedEvent(this.wrappedNPC, attackingEntity, i, damagesource);
|
|
|
|
|
if(EventHooks.onNPCDamaged(this, event) || isKilled())
|
2018-09-13 12:03:28 -04:00
|
|
|
return false;
|
2022-06-10 18:32:42 -05:00
|
|
|
i = event.getDamage();
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
if(isKilled())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(attackingEntity == null)
|
|
|
|
|
return super.attackEntityFrom(damagesource, i);
|
|
|
|
|
|
|
|
|
|
try{
|
|
|
|
|
if (isAttacking()){
|
|
|
|
|
if(getAttackTarget() != null && attackingEntity != null && this.getDistanceSqToEntity(getAttackTarget()) > this.getDistanceSqToEntity(attackingEntity)){
|
|
|
|
|
setAttackTarget(attackingEntity);
|
|
|
|
|
}
|
|
|
|
|
return super.attackEntityFrom(damagesource, i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
List<EntityNPCInterface> inRange = worldObj.getEntitiesWithinAABB(EntityNPCInterface.class, this.boundingBox.expand(32D, 16D, 32D));
|
|
|
|
|
for (EntityNPCInterface npc : inRange) {
|
|
|
|
|
if (npc.isKilled() || !npc.advanced.defendFaction || npc.faction.id != faction.id)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (npc.canSee(this) || npc.ai.directLOS || npc.canSee(attackingEntity))
|
|
|
|
|
npc.onAttack(attackingEntity);
|
|
|
|
|
}
|
|
|
|
|
setAttackTarget(attackingEntity);
|
|
|
|
|
}
|
|
|
|
|
return super.attackEntityFrom(damagesource, i);
|
|
|
|
|
}
|
|
|
|
|
finally{
|
2022-06-10 18:32:42 -05:00
|
|
|
if(event.getClearTarget()){
|
2018-09-13 12:03:28 -04:00
|
|
|
setAttackTarget(null);
|
|
|
|
|
setRevengeTarget(null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void onAttack(EntityLivingBase entity) {
|
|
|
|
|
if (entity == null || entity == this || isAttacking() || ai.onAttack == 3 || entity == getOwner())
|
|
|
|
|
return;
|
|
|
|
|
super.setAttackTarget(entity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setAttackTarget(EntityLivingBase entity){
|
|
|
|
|
if(entity instanceof EntityPlayer && ((EntityPlayer)entity).capabilities.disableDamage || entity != null && entity == getOwner())
|
|
|
|
|
return;
|
2022-06-10 17:25:58 -05:00
|
|
|
if (!isRemote()) {
|
|
|
|
|
if (getAttackTarget() != entity && entity != null) {
|
2022-06-10 18:32:42 -05:00
|
|
|
NpcEvent.TargetEvent event = new NpcEvent.TargetEvent(wrappedNPC,entity);
|
|
|
|
|
if (EventHooks.onNPCTarget(this, event))
|
2022-06-10 17:25:58 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (event.getTarget() == null)
|
|
|
|
|
entity = null;
|
|
|
|
|
else
|
|
|
|
|
entity = event.getTarget().getMCEntity();
|
|
|
|
|
}
|
|
|
|
|
if (entity != null && entity != this && ai.onAttack != 3 && !isAttacking()) {
|
|
|
|
|
Line line = advanced.getAttackLine();
|
|
|
|
|
if (line != null)
|
|
|
|
|
saySurrounding(line.formatTarget(entity));
|
|
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
super.setAttackTarget(entity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void attackEntityWithRangedAttack(EntityLivingBase entity, float f) {
|
|
|
|
|
ItemStack proj = inventory.getProjectile();
|
|
|
|
|
if(proj == null){
|
|
|
|
|
updateTasks();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-10 17:25:58 -05:00
|
|
|
if (!isRemote()) {
|
2022-06-10 18:32:42 -05:00
|
|
|
NpcEvent.RangedLaunchedEvent event = new NpcEvent.RangedLaunchedEvent(wrappedNPC,stats.pDamage,entity);
|
|
|
|
|
if (EventHooks.onNPCRangedAttack(this, event))
|
2022-06-10 17:25:58 -05:00
|
|
|
return;
|
|
|
|
|
for (int i = 0; i < this.stats.shotCount; i++) {
|
|
|
|
|
EntityProjectile projectile = shoot(entity, stats.accuracy, proj, f == 1);
|
|
|
|
|
projectile.damage = event.getDamage();
|
|
|
|
|
}
|
|
|
|
|
this.playSound(this.stats.fireSound, 2.0F, 1.0f);
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EntityProjectile shoot(EntityLivingBase entity, int accuracy, ItemStack proj, boolean indirect){
|
|
|
|
|
return shoot(entity.posX, entity.boundingBox.minY + (double)(entity.height / 2.0F), entity.posZ, accuracy, proj, indirect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EntityProjectile shoot(double x, double y, double z, int accuracy, ItemStack proj, boolean indirect){
|
|
|
|
|
EntityProjectile projectile = new EntityProjectile(this.worldObj, this, proj.copy(), true);
|
|
|
|
|
//TODO calculate height of the thrower
|
|
|
|
|
double varX = x - this.posX;
|
|
|
|
|
double varY = y - (this.posY + this.getEyeHeight());
|
|
|
|
|
double varZ = z - this.posZ;
|
|
|
|
|
float varF = projectile.hasGravity() ? MathHelper.sqrt_double(varX * varX + varZ * varZ) : 0.0F;
|
|
|
|
|
float angle = projectile.getAngleForXYZ(varX, varY, varZ, varF, indirect);
|
|
|
|
|
float acc = 20.0F - MathHelper.floor_float(accuracy / 5.0F);
|
|
|
|
|
projectile.setThrowableHeading(varX, varY, varZ, angle, acc);
|
|
|
|
|
worldObj.spawnEntityInWorld(projectile);
|
|
|
|
|
return projectile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void clearTasks(EntityAITasks tasks){
|
|
|
|
|
Iterator iterator = tasks.taskEntries.iterator();
|
|
|
|
|
List<EntityAITaskEntry> list = new ArrayList(tasks.taskEntries);
|
|
|
|
|
for (EntityAITaskEntry entityaitaskentry : list)
|
|
|
|
|
{
|
|
|
|
|
tasks.removeTask(entityaitaskentry.action);
|
|
|
|
|
}
|
|
|
|
|
tasks.taskEntries = new ArrayList<EntityAITaskEntry>();
|
|
|
|
|
}
|
2022-07-27 18:47:20 -05:00
|
|
|
public void updateTasks() {
|
2018-09-13 12:03:28 -04:00
|
|
|
if (worldObj == null || worldObj.isRemote)
|
|
|
|
|
return;
|
|
|
|
|
aiLeap = aiAttackTarget = aiResponse = aiSprint = aiRange = null;
|
2021-06-13 16:22:06 -04:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
clearTasks(tasks);
|
|
|
|
|
clearTasks(targetTasks);
|
|
|
|
|
IEntitySelector attackEntitySelector = new NPCAttackSelector(this);
|
|
|
|
|
this.targetTasks.addTask(0, new EntityAIClearTarget(this));
|
|
|
|
|
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
|
|
|
|
|
this.targetTasks.addTask(2, new EntityAIClosestTarget(this, EntityLivingBase.class, 4, this.ai.directLOS, false, attackEntitySelector));
|
|
|
|
|
this.targetTasks.addTask(3, new EntityAIOwnerHurtByTarget(this));
|
|
|
|
|
this.targetTasks.addTask(4, new EntityAIOwnerHurtTarget(this));
|
2021-06-13 16:22:06 -04:00
|
|
|
|
2021-12-07 03:57:57 -06:00
|
|
|
if (canFly()) {
|
2021-12-03 00:49:10 -06:00
|
|
|
this.getNavigator().setCanSwim(true);
|
2021-12-07 03:57:57 -06:00
|
|
|
} else {
|
2021-12-03 00:49:10 -06:00
|
|
|
this.tasks.addTask(0, new EntityAIWaterNav(this));
|
|
|
|
|
}
|
2021-07-10 00:48:03 -04:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
this.taskCount = 1;
|
|
|
|
|
this.doorInteractType();
|
|
|
|
|
this.seekShelter();
|
|
|
|
|
this.setResponse();
|
|
|
|
|
this.setMoveType();
|
|
|
|
|
this.addRegularEntries();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void removeTask(EntityAIBase task){
|
|
|
|
|
if(task != null)
|
|
|
|
|
tasks.removeTask(task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Branch task function for setting how an NPC responds to a threat
|
|
|
|
|
*/
|
|
|
|
|
public void setResponse(){
|
|
|
|
|
removeTask(aiLeap);
|
|
|
|
|
removeTask(aiResponse);
|
|
|
|
|
removeTask(aiSprint);
|
|
|
|
|
removeTask(aiAttackTarget);
|
|
|
|
|
removeTask(aiRange);
|
|
|
|
|
aiLeap = aiAttackTarget = aiResponse = aiSprint = aiRange = null;
|
|
|
|
|
|
|
|
|
|
if (this.ai.onAttack == 1)
|
|
|
|
|
this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIPanic(this, 1.2F));
|
|
|
|
|
|
|
|
|
|
else if (this.ai.onAttack == 2) {
|
|
|
|
|
this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIAvoidTarget(this));
|
|
|
|
|
this.setCanSprint();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (this.ai.onAttack == 0) {
|
|
|
|
|
this.setCanLeap();
|
|
|
|
|
this.setCanSprint();
|
|
|
|
|
if (this.inventory.getProjectile() == null || this.ai.useRangeMelee == 2)
|
|
|
|
|
{
|
|
|
|
|
switch(this.ai.tacticalVariant)
|
|
|
|
|
{
|
|
|
|
|
case Dodge : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIZigZagTarget(this, 1.0D, this.ai.tacticalRadius)); break;
|
|
|
|
|
case Surround : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIOrbitTarget(this, 1.0D, this.ai.tacticalRadius, true)); break;
|
|
|
|
|
case HitNRun : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIAvoidTarget(this)); break;
|
|
|
|
|
case Ambush : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIAmbushTarget(this, 1.2D, this.ai.tacticalRadius, false)); break;
|
|
|
|
|
case Stalk : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIStalkTarget(this, this.ai.tacticalRadius)); break;
|
|
|
|
|
default :
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch(this.ai.tacticalVariant)
|
|
|
|
|
{
|
|
|
|
|
case Dodge : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIDodgeShoot(this)); break;
|
|
|
|
|
case Surround : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIOrbitTarget(this, 1.0D, stats.rangedRange, false)); break;
|
|
|
|
|
case HitNRun : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIAvoidTarget(this)); break;
|
|
|
|
|
case Ambush : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIAmbushTarget(this, 1.2D, this.ai.tacticalRadius, false)); break;
|
|
|
|
|
case Stalk : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIStalkTarget(this, this.ai.tacticalRadius)); break;
|
|
|
|
|
default :
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.tasks.addTask(this.taskCount, aiAttackTarget = new EntityAIAttackTarget(this));
|
|
|
|
|
((EntityAIAttackTarget)aiAttackTarget).navOverride(ai.tacticalVariant == EnumNavType.None);
|
|
|
|
|
|
|
|
|
|
if(this.inventory.getProjectile() != null){
|
|
|
|
|
this.tasks.addTask(this.taskCount++, aiRange = new EntityAIRangedAttack(this));
|
|
|
|
|
aiRange.navOverride(ai.tacticalVariant == EnumNavType.None);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (this.ai.onAttack == 3) {
|
|
|
|
|
//do nothing
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Branch task function for setting if an NPC wanders or not
|
|
|
|
|
*/
|
|
|
|
|
public void setMoveType(){
|
|
|
|
|
if (ai.movingType == EnumMovingType.Wandering){
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIWander(this));
|
|
|
|
|
}
|
|
|
|
|
if (ai.movingType == EnumMovingType.MovingPath){
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIMovingPath(this));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Branch task function for adjusting NPC door interactivity
|
|
|
|
|
*/
|
2021-06-13 16:22:06 -04:00
|
|
|
public void doorInteractType(){
|
|
|
|
|
if(canFly()) //currently flying does not support opening doors
|
|
|
|
|
return;
|
2018-09-13 12:03:28 -04:00
|
|
|
EntityAIBase aiDoor = null;
|
|
|
|
|
if (this.ai.doorInteract == 1)
|
|
|
|
|
{
|
|
|
|
|
this.tasks.addTask(this.taskCount++, aiDoor = new EntityAIOpenDoor(this, true));
|
|
|
|
|
}
|
|
|
|
|
else if (this.ai.doorInteract == 0)
|
|
|
|
|
{
|
|
|
|
|
this.tasks.addTask(this.taskCount++, aiDoor = new EntityAIBustDoor(this));
|
|
|
|
|
}
|
|
|
|
|
this.getNavigator().setBreakDoors(aiDoor != null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Branch task function for finding shelter under the appropriate conditions
|
|
|
|
|
*/
|
|
|
|
|
public void seekShelter() {
|
|
|
|
|
if (this.ai.findShelter == 0)
|
|
|
|
|
{
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIMoveIndoors(this));
|
|
|
|
|
}
|
|
|
|
|
else if (this.ai.findShelter == 1)
|
|
|
|
|
{
|
2021-06-13 16:22:06 -04:00
|
|
|
if(!canFly()) // doesnt work when flying
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIRestrictSun(this));
|
2018-09-13 12:03:28 -04:00
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIFindShade(this));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Branch task function for leaping
|
|
|
|
|
*/
|
|
|
|
|
public void setCanLeap() {
|
|
|
|
|
if (this.ai.canLeap)
|
|
|
|
|
this.tasks.addTask(this.taskCount++, aiLeap = new EntityAILeapAtTarget(this, 0.4F));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Branch task function for sprinting
|
|
|
|
|
*/
|
|
|
|
|
public void setCanSprint() {
|
|
|
|
|
if (this.ai.canSprint)
|
|
|
|
|
this.tasks.addTask(this.taskCount++, aiSprint = new EntityAISprintToTarget(this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Add immutable task entries.
|
|
|
|
|
*/
|
|
|
|
|
public void addRegularEntries() {
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIFollow(this));
|
2022-07-20 13:33:21 -05:00
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIReturn(this));
|
2018-09-13 12:03:28 -04:00
|
|
|
if (this.ai.standingType != EnumStandingType.NoRotation && this.ai.standingType != EnumStandingType.HeadRotation)
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIWatchClosest(this, EntityLivingBase.class, 5.0F));
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAILook(this));
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIWorldLines(this));
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIJob(this));
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIRole(this));
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAIAnimation(this));
|
|
|
|
|
if(transform.isValid())
|
|
|
|
|
this.tasks.addTask(this.taskCount++, new EntityAITransform(this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function for getting proper move speeds. This way we don't have to modify them every time we use them.
|
|
|
|
|
*/
|
|
|
|
|
public float getSpeed() {
|
|
|
|
|
return (float)ai.getWalkingSpeed() / 20.0F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public float getBlockPathWeight(int par1, int par2, int par3){
|
|
|
|
|
float weight = this.worldObj.getLightBrightness(par1, par2, par3) - 0.5F;
|
|
|
|
|
Block block = worldObj.getBlock(par1, par2, par3);
|
|
|
|
|
if(block.isOpaqueCube())
|
|
|
|
|
weight += 10;
|
|
|
|
|
return weight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Used for getting the applied potion effect from dataStats.
|
|
|
|
|
*/
|
|
|
|
|
private int getPotionEffect(EnumPotionType p) {
|
|
|
|
|
switch(p)
|
|
|
|
|
{
|
|
|
|
|
case Poison : return Potion.poison.id;
|
|
|
|
|
case Hunger : return Potion.hunger.id;
|
|
|
|
|
case Weakness : return Potion.weakness.id;
|
|
|
|
|
case Slowness : return Potion.moveSlowdown.id;
|
|
|
|
|
case Nausea : return Potion.confusion.id;
|
|
|
|
|
case Blindness : return Potion.blindness.id;
|
|
|
|
|
case Wither : return Potion.wither.id;
|
|
|
|
|
default : return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:21:30 -05:00
|
|
|
@Override
|
|
|
|
|
public void setAir(int air) {
|
2022-06-29 14:36:17 -05:00
|
|
|
if (this.isInWater() || air < this.getAir() || this.stats.drowningType != 2) {
|
2022-06-29 12:21:30 -05:00
|
|
|
super.setAir(air);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
@Override
|
|
|
|
|
protected int decreaseAirSupply(int par1)
|
|
|
|
|
{
|
2022-06-29 12:21:30 -05:00
|
|
|
if (this.stats.drowningType == 0)
|
2018-09-13 12:03:28 -04:00
|
|
|
return par1;
|
|
|
|
|
return super.decreaseAirSupply(par1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public EnumCreatureAttribute getCreatureAttribute()
|
|
|
|
|
{
|
|
|
|
|
return this.stats.creatureType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the sound this mob makes while it's alive.
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected String getLivingSound() {
|
|
|
|
|
if (!this.isEntityAlive())
|
|
|
|
|
return null;
|
|
|
|
|
if (this.getAttackTarget() != null)
|
|
|
|
|
return advanced.angrySound.isEmpty() ? null : advanced.angrySound;
|
|
|
|
|
|
|
|
|
|
return advanced.idleSound.isEmpty() ? null : advanced.idleSound;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int getTalkInterval(){
|
|
|
|
|
return 160;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Returns the sound this mob makes when it is hurt.
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected String getHurtSound(){
|
|
|
|
|
if(this.advanced.hurtSound.isEmpty())
|
|
|
|
|
return null;
|
|
|
|
|
return this.advanced.hurtSound;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the sound this mob makes on death.
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected String getDeathSound(){
|
|
|
|
|
if(this.advanced.deathSound.isEmpty())
|
|
|
|
|
return null;
|
|
|
|
|
return this.advanced.deathSound;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected float getSoundPitch(){
|
|
|
|
|
if(this.advanced.disablePitch)
|
|
|
|
|
return 1;
|
|
|
|
|
return super.getSoundPitch();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Plays step sound at given x, y, z for the entity
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected void func_145780_a(int p_145780_1_, int p_145780_2_, int p_145780_3_, Block p_145780_4_)
|
|
|
|
|
{
|
|
|
|
|
if (!this.advanced.stepSound.equals(""))
|
|
|
|
|
{
|
|
|
|
|
this.playSound(this.advanced.stepSound, 0.15F, 1.0F);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
super.func_145780_a(p_145780_1_, p_145780_2_, p_145780_3_, p_145780_4_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public EntityPlayerMP getFakePlayer(){
|
|
|
|
|
if(worldObj.isRemote)
|
|
|
|
|
return null;
|
|
|
|
|
if(chateventPlayer == null)
|
|
|
|
|
chateventPlayer = new FakePlayer((WorldServer)worldObj, chateventProfile);
|
|
|
|
|
EntityUtil.Copy(this, chateventPlayer);
|
|
|
|
|
chateventProfile.npc = this;
|
|
|
|
|
chateventPlayer.refreshDisplayName();
|
|
|
|
|
return chateventPlayer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void saySurrounding(Line line) {
|
2022-03-23 03:54:06 -05:00
|
|
|
if (line == null || line.text == null || getFakePlayer() == null)
|
2018-09-13 12:03:28 -04:00
|
|
|
return;
|
|
|
|
|
ServerChatEvent event = new ServerChatEvent(getFakePlayer(), line.text, new ChatComponentTranslation(line.text.replace("%", "%%")));
|
|
|
|
|
if (MinecraftForge.EVENT_BUS.post(event) || event.component == null){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
line.text = event.component.getUnformattedText().replace("%%", "%");
|
|
|
|
|
List<EntityPlayer> inRange = worldObj.getEntitiesWithinAABB(
|
|
|
|
|
EntityPlayer.class, this.boundingBox.expand(20D, 20D, 20D));
|
|
|
|
|
for (EntityPlayer player : inRange)
|
|
|
|
|
say(player, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void say(EntityPlayer player, Line line) {
|
|
|
|
|
if (line == null || !this.canSee(player) || line.text == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if(!line.sound.isEmpty()){
|
|
|
|
|
Server.sendData((EntityPlayerMP)player, EnumPacketClient.PLAY_SOUND, line.sound, (float)posX, (float)posY, (float)posZ);
|
|
|
|
|
}
|
|
|
|
|
Server.sendData((EntityPlayerMP)player, EnumPacketClient.CHATBUBBLE, this.getEntityId(), line.text, !line.hideText);
|
|
|
|
|
}
|
|
|
|
|
public boolean getAlwaysRenderNameTagForRender(){
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void readEntityFromNBT(NBTTagCompound compound) {
|
|
|
|
|
super.readEntityFromNBT(compound);
|
|
|
|
|
npcVersion = compound.getInteger("ModRev");
|
|
|
|
|
VersionCompatibility.CheckNpcCompatibility(this, compound);
|
2022-06-14 22:26:11 -04:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
display.readToNBT(compound);
|
|
|
|
|
stats.readToNBT(compound);
|
|
|
|
|
ai.readToNBT(compound);
|
|
|
|
|
script.readFromNBT(compound);
|
2021-10-20 23:04:52 -05:00
|
|
|
timers.readFromNBT(compound);
|
2022-06-12 01:26:23 -05:00
|
|
|
if (compound.hasKey("ItemGiverId")) {
|
|
|
|
|
itemGiverId = compound.getInteger("ItemGiverId");
|
|
|
|
|
} else {
|
|
|
|
|
itemGiverId = -1;
|
|
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
advanced.readToNBT(compound);
|
|
|
|
|
if (advanced.role != EnumRoleType.None && roleInterface != null)
|
|
|
|
|
roleInterface.readFromNBT(compound);
|
|
|
|
|
if (advanced.job != EnumJobType.None && jobInterface != null)
|
|
|
|
|
jobInterface.readFromNBT(compound);
|
|
|
|
|
|
|
|
|
|
inventory.readEntityFromNBT(compound);
|
|
|
|
|
transform.readToNBT(compound);
|
|
|
|
|
|
|
|
|
|
killedtime = compound.getLong("KilledTime");
|
|
|
|
|
totalTicksAlive = compound.getLong("TotalTicksAlive");
|
|
|
|
|
|
|
|
|
|
linkedName = compound.getString("LinkedNpcName");
|
2022-05-24 03:06:16 -05:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
if(!isRemote())
|
|
|
|
|
LinkedNpcController.Instance.loadNpcData(this);
|
|
|
|
|
|
|
|
|
|
this.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(CustomNpcs.NpcNavRange);
|
|
|
|
|
|
|
|
|
|
this.updateTasks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void writeEntityToNBT(NBTTagCompound compound) {
|
|
|
|
|
super.writeEntityToNBT(compound);
|
|
|
|
|
display.writeToNBT(compound);
|
|
|
|
|
stats.writeToNBT(compound);
|
|
|
|
|
ai.writeToNBT(compound);
|
|
|
|
|
script.writeToNBT(compound);
|
2021-10-20 23:04:52 -05:00
|
|
|
timers.writeToNBT(compound);
|
2018-09-13 12:03:28 -04:00
|
|
|
advanced.writeToNBT(compound);
|
|
|
|
|
if (advanced.role != EnumRoleType.None && roleInterface != null)
|
|
|
|
|
roleInterface.writeToNBT(compound);
|
|
|
|
|
if (advanced.job != EnumJobType.None && jobInterface != null)
|
|
|
|
|
jobInterface.writeToNBT(compound);
|
|
|
|
|
|
|
|
|
|
inventory.writeEntityToNBT(compound);
|
|
|
|
|
transform.writeToNBT(compound);
|
|
|
|
|
|
|
|
|
|
compound.setLong("KilledTime", killedtime);
|
|
|
|
|
compound.setLong("TotalTicksAlive", totalTicksAlive);
|
|
|
|
|
compound.setInteger("ModRev", npcVersion);
|
|
|
|
|
compound.setString("LinkedNpcName", linkedName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void updateHitbox() {
|
|
|
|
|
|
|
|
|
|
if(currentAnimation == EnumAnimation.LYING || currentAnimation == EnumAnimation.CRAWLING){
|
|
|
|
|
width = 0.8f;
|
|
|
|
|
height = 0.4f;
|
|
|
|
|
}
|
|
|
|
|
else if (isRiding()){
|
|
|
|
|
width = 0.6f;
|
|
|
|
|
height = baseHeight * 0.77f;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
width = 0.6f;
|
|
|
|
|
height = baseHeight;
|
|
|
|
|
}
|
|
|
|
|
width = (width / 5f) * display.modelSize;
|
|
|
|
|
height = (height / 5f) * display.modelSize;
|
|
|
|
|
|
|
|
|
|
this.setPosition(posX, posY, posZ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onDeathUpdate(){
|
|
|
|
|
if(stats.spawnCycle == 3){
|
|
|
|
|
super.onDeathUpdate();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++this.deathTime;
|
|
|
|
|
if(worldObj.isRemote)
|
|
|
|
|
return;
|
|
|
|
|
if(!hasDied){
|
|
|
|
|
setDead();
|
|
|
|
|
}
|
|
|
|
|
if (killedtime < System.currentTimeMillis()) {
|
|
|
|
|
if (stats.spawnCycle == 0 || (this.worldObj.isDaytime() && stats.spawnCycle == 1) || (!this.worldObj.isDaytime() && stats.spawnCycle == 2)) {
|
|
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void reset() {
|
|
|
|
|
hasDied = false;
|
|
|
|
|
isDead = false;
|
|
|
|
|
wasKilled = false;
|
|
|
|
|
setSprinting(false);
|
|
|
|
|
setHealth(getMaxHealth());
|
|
|
|
|
dataWatcher.updateObject(14, 0); // animation Normal
|
|
|
|
|
dataWatcher.updateObject(15, 0);
|
|
|
|
|
this.setAttackTarget(null);
|
|
|
|
|
this.setRevengeTarget(null);
|
|
|
|
|
this.deathTime = 0;
|
|
|
|
|
//fleeingTick = 0;
|
|
|
|
|
if(ai.returnToStart && !hasOwner())
|
|
|
|
|
setLocationAndAngles(getStartXPos(), getStartYPos(), getStartZPos(), rotationYaw, rotationPitch);
|
|
|
|
|
killedtime = 0;
|
|
|
|
|
extinguish();
|
|
|
|
|
this.clearActivePotions();
|
|
|
|
|
getNavigator().clearPathEntity();
|
2022-11-07 21:23:46 -05:00
|
|
|
if(this.canFly()){
|
|
|
|
|
((PathNavigateFlying)getNavigator()).targetPos = null;
|
|
|
|
|
((PathNavigateFlying)getNavigator()).clearPathEntity();
|
2022-11-07 01:40:11 -05:00
|
|
|
((FlyingMoveHelper)getMoveHelper()).update = false;
|
|
|
|
|
}
|
2022-11-07 21:23:46 -05:00
|
|
|
moveEntityWithHeading(0,0);
|
|
|
|
|
distanceWalkedModified = 0;
|
2018-09-13 12:03:28 -04:00
|
|
|
currentAnimation = EnumAnimation.NONE;
|
|
|
|
|
updateHitbox();
|
|
|
|
|
updateAI = true;
|
|
|
|
|
ai.movingPos = 0;
|
|
|
|
|
if(getOwner() != null){
|
|
|
|
|
getOwner().setLastAttacker(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(jobInterface != null)
|
|
|
|
|
jobInterface.reset();
|
2022-03-23 03:54:06 -05:00
|
|
|
|
2022-06-10 17:25:58 -05:00
|
|
|
if (!isRemote()) {
|
|
|
|
|
EventHooks.onNPCInit(this);
|
|
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onCollide() {
|
|
|
|
|
if(!isEntityAlive() || ticksExisted % 4 != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
AxisAlignedBB axisalignedbb = null;
|
|
|
|
|
|
|
|
|
|
if (this.ridingEntity != null && this.ridingEntity.isEntityAlive()){
|
|
|
|
|
axisalignedbb = this.boundingBox.func_111270_a(this.ridingEntity.boundingBox).expand(1.0D, 0.0D, 1.0D);
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
axisalignedbb = this.boundingBox.expand(1.0D, 0.5D, 1.0D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, axisalignedbb);
|
|
|
|
|
if(list == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2022-06-10 17:25:58 -05:00
|
|
|
if (!isRemote()) {
|
|
|
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
|
|
|
Entity entity = (Entity) list.get(i);
|
|
|
|
|
if (entity.isEntityAlive()) {
|
|
|
|
|
EventHooks.onNPCCollide(this, entity);
|
|
|
|
|
}
|
2022-03-23 03:54:06 -05:00
|
|
|
}
|
2022-06-10 17:25:58 -05:00
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setInPortal(){
|
|
|
|
|
//prevent npcs from walking into portals
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public double field_20066_r;
|
|
|
|
|
public double field_20065_s;
|
|
|
|
|
public double field_20064_t;
|
|
|
|
|
public double field_20063_u;
|
|
|
|
|
public double field_20062_v;
|
|
|
|
|
public double field_20061_w;
|
|
|
|
|
|
|
|
|
|
public void cloakUpdate() {
|
|
|
|
|
field_20066_r = field_20063_u;
|
|
|
|
|
field_20065_s = field_20062_v;
|
|
|
|
|
field_20064_t = field_20061_w;
|
|
|
|
|
double d = posX - field_20063_u;
|
|
|
|
|
double d1 = posY - field_20062_v;
|
|
|
|
|
double d2 = posZ - field_20061_w;
|
|
|
|
|
double d3 = 10D;
|
|
|
|
|
if (d > d3) {
|
|
|
|
|
field_20066_r = field_20063_u = posX;
|
|
|
|
|
}
|
|
|
|
|
if (d2 > d3) {
|
|
|
|
|
field_20064_t = field_20061_w = posZ;
|
|
|
|
|
}
|
|
|
|
|
if (d1 > d3) {
|
|
|
|
|
field_20065_s = field_20062_v = posY;
|
|
|
|
|
}
|
|
|
|
|
if (d < -d3) {
|
|
|
|
|
field_20066_r = field_20063_u = posX;
|
|
|
|
|
}
|
|
|
|
|
if (d2 < -d3) {
|
|
|
|
|
field_20064_t = field_20061_w = posZ;
|
|
|
|
|
}
|
|
|
|
|
if (d1 < -d3) {
|
|
|
|
|
field_20065_s = field_20062_v = posY;
|
|
|
|
|
}
|
|
|
|
|
field_20063_u += d * 0.25D;
|
|
|
|
|
field_20061_w += d2 * 0.25D;
|
|
|
|
|
field_20062_v += d1 * 0.25D;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected boolean canDespawn() {
|
|
|
|
|
return stats.canDespawn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ItemStack getHeldItem() {
|
|
|
|
|
if (isAttacking())
|
|
|
|
|
return inventory.getWeapon();
|
|
|
|
|
else if(advanced.role == EnumRoleType.Companion)
|
|
|
|
|
return ((RoleCompanion)roleInterface).getHeldItem();
|
|
|
|
|
else if (jobInterface != null && jobInterface.overrideMainHand)
|
|
|
|
|
return jobInterface.mainhand;
|
|
|
|
|
else
|
|
|
|
|
return inventory.getWeapon();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ItemStack getEquipmentInSlot(int slot){
|
|
|
|
|
if(slot == 0)
|
|
|
|
|
return inventory.weapons.get(0);
|
|
|
|
|
return inventory.armorItemInSlot(4 - slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ItemStack func_130225_q(int slot){
|
|
|
|
|
return inventory.armorItemInSlot(3 - slot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setCurrentItemOrArmor(int slot, ItemStack item){
|
|
|
|
|
if(slot == 0)
|
|
|
|
|
inventory.setWeapon(item);
|
|
|
|
|
else{
|
|
|
|
|
inventory.armor.put(4 - slot, item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private static final ItemStack[] lastActive = new ItemStack[5];
|
|
|
|
|
@Override
|
|
|
|
|
public ItemStack[] getLastActiveItems(){
|
|
|
|
|
return lastActive;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void dropEquipment(boolean p_82160_1_, int p_82160_2_){
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ItemStack getOffHand() {
|
|
|
|
|
if (isAttacking())
|
|
|
|
|
return inventory.getOffHand();
|
|
|
|
|
else if (jobInterface != null && jobInterface.overrideOffHand)
|
|
|
|
|
return jobInterface.offhand;
|
|
|
|
|
else
|
|
|
|
|
return inventory.getOffHand();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onDeath(DamageSource damagesource){
|
|
|
|
|
setSprinting(false);
|
|
|
|
|
getNavigator().clearPathEntity();
|
|
|
|
|
extinguish();
|
|
|
|
|
clearActivePotions();
|
|
|
|
|
|
|
|
|
|
Entity entity = damagesource.getEntity();
|
|
|
|
|
|
|
|
|
|
EntityLivingBase attackingEntity = null;
|
|
|
|
|
|
|
|
|
|
if (entity instanceof EntityLivingBase)
|
|
|
|
|
attackingEntity = (EntityLivingBase) entity;
|
|
|
|
|
|
|
|
|
|
if ((entity instanceof EntityArrow) && ((EntityArrow) entity).shootingEntity instanceof EntityLivingBase)
|
|
|
|
|
attackingEntity = (EntityLivingBase) ((EntityArrow) entity).shootingEntity;
|
|
|
|
|
else if ((entity instanceof EntityThrowable))
|
|
|
|
|
attackingEntity = ((EntityThrowable) entity).getThrower();
|
|
|
|
|
|
2022-06-10 17:25:58 -05:00
|
|
|
|
|
|
|
|
int droppedXp = inventory.getDroppedXp();
|
|
|
|
|
ArrayList<ItemStack> droppedItems = inventory.getDroppedItems(damagesource);
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
if(!isRemote()){
|
2022-06-10 17:25:58 -05:00
|
|
|
NpcEvent.DiedEvent event = new NpcEvent.DiedEvent(this.wrappedNPC,damagesource,entity,droppedItems, droppedXp);
|
2022-06-10 18:32:42 -05:00
|
|
|
if(EventHooks.onNPCKilled(this, event))
|
2022-06-10 17:25:58 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
droppedItems.clear();
|
|
|
|
|
for (IItemStack iItemStack : event.droppedItems) {
|
|
|
|
|
droppedItems.add(iItemStack.getMCItemStack());
|
|
|
|
|
}
|
|
|
|
|
droppedXp = event.expDropped;
|
|
|
|
|
|
|
|
|
|
if(this.recentlyHit > 0) {
|
|
|
|
|
inventory.dropItems(entity, droppedItems);
|
|
|
|
|
inventory.dropXp(entity, droppedXp);
|
|
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
Line line = advanced.getKilledLine();
|
|
|
|
|
if(line != null)
|
|
|
|
|
saySurrounding(line.formatTarget(attackingEntity));
|
|
|
|
|
}
|
|
|
|
|
super.onDeath(damagesource);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setDead() {
|
|
|
|
|
hasDied = true;
|
|
|
|
|
if(worldObj.isRemote || stats.spawnCycle == 3){
|
|
|
|
|
this.spawnExplosionParticle();
|
|
|
|
|
delete();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if(this.riddenByEntity != null)
|
|
|
|
|
this.riddenByEntity.mountEntity(null);
|
|
|
|
|
if(this.ridingEntity != null)
|
|
|
|
|
this.mountEntity(null);
|
|
|
|
|
setHealth(-1);
|
|
|
|
|
setSprinting(false);
|
|
|
|
|
getNavigator().clearPathEntity();
|
|
|
|
|
if(killedtime <= 0)
|
|
|
|
|
killedtime = stats.respawnTime * 1000 + System.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
if (advanced.role != EnumRoleType.None && roleInterface != null)
|
|
|
|
|
roleInterface.killed();
|
|
|
|
|
if (advanced.job != EnumJobType.None && jobInterface != null)
|
|
|
|
|
jobInterface.killed();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void delete() {
|
|
|
|
|
if (advanced.role != EnumRoleType.None && roleInterface != null)
|
|
|
|
|
roleInterface.delete();
|
|
|
|
|
if (advanced.job != EnumJobType.None && jobInterface != null)
|
|
|
|
|
jobInterface.delete();
|
|
|
|
|
super.setDead();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float getStartXPos(){
|
|
|
|
|
|
|
|
|
|
return getStartPos()[0] + ai.bodyOffsetX / 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float getStartZPos(){
|
|
|
|
|
return getStartPos()[2] + ai.bodyOffsetZ / 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int[] getStartPos(){
|
|
|
|
|
if(ai.startPos == null || ai.startPos.length != 3)
|
|
|
|
|
ai.startPos = new int[] {
|
|
|
|
|
MathHelper.floor_double(posX),
|
|
|
|
|
MathHelper.floor_double(posY),
|
|
|
|
|
MathHelper.floor_double(posZ) };
|
|
|
|
|
return ai.startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isVeryNearAssignedPlace() {
|
|
|
|
|
double xx = posX - getStartXPos();
|
|
|
|
|
double zz = posZ - getStartZPos();
|
|
|
|
|
if (xx < -0.2 || xx > 0.2)
|
|
|
|
|
return false;
|
|
|
|
|
if (zz < -0.2 || zz > 0.2)
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public IIcon getItemIcon(ItemStack par1ItemStack, int par2){
|
2021-09-24 16:50:28 -04:00
|
|
|
if (par1ItemStack.getItem() instanceof ItemBow){
|
|
|
|
|
return par1ItemStack.getItem().getIcon(par1ItemStack, par2);
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
EntityPlayer player = CustomNpcs.proxy.getPlayer();
|
|
|
|
|
if(player == null)
|
|
|
|
|
return super.getItemIcon(par1ItemStack, par2);
|
|
|
|
|
return player.getItemIcon(par1ItemStack, par2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public double getStartYPos() {
|
|
|
|
|
int i = getStartPos()[0];
|
|
|
|
|
int j = getStartPos()[1];
|
|
|
|
|
int k = getStartPos()[2];
|
|
|
|
|
double yy = 0;
|
|
|
|
|
for (int ii = j; ii >= 0; ii--) {
|
|
|
|
|
Block block = worldObj.getBlock(i, ii, k);
|
|
|
|
|
if (block == null)
|
|
|
|
|
continue;
|
|
|
|
|
AxisAlignedBB bb = block.getCollisionBoundingBoxFromPool(worldObj, i, ii, k);
|
|
|
|
|
if (bb == null)
|
|
|
|
|
continue;
|
|
|
|
|
yy = bb.maxY;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (yy <= 0)
|
|
|
|
|
setDead();
|
|
|
|
|
yy += 0.5;
|
|
|
|
|
return yy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void givePlayerItem(EntityPlayer player, ItemStack item) {
|
|
|
|
|
if (worldObj.isRemote) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
item = item.copy();
|
|
|
|
|
float f = 0.7F;
|
|
|
|
|
double d = (double) (worldObj.rand.nextFloat() * f)
|
|
|
|
|
+ (double) (1.0F - f);
|
|
|
|
|
double d1 = (double) (worldObj.rand.nextFloat() * f)
|
|
|
|
|
+ (double) (1.0F - f);
|
|
|
|
|
double d2 = (double) (worldObj.rand.nextFloat() * f)
|
|
|
|
|
+ (double) (1.0F - f);
|
|
|
|
|
EntityItem entityitem = new EntityItem(worldObj, posX + d, posY + d1,
|
|
|
|
|
posZ + d2, item);
|
|
|
|
|
entityitem.delayBeforeCanPickup = 2;
|
|
|
|
|
worldObj.spawnEntityInWorld(entityitem);
|
|
|
|
|
|
|
|
|
|
int i = item.stackSize;
|
|
|
|
|
|
|
|
|
|
if (player.inventory.addItemStackToInventory(item)) {
|
|
|
|
|
worldObj.playSoundAtEntity(
|
|
|
|
|
entityitem,
|
|
|
|
|
"random.pop",
|
|
|
|
|
0.2F,
|
|
|
|
|
((rand.nextFloat() - rand.nextFloat()) * 0.7F + 1.0F) * 2.0F);
|
|
|
|
|
player.onItemPickup(entityitem, i);
|
|
|
|
|
|
|
|
|
|
if (item.stackSize <= 0) {
|
|
|
|
|
entityitem.setDead();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isPlayerSleeping() {
|
|
|
|
|
return currentAnimation == EnumAnimation.LYING && !isAttacking();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isRiding() {
|
|
|
|
|
return currentAnimation == EnumAnimation.SITTING && !isAttacking() || ridingEntity != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isWalking() {
|
|
|
|
|
return ai.movingType != EnumMovingType.Standing || isAttacking() || isFollower() || getBoolFlag(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setBoolFlag(boolean bo, int id){
|
|
|
|
|
int i = dataWatcher.getWatchableObjectInt(15);
|
|
|
|
|
if(bo && (i & id) == 0)
|
|
|
|
|
dataWatcher.updateObject(15, i | id);
|
|
|
|
|
if(!bo && (i & id) != 0)
|
|
|
|
|
dataWatcher.updateObject(15, i - id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 1: walking, 2:interacting, 4:attacking, 8:killed
|
|
|
|
|
*/
|
|
|
|
|
public boolean getBoolFlag(int id){
|
|
|
|
|
return (dataWatcher.getWatchableObjectInt(15) & id) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isSneaking() {
|
|
|
|
|
return currentAnimation == EnumAnimation.SNEAKING;
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public void knockBack(Entity par1Entity, float par2, double par3, double par5)
|
|
|
|
|
{
|
|
|
|
|
if(stats.resistances.knockback >= 2)
|
|
|
|
|
return;
|
|
|
|
|
this.isAirBorne = true;
|
|
|
|
|
float f1 = MathHelper.sqrt_double(par3 * par3 + par5 * par5);
|
|
|
|
|
float f2 = 0.5F * (2 - stats.resistances.knockback);
|
|
|
|
|
this.motionX /= 2.0D;
|
|
|
|
|
this.motionY /= 2.0D;
|
|
|
|
|
this.motionZ /= 2.0D;
|
|
|
|
|
this.motionX -= par3 / (double)f1 * (double)f2;
|
|
|
|
|
this.motionY += 0.2 + f2 / 2;
|
|
|
|
|
this.motionZ -= par5 / (double)f1 * (double)f2;
|
|
|
|
|
|
|
|
|
|
if (this.motionY > 0.4000000059604645D)
|
|
|
|
|
{
|
|
|
|
|
this.motionY = 0.4000000059604645D;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-16 12:30:58 -05:00
|
|
|
@Override
|
|
|
|
|
public void addVelocity(double p_70024_1_, double p_70024_3_, double p_70024_5_) {
|
|
|
|
|
if (this.attackingPlayer != null) {
|
|
|
|
|
float f2 = 0.5F * (2 - stats.resistances.knockback);
|
|
|
|
|
super.addVelocity(p_70024_1_ * (double)f2,p_70024_3_ * (double)f2,p_70024_5_ * (double)f2);
|
|
|
|
|
} else {
|
|
|
|
|
super.addVelocity(p_70024_1_,p_70024_3_,p_70024_5_);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-13 12:03:28 -04:00
|
|
|
|
|
|
|
|
public Faction getFaction() {
|
|
|
|
|
String[] split = dataWatcher.getWatchableObjectString(13).split(":");
|
|
|
|
|
int faction = 0;
|
|
|
|
|
if(worldObj == null || split.length <= 1 && worldObj.isRemote)
|
|
|
|
|
return new Faction();
|
|
|
|
|
if(split.length > 1)
|
|
|
|
|
faction = Integer.parseInt(split[0]);
|
|
|
|
|
if(worldObj.isRemote){
|
|
|
|
|
Faction fac = new Faction();
|
|
|
|
|
fac.id = faction;
|
|
|
|
|
fac.color = Integer.parseInt(split[1]);
|
|
|
|
|
fac.name = split[2];
|
|
|
|
|
return fac;
|
|
|
|
|
}
|
|
|
|
|
else{
|
2022-01-10 15:21:48 -06:00
|
|
|
Faction fac = FactionController.getInstance().get(faction);
|
2018-09-13 12:03:28 -04:00
|
|
|
if (fac == null) {
|
|
|
|
|
faction = FactionController.getInstance().getFirstFactionId();
|
2022-01-10 15:21:48 -06:00
|
|
|
fac = FactionController.getInstance().get(faction);
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
return fac;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public boolean isRemote(){
|
|
|
|
|
return worldObj == null || worldObj.isRemote;
|
|
|
|
|
}
|
|
|
|
|
public void setFaction(int integer) {
|
|
|
|
|
if(integer < 0|| isRemote())
|
|
|
|
|
return;
|
2022-01-10 15:21:48 -06:00
|
|
|
Faction faction = FactionController.getInstance().get(integer);
|
2018-09-13 12:03:28 -04:00
|
|
|
if(faction == null)
|
|
|
|
|
return;
|
|
|
|
|
String str = faction.id + ":" + faction.color + ":" + faction.name;
|
|
|
|
|
if(str.length() > 64)
|
|
|
|
|
str = str.substring(0, 64);
|
|
|
|
|
dataWatcher.updateObject(13, str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isPotionApplicable(PotionEffect effect){
|
|
|
|
|
if(stats.potionImmune)
|
|
|
|
|
return false;
|
|
|
|
|
if(getCreatureAttribute() == EnumCreatureAttribute.ARTHROPOD && effect.getPotionID() == Potion.poison.id)
|
|
|
|
|
return false;
|
|
|
|
|
return super.isPotionApplicable(effect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isAttacking() {
|
|
|
|
|
return getBoolFlag(4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isKilled() {
|
|
|
|
|
return getBoolFlag(8) || isDead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void writeSpawnData(ByteBuf buffer) {
|
|
|
|
|
try {
|
|
|
|
|
Server.writeNBT(buffer, writeSpawnData());
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public NBTTagCompound writeSpawnData() {
|
|
|
|
|
NBTTagCompound compound = new NBTTagCompound();
|
|
|
|
|
display.writeToNBT(compound);
|
2021-12-03 00:49:10 -06:00
|
|
|
compound.setDouble("MaxHealth", stats.maxHealth);
|
2018-09-13 12:03:28 -04:00
|
|
|
compound.setTag("Armor", NBTTags.nbtItemStackList(inventory.getArmor()));
|
|
|
|
|
compound.setTag("Weapons", NBTTags.nbtItemStackList(inventory.getWeapons()));
|
|
|
|
|
compound.setInteger("Speed", ai.getWalkingSpeed());
|
|
|
|
|
compound.setBoolean("DeadBody", stats.hideKilledBody);
|
|
|
|
|
compound.setInteger("StandingState", ai.standingType.ordinal());
|
|
|
|
|
compound.setInteger("MovingState", ai.movingType.ordinal());
|
|
|
|
|
compound.setInteger("Orientation", ai.orientation);
|
|
|
|
|
compound.setInteger("Role", advanced.role.ordinal());
|
|
|
|
|
compound.setInteger("Job", advanced.job.ordinal());
|
|
|
|
|
if(advanced.job == EnumJobType.Bard){
|
|
|
|
|
NBTTagCompound bard = new NBTTagCompound();
|
|
|
|
|
jobInterface.writeToNBT(bard);
|
|
|
|
|
compound.setTag("Bard", bard);
|
|
|
|
|
}
|
|
|
|
|
if(advanced.job == EnumJobType.Puppet){
|
|
|
|
|
NBTTagCompound bard = new NBTTagCompound();
|
|
|
|
|
jobInterface.writeToNBT(bard);
|
|
|
|
|
compound.setTag("Puppet", bard);
|
|
|
|
|
}
|
|
|
|
|
if(advanced.role == EnumRoleType.Companion){
|
|
|
|
|
NBTTagCompound bard = new NBTTagCompound();
|
|
|
|
|
roleInterface.writeToNBT(bard);
|
|
|
|
|
compound.setTag("Companion", bard);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(this instanceof EntityCustomNpc){
|
|
|
|
|
compound.setTag("ModelData", ((EntityCustomNpc)this).modelData.writeToNBT());
|
|
|
|
|
}
|
|
|
|
|
return compound;
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public void readSpawnData(ByteBuf buf) {
|
|
|
|
|
try {
|
|
|
|
|
readSpawnData(Server.readNBT(buf));
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void readSpawnData(NBTTagCompound compound) {
|
2021-12-03 00:49:10 -06:00
|
|
|
stats.maxHealth = compound.getDouble("MaxHealth");
|
2018-09-13 12:03:28 -04:00
|
|
|
ai.setWalkingSpeed(compound.getInteger("Speed"));
|
|
|
|
|
stats.hideKilledBody = compound.getBoolean("DeadBody");
|
|
|
|
|
ai.standingType = EnumStandingType.values()[compound.getInteger("StandingState") % EnumStandingType.values().length];
|
|
|
|
|
ai.movingType = EnumMovingType.values()[compound.getInteger("MovingState") % EnumMovingType.values().length];
|
|
|
|
|
ai.orientation = compound.getInteger("Orientation");
|
|
|
|
|
|
|
|
|
|
this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(stats.maxHealth);
|
|
|
|
|
inventory.setArmor(NBTTags.getItemStackList(compound.getTagList("Armor", 10)));
|
|
|
|
|
inventory.setWeapons(NBTTags.getItemStackList(compound.getTagList("Weapons", 10)));
|
|
|
|
|
advanced.setRole(compound.getInteger("Role"));
|
|
|
|
|
advanced.setJob(compound.getInteger("Job"));
|
|
|
|
|
if(advanced.job == EnumJobType.Bard){
|
|
|
|
|
NBTTagCompound bard = compound.getCompoundTag("Bard");
|
|
|
|
|
jobInterface.readFromNBT(bard);
|
|
|
|
|
}
|
|
|
|
|
if(advanced.job == EnumJobType.Puppet){
|
|
|
|
|
NBTTagCompound puppet = compound.getCompoundTag("Puppet");
|
|
|
|
|
jobInterface.readFromNBT(puppet);
|
|
|
|
|
}
|
|
|
|
|
if(advanced.role == EnumRoleType.Companion){
|
|
|
|
|
NBTTagCompound puppet = compound.getCompoundTag("Companion");
|
|
|
|
|
roleInterface.readFromNBT(puppet);
|
|
|
|
|
}
|
|
|
|
|
if(this instanceof EntityCustomNpc){
|
|
|
|
|
((EntityCustomNpc)this).modelData.readFromNBT(compound.getCompoundTag("ModelData"));
|
|
|
|
|
}
|
|
|
|
|
display.readToNBT(compound);
|
|
|
|
|
}
|
2021-09-30 21:44:30 -05:00
|
|
|
|
|
|
|
|
public Entity func_174793_f() {
|
|
|
|
|
if (this.worldObj.isRemote) {
|
|
|
|
|
return this;
|
|
|
|
|
} else {
|
|
|
|
|
EntityUtil.Copy(this, CommandPlayer);
|
|
|
|
|
CommandPlayer.setWorld(this.worldObj);
|
|
|
|
|
CommandPlayer.setPosition(this.posX, this.posY, this.posZ);
|
|
|
|
|
return CommandPlayer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
@Override
|
|
|
|
|
public String getCommandSenderName() {
|
|
|
|
|
return display.name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean canCommandSenderUseCommand(int var1, String var2) {
|
|
|
|
|
if(CustomNpcs.NpcUseOpCommands)
|
|
|
|
|
return true;
|
|
|
|
|
return var1 <= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ChunkCoordinates getPlayerCoordinates() {
|
|
|
|
|
return new ChunkCoordinates(MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean canAttackClass(Class par1Class)
|
|
|
|
|
{
|
|
|
|
|
return EntityBat.class != par1Class;
|
|
|
|
|
}
|
|
|
|
|
public void setImmuneToFire(boolean immuneToFire) {
|
|
|
|
|
this.isImmuneToFire = immuneToFire;
|
|
|
|
|
stats.immuneToFire = immuneToFire;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setAvoidWater(boolean avoidWater) {
|
|
|
|
|
this.getNavigator().setAvoidsWater(avoidWater);
|
|
|
|
|
ai.avoidsWater = avoidWater;
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
protected void fall(float par1) {
|
|
|
|
|
if (!this.stats.noFallDamage)
|
|
|
|
|
super.fall(par1);
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public void setInWeb(){
|
|
|
|
|
if(!ai.ignoreCobweb)
|
|
|
|
|
super.setInWeb();
|
|
|
|
|
}
|
2021-12-13 00:16:06 -06:00
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
@Override
|
|
|
|
|
public boolean canBeCollidedWith(){
|
|
|
|
|
return !isKilled();
|
|
|
|
|
}
|
2021-06-13 16:22:06 -04:00
|
|
|
|
2021-12-13 00:16:06 -06:00
|
|
|
// obviously we dont want this
|
|
|
|
|
@Override
|
|
|
|
|
public boolean canBePushed() {
|
2022-01-14 19:07:41 -06:00
|
|
|
return this.display.collidesWith == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// checks for any entity within a certain boundingbox, eg minecarts
|
|
|
|
|
@Override
|
|
|
|
|
protected void collideWithNearbyEntities() {
|
|
|
|
|
if(this.display.collidesWith != 1) {
|
|
|
|
|
List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
|
|
|
|
|
|
|
|
|
|
if (list != null && !list.isEmpty()) {
|
|
|
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
|
|
|
Entity entity = (Entity) list.get(i);
|
|
|
|
|
|
|
|
|
|
if (this.canBePushed() ||
|
|
|
|
|
(entity instanceof EntityNPCInterface && (this.display.collidesWith == 2 || this.display.collidesWith == 4)) ||
|
|
|
|
|
(entity instanceof EntityPlayerMP && (this.display.collidesWith == 3 || this.display.collidesWith == 4))
|
|
|
|
|
) {
|
|
|
|
|
super.collideWithEntity(entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void applyEntityCollision(Entity entity)
|
|
|
|
|
{
|
|
|
|
|
if (entity.riddenByEntity != this && entity.ridingEntity != this)
|
|
|
|
|
{
|
|
|
|
|
double d0 = entity.posX - this.posX;
|
|
|
|
|
double d1 = entity.posZ - this.posZ;
|
|
|
|
|
double d2 = MathHelper.abs_max(d0, d1);
|
|
|
|
|
|
|
|
|
|
if (d2 >= 0.009999999776482582D)
|
|
|
|
|
{
|
|
|
|
|
d2 = (double)MathHelper.sqrt_double(d2);
|
|
|
|
|
d0 /= d2;
|
|
|
|
|
d1 /= d2;
|
|
|
|
|
double d3 = 1.0D / d2;
|
|
|
|
|
|
|
|
|
|
if (d3 > 1.0D)
|
|
|
|
|
{
|
|
|
|
|
d3 = 1.0D;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d0 *= d3;
|
|
|
|
|
d1 *= d3;
|
|
|
|
|
d0 *= 0.05000000074505806D;
|
|
|
|
|
d1 *= 0.05000000074505806D;
|
|
|
|
|
d0 *= (double)(1.0F - this.entityCollisionReduction);
|
|
|
|
|
d1 *= (double)(1.0F - this.entityCollisionReduction);
|
|
|
|
|
if (this.canBePushed() ||
|
|
|
|
|
(entity instanceof EntityNPCInterface && (this.display.collidesWith == 2 || this.display.collidesWith == 4)) ||
|
|
|
|
|
(entity instanceof EntityPlayerMP && (this.display.collidesWith == 3 || this.display.collidesWith == 4))
|
|
|
|
|
)
|
|
|
|
|
this.addVelocity(-d0, 0.0D, -d1);
|
|
|
|
|
entity.addVelocity(d0, 0.0D, d1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-13 00:16:06 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// not any entity can collide. if you want projectiles to still be
|
|
|
|
|
// effective, you will have to handle those yourself
|
|
|
|
|
@Override
|
2022-01-14 19:07:41 -06:00
|
|
|
protected void collideWithEntity(Entity p_82167_1_) {
|
2021-12-13 00:16:06 -06:00
|
|
|
|
2022-01-14 19:07:41 -06:00
|
|
|
}
|
2021-12-13 00:16:06 -06:00
|
|
|
|
2021-06-13 16:22:06 -04:00
|
|
|
public boolean canFly(){
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
public EntityAIRangedAttack getRangedTask(){
|
|
|
|
|
return this.aiRange;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getRoleDataWatcher(){
|
|
|
|
|
return dataWatcher.getWatchableObjectString(16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setRoleDataWatcher(String s){
|
|
|
|
|
dataWatcher.updateObject(16, s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public World getEntityWorld() {
|
|
|
|
|
return worldObj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isInvisibleToPlayer(EntityPlayer player){
|
2021-11-23 15:08:35 -06:00
|
|
|
return (scriptInvisibleToPlayer(player) || display.visible == 1) && (player.getHeldItem() == null || player.getHeldItem().getItem() != CustomItems.wand);
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|
|
|
|
|
|
2021-11-22 23:34:02 -06:00
|
|
|
public boolean scriptInvisibleToPlayer(EntityPlayer player){
|
|
|
|
|
return display.invisibleToList != null && display.invisibleToList.contains(player.getPersistentID());
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 12:03:28 -04:00
|
|
|
@Override
|
|
|
|
|
public boolean isInvisible(){
|
|
|
|
|
return display.visible != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void addChatMessage(IChatComponent var1) {}
|
|
|
|
|
|
|
|
|
|
public void setCurrentAnimation(EnumAnimation animation) {
|
|
|
|
|
currentAnimation = animation;
|
|
|
|
|
dataWatcher.updateObject(14, animation.ordinal());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean canSee(Entity entity){
|
|
|
|
|
return this.getEntitySenses().canSee(entity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isFollower() {
|
|
|
|
|
return advanced.role == EnumRoleType.Follower && ((RoleFollower) roleInterface).isFollowing() ||
|
|
|
|
|
advanced.role == EnumRoleType.Companion && ((RoleCompanion) roleInterface).isFollowing() ||
|
|
|
|
|
advanced.job == EnumJobType.Follower && ((JobFollower)jobInterface).isFollowing();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EntityLivingBase getOwner(){
|
|
|
|
|
if(roleInterface instanceof RoleFollower)
|
|
|
|
|
return ((RoleFollower)roleInterface).owner;
|
|
|
|
|
|
|
|
|
|
if(roleInterface instanceof RoleCompanion)
|
|
|
|
|
return ((RoleCompanion)roleInterface).owner;
|
|
|
|
|
|
|
|
|
|
if(jobInterface instanceof JobFollower)
|
|
|
|
|
return ((JobFollower)jobInterface).following;
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean hasOwner(){
|
|
|
|
|
return advanced.role == EnumRoleType.Follower && ((RoleFollower) roleInterface).hasOwner() ||
|
|
|
|
|
advanced.role == EnumRoleType.Companion && ((RoleCompanion) roleInterface).hasOwner() ||
|
|
|
|
|
advanced.job == EnumJobType.Follower && ((JobFollower)jobInterface).hasOwner();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int followRange() {
|
|
|
|
|
if(advanced.role == EnumRoleType.Follower && ((RoleFollower) roleInterface).isFollowing())
|
|
|
|
|
return 36;
|
|
|
|
|
if(advanced.role == EnumRoleType.Companion && ((RoleCompanion) roleInterface).isFollowing())
|
|
|
|
|
return ((RoleCompanion) roleInterface).followRange();
|
|
|
|
|
if(advanced.job == EnumJobType.Follower && ((JobFollower)jobInterface).isFollowing())
|
|
|
|
|
return 16;
|
|
|
|
|
|
|
|
|
|
return 225;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setHomeArea(int x, int y, int z, int range){
|
|
|
|
|
super.setHomeArea(x, y, z, range);
|
|
|
|
|
ai.startPos = new int[]{x, y, z};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected float applyArmorCalculations(DamageSource source, float damage){
|
|
|
|
|
if(advanced.role == EnumRoleType.Companion)
|
|
|
|
|
damage = ((RoleCompanion)roleInterface).applyArmorCalculations(source, damage);
|
|
|
|
|
return damage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isOnSameTeam(EntityLivingBase entity){
|
|
|
|
|
if(entity instanceof EntityPlayer && !isRemote() && getFaction().isFriendlyToPlayer((EntityPlayer)entity))
|
|
|
|
|
return true;
|
|
|
|
|
return super.isOnSameTeam(entity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setDataWatcher(DataWatcher dataWatcher) {
|
|
|
|
|
this.dataWatcher = dataWatcher;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void moveEntityWithHeading(float p_70612_1_, float p_70612_2_){
|
|
|
|
|
double d0 = this.posX;
|
|
|
|
|
double d1 = this.posY;
|
|
|
|
|
double d2 = this.posZ;
|
|
|
|
|
super.moveEntityWithHeading(p_70612_1_, p_70612_2_);
|
|
|
|
|
if(advanced.role == EnumRoleType.Companion && !isRemote())
|
|
|
|
|
((RoleCompanion)roleInterface).addMovementStat(this.posX - d0, this.posY - d1, this.posZ - d2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean allowLeashing(){
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean shouldDismountInWater(Entity rider){
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-04-29 20:42:52 -04:00
|
|
|
|
|
|
|
|
// Model Types: 0: Steve 64x32, 1: Steve 64x64, 2: Alex 64x64
|
|
|
|
|
public int getModelType()
|
|
|
|
|
{
|
|
|
|
|
return this.display.modelType;
|
|
|
|
|
}
|
2021-05-08 03:51:29 -04:00
|
|
|
|
2021-04-29 20:42:52 -04:00
|
|
|
public void setModelType(int val)
|
|
|
|
|
{
|
|
|
|
|
this.display.modelType = val;
|
|
|
|
|
}
|
2022-02-20 00:56:57 -06:00
|
|
|
|
|
|
|
|
protected void updateLeashedState(){}
|
2018-09-13 12:03:28 -04:00
|
|
|
}
|