/*
* 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.buildings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.puppygames.applet.Game;
import org.lwjgl.util.Color;
import org.lwjgl.util.Point;
import org.lwjgl.util.ReadableColor;
import org.lwjgl.util.Rectangle;
import org.w3c.dom.Element;
import worm.ClickAction;
import worm.Entity;
import worm.GameMap;
import worm.Hints;
import worm.Layers;
import worm.MapRenderer;
import worm.Medals;
import worm.Mode;
import worm.Res;
import worm.SFX;
import worm.Worm;
import worm.effects.RangeEffect;
import worm.entities.Building;
import worm.entities.Gidrah;
import worm.entities.Turret;
import worm.features.LayersFeature;
import worm.features.ResearchFeature;
import worm.screens.GameScreen;
import worm.weapons.WeaponFeature;
import com.shavenpuppy.jglib.resources.PointParser;
import com.shavenpuppy.jglib.sprites.Appearance;
import com.shavenpuppy.jglib.sprites.Sprite;
import com.shavenpuppy.jglib.util.FPMath;
import com.shavenpuppy.jglib.util.Util;
import com.shavenpuppy.jglib.util.XMLUtil;
/**
* $Id: TurretBuildingFeature.java,v 1.96 2010/11/08 02:03:11 foo Exp $
* A defence turret, which shoots autonomously
* @author $Author: foo $
* @version $Revision: 1.96 $
*/
public class TurretBuildingFeature extends BuildingFeature {
private static final long serialVersionUID = 1L;
protected static final ReadableColor RANGE_COLOR = new Color(255, 10, 10, 48);
protected static final ReadableColor MIN_RANGE_COLOR = new Color(255, 255, 10, 48);
protected static final ReadableColor BLAST_RANGE_COLOR = new Color(255, 10, 255, 48);
private static final int LIGHTS_OFF_TIME = 120;
private static final int ALPHA_ADJUST = 8;
private static final float ATTENUATION = 256.0f;
private static final int FIND_TARGET_INTERVAL = 8;
private static final int USELESS_WARNING_TIME = 1800;
private static final int RETARGET_TIME = 120;
/** Target acquisistion */
private static final ArrayList<Entity> ENTITIES = new ArrayList<Entity>();
private static final ArrayList<Gid> TARGETS = new ArrayList<Gid>();
private static class Gid {
Gidrah gidrah;
float distance;
}
private static final Rectangle TEMP = new Rectangle();
private int maxReactors;
private int maxScanners;
/** Weapon */
private String weapon;
/** Ignore deflections */
private boolean ignoreDeflection;
/** Turret position offset */
private int beamOffsetX, beamOffsetY;
/** Light movement speed */
private float lightSpeed;
/** Base range, defaults to AIM_RANGE */
private float baseRange;
/** Range increment per scanner, defaults to RANGE_PER_SCANNER */
private float rangeIncrement;
/** Minimum range */
private float minimumRange;
/** Light */
private String light;
/** Light layer */
private int lightLayer;
/** Beam */
private String beam;
/** Beam layer */
private int beamLayer;
/** Reload appearance */
private LayersFeature reloadAppearance, reloadingAppearance;
/** heavy weapons use different dits */
private boolean heavyWeapon;
/** Bullet offsets, in sequence */
private List<Point> barrels;
/** Don't target flying targets */
private boolean dontTargetFlyingTargets;
/** Allow targeting in to mountains */
private boolean targetIntoMountains;
/*
* Transient
*/
private transient WeaponFeature weaponFeature;
private transient Appearance beamResource;
/**
* Building instances
*/
protected class TurretBuildingInstance extends Turret {
private static final long serialVersionUID = 1L;
private WeaponFeature.WeaponInstance weaponInstance;
/** Find target tick */
private int findTick;
/** Useless tick */
private int uselessTick;
/** Sight check tick */
private int sightTick;
/** Retarget tick */
private int retargetTick;
/** Reload warning */
private Sprite reloadSprite;
/** Lighting */
private Sprite beamSprite;
/** Current target */
private Entity target;
/** Light position */
private float lightX, lightY;
/** Target light alpha */
private int targetLightAlpha, currentLightAlpha;
/** Lights off tick */
private int lightsOffTick;
/** Light attenuation */
private float attenuation;
/** Range indicator */
private transient RangeEffect rangeEffect, minRangeEffect, blastRangeEffect;
/** Danger radius added */
private float dangerAdded;
/** Extra damage (xenobiology research) */
private int extraDamage;
/** Extra scanning range (optics research) */
private float extraScan;
/** Extra minimum range (rockets with plastic charge pattern) */
private float extraMinimum;
/** Barrel */
private int barrel;
/** Ignore list */
private ArrayList<Entity> ignore = new ArrayList<Entity>();
/**
* C'tor
* @param feature
* @param x
* @param y
*/
protected TurretBuildingInstance(boolean ghost) {
super(TurretBuildingFeature.this, ghost);
}
@Override
public void disruptorDamage(int amount, boolean friendly) {
if (weaponFeature != null && weaponFeature.confersImmunityFromDisruptors()) {
return;
}
super.disruptorDamage(amount, friendly);
}
@Override
public boolean isFiringAtAerialTargets() {
return target != null && target.isActive() && target.isFlying();
}
@Override
public void onBezerk() {
if (weaponInstance != null) {
weaponInstance.instantReload();
updateAppearance();
}
}
@Override
protected void doOnBuild() {
if (weaponFeature != null) {
weaponInstance = weaponFeature.spawn(this);
addDanger(weaponFeature.getDanger());
} else {
addDanger(0); // Decoys!
}
// Create lights
if (beamResource != null) {
beamSprite = GameScreen.getInstance().allocateSprite(this);
beamSprite.setLayer(beamLayer);
beamSprite.setAppearance(beamResource);
beamSprite.setAlpha(0);
}
}
private void updateLight() {
if (beamSprite != null) {
beamSprite.setLocation(getScreenX() + getBeamOffsetX(), getScreenY() + getBeamOffsetY());
}
}
@Override
public WeaponFeature.WeaponInstance getWeapon() {
return weaponInstance;
}
@Override
public boolean usesAmmo() {
return true;
}
@Override
public boolean isApparentlyValuable() {
return weaponFeature == null; // Decoy!
}
@Override
public int getExtraDamage() {
return extraDamage + Math.min(maxReactors, getReactors());
}
@Override
public void setWeapon(WeaponFeature.WeaponInstance weapon) {
this.weaponInstance = weapon;
}
@Override
public float getBeamXOffset() {
return 0.0f;
}
@Override
public float getBeamYOffset() {
return 0.0f;
}
@Override
public void onBulletDeflected(Entity target) {
if (ignoreDeflection || target != this.target) {
return;
}
ignore.remove(target);
ignore.add(target);
this.target = null;
}
/**
* Find a new target
*/
protected void findTarget() {
if (findTick > 0) {
findTick --;
return;
}
// Find a target and kill it
target = null;
TARGETS.clear();
float minDist = getScanRadius();
ENTITIES.clear();
TEMP.setBounds((int) (getX() - minDist), (int) (getY() - minDist), (int) (minDist * 2.0f), (int) (minDist * 2.0f));
Entity.getCollisions(TEMP, ENTITIES);
int n = ENTITIES.size();
if (n == 0) {
// No gidrahs left!
findTick = FIND_TARGET_INTERVAL;
return;
}
for (int j = ignore.size(); -- j >= 0; ) {
Entity e = ignore.get(j);
if (!e.isActive()) {
// Clean up the ignore list while we're at it...
ignore.remove(j);
}
}
// Get all the gidrahs in scanning range which we can potentially aim at
outer: for (int i = 0; i < n; i ++) {
Entity ent = ENTITIES.get(i);
if (!(ent instanceof Gidrah)) {
continue;
}
Gidrah g = (Gidrah) ent;
// Ignore gidlets: need units to combat these! And wraiths: need capacitors for these!
if (!g.isShootable() || !g.isVisibleToTurrets()) {
continue;
}
// Rocket turrets ignore flying targets
if (dontTargetFlyingTargets && g.getFeature().isFlying()) {
continue;
}
float dist = g.getDistanceTo(getX(), getY());
if (dist >= minDist || dist <= getMinimumRange()) {
continue;
}
if (!canSee(g.getX(), g.getY(), g, targetIntoMountains)) {
continue;
}
// If the gidrah is in the ignore list... ignore it
for (int j = ignore.size(); -- j >= 0; ) {
if (g == ignore.get(j)) {
// Ignore!
continue outer;
}
}
Gid gid = new Gid();
gid.gidrah = g;
gid.distance = dist;
TARGETS.add(gid);
}
if (TARGETS.size() == 0) {
findTick = FIND_TARGET_INTERVAL;
return;
}
// Sort the targets in order of distance, with a twiddle for flying gids so that they are preferred over ground based
// gids if this is a laser ("targetIntoMountains" is true)
Collections.sort(TARGETS, new Comparator<Gid>() {
@Override
public int compare(Gid g0, Gid g1) {
if (targetIntoMountains) {
if (g0.gidrah.isFlying() && !g1.gidrah.isFlying()) {
return -1;
} else if (!g0.gidrah.isFlying() && g1.gidrah.isFlying()) {
return 1;
}
}
if (g0.distance < g1.distance) {
return -1;
} else if (g0.distance > g1.distance) {
return 1;
} else {
return 0;
}
}
});
target = TARGETS.get(0).gidrah;
retargetTick = RETARGET_TIME;
findTick = FIND_TARGET_INTERVAL;
}
@Override
protected void doBuildingSetLocation() {
lightX = getX() + getBeamOffsetX();
lightY = getY() + getBeamOffsetY();
if (rangeEffect != null) {
rangeEffect.setLocation(getX(), getY());
}
if (minRangeEffect != null) {
minRangeEffect.setLocation(getX(), getY());
}
if (blastRangeEffect != null) {
blastRangeEffect.setLocation(getX(), getY());
}
}
/**
* @return true if we have a current valid target that's in range and visible
*/
private boolean isTargetValid() {
if (target == null || !target.isActive() || !target.isShootable()) {
return false;
}
// Ensure target still in range
float distanceTo = target.getDistanceTo(getX(), getY());
if (distanceTo > getScanRadius() || distanceTo <= getMinimumRange()) {
return false;
}
// Retarget every so often
if (retargetTick > 0) {
retargetTick --;
if (retargetTick == 0) {
return false;
}
}
// Ensure we can still see the target every now and again
if (sightTick > 0) {
sightTick --;
return true;
}
sightTick = Util.random(FIND_TARGET_INTERVAL / 2, FIND_TARGET_INTERVAL * 2);
return canSee(target.getX(), target.getY(), target, targetIntoMountains);
}
@Override
public float getScanRadius() {
return baseRange + Math.min(maxScanners, getScanners()) * rangeIncrement + extraScan;
}
@Override
public LayersFeature getMousePointer(boolean clicked) {
if (Worm.getGameState().isSelling()) {
return Res.getMousePointerSellOn();
}
if (Worm.getGameState().isBuilding() || weaponInstance == null || !weaponInstance.canReload()) {
return super.getMousePointer(clicked);
}
return Res.getMousePointerReload();
}
@Override
public void onReloaded() {
updateAppearance();
}
@Override
public int onClicked(int mode) {
if (mode == Mode.MODE_SELL || mode == Mode.MODE_BUILD || weaponInstance == null || !weaponInstance.canReload()) {
return super.onClicked(mode);
}
reload();
return ClickAction.DRAG;
}
private void reload() {
weaponInstance.reload(reloadSprite);
updateAppearance();
targetLightAlpha = 0;
SFX.reload();
}
@Override
public void createGhostProximityEffects() {
super.createGhostProximityEffects();
// Show the turret range effect for ghosts
rangeEffect = new RangeEffect(RANGE_COLOR);
rangeEffect.setLocation(getX(), getY());
rangeEffect.spawn(GameScreen.getInstance());
rangeEffect.setShow(true);
rangeEffect.setRadius(getScanRadius());
if (getMinimumRange() > 0.0f) {
minRangeEffect = new RangeEffect(MIN_RANGE_COLOR);
minRangeEffect.setLocation(getX(), getY());
minRangeEffect.spawn(GameScreen.getInstance());
minRangeEffect.setShow(true);
minRangeEffect.setRadius(getMinimumRange());
}
if (weaponFeature != null) {
weaponInstance = weaponFeature.spawn(this);
if (weaponInstance.getBlastRange() > 0.0f) {
blastRangeEffect = new RangeEffect(BLAST_RANGE_COLOR);
blastRangeEffect.setLocation(getX(), getY());
blastRangeEffect.spawn(GameScreen.getInstance());
blastRangeEffect.setShow(true);
blastRangeEffect.setRadius(weaponInstance.getBlastRange());
}
}
}
@Override
protected void doBuildingSpawn() {
if (weaponFeature != null) {
reloadSprite = GameScreen.getInstance().allocateSprite(this);
reloadSprite.setLayer(Layers.BUILDING_INFO);
if (heavyWeapon) {
reloadSprite.setAppearance(Res.getAmmoLarge(1, 1));
} else {
reloadSprite.setAppearance(Res.getAmmo(1, 1));
}
reloadSprite.setScale(FPMath.fpValue(TurretBuildingFeature.this.getAppearance(this).getScale()));
extraDamage = Worm.getGameState().isResearched(ResearchFeature.BIOLOGY) ? 1 : 0;
calcExtraScan();
}
}
@Override
protected void doGhostSpawn() {
calcExtraScan();
}
private void calcExtraScan() {
int optics = Worm.getGameState().isResearched(ResearchFeature.OPTICS) ? 1 : 0;
int xrays = Worm.getGameState().isResearched(ResearchFeature.XRAYS) ? -1 : 0;
extraScan = (optics + xrays) * rangeIncrement / 2.0f;
boolean bigBlast = Worm.getGameState().isResearched(ResearchFeature.PLASTIC) && minimumRange > 0.0f;
extraScan += bigBlast ? 32.0f : 0.0f;
extraMinimum = bigBlast ? 32.0f : 0.0f;
}
private void addDanger(int amount) {
if (amount == 0) {
// It's a decoy
Gidrah.rethinkTargets();
return;
}
// Increase danger level nearby
float scanRadius = getScanRadius()+ MapRenderer.TILE_SIZE;
GameMap map = Worm.getGameState().getMap();
int bottomLeftY = (int) (getY() - scanRadius - 1.0f) / MapRenderer.TILE_SIZE;
int height = (int) (getY() + scanRadius + 1.0f) / MapRenderer.TILE_SIZE;
int bottomLeftX = (int) (getX() - scanRadius - 1.0f) / MapRenderer.TILE_SIZE;
int width = (int) (getX() + scanRadius + 1.0f) / MapRenderer.TILE_SIZE;
for (int yy = bottomLeftY; yy <= height; yy ++) {
float dy = getY() - yy * MapRenderer.TILE_SIZE - MapRenderer.TILE_SIZE * 0.5f;
for (int xx = bottomLeftX; xx <= width; xx ++) {
float dx = getX() - xx * MapRenderer.TILE_SIZE - MapRenderer.TILE_SIZE * 0.5f;
double dist = Math.sqrt(dx * dx + dy * dy);
if (dist <= scanRadius + 1.0f && dist > getMinimumRange()) {
map.setDanger(xx, yy, map.getDanger(xx, yy) + amount);
}
}
}
// All gidrahs rethink your routes!
Gidrah.rethinkRoutes(new Rectangle(bottomLeftX, bottomLeftY, width + 1, height + 1));
}
@Override
public void addScanners(int n) {
if (weaponFeature != null && !isGhost()) {
addDanger(-weaponFeature.getDanger());
}
super.addScanners(n);
if (weaponFeature != null && !isGhost()) {
addDanger(weaponFeature.getDanger());
}
checkAwesome();
}
@Override
public void addBatteries(int n) {
super.addBatteries(n);
if (weaponInstance != null) {
weaponInstance.addBatteries(n);
}
checkAwesome();
}
@Override
protected void adjustProximity(Building target, int delta) {
target.addTurrets(delta);
}
@Override
protected void doBuildingUpdate() {
if (weaponInstance != null && reloadSprite != null) {
reloadSprite.setLocation(getScreenX(), getScreenY());
}
updateLight();
}
@Override
protected void doBuildingDestroy() {
if (weaponInstance != null) {
weaponInstance.remove();
weaponInstance = null;
}
}
@Override
protected void doBuildingRemove() {
if (weaponFeature != null && !isGhost()) {
addDanger(-weaponFeature.getDanger());
}
}
@Override
protected void doGhostTick() {
if (rangeEffect != null) {
rangeEffect.setLocation(getX(), getY());
rangeEffect.setRadius(getScanRadius());
rangeEffect.setVisible(isVisible());
}
if (minRangeEffect != null) {
minRangeEffect.setLocation(getX(), getY());
minRangeEffect.setRadius(getMinimumRange());
minRangeEffect.setVisible(isVisible());
}
if (blastRangeEffect != null) {
blastRangeEffect.setLocation(getX(), getY());
blastRangeEffect.setRadius(weaponInstance.getBlastRange());
blastRangeEffect.setVisible(isVisible());
}
}
@Override
protected void doBuildingTick() {
if (weaponInstance == null) {
return;
}
if (!isTargetValid()) {
findTarget();
}
// Turn light to meet target
float dist = 0.0f;
float aimX = 0.0f, aimY = 0.0f;
if (target != null) {
uselessTick = 0;
aimX = (int) target.getX();
aimY = (int) target.getY();
} else {
uselessTick ++;
if (uselessTick > USELESS_WARNING_TIME && Worm.getGameState().isLevelActive()) {
uselessTick = 0;
Worm.getGameState().flagHint(Hints.SELL_TURRETS);
}
}
if (target != null && weaponInstance.getAmmo() > 0) {
targetLightAlpha = 255;
lightsOffTick = 0;
float tx = aimX;
float ty = aimY;
float dx = tx - lightX;
float dy = ty - lightY;
dist = (float) Math.sqrt(dx * dx + dy * dy);
if (dist > 0.0f) {
float move = lightSpeed / dist;
if (Math.abs(dx) <= lightSpeed) {
lightX = tx;
} else {
lightX += dx * move;
}
if (Math.abs(dy) <= lightSpeed) {
lightY = ty;
} else {
lightY += dy * move;
}
}
// What's the new distance?
dx = lightX - (getX() + getBeamOffsetX());
dy = lightY - (getY() + getBeamOffsetY());
if (beamSprite != null) {
beamSprite.setAngle(FPMath.fpYaklyDegrees(Math.atan2(dy, dx)));
}
} else {
if (lightsOffTick < LIGHTS_OFF_TIME) {
lightsOffTick ++;
if (lightsOffTick == LIGHTS_OFF_TIME) {
targetLightAlpha = 0;
}
}
}
if (currentLightAlpha < targetLightAlpha) {
currentLightAlpha = Math.min(targetLightAlpha, currentLightAlpha + ALPHA_ADJUST);
} else if (currentLightAlpha > targetLightAlpha) {
currentLightAlpha = Math.max(targetLightAlpha, currentLightAlpha - ALPHA_ADJUST);
}
if (beamSprite != null) {
beamSprite.setAlpha(currentLightAlpha);
}
weaponInstance.tick();
if (weaponInstance.isReady()) {
if (target != null) {
if (!weaponInstance.fire((int) aimX, (int) aimY)) {
return;
}
cancelUndo();
if (barrels != null) {
barrel ++;
if (barrel == barrels.size()) {
barrel = 0;
}
}
if (weaponInstance.getAmmo() == 0) {
SFX.noAmmo();
targetLightAlpha = 0;
updateAppearance();
reloadSprite.setAnimation(null);
reload();
} else {
reloadSprite.setAnimation(null);
// Reset color - animation changes alpha
reloadSprite.setColors(ReadableColor.WHITE);
if (heavyWeapon) {
reloadSprite.setAppearance(Res.getAmmoLarge(weaponInstance.getAmmo(), weaponInstance.getMaxAmmo()));
} else {
reloadSprite.setAppearance(Res.getAmmo(weaponInstance.getAmmo(), weaponInstance.getMaxAmmo()));
}
}
}
}
float mx = GameScreen.getInstance().getMouseX() - GameScreen.getSpriteOffset().getX();
float my = GameScreen.getInstance().getMouseY() - GameScreen.getSpriteOffset().getY();
if (isTouching(mx, my)) {
if (rangeEffect == null) {
rangeEffect = new RangeEffect(RANGE_COLOR);
rangeEffect.setLocation(getX(), getY());
rangeEffect.spawn(GameScreen.getInstance());
}
rangeEffect.setShow(true);
if (getMinimumRange() > 0.0f) {
if (minRangeEffect == null) {
minRangeEffect = new RangeEffect(MIN_RANGE_COLOR);
minRangeEffect.setLocation(getX(), getY());
minRangeEffect.spawn(GameScreen.getInstance());
}
minRangeEffect.setShow(true);
}
if (weaponInstance.getBlastRange() > 0.0f) {
if (blastRangeEffect == null) {
blastRangeEffect = new RangeEffect(BLAST_RANGE_COLOR);
blastRangeEffect.setLocation(getX(), getY());
blastRangeEffect.spawn(GameScreen.getInstance());
}
blastRangeEffect.setShow(true);
}
} else {
if (rangeEffect != null) {
rangeEffect.setShow(false);
}
if (minRangeEffect != null) {
minRangeEffect.setShow(false);
}
if (blastRangeEffect != null) {
blastRangeEffect.setShow(false);
}
}
if (rangeEffect != null) {
rangeEffect.setRadius(getScanRadius());
}
if (minRangeEffect != null) {
minRangeEffect.setRadius(getMinimumRange());
}
if (blastRangeEffect != null) {
blastRangeEffect.setRadius(weaponInstance.getBlastRange());
}
}
@Override
protected void doRemoveSpecialEffects() {
if (reloadSprite != null) {
reloadSprite.deallocate();
reloadSprite = null;
}
if (beamSprite != null) {
beamSprite.deallocate();
beamSprite = null;
}
if (rangeEffect != null) {
rangeEffect.finish();
rangeEffect = null;
}
if (minRangeEffect != null) {
minRangeEffect.finish();
minRangeEffect = null;
}
if (blastRangeEffect != null) {
blastRangeEffect.finish();
blastRangeEffect = null;
}
}
public float getBeamOffsetX() {
return beamOffsetX;
}
public float getBeamOffsetY() {
return beamOffsetY;
}
@Override
public float getOffsetX() {
if (barrels == null) {
return getBeamOffsetX();
} else {
return barrels.get(barrel).getX();
}
}
@Override
public float getOffsetY() {
if (barrels == null) {
return getBeamOffsetY();
} else {
return barrels.get(barrel).getY();
}
}
@Override
public void addCoolingTowers(int n) {
super.addCoolingTowers(n);
checkAwesome();
}
@Override
public void addReactors(int n) {
super.addReactors(n);
checkAwesome();
}
@Override
public void addAutoLoaders(int n) {
super.addAutoLoaders(n);
checkAwesome();
}
private void checkAwesome() {
if (isDecoy() || isGhost()) {
return;
}
if (!Worm.getGameState().isAwesome() && getReactors() >= 4 && getScanners() >= 4 && getBatteries() >= 4 && getCoolingTowers() >= 4 && getAutoLoaders() >= 4) {
Worm.getGameState().awardMedal(Medals.AWESOME);
Worm.getGameState().setAwesome();
}
}
private float getMinimumRange() {
return minimumRange + extraMinimum;
}
}
/**
* @param name
*/
public TurretBuildingFeature(String name) {
super(name);
}
@Override
public Building doSpawn(boolean ghost) {
return new TurretBuildingInstance(ghost);
}
@Override
public boolean isAffectedBy(BuildingFeature feature) {
if (isDecoy()) {
return feature instanceof ShieldGeneratorBuildingFeature;
} else {
return
feature instanceof ReactorBuildingFeature
|| feature instanceof ShieldGeneratorBuildingFeature
|| feature instanceof BatteryBuildingFeature
|| feature instanceof CoolingTowerBuildingFeature
|| feature instanceof ScannerBuildingFeature
|| feature instanceof AutoLoaderBuildingFeature
|| feature instanceof CloakBuildingFeature
;
}
}
public boolean isDecoy() {
return weaponFeature == null;
}
@Override
public void getResearchStats(StringBuilder stats_1_text, StringBuilder stats_2_text) {
super.getResearchStats(stats_1_text, stats_2_text);
if (!isDecoy()) {
weaponFeature.getResearchStats(stats_1_text, stats_2_text);
}
}
@Override
protected String getBuildingType() {
if (isDecoy()) {
return super.getBuildingType();
} else {
return Game.getMessage("ultraworm.researchstats.building_type_turret");
}
}
@Override
public void appendFullStats(StringBuilder dest) {
super.appendFullStats(dest);
if (weaponFeature != null) {
weaponFeature.appendFullStats(dest);
}
}
@Override
public LayersFeature getAppearance(Building building) {
TurretBuildingInstance turret = (TurretBuildingInstance) building;
if (turret.weaponInstance == null || turret.weaponInstance.getAmmo() > 0) {
return super.getAppearance(building);
} else if (turret.weaponInstance.isReloading()) {
return reloadingAppearance;
} else {
return reloadAppearance;
}
}
@Override
public void load(Element element, Loader loader) throws Exception {
super.load(element, loader);
List<Element> children = XMLUtil.getChildren(element, "barrel");
if (children != null && children.size() > 0) {
barrels = new ArrayList<Point>(children.size());
for (Element child : children) {
barrels.add(PointParser.parse(XMLUtil.getText(child, "0,0")));
}
}
}
}