/** * Copyright (c) Lambda Innovation, 2013-2015 * 本作品版权由Lambda Innovation所有。 * http://www.li-dev.cn/ * * This project is open-source, and it is distributed under * the terms of GNU General Public License. You can modify * and distribute freely as long as you follow the license. * 本项目是一个开源项目,且遵循GNU通用公共授权协议。 * 在遵照该协议的情况下,您可以自由传播和修改。 * http://www.gnu.org/licenses/gpl.html */ package cn.dawn47.mob.entity; import java.util.ArrayList; import java.util.List; import cn.annoreg.core.RegWithName; import cn.annoreg.core.Registrant; import cn.annoreg.mc.RegEntity; import cn.annoreg.mc.network.RegNetworkCall; import cn.annoreg.mc.s11n.StorageOption.Data; import cn.annoreg.mc.s11n.StorageOption.Instance; import cn.annoreg.mc.s11n.StorageOption.RangedTarget; import cn.dawn47.core.register.DWItems; import cn.dawn47.mob.client.render.RenderWeaponSoldier; import cn.dawn47.weapon.DawnWeapon; import cn.liutils.template.entity.LIEntityMob; import cn.liutils.util.generic.RandUtils; import cn.liutils.util.generic.VecUtils; import cn.liutils.util.helper.Motion3D; import cn.liutils.util.mc.EntitySelectors; import cn.liutils.util.raytrace.Raytrace; import cn.weaponry.impl.generic.entity.EntityBullet; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EnumCreatureAttribute; import net.minecraft.entity.IRangedAttackMob; import net.minecraft.entity.ai.EntityAIArrowAttack; import net.minecraft.entity.ai.EntityAIAttackOnCollide; import net.minecraft.entity.ai.EntityAIFleeSun; import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAILookIdle; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAIRestrictSun; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Vec3; import net.minecraft.world.World; /** * @author WeAthFolD * */ @Registrant @RegWithName("WeaponSoldier") @RegEntity @RegEntity.HasRender public class EntityWeaponSoldier extends LIEntityMob implements IRangedAttackMob { @RegEntity.Render @SideOnly(Side.CLIENT) public static RenderWeaponSoldier render; static List<DawnWeapon> weapons = new ArrayList(); static boolean loaded = false; public int weaponID = -1; public boolean isShooting; int lastShootTick; int shootCount; private EntityAIAttackOnCollide aiAttackOnCollide = new EntityAIAttackOnCollide(this, EntityPlayer.class, 1.2D, false); public EntityWeaponSoldier(World world) { super(world); if(!loaded) { loaded = true; weapons.add(DWItems.soldierAR); weapons.add(DWItems.soldierHandgun); } this.tasks.addTask(1, new EntityAISwimming(this)); this.tasks.addTask(2, new EntityAIRestrictSun(this)); this.tasks.addTask(3, new EntityAIFleeSun(this, 1.0D)); this.tasks.addTask(5, new EntityAIWander(this, 1.0D)); this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); this.tasks.addTask(6, new EntityAILookIdle(this)); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, true)); if (world != null && !world.isRemote) { weaponID = rand.nextInt(weapons.size()); this.setCombatTask(); } } public EnumCreatureAttribute getCreatureAttribute() { return EnumCreatureAttribute.UNDEAD; } protected boolean isAIEnabled() { return true; } @Override public void entityInit() { super.entityInit(); dataWatcher.addObject(15, (byte) 0); dataWatcher.addObject(16, (byte) 0); } public void onUpdate() { super.onUpdate(); isShooting = ticksExisted - lastShootTick < 10; if(this.isShooting) { Entity target = getAttackTarget(); if(target != null) this.faceEntity(target, 20, 20); } sync(); } private void sync() { if(worldObj.isRemote) { weaponID = dataWatcher.getWatchableObjectByte(15); isShooting = dataWatcher.getWatchableObjectByte(16) != 0; } else { dataWatcher.updateObject(15, (byte) weaponID); dataWatcher.updateObject(16, (byte) (isShooting ? 1 : 0)); } } public void writeEntityToNBT(NBTTagCompound tag) { super.writeEntityToNBT(tag); tag.setInteger("weaponID", weaponID); } public void readEntityFromNBT(NBTTagCompound tag) { super.readEntityFromNBT(tag); weaponID = tag.getInteger("weaponID"); } DawnWeapon getWeapon() { return weaponID == -1 ? null : weapons.get(weaponID); } @Override public void attackEntityWithRangedAttack(EntityLivingBase target, float wtf) { EntityBullet bullet; if(rand.nextDouble() < 0.3) { double yOffset = 1.5; double dx = target.posX - posX, dy = target.posY + 1.0 - (posY + yOffset), dz = target.posZ - posZ; Vec3 start = VecUtils.vec(posX, posY + yOffset, posZ), vel = VecUtils.vec(dx, dy, dz).normalize(), end = new Motion3D(start, vel).move(20).getPosVec(); // CLIENT spawnBulletEffect(this, this, VecUtils.vec(posX, posY + yOffset, posZ), vel); // SERVER MovingObjectPosition result = Raytrace.perform(worldObj, start, end, EntitySelectors.combine(EntitySelectors.living, EntitySelectors.excludeOf(this))); if(result != null && result.entityHit != null) { EntityLivingBase hit = (EntityLivingBase) result.entityHit; double lmx = hit.motionX, lmy = hit.motionY, lmz = hit.motionZ; hit.hurtResistantTime = -1; hit.attackEntityFrom(DamageSource.causeMobDamage(this), 2); if(RandUtils.ranged(0, 1) < 0.8) { hit.motionX = lmx; hit.motionY = lmy; hit.motionZ = lmz; } } } worldObj.playSoundAtEntity(this, getWeapon().shootSound, 0.5f, 1.0f); lastShootTick = ticksExisted; ++shootCount; } @Override protected double getMaxHealth2() { return 18; } @Override protected double getFollowRange() { return 16; } @Override protected double getMoveSpeed() { return 0.3; } @Override protected double getKnockBackResistance() { return 3; } @Override protected double getAttackDamage() { return 4; } @Override public ResourceLocation getTexture() { return null; } ItemStack equip; @Override public ItemStack getEquipmentInSlot(int i) { if(i == 0) { if(equip == null && weaponID != -1) { equip = new ItemStack(getWeapon()); } return equip; } return super.getEquipmentInSlot(i); } @Override protected Item getDropItem() { return null; } /** * sets this entity's combat AI. */ public void setCombatTask() { DawnWeapon wpn = getWeapon(); this.tasks.addTask(3, new EntityAIArrowAttack (this, 1.0D, wpn.shootInterval, wpn.shootInterval, 15.0F) { int thisMax = 3; public void resetTask() { shootCount = 0; thisMax = RandUtils.rangei(3, 5); } public boolean continueExecuting() { boolean b = super.continueExecuting(); if(!b) return false; return shootCount <= thisMax; } }); } @RegNetworkCall(side = Side.CLIENT) private static void spawnBulletEffect( @RangedTarget(range = 15) EntityLivingBase _player, @Instance EntityLivingBase player, @Data Vec3 pos, @Data Vec3 vel) { player.worldObj.spawnEntityInWorld(new EntityBullet(player, new Motion3D( pos.xCoord, pos.yCoord, pos.zCoord, vel.xCoord, vel.yCoord, vel.zCoord), 0.06)); } }