package net.tropicraft.entity.underdasea;
import net.minecraft.entity.Entity;
import net.minecraft.entity.passive.EntityWaterMob;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
public abstract class EntityEchinoderm extends EntityWaterMob {
/**
* Data watcher field for growing age.
*/
public static final int DW_GROWING_AGE = 16;
/**
* How many ticks it takes for a baby to grow into an adult.
*/
public static final int GROWTH_TICKS = 10*60*20; // 10 minutes
/**
* How many ticks to wait between breeding sessions.
*/
public static final int BREEDING_COOLDOWN = 10*60*20; // 10 minutes
/**
* How close another sea urchin has to be for it to be considered a
* potential mate.
*/
public static final int BREEDING_PROXIMITY = 4;
/**
* Number of neighboring sea urchins above which breeding doesn't happen.
*/
public static final int MAX_NEIGHBORS = 6;
/**
* Number of blocks around this sea urchin within which to look for
* neighbors.
*/
public static final int NEIGHBORHOOD_SIZE = 8;
/**
* Number of ticks to wait between trying to scan for mates.
*/
public static final int MATE_SCAN_INTERVAL = 5*20; // 5 seconds
/**
* Growing age from previous tick (client side). Used for updating bounding
* box and yOffset on change.
*/
private int prevGrowingAge;
/**
* Number of ticks until next mate finding attempt.
*/
private int mateScanCooldown;
public EntityEchinoderm(World world) {
super(world);
setEchinodermSize();
}
public EntityEchinoderm(World world, boolean baby) {
super(world);
setGrowingAge(baby ? -GROWTH_TICKS : 0);
setEchinodermSize();
}
@Override
public void updateEntityActionState() {
super.updateEntityActionState();
isJumping = false;
}
@Override
public boolean attackEntityFrom(DamageSource source, float amt) {
if (source == DamageSource.inWall) {
return false;
}
return super.attackEntityFrom(source, amt);
}
@Override
public boolean isMovementCeased() {
return true;
}
@Override
public void knockBack(Entity ent, float par2, double par3, double par5) {
// don't move when hit
}
@Override
public void onEntityUpdate()
{
super.onEntityUpdate();
int growingAge = getGrowingAge();
if (worldObj.isRemote) {
motionY = 0D;
if (growingAge != prevGrowingAge) {
setEchinodermSize();
prevGrowingAge = growingAge;
}
} else {
this.noClip = this.func_145771_j(this.posX, (this.boundingBox.minY + this.boundingBox.maxY) / 2.0D, this.posZ);
if (growingAge < 0) {
setGrowingAge(growingAge+1);
setEchinodermSize();
} else if (growingAge > 0) {
// update inter-breeding cooldown
setGrowingAge(growingAge-1);
}
if (isHorny()) {
if (mateScanCooldown > 0) {
mateScanCooldown--;
} else {
mateScanCooldown = MATE_SCAN_INTERVAL;
EntityEchinoderm mate = findMate();
if (mate != null) {
setGrowingAge(BREEDING_COOLDOWN);
mate.setGrowingAge(BREEDING_COOLDOWN);
EntityEchinodermEgg egg = createEgg();
double newX = posX+0.5*(mate.posX-posX);
double newY = posY+1;
double newZ = posZ+0.5*(mate.posZ-posZ);
egg.setLocationAndAngles(newX, newY, newZ, 0f, 0f);
worldObj.spawnEntityInWorld(egg);
}
}
}
}
}
public abstract EntityEchinodermEgg createEgg();
public boolean isChild() {
return getGrowingAge() < 0;
}
public boolean isHorny() {
return getGrowingAge() == 0;
}
private EntityEchinoderm findMate() {
int neighbors = 0;
EntityEchinoderm closestMate = null;
double closestSqDist = -1f;
AxisAlignedBB aabb = this.boundingBox.expand(NEIGHBORHOOD_SIZE, NEIGHBORHOOD_SIZE, NEIGHBORHOOD_SIZE);
for (Object obj : worldObj.getEntitiesWithinAABB(getClass(), aabb)) {
// don't masturbate
if (obj == this) {
continue;
}
neighbors++;
EntityEchinoderm other = (EntityEchinoderm) obj;
if (!isPotentialMate(other)) {
continue;
}
double sqDist = getDistanceSqToEntity(other);
if (sqDist < BREEDING_PROXIMITY && (closestSqDist == -1f || sqDist < closestSqDist)) {
closestMate = other;
closestSqDist = sqDist;
}
}
if (neighbors > MAX_NEIGHBORS) {
return null;
} else {
return closestMate;
}
}
public boolean isPotentialMate(EntityEchinoderm other) {
// we are no pedophiles or rapists
return !other.isChild() && other.isHorny();
}
@Override
public void entityInit() {
super.entityInit();
dataWatcher.addObject(DW_GROWING_AGE, Integer.valueOf(0));
}
/**
* Negative, to be incremented if a child. Positive, to be decremented, if
* an adult that has just procreated, as a cooldown.
* @return the number of ticks.
*/
public int getGrowingAge() {
return dataWatcher.getWatchableObjectInt(DW_GROWING_AGE);
}
public void setGrowingAge(int age) {
dataWatcher.updateObject(DW_GROWING_AGE, Integer.valueOf(age));
}
@Override
public void writeEntityToNBT(NBTTagCompound compound) {
super.writeEntityToNBT(compound);
compound.setInteger("Age", this.getGrowingAge());
}
@Override
public void readEntityFromNBT(NBTTagCompound compound) {
super.readEntityFromNBT(compound);
this.setGrowingAge(compound.getInteger("Age"));
}
/**
* Calculates the growth progress of this sea urchin.
* @return number between 0 and 1: 0 = freshly hatched, 1 = adult
*/
public float getGrowthProgress() {
int growingAge = getGrowingAge();
float growthProgress = growingAge < 0 ? 1f+((float)growingAge)/GROWTH_TICKS : 1f;
return growthProgress;
}
private void setEchinodermSize() {
float growthProgress = getGrowthProgress();
float width = getBabyWidth() + growthProgress*(getAdultWidth()-getBabyWidth());
float height = getBabyHeight() + growthProgress*(getAdultHeight()-getBabyHeight());
float yO = getBabyYOffset() + growthProgress*(getAdultYOffset()-getBabyYOffset());
setSize(width, height);
yOffset = yO;
}
public abstract float getBabyWidth();
public abstract float getAdultWidth();
public abstract float getBabyHeight();
public abstract float getAdultHeight();
public abstract float getBabyYOffset();
public abstract float getAdultYOffset();
}