package com.arkcraft.module.creature.common.entity; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Random; import java.util.UUID; import com.arkcraft.module.core.ARKCraft; import com.arkcraft.module.core.GlobalAdditions.GUI; import com.arkcraft.module.core.common.entity.data.ARKPlayer; import com.arkcraft.module.core.common.handlers.GuiHandler; import com.arkcraft.module.creature.common.entity.creature.Creature; import com.arkcraft.module.items.common.general.ItemDinosaurSaddle; import com.arkcraft.module.resource.common.item.food.CreatureFoodType; import com.arkcraft.module.resource.common.item.food.DinoFood; import com.arkcraft.module.resource.common.item.food.INarcotic; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.IProjectile; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAILookIdle; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.pathfinding.PathNavigateGround; import net.minecraft.util.DamageSource; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; /** * @author gegy1000 * @author Lewis_McReu */ public class EntityARKCreature extends EntityAnimal implements IEntityAdditionalSpawnData, IInventory { private static final int DATA_WATCHER_UNCONSCIOUS = 20, DATA_WATCHER_LEVEL = 21, DATA_WATCHER_TAMING_PROGRESS = 27, DATA_WATCHER_XP = 28; public static final int HEALTH = 0, DAMAGE = 1, STAMINA = 2, WEIGHT = 3, OXYGEN = 4, FOOD = 5, SPEED = 6; private static final int WEIGHT_PER_STACK = 10; private int oxygen, food, stamina, torpor, level, tamingProgress, xp, points = 0; private int maxHealth, maxWeight, maxOxygen, maxFood, maxDamage, maxSpeed, maxStamina, maxTorpor, baseLevel; private boolean unconscious, grownUp; protected CreatureFoodType type; private ItemStack[] inventory; private ItemStack saddle; private Creature creature; private UUID owner; private UUID tamer; public EntityARKCreature(World world, CreatureFoodType type) { super(world); this.type = type; grownUp = true; updateHitbox(); ((PathNavigateGround) this.getNavigator()).func_179690_a(true); this.tasks.addTask(0, new EntityAISwimming(this)); this.tasks.addTask(7, new EntityAIWander(this, 1.0D)); this.tasks.addTask(8, new EntityAILookIdle(this)); } @Override public void entityInit() { super.entityInit(); creature = ARKEntityRegistry.getCreature(this); if (!this.worldObj.isRemote) { points = 0; // Determine and set stats Random r = new Random(); baseLevel = r.nextInt(90) + 1; level = baseLevel; distributeWildPoints(baseLevel); // set actual stats oxygen = maxOxygen; food = maxFood; stamina = maxStamina; torpor = 0; inventory = new ItemStack[maxWeight / WEIGHT_PER_STACK]; } this.dataWatcher.addObject(DATA_WATCHER_UNCONSCIOUS, (byte) (unconscious ? 1 : 0)); this.dataWatcher.addObject(DATA_WATCHER_LEVEL, level); this.dataWatcher.addObject(DATA_WATCHER_TAMING_PROGRESS, tamingProgress); this.dataWatcher.addObject(DATA_WATCHER_XP, xp); } private void distributeWildPoints(int points) { Random r = new Random(); int div = points / 3; int maxIncrease = div; int healthInc = r.nextInt(maxIncrease); points -= healthInc; maxIncrease = div < points ? div : points; int weightInc = r.nextInt(maxIncrease); points -= weightInc; maxIncrease = div < points ? div : points; int speedInc = r.nextInt(maxIncrease); points -= speedInc; maxIncrease = div < points ? div : points; int oxygenInc = r.nextInt(maxIncrease); points -= oxygenInc; maxIncrease = div < points ? div : points; int torporInc = r.nextInt(maxIncrease); points -= torporInc; maxIncrease = div < points ? div : points; int damageInc = r.nextInt(maxIncrease); points -= damageInc; maxIncrease = div < points ? div : points; int staminaInc = r.nextInt(maxIncrease); points -= staminaInc; int foodInc = points; // TODO fix in comparison to ark maxHealth = (int) (creature.getBaseHealth() + creature.getWildHealthIncrease() * healthInc); maxWeight = (int) (creature .getBaseWeight() + creature.getWildWeightIncrease() * weightInc) / WEIGHT_PER_STACK; maxOxygen = (int) (creature.getBaseOxygen() + creature.getWildOxygenIncrease() * oxygenInc); maxFood = (int) (creature.getBaseFood() + creature.getWildFoodIncrease() * foodInc); maxDamage = (int) (100 + creature.getWildDamageIncrease() * damageInc); maxSpeed = 100; maxStamina = (int) (creature .getBaseStamina() + creature.getWildStaminaIncrease() * staminaInc); maxTorpor = (int) (creature.getBaseTorpor() + creature.getWildTorporIncrease() * torporInc); } @Override public void writeSpawnData(ByteBuf buffer) { buffer.writeInt(maxHealth); buffer.writeInt(maxWeight); buffer.writeInt(maxOxygen); buffer.writeInt(maxFood); buffer.writeInt(maxDamage); buffer.writeInt(maxSpeed); buffer.writeInt(maxStamina); buffer.writeInt(maxTorpor); buffer.writeInt(baseLevel); buffer.writeInt(oxygen); buffer.writeInt(food); buffer.writeInt(stamina); buffer.writeInt(torpor); } @Override public void readSpawnData(ByteBuf buffer) { maxHealth = buffer.readInt(); maxWeight = buffer.readInt(); maxOxygen = buffer.readInt(); maxFood = buffer.readInt(); maxDamage = buffer.readInt(); maxSpeed = buffer.readInt(); maxStamina = buffer.readInt(); maxTorpor = buffer.readInt(); baseLevel = buffer.readInt(); level = baseLevel; oxygen = buffer.readInt(); food = buffer.readInt(); stamina = buffer.readInt(); torpor = buffer.readInt(); updateEntityAttributes(); } // private UUID owner; // public EntityPlayer playerTaming; // public EntityARKCreature(World world) // { // super(world); // updateHitbox(); // inventory = new ItemStack[creature.getInventorySize()]; // } // @Override // public void entityInit() // { // super.entityInit(); // // creature = ARKEntityRegistry.getCreature(this); // // this.dataWatcher.addObject(DATA_WATCHER_AGE, 0); // this.dataWatcher.addObject(DATA_WATCHER_TORPOR, 0); // this.dataWatcher.addObject(DATA_WATCHER_STAMINA, 0); // this.dataWatcher.addObject(DATA_WATCHER_HUNGER, 0); // this.dataWatcher.addObject(DATA_WATCHER_LEVEL, 0); // this.dataWatcher.addObject(DATA_WATCHER_UNCONSCIOUS, (byte) 0); // this.dataWatcher.addObject(DATA_WATCHER_TAMING_PROGRESS, 0); // // this.dataWatcher.addObject(DATA_WATCHER_XP, 0.0F); // // this.dataWatcher.addObject(DATA_WATCHER_SADDLED, (byte) 0); // // // levelManager.initDataWatcher(); // } @Override public void applyEntityAttributes() { super.applyEntityAttributes(); if (!this.worldObj.isRemote) { this.updateEntityAttributes(); } this.updateHitbox(); } public void updateEntityAttributes() { this.getAttributeMap().registerAttribute(SharedMonsterAttributes.attackDamage); getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(maxHealth); // TODO change speed value getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(1); getEntityAttribute(SharedMonsterAttributes.attackDamage).setBaseValue(maxDamage); if (inventory != null) { ItemStack[] inventoryOld = inventory; inventory = new ItemStack[maxWeight / WEIGHT_PER_STACK]; for (int i = 0; i < inventoryOld.length; i++) { inventory[i] = inventoryOld[i]; } } else inventory = new ItemStack[maxWeight / WEIGHT_PER_STACK]; } @Override public void onDeath(DamageSource cause) { super.onDeath(cause); Entity killedBy = cause.getSourceOfDamage(); Entity indirect = cause.getEntity(); Entity actualKiller; if (indirect != null && killedBy instanceof IProjectile) { actualKiller = indirect; } else { actualKiller = killedBy; } // TODO grant xp if creature is ridden (possible to kill while ridden) // TODO grant xp to owner nearby if (actualKiller instanceof EntityARKCreature) { if (((EntityARKCreature) killedBy) .isOwned()) ((EntityARKCreature) killedBy).addXP(creature.getBaseKillXP()); } else if (actualKiller instanceof EntityPlayer) { ARKPlayer data = ARKPlayer.get((EntityPlayer) actualKiller); data.addXP(getKillXP()); } } private int getKillXP() { // TODO Auto-generated method stub return creature.getBaseKillXP() * level * level; } private boolean isOwned() { return this.owner != null; } @Override public boolean interact(EntityPlayer player) { GuiHandler.rightClickedEntity = this; if (unconscious && !this.worldObj.isRemote && owner == null) { player.openGui(ARKCraft.instance, GUI.TAMING_GUI.getID(), this.worldObj, (int) this.posX, (int) this.posY, (int) this.posZ); return true; } return false; } public void addXP(float xp) { this.xp += xp; while (checkLevel()) { } } private boolean checkLevel() { int level = this.level + 1; int xpNeeded = (int) (Math.log(level * level * level * level) * level * level * creature .getLevelingMultiplier()); if (xp > xpNeeded) { this.level++; this.points++; xp = xp - xpNeeded; return true; } return false; } public int getMaxLevel() { return baseLevel + 59; } private float getScaled(float value, float maxValue, float scale) { return maxValue != 0 && value != 0 ? value * scale / maxValue : 0; } public void increaseTorpor(int amount, Entity shootingEntity) { torpor += amount; if (torpor >= maxTorpor) // DONE - all stats are randomly increased, so // fair chance for high level creatures to // have high torpor { if (shootingEntity instanceof EntityPlayer) this.tamer = shootingEntity.getUniqueID(); this.unconscious = true; this.torpor = maxTorpor; this.tamingProgress = 0; } } @Override public void onLivingUpdate() { super.onLivingUpdate(); if (!worldObj.isRemote) { this.dataWatcher.updateObject(DATA_WATCHER_UNCONSCIOUS, (byte) (unconscious ? 1 : 0)); this.dataWatcher.updateObject(DATA_WATCHER_LEVEL, level); this.dataWatcher.updateObject(DATA_WATCHER_TAMING_PROGRESS, tamingProgress); this.dataWatcher.updateObject(DATA_WATCHER_XP, xp); } else { level = dataWatcher.getWatchableObjectInt(DATA_WATCHER_LEVEL); tamingProgress = dataWatcher.getWatchableObjectInt(DATA_WATCHER_TAMING_PROGRESS); unconscious = dataWatcher .getWatchableObjectByte(DATA_WATCHER_UNCONSCIOUS) == 1 ? true : false; xp = dataWatcher.getWatchableObjectInt(DATA_WATCHER_XP); } if (!grownUp) { updateHitbox(); } if (this.food > 0) { this.food -= 1; } else this.food = 0; if (torpor > 0) { torpor -= creature.getTorporLossSpeed(); if (tamer != null) { for (ItemStack stack : inventory) { if (stack != null) { boolean consumed = false; if (isValidFood(stack)) { if (canEat(stack)) { consumed = true; stack.stackSize--; DinoFood food = (DinoFood) stack.getItem(); this.food += food.getFoodValue(); tamingProgress += ((DinoFood) stack.getItem()).getTamingIncrease(); } } if (stack.getItem() instanceof INarcotic) { INarcotic narc = (INarcotic) stack.getItem(); if (this.maxTorpor >= this.torpor + narc.getTorporIncrease()) { if (!consumed) stack.stackSize--; this.torpor += narc.getTorporIncrease(); } } if (stack.stackSize == 0) stack = null; } } } } if (unconscious && torpor <= 0) { unconscious = false; this.tamer = null; torpor = 0; tamingProgress = 0; } if (tamer != null && tamingProgress >= getTamingProgressRequired()) { this.owner = tamer; this.tamingProgress = 0; } } private boolean canEat(ItemStack stack) { return stack.getItem() instanceof DinoFood && ((DinoFood) stack.getItem()) .getFoodValue() + food <= maxFood; } private boolean isValidFood(ItemStack stack) { return stack != null && stack.getItem() instanceof DinoFood && ((DinoFood) stack.getItem()) .getType().equals(this.type); } public boolean isSaddled() { return saddle != null; } public void updateHitbox() { this.setSize(scaleByAge(creature.getBabySizeXZ(), creature.getAdultSizeXZ()), scaleByAge(creature.getBabySizeY(), creature.getAdultSizeY())); if (ticksExisted >= creature.getGrowthTime()) grownUp = true; } public float scaleByAge(float baby, float adult) { int growthTime = ticksExisted > creature.getGrowthTime() ? creature .getGrowthTime() : ticksExisted; return (adult - baby) / creature.getGrowthTime() * growthTime + baby; } // @Override // public void writeSpawnData(ByteBuf buffer) // { // buffer.writeInt(creatureAge); // buffer.writeInt(torpor); // buffer.writeInt(stamina); // buffer.writeInt(hunger); // buffer.writeInt(baseLevel); // buffer.writeInt(level); // buffer.writeBoolean(unconscious); // buffer.writeInt(tamingProgress); // } // // @Override // public void readSpawnData(ByteBuf additionalData) // { // creatureAge = additionalData.readInt(); // torpor = additionalData.readInt(); // stamina = additionalData.readInt(); // hunger = additionalData.readInt(); // baseLevel = additionalData.readInt(); // level = additionalData.readInt(); // unconscious = additionalData.readBoolean(); // tamingProgress = additionalData.readInt(); // } @Override public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); this.maxDamage = nbt.getInteger("maxDamage"); this.maxFood = nbt.getInteger("maxFood"); this.maxHealth = nbt.getInteger("maxHealth"); this.baseLevel = nbt.getInteger("baseLevel"); this.maxOxygen = nbt.getInteger("maxOxygen"); this.maxSpeed = nbt.getInteger("maxSpeed"); this.maxStamina = nbt.getInteger("maxStamina"); this.maxTorpor = nbt.getInteger("maxTorpor"); this.maxWeight = nbt.getInteger("maxWeight"); this.food = nbt.getInteger("food"); this.level = nbt.getInteger("level"); this.oxygen = nbt.getInteger("oxygen"); this.stamina = nbt.getInteger("stamina"); this.torpor = nbt.getInteger("torpor"); this.xp = nbt.getInteger("xp"); inventory = new ItemStack[maxWeight]; if (nbt.hasKey("owner")) owner = UUID.fromString(nbt.getString("owner")); if (nbt.hasKey("tamer")) { this.tamingProgress = nbt.getInteger("tamingProgress"); this.unconscious = nbt.getBoolean("unconscious"); this.tamer = UUID.fromString(nbt.getString("tamer")); } this.grownUp = nbt.getBoolean("grownUp"); this.saddle = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("saddle")); NBTTagList inv = nbt.getTagList("creatureInventory", 10); for (int i = 0; i < inv.tagCount(); i++) { NBTTagCompound comp = inv.getCompoundTagAt(i); NBTTagCompound comp2 = comp.getCompoundTag("stack"); if (comp2 != null) { int index = comp.getInteger("index"); ItemStack stack = ItemStack.loadItemStackFromNBT(comp2); inventory[index] = stack; } } } @Override public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); nbt.setInteger("maxDamage", maxDamage); nbt.setInteger("maxFood", maxFood); nbt.setInteger("maxHealth", maxHealth); nbt.setInteger("baseLevel", baseLevel); nbt.setInteger("maxOxygen", maxOxygen); nbt.setInteger("maxSpeed", maxSpeed); nbt.setInteger("maxStamina", maxStamina); nbt.setInteger("maxTorpor", maxTorpor); nbt.setInteger("maxWeight", maxWeight); nbt.setInteger("food", food); nbt.setInteger("level", level); nbt.setInteger("oxygen", oxygen); nbt.setInteger("stamina", stamina); nbt.setInteger("torpor", torpor); nbt.setInteger("xp", xp); if (owner != null) nbt.setString("owner", owner.toString()); else if (tamer != null) { nbt.setInteger("tamingProgress", tamingProgress); nbt.setString("tamer", tamer.toString()); } nbt.setBoolean("unconscious", unconscious); nbt.setBoolean("grownUp", grownUp); if (saddle != null) { NBTTagCompound sad = new NBTTagCompound(); saddle.writeToNBT(sad); nbt.setTag("saddle", sad); } NBTTagList inv = new NBTTagList(); for (int i = 0; i < inventory.length; i++) { if (inventory[i] != null) { NBTTagCompound comp = new NBTTagCompound(); comp.setInteger("index", i); NBTTagCompound comp2 = new NBTTagCompound(); inventory[i].writeToNBT(comp2); comp.setTag("stack", comp2); inv.appendTag(comp); } } nbt.setTag("creatureInventory", inv); } @Override public int getSizeInventory() { return maxWeight; } @Override public ItemStack getStackInSlot(int index) { return index < inventory.length ? inventory[index] : saddle; } @Override public ItemStack decrStackSize(int index, int count) { if (inventory[index] != null) { ItemStack itemstack; if (inventory[index].stackSize <= count) { itemstack = inventory[index]; setInventorySlotContents(index, null); return itemstack; } else { itemstack = inventory[index].splitStack(count); if (inventory[index].stackSize == 0) { setInventorySlotContents(index, null); } return itemstack; } } else { return null; } } @Override public ItemStack getStackInSlotOnClosing(int index) { if (inventory[index] != null) { ItemStack itemstack = inventory[index]; setInventorySlotContents(index, null); return itemstack; } else { return null; } } @Override public void setInventorySlotContents(int index, ItemStack stack) { //TODO ArrayIndexOutOfBoundsException occurring here -- figure it out if (index > 0 && index < inventory.length) { inventory[index] = stack; if (stack != null && stack.stackSize > getInventoryStackLimit()) { stack.stackSize = getInventoryStackLimit(); } } } @Override public int getInventoryStackLimit() { return 64; } @Override public void markDirty() { } @Override public boolean isUseableByPlayer(EntityPlayer player) { return isDead ? false : player.getDistanceSqToEntity(this) <= 64.0D; } @Override public void openInventory(EntityPlayer player) { } @Override public void closeInventory(EntityPlayer player) { } @Override public boolean isItemValidForSlot(int index, ItemStack stack) { return index > inventory.length ? stack != null && stack .getItem() instanceof ItemDinosaurSaddle && ((ItemDinosaurSaddle) stack.getItem()) .getSaddleType().equals(creature.getSaddleType()) : true; } @Override public int getField(int id) { return 0; } @Override public void setField(int id, int value) { } @Override public int getFieldCount() { return 0; } @Override public void clear() { saddle = null; for (int i = 0; i < getSizeInventory(); i++) { setInventorySlotContents(i, null); } } public Creature getCreature() { return creature; } public void setSitting(boolean b) { // TODO Auto-generated method stub } public int getTamingProgress() { return tamingProgress; } public int getTamingProgressRequired() { // TODO Auto-generated method stub return (getBaseLevel() * 20); } public double getRelativeTamingProgress() { return (double) tamingProgress / (double) getTamingProgressRequired(); } public int getTorpor() { return torpor; } public int getMaxTorpor() { return maxTorpor; } public double getRelativeTorpor() { return (double) torpor / (double) maxTorpor; } public double getRelativeOxygen() { return (double) oxygen / (double) maxOxygen; } public double getRelativeHealth() { return (double) this.getHealth() / (double) maxHealth; } public double getRelativeFood() { return (double) food / (double) maxFood; } public double getRelativeStamina() { return (double) stamina / (double) maxStamina; } public double getRelativeWeight() { return (double) countStacks() / (double) maxWeight; } public int countStacks() { int out = 0; for (ItemStack s : inventory) { if (s != null) { out++; } } return out; } public int getBaseLevel() { return baseLevel; } public int getMaxOxygen() { return maxOxygen; } public int getMaxDamage() { return maxDamage; } public int getMaxFood() { return maxFood; } public int getMaxSpeed() { return maxSpeed; } public int getMaxStamina() { return maxStamina; } public int getMaxWeight() { return maxWeight; } public int getOxygen() { return oxygen; } public int getFood() { return food; } public int getStamina() { return stamina; } public int getLevel() { return level; } public void increaseStat(int statIndex) { switch (statIndex) { case HEALTH: maxHealth += creature.getTamedHealthIncrease(); break; case DAMAGE: maxDamage += creature.getTamedDamageIncrease(); break; case FOOD: maxFood += creature.getTamedFoodIncrease(); break; case OXYGEN: maxOxygen += creature.getTamedOxygenIncrease(); break; case SPEED: maxSpeed += creature.getTamedSpeedIncrease(); break; case STAMINA: maxStamina += creature.getTamedStaminaIncrease(); break; case WEIGHT: maxWeight += creature.getTamedWeightIncrease(); break; } updateEntityAttributes(); } @Override public EntityAgeable createChild(EntityAgeable ageable) { EntityARKCreature child = null; try { Class<? extends EntityARKCreature> cl = this.getClass(); Constructor<? extends EntityARKCreature> co = cl.getConstructor(World.class); child = co.newInstance(this.worldObj); } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } child.grownUp = false; child.updateHitbox(); return child; } }