package com.pointcliki.dizgruntled.logic;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import org.json.JSONException;
import org.json.JSONObject;
import org.newdawn.slick.Image;
import org.newdawn.slick.Sound;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;
import com.pointcliki.core.AnimatedSprite;
import com.pointcliki.core.Entity;
import com.pointcliki.core.Sprite;
import com.pointcliki.dizgruntled.GridLogic;
import com.pointcliki.dizgruntled.GruntzGame;
import com.pointcliki.dizgruntled.LogicProperty;
import com.pointcliki.dizgruntled.StringLogicProperty;
import com.pointcliki.dizgruntled.grunt.GruntState;
import com.pointcliki.dizgruntled.grunt.Task;
import com.pointcliki.dizgruntled.map.Map;
import com.pointcliki.dizgruntled.modifier.AssignModifier;
import com.pointcliki.dizgruntled.modifier.Attribute;
import com.pointcliki.dizgruntled.player.GruntzPlayer;
import com.pointcliki.dizgruntled.player.HumanPlayer;
import com.pointcliki.dizgruntled.rez.MonolithANI;
import com.pointcliki.dizgruntled.rez.MonolithPID;
import com.pointcliki.dizgruntled.rez.MonolithWAV;
import com.pointcliki.dizgruntled.rez.MonolithWWD;
import com.pointcliki.dizgruntled.task.GooSuckTask;
import com.pointcliki.dizgruntled.task.HoleDigTask;
import com.pointcliki.dizgruntled.task.RockBreakTask;
import com.pointcliki.dizgruntled.task.WalkTask;
import com.pointcliki.dizgruntled.task.WalkToActionTask;
import com.pointcliki.dizgruntled.utils.GruntPalette;
import com.pointcliki.event.Dispatcher;
import com.pointcliki.event.FrameEvent;
import com.pointcliki.event.Minion;
import com.pointcliki.event.PeriodicRogue;
import com.pointcliki.event.ProgressEvent;
import com.pointcliki.grid.GridCoordinate;
import com.pointcliki.grid.GridManager.GridEvent;
import com.pointcliki.movement.GridAlignedMovementOld;
import com.pointcliki.net.Player;
import com.pointcliki.transition.LinearLerper;
public class Grunt extends GridLogic {
/**
* Serial key
*/
private static final long serialVersionUID = -249620165769083641L;
public static final String[] TOOLS = new String[] {"NORMAL", "BOMB", "BOOMERANG", "BRICK", "CLUB", "GAUNTLETZ", "GLOVEZ", "GOOBER", "GRAVITYBOOTZ", "GUNHAT", "NERFGUN", "ROCK", "SHIELD", "SHOVEL", "SPRING", "SPY", "SWORD", "TIMEBOMB", "TOOB", "WAND", "WARPSTONE", "WELDER", "WINGZ"};
public static final String[] TOYS = new String[] {"NO TOY", "BABYWALKER", "BEACHBALL", "BIGWHEEL", "GOKART", "JACKINTHEBOX", "JUMPROPE", "POGOSTICK", "SCROLL", "SQUEAKTOY", "YOYO"};
public static final String[] COLORS = new String[] {"ORANGE", "GREEN", "DKGREEN", "YELLOW", "PURPLE", "PINK", "HOTPINK", "RED", "DKBLUE", "BLUE", "CYAN", "TURQ", "DKRED", "BLACK", "WHITE"};
public static final String[] AI = new String[] {"NO AI", "DUMB CHASER", "SMART CHASER", "HIT AND RUN", "DEFENDER", "POST GUARD", "OBJECT GUARD", "BOMBER", "BRICK LAYER", "GAUNTLETZ GRUNT", "GOOBERSTRAW GRUNT", "SHOVEL GRUNT", "TIMEBOMB GRUNT", "TOOL THIEF", "TOY THIEF"};
public static final String[] PLAYERS = new String[] {"human", "enemy 1", "enemy 2", "enemy 3"};
public static final Rectangle COLLISION_RECT = new Rectangle(5, 16, 22, 16);
private GruntzPlayer fPlayer;
private int fPlayerValue;
private String fTool;
private String fToy;
private String fColor;
private String fAI;
private GruntPalette fPalette;
private String fAnimationName = "";
private AnimatedSprite fAnimation;
private AnimatedSprite fCursor;
private String fDir = "SOUTH";
private Sound fVoice;
private GridAlignedMovementOld<Grunt> fMovement;
private GruntState fState;
private Task fTask;
private Sprite fHealthSprite;
private Sprite fStaminaSprite;
private PeriodicRogue<Grunt> fHurter;
private PeriodicRogue<Grunt> fStaminater;
private Minion<GridEvent> fTileWatcher;
private HashMap<String, Attribute<?>> fAttributes;
private static AssignModifier<Boolean> sFalseStateAttribute = new AssignModifier<Boolean>(0, false);
private AssignModifier<Integer> fHealth = new AssignModifier<Integer>(0, 20);
private AssignModifier<Integer> fStamina = new AssignModifier<Integer>(0, 20);
@Override
public void importFromWWD(String logic, String image, String animation, byte[] data) {
fSnapToGrid = true;
super.importFromWWD(logic, image, animation, data);
fTool = TOOLS[MonolithWWD.readPowerup(data)];
fToy = "NONE";
fColor = COLORS[MonolithWWD.readPoints(data)];
fAI = AI[MonolithWWD.readPoints(data)];
fPlayerValue = MonolithWWD.readSmarts(data);
setup();
}
@Override
public byte[] exportToWWD() {
return null;
}
@Override
public void importFromJSON(JSONObject object) {
fSnapToGrid = true;
super.importFromJSON(object);
fTool = object.optString("tool");
fToy = object.optString("toy");
fColor = object.optString("color");
fAI = object.optString("ai");
fPlayerValue = object.optInt("player");
setup();
}
@Override
public JSONObject exportToJSON() throws JSONException {
JSONObject o = super.exportToJSON();
o.put("tool", fTool);
o.put("toy", fToy);
o.put("color", fColor);
o.put("ai", fAI);
o.put("player", fPlayerValue);
return o;
}
private void setup() {
// Give AI correct tools
if (fAI.equals("GAUNTLETZ GRUNT")) fTool = "GAUNTLETZ";
else if (fAI.equals("SHOVEL GRUNT")) fTool = "SHOVEL";
else if (fAI.equals("GOOBERSTRAW GRUNT")) fTool = "GOOBER";
else if (fAI.equals("TIMEBOMB GRUNT")) fTool = "TIMEBOMB";
else if (fAI.equals("BRICKLAYER GRUNT")) fTool = "BRICK";
// Setup attributes
fAttributes = new HashMap<String, Attribute<?>>();
fAttributes.put("selectable", new Attribute<Boolean>(true));
fAttributes.put("controllable", new Attribute<Boolean>(true));
fAttributes.put("walkable", new Attribute<Boolean>(true));
fAttributes.put("hurtable", new Attribute<Boolean>(true));
fAttributes.put("health", new Attribute<Integer>(20).addModifier(fHealth));
fAttributes.put("stamina", new Attribute<Integer>(20).addModifier(fStamina));
// Create the grunt body
fPalette = new GruntPalette(fColor, GruntzGame.resourceManager().rez().file("GRUNTZ/PALETTEZ/" + fColor + "TOOL", "pal"));
animate("IDLE1", "IDLE");
fCursor = new MonolithANI(GruntzGame.resourceManager().rez().file("GAME/ANIZ/GRUNTSELECTEDSPRITE", "ani"), "GAME/IMAGEZ/GRUNTSELECTEDSPRITE").sprite();
// Health
fHealthSprite = new Sprite(new MonolithPID(GruntzGame.resourceManager().rez().file("GAME/IMAGEZ/GRUNTHEALTHSPRITE/FRAME001", "pid")).image());
fHealthSprite.position(new Vector2f(-12, -26));
fStaminaSprite = new Sprite(new MonolithPID(GruntzGame.resourceManager().rez().file("GAME/IMAGEZ/GRUNTSTAMINASPRITE/FRAME001", "pid")).image());
fStaminaSprite.position(new Vector2f(-12, -32));
// Setup the grunt movement
fMovement = new GridAlignedMovementOld<Grunt>(this, new MovementMinion(), 0, 0) {
/**
* Serial key
*/
private static final long serialVersionUID = -3074929548144342979L;
@Override
public boolean canMove(GridCoordinate target) {
TreeSet<String> traits = fMap.traits(target);
return (!traits.contains("solid") && !traits.contains("nogo") && !traits.contains("water") && gridManager().getFirstEntityOfTypeAt(target, Grunt.class, Grunt.this) == null);
}
};
fMovement.setup(500, new LinearLerper());
// Setup the tile watcher
fTileWatcher = new Minion<GridEvent>() {
public long run(com.pointcliki.event.Dispatcher<GridEvent> dispatcher, String type, GridEvent event) {
checkTile();
return Minion.CONTINUE;
};
};
fHurter = new PeriodicRogue<Grunt>(this, null, 40, 0) {
/**
* Serial key
*/
private static final long serialVersionUID = 6455636894570231644L;
@Override
public void run(Grunt entity, long currentFrame) {
if (attributeAsBoolean("hurtable")) setStateHealth(fHealth.value() - 2);
}
};
fStaminater = new PeriodicRogue<Grunt>(this, null, 4, 0) {
/**
* Serial key
*/
private static final long serialVersionUID = 6455636894570231644L;
@Override
public void run(Grunt entity, long currentFrame) {
fStamina.assign(fStamina.value() + 1);
int val = Math.max(0, attributeAsInteger("stamina"));
String s = (21 - val) + "";
while (s.length() < 3) s = "0" + s;
fStaminaSprite.image(new MonolithPID(GruntzGame.resourceManager().rez().file("GAME/IMAGEZ/GRUNTSTAMINASPRITE/FRAME" + s, "pid")).image());
if ((fStamina).value() == 20) {
removeChild(fStaminaSprite);
cancel();
}
}
};
}
private void setStateHealth(int h) {
fHealth.assign(h);
int val = Math.max(0, attributeAsInteger("health"));
String s = (21 - val) + "";
while (s.length() < 3) s = "0" + s;
fHealthSprite.image(new MonolithPID(GruntzGame.resourceManager().rez().file("GAME/IMAGEZ/GRUNTHEALTHSPRITE/FRAME" + s, "pid")).image());
}
public void depleteStamina(int rate) {
if (fStaminater.isRunning()) fStaminater.cancel();
addChild(fStaminaSprite, 101);
fStamina.assign(0);
int val = Math.max(0, attributeAsInteger("stamina"));
String s = (21 - val) + "";
while (s.length() < 3) s = "0" + s;
fStaminaSprite.image(new MonolithPID(GruntzGame.resourceManager().rez().file("GAME/IMAGEZ/GRUNTSTAMINASPRITE/FRAME" + s, "pid")).image());
fStaminater.period(rate);
fStaminater.begin();
}
public boolean attributeAsBoolean(String s) {
return (Boolean) fAttributes.get(s).value();
}
public int attributeAsInteger(String s) {
return (Integer) fAttributes.get(s).value();
}
@SuppressWarnings("unchecked")
public Attribute<Boolean> attributeBoolean(String s) {
return (Attribute<Boolean>) fAttributes.get(s);
}
@SuppressWarnings("unchecked")
public Attribute<Integer> attributeInteger(String s) {
return (Attribute<Integer>) fAttributes.get(s);
}
public void rawAnimate(String ani, String graphics) {
// Get ani first in case it causes an exception
AnimatedSprite sprite = new MonolithANI(GruntzGame.resourceManager().rez().file("GRUNTZ/ANIZ/" + ani, "ani"), "GRUNTZ/IMAGEZ/" + graphics).sprite(fPalette);
if (fAnimation != null) fAnimation.cleanup();
fAnimation = sprite;
fAnimationName = "";
addChild(fAnimation, 50);
fSpan = fAnimation.span();
if (fMap != null) fAnimation.start();
}
public void rawAnimate(String ani, String graphics, int frames) {
// Get ani first in case it causes an exception
AnimatedSprite sprite = new MonolithANI(GruntzGame.resourceManager().rez().file("GRUNTZ/ANIZ/" + ani, "ani"), "GRUNTZ/IMAGEZ/" + graphics).sprite(fPalette);
sprite.splice(0, frames);
if (fAnimation != null) fAnimation.cleanup();
fAnimation = sprite;
fAnimationName = "";
addChild(fAnimation, 50);
fSpan = fAnimation.span();
if (fMap != null) fAnimation.start();
}
public void animate(String ani, String graphics) {
rawAnimate(fTool + "GRUNT/" + ani, fTool + "GRUNT/" + fDir + "/" + graphics);
fAnimationName = ani;
}
public void animate(String ani, String graphics, GridCoordinate dir) {
String direction = dir.toName();
// Check we're not already doing this animation
if (fAnimationName.equals(ani) && direction.equals(fDir)) return;
fDir = direction;
animate(ani, graphics);
}
@Override
public void init(Map map) {
super.init(map);
fAnimation.start();
// Put in grid manager
if (!map.editing() && fPlayerValue == 0) {
fPlayer = levelScene().player("human");
fPlayer.add(this);
}
enable();
}
@Override
public void select() {
boolean again = fSelected;
if (!fMap.editing()) {
// Decide on a sound
String sound;
if (!attributeAsBoolean("selectable")) return;
// Select the grunt
if (fPlayer instanceof HumanPlayer) {
((HumanPlayer) fPlayer).selectGrunt(this);
if (!again) {
addChild(fCursor, 0);
addChild(fHealthSprite, 100);
if (fStamina.value() < 20) addChild(fStaminaSprite, 101);
fCursor.start();
}
sound = "ACKNOWLEDGE/SELECTGRUNT1" + ((char) ((int) Math.floor(Math.random() * 11) + 65));
} else {
int r = (int) Math.floor(Math.random() * 11) + 65;
sound = "ENEMYSELECT/SELECTGRUNT" + (char) r;
}
MonolithWAV wav = new MonolithWAV(GruntzGame.resourceManager().voicez().file("VOICES/" + sound, "wav"));
speak(wav.sound());
}
super.select();
}
@Override
public void deselect() {
if (!fSelected) return;
super.deselect();
fCursor.stop();
removeChild(fCursor);
removeChild(fHealthSprite);
removeChild(fStaminaSprite);
}
public void speak(Sound s) {
if (fVoice != null) fVoice.stop();
fVoice = s;
if (!GruntzGame.instance().mute() && fVoice != null) fVoice.play(1, 0.2f);
}
public void speak(String s) {
MonolithWAV wav = new MonolithWAV(GruntzGame.resourceManager().voicez().file("VOICES/" + s, "wav"));
speak(wav.sound());
}
public void move(GridCoordinate xy) {
// Check whether the grunt is accepting commands
if (!attributeAsBoolean("controllable")) return;
state(GruntState.MOVING);
// Start a path find
if (fTask != null) fTask.cancel();
fTask = new WalkTask(this, xy);
boolean okay = fTask.start();
if (okay) {
speak("ACKNOWLEDGE/GOODCOMMAND" + ((char) ((int) Math.floor(Math.random() * 10) + 65)));
// Check we can walk
if (!fMovement.isRunning() && attributeAsBoolean("walkable")) fTask.next();
} else {
speak("ACKNOWLEDGE/BADCOMMAND" + ((char) ((int) Math.floor(Math.random() * 11) + 65)));
fTask = null;
}
}
public void useTool(GridCoordinate xy) {
// Check whether the grunt is accepting commands
if (!attributeAsBoolean("controllable")) return;
if (!canUseToolAt(xy)) return;
state(GruntState.MOVING);
if (fTask != null) fTask.cancel();
fTask = new WalkToActionTask(this, xy);
boolean okay = fTask.start();
if (okay) {
speak("ACKNOWLEDGE/GOODCOMMAND" + ((char) ((int) Math.floor(Math.random() * 10) + 65)));
// Check we can walk
if (!fMovement.isRunning() && attributeAsBoolean("walkable")) fTask.next();
} else {
speak("ACKNOWLEDGE/BADCOMMAND" + ((char) ((int) Math.floor(Math.random() * 11) + 65)));
fTask = null;
}
}
public boolean canUseToolAt(GridCoordinate xy) {
TreeSet<String> traits = map().traits(xy);
if (fTool.equals("GAUNTLETZ") && traits.contains("break")) return true;
else if (fTool.equals("SHOVEL") && traits.contains("dig")) return true;
else if (fTool.equals("GOOBER") && gridManager().getEntitiesOfTypeAt(xy, GruntPuddle.class).size() > 0) return true;
return false;
}
public void performAction(final GridCoordinate xy) {
fMovement.stop();
// Check we can still use the tool
if (!canUseToolAt(xy) || fStamina.value() < 20) {
if (fTask != null) fTask.cancel();
fTask = null;
animate("IDLE1", "IDLE");
state(GruntState.IDLE);
return;
}
Task t = null;
if (fTool.equals("GAUNTLETZ")) t = new RockBreakTask(this, xy);
else if (fTool.equals("SHOVEL")) t = new HoleDigTask(this, xy);
else if (fTool.equals("GOOBER")) t = new GooSuckTask(this, xy);
if (t != null) {
boolean okay = t.start();
if (okay) {
fTask = t;
t.next();
state(GruntState.ACTING);
animate("ITEM", "ITEM", xy.subtract(fTile));
} else {
if (fTask != null) fTask.cancel();
fTask = null;
animate("IDLE1", "IDLE");
state(GruntState.IDLE);
}
} else {
if (fTask != null) fTask.cancel();
fTask = null;
animate("IDLE1", "IDLE");
state(GruntState.IDLE);
}
}
public void finishAction() {
fTask = null;
checkTile();
}
public void win() {
rawAnimate("EXITZ/ONE", "EXITZ", 196);
doDie();
}
public void squash() {
if (state() != GruntState.DYING) {
doSquashDeath();
doDie();
}
}
@Override
public void cleanup() {
if (fPlayer != null) fPlayer.remove(this);
gridManager().dispatcher().removeGridMinion(fTile, "tilechange", fTileWatcher);
fTileWatcher = null;
if (fTask != null) fTask.cancel();
fTask = null;
fPlayer = null;
fTile = null;
fDir = null;
fPalette = null;
fMovement = null;
fState = null;
fAttributes = null;
super.cleanup();
fAnimation = null;
fHealthSprite = null;
fStaminaSprite = null;
fHurter.cleanup();
fStaminater.cleanup();
}
private class MovementMinion extends Minion<ProgressEvent<Grunt>> {
@Override
public long run(Dispatcher<ProgressEvent<Grunt>> dispatcher, String type, ProgressEvent<Grunt> event) {
if (type.equals(GridAlignedMovementOld.ON_BEGIN)) {
pressureManager().tileDepressure(fTile);
} else if (type.equals(GridAlignedMovementOld.ON_END)) {
// Allow walking again, for example if we've been folling an arrow
attributeBoolean("walkable").removeModifier(sFalseStateAttribute);
pressureManager().tilePressure(fTile);
checkTile();
} else if (type.equals(GridAlignedMovementOld.PROGRESS_LAST_STOP)) {
if (fState == GruntState.MOVING) {
animate("IDLE1", "IDLE");
state(GruntState.WAITING_TO_MOVE);
}
gridManager().dispatcher().addGridMinion(fTile, "tilechange", fTileWatcher);
} else if (type.equals(GridAlignedMovementOld.PROGRESS_FIRST_START)) {
gridManager().dispatcher().removeGridMinion(fTile, "tilechange", fTileWatcher);
}
return Minion.CONTINUE;
}
}
protected void checkTile() {
TreeSet<String> traits = fMap.traits(fTile);
boolean done = false;
// Check we're still alive
if (state() == GruntState.DYING) return;
done = checkForDamage(traits);
if (!done) done = checkForWin(traits);
if (!done) done = checkForDeath(traits);
if (!done) done = checkForHelpBook();
if (!done) done = checkForPickup();
if (!done) done = checkForArrows(traits);
if (!done) {
if (fTask != null) done = fTask.next();
if (!done) {
fMovement.stop();
animate("IDLE1", "IDLE");
state(GruntState.IDLE);
}
}
}
private boolean checkForWin(TreeSet<String> traits) {
if (!fTool.equals("WARPSTONE")) return false;
if (gridManager().getFirstEntityOfTypeAt(fTile, Fort.class) != null) {
if (fPlayer != null) fPlayer.win();
speak("EXITZ/ONEA");
return true;
}
return false;
}
protected boolean checkForDeath(Set<String> traits) {
boolean die = false;
if (traits.contains("hole")) {
die = true;
doHoleDeath();
}
if (traits.contains("solid") || traits.contains("nogo")) {
die = true;
doFlyUpDeath();
}
if (traits.contains("water")) {
die = true;
doSinkDeath();
}
if (traits.contains("death")) {
die = true;
doSinkDeath();
}
if (attributeAsInteger("health") == 0) {
die = true;
doHealthDeath();
}
if (die) {
doDie();
return true;
}
return false;
}
protected boolean checkForDamage(Set<String> traits) {
if (traits.contains("pain")) {
if (!fHurter.isRunning()) fHurter.begin();
} else {
if (fHurter.isRunning()) fHurter.cancel();
}
return false;
}
protected boolean checkForHelpBook() {
final HelpBook book = gridManager().getFirstEntityOfTypeAt(fTile, HelpBook.class);
if (book != null) {
state(GruntState.PICKUP);
attributeBoolean("walkable").addModifier(sFalseStateAttribute);
fMovement.stop();
rawAnimate("PICKUPS/HELPBOX", "PICKUPS");
GruntzGame.resourceManager().playSound("GAME/SOUNDZ/HELPBOOK");
speak("PICKUPZ/HELPBOOKPICKUPA");
book.cleanup();
// Clean up the grunt after the read animation ends
frameManager().queue(new Minion<FrameEvent>() {
public long run(Dispatcher<FrameEvent> dispatcher, String type, FrameEvent event) {
levelScene().hud().showText(book.text());
return Minion.FINISH;
};
}, fAnimation.frameDuration() - 1);
// Clean up the grunt after the read animation ends
frameManager().queue(new Minion<FrameEvent>() {
public long run(Dispatcher<FrameEvent> dispatcher, String type, FrameEvent event) {
// Allow walking again
attributeBoolean("walkable").removeModifier(sFalseStateAttribute);
Grunt.this.checkTile();
return Minion.FINISH;
};
}, fAnimation.frameDuration());
return true;
}
return false;
}
protected boolean checkForPickup() {
final Pickup pickup = gridManager().getFirstEntityOfTypeAt(fTile, Pickup.class);
if (pickup != null) {
GruntzGame.resourceManager().playSound("GAME/SOUNDZ/TREASURE");
pickup.cleanup();
state(GruntState.PICKUP);
attributeBoolean("walkable").addModifier(sFalseStateAttribute);
try {
rawAnimate("PICKUPS/" + pickup.item(), "PICKUPS");
} catch (NullPointerException e) {
try {
rawAnimate("PICKUPS/" + pickup.item().substring(0, pickup.item().length() - 1), "PICKUPS");
} catch (NullPointerException e2) {
rawAnimate("PICKUPS/" + pickup.item().substring(0, pickup.item().length() - 2), "PICKUPS");
}
}
fMovement.stop();
// Carry on after animation has ended
frameManager().queue(new Minion<FrameEvent>() {
public long run(Dispatcher<FrameEvent> dispatcher, String type, FrameEvent event) {
if (pickup.type().equals("TOOL")) {
fTool = pickup.item();
// Check for warpstone
if (fTool.startsWith("WARPSTONE")) fTool = "WARPSTONE";
// Remove Z if not required
if (fTool.endsWith("Z") && !fTool.equals("GAUNTLETZ") && !fTool.equals("GLOVEZ") && !fTool.equals("GRAVITYBOOTZ") && !fTool.equals("WINGZ")) fTool = fTool.substring(0, fTool.length() - 1);
} else if (pickup.type().equals("TOY")) fToy = pickup.item();
// Allow walking again
attributeBoolean("walkable").removeModifier(sFalseStateAttribute);
Grunt.this.checkTile();
return Minion.FINISH;
};
}, fAnimation.frameDuration());
return true;
}
return false;
}
protected boolean checkForArrows(Set<String> traits) {
if (traits.contains("arrow")) {
fTask = null;
if (traits.contains("downArrow")) {
fMovement.move(GridCoordinate.SOUTH);
animate("WALK", "WALK", GridCoordinate.SOUTH);
} else if (traits.contains("leftArrow")) {
fMovement.move(GridCoordinate.WEST);
animate("WALK", "WALK", GridCoordinate.WEST);
} else if (traits.contains("rightArrow")) {
fMovement.move(GridCoordinate.EAST);
animate("WALK", "WALK", GridCoordinate.EAST);
} else if (traits.contains("upArrow")) {
fMovement.move(GridCoordinate.NORTH);
animate("WALK", "WALK", GridCoordinate.NORTH);
}
fTask = null;
state(GruntState.MOVING);
attributeBoolean("walkable").addModifier(sFalseStateAttribute);
return true;
}
return false;
}
protected void doDie() {
state(GruntState.DYING);
attributeBoolean("selectable").addModifier(sFalseStateAttribute);
attributeBoolean("controllable").addModifier(sFalseStateAttribute);
attributeBoolean("walkable").addModifier(sFalseStateAttribute);
fMovement.pause();
if (fTask != null) fTask.cancel();
fTask = null;
deselect();
gridManager().removeObject(fTile, Grunt.this);
// Clean up the grunt after the death animation ends
frameManager().queue(new Minion<FrameEvent>() {
public long run(Dispatcher<FrameEvent> dispatcher, String type, FrameEvent event) {
Grunt.this.cleanup();
return Minion.FINISH;
};
}, fAnimation.frameDuration());
}
protected void doHoleDeath() {
rawAnimate("DEATHZ/HOLE", "DEATHZ/HOLE");
GruntzGame.resourceManager().playSound("GRUNTZ/SOUNDZ/DEATHZ/DEATHZHOLEZ1A");
frameManager().queue(new Minion<FrameEvent>() {
public long run(Dispatcher<FrameEvent> dispatcher, String type, FrameEvent event) {
GruntzGame.resourceManager().playSound("GRUNTZ/SOUNDZ/DEATHZ/DEATHZHOLEZ1B");
return Minion.FINISH;
};
}, 40);
}
protected void doSquashDeath() {
rawAnimate("DEATHZ/SQUASH", "DEATHZ/SQUASH");
order(-1000);
GruntzGame.resourceManager().playSound("GRUNTZ/SOUNDZ/DEATHZ/DEATHZSQUASH1A");
speak(new MonolithWAV(GruntzGame.resourceManager().voicez().file("VOICES/DEATHZ/EXPLODEA", "wav")).sound());
}
protected void doHealthDeath() {
rawAnimate(fTool + "GRUNT/DEATH", fTool + "GRUNT/DEATH");
}
protected void doFlyUpDeath() {
rawAnimate("DEATHZ/FLYUP", "DEATHZ/FLYUP", 15);
GruntzGame.resourceManager().playSound("GRUNTZ/SOUNDZ/DEATHZ/DEATHZEXPLODE1A");
}
protected void doSinkDeath() {
rawAnimate("DEATHZ/SINK", "DEATHZ/SINK");
GruntzGame.resourceManager().playSound("GRUNTZ/SOUNDZ/DEATHZ/DEATHZSINK1B");
}
@Override
public Entity position(Vector2f position) {
order((int) position.y - 40);
return super.position(position);
}
public GruntzPlayer player() {
return fPlayer;
}
public GridAlignedMovementOld<Grunt> movement() {
return fMovement;
}
public void state(GruntState s) {
fState = s;
}
public GruntState state() {
return fState;
}
@Override
public String toString() {
return "[Grunt #" + fID + " " + fTool + " " + fToy + "]";
}
@Override
public void initProperties() {
fProperties = new LogicProperty[] {
new StringLogicProperty("tool") {
@Override
public String description() {
return "The tool the grunt starts with";
}
@Override
public String value() {
return fTool;
}
@Override
public String[] choices() {
return TOOLS;
}
@Override
public void choice(int i) {
fTool = TOOLS[i];
animate("IDLE1", "IDLE");
}
},
new StringLogicProperty("toy") {
@Override
public String description() {
return "The toy the grunt starts with";
}
@Override
public String value() {
return fToy;
}
@Override
public String[] choices() {
return TOYS;
}
@Override
public void choice(int i) {
fToy = TOYS[i];
}
},
new StringLogicProperty("color") {
@Override
public String description() {
return "The color of the grunt";
}
@Override
public String value() {
return fColor;
}
@Override
public String[] choices() {
return COLORS;
}
@Override
public void choice(int i) {
fColor = COLORS[i];
fPalette = new GruntPalette(fColor, GruntzGame.resourceManager().rez().file("GRUNTZ/PALETTEZ/" + fColor + "TOOL", "pal"));
animate("IDLE1", "IDLE");
}
},
new StringLogicProperty("player") {
@Override
public String description() {
return "The player of the grunt";
}
@Override
public String value() {
return PLAYERS[fPlayerValue];
}
@Override
public String[] choices() {
return PLAYERS;
}
@Override
public void choice(int i) {
fPlayerValue = i;
}
},
new StringLogicProperty("ai") {
@Override
public String description() {
return "The AI type of the grunt";
}
@Override
public String value() {
return fAI;
}
@Override
public String[] choices() {
return AI;
}
@Override
public void choice(int i) {
fAI = AI[i];
}
}
};
}
@Override
public String name() {
return "Grunt";
}
public int toolID() {
for (int i = 0; i < TOOLS.length; i++) if (TOOLS[i].equals(fTool)) return i;
return 0;
}
public int toyID() {
for (int i = 0; i < TOYS.length; i++) if (TOYS[i].equals(fToy)) return i;
return 0;
}
public static AnimatedSprite editorIcon(JSONObject object) throws JSONException {
GruntPalette pal = new GruntPalette(object.getString("color"), GruntzGame.resourceManager().rez().file("GRUNTZ/PALETTEZ/" + object.getString("color") + "TOOL", "pal"));
MonolithPID pid = GruntzGame.resourceManager().pid("GRUNTZ/IMAGEZ/" + object.getString("tool") + "GRUNT/SOUTH/IDLE/FRAME001", pal);
return new AnimatedSprite(new Image[] {pid.image()}, new Vector2f[] {pid.offset()});
}
}