/** * 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 java.util.HashMap; import com.gundogstudios.gl.Actions; import com.gundogstudios.gl.Sprite; import com.gundogstudios.modules.Modules; import com.gundogstudios.util.FastMath; public class MovingProjectile implements Sprite, Projectile, Externalizable { public static final String FIRE_BALL_PROJECTILE = "fire_ball_projectile"; public static final String ICE_BALL_PROJECTILE = "ice_ball_projectile"; public static final String WIND_BALL_PROJECTILE = "wind_ball_projectile"; public static final String EARTH_BALL_PROJECTILE = "earth_ball_projectile"; public static final String LIFE_BALL_PROJECTILE = "life_ball_projectile"; public static final String UNDEAD_BALL_PROJECTILE = "undead_ball_projectile"; public static final String FIRE_ARROW_PROJECTILE = "fire_arrow_projectile"; public static final String ICE_ARROW_PROJECTILE = "ice_arrow_projectile"; public static final String EARTH_ARROW_PROJECTILE = "earth_arrow_projectile"; private static final float SPEED = 200; // 200ms to move 1 grid square private static final float Z_OFFSET = .5f;// hits the center of the models private static final HashMap<String, String> type = new HashMap<String, String>(); static { type.put(BaseTower.EARTH_BALLISTA, EARTH_ARROW_PROJECTILE); type.put(BaseTower.FLAME_BALLISTA, FIRE_ARROW_PROJECTILE); type.put(BaseTower.ICE_BALLISTA, ICE_ARROW_PROJECTILE); } private Creature target; private Tower source; private float x; private float y; private float z; private int id; private boolean atTarget; public MovingProjectile() { } public MovingProjectile(Tower source, Creature target) { this.source = source; this.target = target; this.x = source.getX(); this.y = source.getY(); this.z = Z_OFFSET; this.atTarget = false; this.id = IDGenerator.getNextID(); } public Race getRace() { return source.getRace(); } public float getDamage() { return source.getDamage(); } public Creature getTarget() { return target; } public float getX() { return x; } public float getY() { return y; } public float getZ() { return z; } @Override public boolean attacksAll() { return source.attacksAllInRange(); } public boolean move(int timePassed) { float distanceMoved = (float) timePassed / SPEED; float targetX = target.getX(); float targetY = target.getY(); float targetZ = target.getZ() + Z_OFFSET; float xdiff = (targetX - x); float ydiff = (targetY - y); float zdiff = (targetZ - z); float targetDistance = FastMath.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff); if (targetDistance == 0) return true; xdiff /= targetDistance; ydiff /= targetDistance; zdiff /= targetDistance; if (targetDistance - distanceMoved > 0.0f) { x += xdiff * distanceMoved; y += ydiff * distanceMoved; z += zdiff * distanceMoved; return false; } else { x = targetX; y = targetY; z = targetZ; atTarget = true; return true; } } @Override public int getLevel() { return source.getLevel(); } public boolean atTarget() { return atTarget; } @Override public int getID() { return id; } @Override public String getModel() { String name = type.get(source.getBaseTower().getName()); if (name != null) return name; // TODO can only handle 1 race at a time, not going to work for combo races int race = Races.pickRandomRace(getRace().getRaces()); switch (race) { case Races.DEATH: return UNDEAD_BALL_PROJECTILE; case Races.EARTH: return EARTH_BALL_PROJECTILE; case Races.FIRE: return FIRE_BALL_PROJECTILE; case Races.ICE: return ICE_BALL_PROJECTILE; case Races.LIFE: return LIFE_BALL_PROJECTILE; case Races.WIND: return WIND_BALL_PROJECTILE; } Modules.LOG.error("MovingProjectile", "Unknown race: " + race); return ""; } @Override public int getAction() { if (atTarget) return Actions.DEATH; else return Actions.IDLE; } @Override public String toString() { return "MovingProjectile [x=" + x + ", y=" + y + ", z=" + z + ", id=" + id + "]"; } @Override public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { source = (Tower) input.readObject(); target = (Creature) input.readObject(); x = input.readFloat(); y = input.readFloat(); z = input.readFloat(); id = input.readInt(); atTarget = input.readBoolean(); } @Override public void writeExternal(ObjectOutput output) throws IOException { output.writeObject(source); output.writeObject(target); output.writeFloat(x); output.writeFloat(y); output.writeFloat(z); output.writeInt(id); output.writeBoolean(atTarget); } }