/** * Copyright (C) 2013 Gundog Studios LLC. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.godsandtowers.sprites; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import com.godsandtowers.core.grid.GridSquare; import com.gundogstudios.gl.Actions; import com.gundogstudios.gl.Sprite; import com.gundogstudios.util.FastMath; public class Creature implements Sprite, Externalizable { private static final int ONE_SECOND = 1000; // ms private GridSquare currentGridSquare; private BaseCreature baseCreature; private Race race; private Player owner; private float health; private float slowDuration = 0; private float slowFactor = 0; private float stunDuration = 0; private float drainDuration = 0; private float drainFactor = 0; private float cooldown = 0; private Tower target; private float x = 0; private float y = 0; private float z = 0; private int id = 0; public Creature() { } public Creature(Player owner, BaseCreature baseCreature) { this.owner = owner; this.race = new Race(owner.getRace().getBaseRace(), baseCreature.getRaces()); this.baseCreature = baseCreature; this.health = (int) (baseCreature.getHealth() * race.getCreatureHealthModifier()); this.id = IDGenerator.getNextID(); } public float getPower() { return baseCreature.getPower(); } public int getTotalUpgradeCount() { return baseCreature.getTotalUpgradeCount(); } public int getLevel() { return baseCreature.getLevel(); } public float getAttackRange() { return baseCreature.getAttackRange(); } public String getName() { return baseCreature.getName(); } public Race getRace() { return race; } public float getDefense() { return baseCreature.getDefense() * race.getCreatureDefenseModifier(); } public float getDamage() { return baseCreature.getDamage() * race.getCreatureDamageModifier(); } public float getAttackRate() { return baseCreature.getAttackRate(); } public float getCost() { return baseCreature.getCost(); } public float getIncome() { return baseCreature.getIncome(); } public boolean isAir() { return baseCreature.isAir(); } public boolean isAttacking() { if (owner.isAttacking()) return target != null && target.isAlive(); else { target = null; return false; } } public void setTarget(Tower target) { this.target = target; } public Tower getAttackingTarget() { return target; } @Override public Sprite getTarget() { if (target != null) return target; else { if (isAir()) { return currentGridSquare.getNextAir(); } else { return currentGridSquare.getNext(); } } } public boolean canAttack(int timePassed) { if (cooldown > 0) { cooldown -= timePassed; return false; } else if (!owner.isAttacking() || getDamage() <= 0.0f) { return false; } else { return true; } } public void attacked() { cooldown = baseCreature.getAttackRate(); } public void setSlow(float slowDuration, float slowFactor) { this.slowDuration = slowDuration; this.slowFactor = slowFactor; } public void setStun(float stunDuration) { this.stunDuration = stunDuration; } public void setDrain(float drainDuration, float drainFactor) { this.drainDuration = drainDuration; this.drainFactor = drainFactor; } public void nextTick(int timePassed) { if (slowDuration > 0) slowDuration -= timePassed; if (stunDuration > 0) stunDuration -= timePassed; if (drainDuration > 0) { health -= (health * drainFactor * timePassed / ONE_SECOND); if (health <= 0) { health = 1; } drainDuration -= timePassed; } if (race.isLife()) { float diff = baseCreature.getHealth() - health; if (diff > 0) { float maxIncrease = (baseCreature.getHealth() * race.getHealPercentage() * timePassed / ONE_SECOND); health += (maxIncrease > diff) ? diff : maxIncrease; } } } public boolean isSlowed() { return slowDuration > 0; } public boolean isStunned() { return stunDuration > 0; } public boolean isDraining() { return drainDuration > 0; } public float getHealth() { return health; } public boolean isAlive() { return health > 0.0f; } public void kill() { health = 0.0f; } public void remove() { health = Float.MIN_VALUE; } public void heal() { health = baseCreature.getHealth() * race.getCreatureHealthModifier(); } public void resurrect() { this.health = baseCreature.getHealth() * race.getCreatureHealthModifier(); } public boolean subtractHealth(float damage) { damage /= getDefense(); health -= damage; return health <= 0.0f; } public void modifyHealth(float percent) { health = percent * health; } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public float getZ() { return z; } public void setZ(float z) { this.z = z; } public float getNextX() { if (isAir()) { return currentGridSquare.getNextAir().getX(); } else { return currentGridSquare.getNext().getX(); } } public float getNextY() { if (isAir()) { return currentGridSquare.getNextAir().getY(); } else { return currentGridSquare.getNext().getY(); } } public float getTargetX() { return target.getX(); } public float getTargetY() { return target.getY(); } public void setGridSquare(GridSquare grid) { this.currentGridSquare = grid; } public GridSquare getCurrentGridSquare() { return currentGridSquare; } public float move(int timePassed) { float time = timePassed; if (stunDuration > 0) return 0; time *= race.getCreatureSpeedModifier(); if (slowDuration > 0) time *= slowFactor; float distanceMoved = time / baseCreature.getSpeed(); return moveDistance(distanceMoved); } public float moveDistance(float distanceMoved) { float xdiff = (getNextX() - x); float ydiff = (getNextY() - y); float targetDistance = FastMath.sqrt(xdiff * xdiff + ydiff * ydiff); if (targetDistance == 0) return 0; xdiff /= targetDistance; ydiff /= targetDistance; if (targetDistance - distanceMoved > 0.0f) { x += xdiff * distanceMoved; y += ydiff * distanceMoved; return 0; } else { return distanceMoved - targetDistance; } } @Override public int getID() { return id; } @Override public String getModel() { return baseCreature.getName(); } @Override public int getAction() { if (health <= 0) return Actions.DEATH; else if (stunDuration > 0) return Actions.IDLE; else if (cooldown > 0 && target != null) return Actions.ATTACK; else return Actions.MOVE; } @Override public String toString() { return "Creature [x=" + x + ", y=" + y + ", z=" + z + ", id=" + id + ", getLevel()=" + getLevel() + ", getModel()=" + getModel() + "]"; } @Override public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { race = (Race) input.readObject(); baseCreature = (BaseCreature) input.readObject(); currentGridSquare = (GridSquare) input.readObject(); health = input.readFloat(); slowDuration = input.readFloat(); slowFactor = input.readFloat(); stunDuration = input.readFloat(); drainDuration = input.readFloat(); drainFactor = input.readFloat(); cooldown = input.readFloat(); x = input.readFloat(); y = input.readFloat(); z = input.readFloat(); id = input.readInt(); target = (Tower) input.readObject(); owner = (Player) input.readObject(); } @Override public void writeExternal(ObjectOutput output) throws IOException { output.writeObject(race); output.writeObject(baseCreature); output.writeObject(currentGridSquare); output.writeFloat(health); output.writeFloat(slowDuration); output.writeFloat(slowFactor); output.writeFloat(stunDuration); output.writeFloat(drainDuration); output.writeFloat(drainFactor); output.writeFloat(cooldown); output.writeFloat(x); output.writeFloat(y); output.writeFloat(z); output.writeInt(id); output.writeObject(target); output.writeObject(owner); } }