package net.torocraft.toroquest.entities; import java.util.List; import javax.annotation.Nullable; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIAttackMelee; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAILookIdle; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemArmor; import net.minecraft.item.ItemStack; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.DamageSource; import net.minecraft.util.EntitySelectors; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.World; import net.minecraftforge.fml.client.registry.IRenderFactory; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.registry.EntityRegistry; import net.torocraft.toroquest.ToroQuest; import net.torocraft.toroquest.config.ToroQuestConfiguration; import net.torocraft.toroquest.entities.ai.EntityAIStayCentered; import net.torocraft.toroquest.entities.render.RenderRainbowGuard; public class EntityRainbowGuard extends EntityMob { public static String NAME = "rainbow_guard"; static { if (ToroQuestConfiguration.specificEntityNames) { NAME = ToroQuestEntities.ENTITY_PREFIX + NAME; } } public static enum Color { RED(10040115), ORANGE(0xff9900), YELLOW(0xffff00), GREEN(6717235), BLUE(3361970), PURPLE(8339378); private int color; private Color(int color) { this.color = color; } public int getColor() { return color; } } private Color color = Color.RED; private static final DataParameter<Boolean> AT_ATTENTION = EntityDataManager.<Boolean> createKey(EntityRainbowGuard.class, DataSerializers.BOOLEAN); private static final DataParameter<BlockPos> LOOK_AT = EntityDataManager.<BlockPos> createKey(EntityRainbowGuard.class, DataSerializers.BLOCK_POS); // TODO: add new data parameter for color when we stop using armor public static void init(int entityId) { EntityRegistry.registerModEntity(new ResourceLocation(ToroQuest.MODID, NAME), EntityRainbowGuard.class, NAME, entityId, ToroQuest.INSTANCE, 90, 2, true, 0xffffff, 0x909090); } public static void registerRenders() { RenderingRegistry.registerEntityRenderingHandler(EntityRainbowGuard.class, new IRenderFactory<EntityRainbowGuard>() { @Override public Render<EntityRainbowGuard> createRenderFor(RenderManager manager) { return new RenderRainbowGuard(manager); } }); } public EntityRainbowGuard(World world) { super(world); this.experienceValue = 10; } protected void entityInit() { super.entityInit(); setLeftHanded(false); dataManager.register(AT_ATTENTION, Boolean.valueOf(true)); dataManager.register(LOOK_AT, getPosition()); } public boolean isAtAttention() { return dataManager.get(AT_ATTENTION); } private void setAtAttention(boolean b) { dataManager.set(AT_ATTENTION, Boolean.valueOf(b)); } public void setLookAt(BlockPos pos) { dataManager.set(LOOK_AT, pos.add(0, getEyeHeight(), 0)); } private BlockPos getLookAt() { return dataManager.get(LOOK_AT); } public void setColor(Color color) { this.color = color; } protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty) { } public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata) { livingdata = super.onInitialSpawn(difficulty, livingdata); setLeftHanded(false); setHeldItem(EnumHand.MAIN_HAND, new ItemStack(Items.GOLDEN_SWORD, 1)); setCanPickUpLoot(false); addArmor(); return livingdata; } protected void addArmor() { setItemStackToSlot(EntityEquipmentSlot.HEAD, colorArmor(new ItemStack(Items.LEATHER_HELMET, 1))); setItemStackToSlot(EntityEquipmentSlot.FEET, colorArmor(new ItemStack(Items.LEATHER_BOOTS, 1))); setItemStackToSlot(EntityEquipmentSlot.LEGS, colorArmor(new ItemStack(Items.LEATHER_LEGGINGS, 1))); setItemStackToSlot(EntityEquipmentSlot.CHEST, colorArmor(new ItemStack(Items.LEATHER_CHESTPLATE, 1))); } protected ItemStack colorArmor(ItemStack stack) { ItemArmor armor = (ItemArmor) stack.getItem(); armor.setColor(stack, color.getColor()); return stack; } protected void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(40D); this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(16.0D); } @Override protected boolean canDespawn() { return false; } protected void initEntityAI() { ai(); } protected void ai() { tasks.addTask(1, new EntityAISwimming(this)); tasks.addTask(2, new EntityAIAtAttention(this)); tasks.addTask(4, new EntityAIAttackMelee(this, 0.5D, false)); tasks.addTask(5, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); tasks.addTask(5, new EntityAILookIdle(this)); targetTasks.addTask(1, new EntityAIHurtByTarget(this, false, new Class[0])); targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true)); } public void onLivingUpdate() { super.onLivingUpdate(); wakeIfPlayerIsClose(true); } private static final int WAKE_DIAMETER = 8; // to be called by partner's waking function public void wokenByPartner() { wakeIfPlayerIsClose(false); } protected void wakeIfPlayerIsClose(boolean wakePartner) { if (world.getTotalWorldTime() % 30 != 0 || !isAtAttention()) { return; } // TODO check if visible? List<EntityPlayer> players = world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB(getPosition()).expand(WAKE_DIAMETER, 6, WAKE_DIAMETER), EntitySelectors.CAN_AI_TARGET); if (players.size() < 1) { return; } if (wakePartner) { List<EntityRainbowGuard> nearbyRainbowGuards = world.getEntitiesWithinAABB(EntityRainbowGuard.class, getEntityBoundingBox().expand(5.0D, 4.0D, 2.0D)); if (nearbyRainbowGuards != null && !nearbyRainbowGuards.isEmpty()) { nearbyRainbowGuards.get(0).wokenByPartner(); } } setAtAttention(false); tasks.removeTask(new EntityAIStayCentered(this)); setAttackTarget(players.get(world.rand.nextInt(players.size()))); } protected void updateAITasks() { super.updateAITasks(); } public class EntityAIAtAttention extends EntityAIBase { protected EntityRainbowGuard entity; public EntityAIAtAttention(EntityRainbowGuard entitylivingIn) { this.entity = entitylivingIn; this.setMutexBits(3); } /** * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute() { return entity.isAtAttention(); } /** * Returns whether an in-progress EntityAIBase should continue executing */ public boolean continueExecuting() { return entity.isAtAttention(); } /** * Execute a one shot task or start executing a continuous task */ public void startExecuting() { } /** * Resets the task */ public void resetTask() { } /** * Updates the task */ public void updateTask() { entity.setPosition(entity.getPosition().getX() + 0.5d, entity.posY, entity.getPosition().getZ() + 0.5d); entity.getLookHelper().setLookPosition(getLookAt().getX(), getLookAt().getY(), getLookAt().getZ(), (float) entity.getHorizontalFaceSpeed(), 0.0f); } } public boolean attackEntityFrom(DamageSource source, float amount) { if (!super.attackEntityFrom(source, amount)) { return false; } if (isAtAttention()) { setAtAttention(false); } EntityLivingBase attacker = this.getAttackTarget(); if (attacker == null && source.getTrueSource() instanceof EntityLivingBase) { setAttackTarget((EntityLivingBase) source.getTrueSource()); } return true; } }