/* * Copyright (c) 2003-onwards Shaven Puppy Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'Shaven Puppy' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package worm.features; import java.util.List; import java.util.StringTokenizer; import net.puppygames.applet.Game; import net.puppygames.applet.Screen; import net.puppygames.applet.effects.EmitterFeature; import org.lwjgl.util.Point; import org.lwjgl.util.Rectangle; import org.w3c.dom.Element; import worm.Res; import worm.Statistics; import worm.Worm; import worm.brains.BrainFeature; import worm.brains.TacticalBrainFeature; import worm.entities.Gidrah; import worm.entities.Movement; import worm.weapons.WeaponFeature; import com.shavenpuppy.jglib.openal.ALBuffer; import com.shavenpuppy.jglib.resources.Data; import com.shavenpuppy.jglib.resources.Feature; import com.shavenpuppy.jglib.resources.Range; import com.shavenpuppy.jglib.resources.ResourceArray; import com.shavenpuppy.jglib.sprites.Appearance; import com.shavenpuppy.jglib.util.Util; import com.shavenpuppy.jglib.util.XMLUtil; /** * $Id: GidrahFeature.java,v 1.47 2010/10/14 22:53:20 foo Exp $ * Describes a gidrah * @author $Author: foo $ * @version $Revision: 1.47 $ */ public class GidrahFeature extends Feature implements Statistics { private static final long serialversionUID = 1L; public static final int SPAWN_TYPE_NONE = 0; public static final int SPAWN_TYPE_CONSTANT = 1; public static final int SPAWN_TYPE_EXPLODE = 2; /* * Feature data */ /** Latin name */ @Data private String latinName; /** Appearance */ private LayersFeature appearance; /** Attack appearance */ private LayersFeature attackAppearance, attackAppearanceLeft, attackAppearanceRight; /** Frozen appearance */ private ResourceArray frozenAppearance; /** Frozen appearance */ private LayersFeature idleAppearance; /** Death appearance */ private LayersFeature deathAppearance, deathAppearanceLeft, deathAppearanceRight; /** Stunned appearance */ private LayersFeature stunAppearance; /** Death sound */ private String death; /** Hit points */ private int hitPoints; private int hitPointsX; private int hitPointsY; /** Armour */ private int armour; /** Points value */ private int points; /** Movement speed (pixels/sec) */ private float speed; /** Pause duration */ private int pause; /** Squares to move */ private int moves; /** Diagonal movement preference */ private boolean diagonal; /** Size, if rectangular */ private Rectangle bounds; /** Offset to sprites */ private Point offset; /** Offset for laser beams */ private Point beamOffset; /** Weapon, if any */ private String weapon; /** Brain */ private String brain; /** Angry? Angry gidrahs can attack multiple times before dying */ private boolean angry; /** Wraith? Wraiths can only be harmed by capacitors, and pass through barriers and over mines */ private boolean wraith; /** Is this a boss gidrah? */ private boolean boss; /** Is this a flying gidrah? Flying gidrahs fly directly over any buildings and tiles. They must be armed with guns to be effective. */ private boolean flying; /** If we're a spawning gidrah, what gidrah do we spawn? */ private String spawn; /** If we're a spawning gidrah, what sort of spawning do we do? 1 = constant, 2 = explode on death */ private int spawnType; /** Spawn rate (constant) or number-to-spawn (explode on death) */ private Range spawnRate; /** Spawn distance */ private Range spawnDistance; /** Are we a gidlet? Gidlets run through barriers and mines and aren't targeted by turrets */ private boolean gidlet; /** Are we a shielded gidrah? Shielded gidrahs must have their shields disabled by explosives */ private boolean shielded; /** If we're a shielded gidrah, what does our shield look like? */ private String shieldAnimation; /** Deflect emitter */ private String deflectEmitter; private int deflectXOffset; private int deflectYOffset; /** Roar */ private String roar; /** Ambient roar */ private String amb; /** Explody? */ private boolean exploding; /** Explosion radius */ private float explosionRadius; /** Strength */ private int strength; /** Bomb */ private String bomb; /** Flying height */ private float height; /** Drop attack - flying gidrah drops on its target to attack it */ private boolean dropAttack; /** Weapon range */ private float minWeaponRange, maxWeaponRange; /** Can gid be stunned when attacking? */ private boolean noStunOnAttack; /** Medal to award when killing boss */ private String medal; /** Minimum level (endless) */ private int minLevel; /** Required research (endless) */ private String[] research; /** Disruptor proofing */ private boolean disruptorProof; /* * Transient data */ private transient EmitterFeature deflectEmitterResource; private transient ALBuffer deathBuffer; private transient WeaponFeature weaponFeature; private transient BrainFeature brainFeature; private transient GidrahFeature spawnFeature; private transient Appearance shieldAnimationResource; private transient ALBuffer roarBuffer; private transient ALBuffer ambBuffer; private transient BombFeature bombFeature; /** * @param name */ public GidrahFeature(String name) { super(name); setAutoCreated(); } /** * @return the noStunOnAttack */ public boolean getNoStunOnAttack() { return noStunOnAttack; } /** * @return the deathBuffer */ public ALBuffer getDeathBuffer() { return deathBuffer; } /** * @return the minWeaponRange */ public float getMinWeaponRange() { return minWeaponRange; } /** * @return the maxWeaponRange */ public float getMaxWeaponRange() { return maxWeaponRange; } /** * @return the dropAttack */ public boolean isDropAttack() { return dropAttack; } /** * @return the bombFeature */ public BombFeature getBomb() { return bombFeature; } /** * @return the height */ public float getHeight() { return height; } /** * @return the strength */ public int getStrength() { return strength; } /** * @return the explosionRadius */ public float getExplosionRadius() { return explosionRadius; } /** * @return the exploding */ public boolean isExploding() { return exploding; } /** * @return the roarBuffer */ public ALBuffer getRoar() { return roarBuffer; } /** * @return the ambBuffer */ public ALBuffer getAmbientRoar() { return ambBuffer; } /** * @return Returns the appearance. */ public LayersFeature getAppearance() { return appearance; } public LayersFeature getIdleAppearance() { return idleAppearance; } /** * @return the deathAppearance */ public LayersFeature getDeathAppearance() { return deathAppearance; } public LayersFeature getDeathAppearanceLeft() { return deathAppearanceLeft; } public LayersFeature getDeathAppearanceRight() { return deathAppearanceRight; } /** * @return the attackAppearance */ public LayersFeature getAttackAppearance() { return attackAppearance; } /** * @return the attackAppearanceLeft */ public LayersFeature getAttackAppearanceLeft() { return attackAppearanceLeft; } /** * @return the attackAppearanceRight */ public LayersFeature getAttackAppearanceRight() { return attackAppearanceRight; } /** * @return the frozenAppearance */ public LayersFeature getFrozenAppearance() { return (LayersFeature) frozenAppearance.getResource(Util.random(0, frozenAppearance.getNumResources() - 1)); } /** * @return the stunAppearance */ public LayersFeature getStunAppearance() { if (stunAppearance!=null) { return stunAppearance; } else { return idleAppearance; } } /** * Spawn a new Gidrah at the specified location. No other gidrah may be present at the specified location. * @param screen * @return the new Gidrah */ public final Gidrah spawn(Screen screen, int tileX, int tileY, int type) { Gidrah ret = new Gidrah(this, tileX, tileY, type); ret.spawn(screen); return ret; } /** * @return the hitPoints */ public final int getHitPoints() { return hitPoints; } /** * @return the hitPoints */ public final int getHitPointsX() { return hitPointsX; } /** * @return the hitPoints */ public final int getHitPointsY() { return hitPointsY; } /** * @return armour points */ public int getArmour() { return armour; } /** * @return the points */ public final int getPoints() { return points; } /** * @return true if this is a wraith */ public boolean isWraith() { return wraith; } /** * @return true if this is a boss gidrah */ public boolean isBoss() { return boss; } /** * @return the bounds */ public Rectangle getBounds() { return bounds; } /** * @return */ public WeaponFeature getWeapon() { return weaponFeature; } /** * @return */ public BrainFeature getBrain() { return brainFeature; } /** * @return the minSpeed */ public float getSpeed() { return speed; } /** * @return the minPause */ public int getPause() { return pause; } /** * @return the angry */ public boolean isAngry() { return angry; } /** * @return the gidlet */ public boolean isGidlet() { return gidlet; } /** * @return the flying */ public boolean isFlying() { return flying; } /** * @return the shielded */ public boolean isShielded() { return shielded; } /** * @return the spawnFeature */ public GidrahFeature getSpawn() { return spawnFeature; } /** * @return the spawnType */ public int getSpawnType() { return spawnType; } /** * @return the spawnRate */ public Range getSpawnRate() { return spawnRate; } public Point getOffset() { return offset; } public Point getBeamOffset() { return beamOffset; } /** * @return the deflectEmitterResource */ public EmitterFeature getDeflectEmitter() { if (deflectEmitterResource!=null) { return deflectEmitterResource; } else { return Res.getDeflectEmitter(); } } public int getDeflectXOffset() { return deflectXOffset; } public int getDeflectYOffset() { return deflectYOffset; } /** * @return the diagonal */ public boolean getDiagonal() { return diagonal; } /** * @return the relative value of the gidrah */ public int getValue() { int ret = hitPoints; ret += armour * 10; ret += strength * 5; if (angry) { ret *= 2; } if (flying) { ret *= 2; } if (weapon != null) { ret *= 2; } if (wraith) { ret *= 2; } if (brainFeature instanceof TacticalBrainFeature) { ret *= 2; } if (spawn != null) { ret *= 2; } return ret; } /** * @return the medal */ public String getMedal() { return medal; } /** * @return the minMove */ public int getMoves() { return moves; } /** * Is this gidrah unlocked in Endless mode? * @return boolean */ public boolean isUnlocked() { // System.out.println("Testing "+this); if (Worm.getGameState().getLevel() >= minLevel) { // Automatically unlock after a certain level // System.out.println("--minlevel satisfied:"+minLevel); return true; } // All research must be present outer: for (int i = 0; i < research.length; i ++) { StringTokenizer st = new StringTokenizer(research[i], " |"); // System.out.println(" research: "+research[i]); while (st.hasMoreTokens()) { String r = st.nextToken(); if (Worm.getGameState().isResearched(r)) { // System.out.println("--"+r+" is researched"); continue outer; } } // System.out.println(" !!!Not available"); return false; } return true; } @Override public void load(Element element, Loader loader) throws Exception { super.load(element, loader); List<Element> children = XMLUtil.getChildren(element, "research"); if (children.size() > 0) { research = new String[children.size()]; int count = 0; for (Element child : children) { research[count ++] = XMLUtil.getText(child, "").trim(); } } } public boolean isDisruptorProof() { return disruptorProof; } public Range getSpawnDistance() { return spawnDistance; } @Override public String toString() { return "GidrahFeature["+getName()+"]"; } // titan:\n{font:smallfont.glfont}GIDRUS GIDRUS{font:tinyfont.glfont}\n\n hitpoints: 2-6\n armour: NONE\n strength: 3\n speed: 20-40 MPH\nweight: 30 T @Override public void appendFullStats(StringBuilder dest) { appendTitle(dest); dest.append("\n\n"); appendBasicStats(dest); } @Override public void appendTitle(StringBuilder dest) { dest.append("titan:\n{font:smallfont.glfont}"); dest.append(latinName); dest.append("{font:tinyfont.glfont}"); } @Override public void appendBasicStats(StringBuilder dest) { dest.append(Game.getMessage("ultraworm.gidrahstats.hitpoints")+": "); if (wraith) { dest.append(Game.getMessage("ultraworm.gidrahstats.unknown")); } else { dest.append(hitPoints); dest.append("+"); } dest.append("\n"+Game.getMessage("ultraworm.gidrahstats.armour")+": "); if (wraith) { dest.append(Game.getMessage("ultraworm.gidrahstats.unknown")); } else if (armour > 0) { dest.append(armour); } else { dest.append(Game.getMessage("ultraworm.gidrahstats.none")); } dest.append("\n"+Game.getMessage("ultraworm.gidrahstats.strength")+": "); if (wraith) { dest.append(Game.getMessage("ultraworm.gidrahstats.unknown")); } else { dest.append(strength); } dest.append("\n"+Game.getMessage("ultraworm.gidrahstats.speed")+": "); if (wraith) { dest.append(Game.getMessage("ultraworm.gidrahstats.unknown")); } else { int minSpeedMph, maxSpeedMph; minSpeedMph = (int) (speed * 2f); maxSpeedMph = (int) (speed * 2f * Movement.MAX_SPEED_MULTIPLIER); if (minSpeedMph > 50) { minSpeedMph -= minSpeedMph % 10; } else if (minSpeedMph > 10) { minSpeedMph -= minSpeedMph % 5; } if (maxSpeedMph > 50) { maxSpeedMph -= maxSpeedMph % 10; } else if (maxSpeedMph > 10) { maxSpeedMph -= maxSpeedMph % 5; } dest.append(minSpeedMph); dest.append("-"); dest.append(maxSpeedMph); if (flying) { dest.append(" KN"); } else { dest.append(" MPH"); } } if (!wraith) { dest.append("\n"+Game.getMessage("ultraworm.gidrahstats.weight")+": "); int weight; if (gidlet) { weight = 1; } else { weight = hitPoints * 5 + 20; weight -= weight % 10; if (angry) { weight *= 3; weight += armour * 20; } else { weight += armour * 5; } if (flying) { weight /= 10; if (weight > 5) { weight -= weight % 5; } } } dest.append(weight); dest.append(" T"); } } }