From 8922e2eae49a9ca7616620f93936d4f99dd47911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Tue, 8 Dec 2015 15:28:46 +0100 Subject: Map: split into smaller inherited classes --- core/src/ch/asynk/rustanddust/game/Map.java | 648 +++------------------ .../ch/asynk/rustanddust/game/battles/Map00.java | 1 - .../src/ch/asynk/rustanddust/game/map/Map0Hex.java | 107 ++++ .../ch/asynk/rustanddust/game/map/Map1Units.java | 117 ++++ .../ch/asynk/rustanddust/game/map/Map2Moves.java | 91 +++ .../asynk/rustanddust/game/map/Map3Animations.java | 143 +++++ .../asynk/rustanddust/game/map/Map4Commands.java | 236 ++++++++ 7 files changed, 778 insertions(+), 565 deletions(-) create mode 100644 core/src/ch/asynk/rustanddust/game/map/Map0Hex.java create mode 100644 core/src/ch/asynk/rustanddust/game/map/Map1Units.java create mode 100644 core/src/ch/asynk/rustanddust/game/map/Map2Moves.java create mode 100644 core/src/ch/asynk/rustanddust/game/map/Map3Animations.java create mode 100644 core/src/ch/asynk/rustanddust/game/map/Map4Commands.java diff --git a/core/src/ch/asynk/rustanddust/game/Map.java b/core/src/ch/asynk/rustanddust/game/Map.java index ecb24d0..b31410f 100644 --- a/core/src/ch/asynk/rustanddust/game/Map.java +++ b/core/src/ch/asynk/rustanddust/game/Map.java @@ -1,610 +1,130 @@ package ch.asynk.rustanddust.game; -import com.badlogic.gdx.audio.Sound; -import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import ch.asynk.rustanddust.RustAndDust; -import ch.asynk.rustanddust.engine.Pawn; -import ch.asynk.rustanddust.engine.Board; -import ch.asynk.rustanddust.engine.Tile; -import ch.asynk.rustanddust.engine.Faction; -import ch.asynk.rustanddust.engine.Move; + import ch.asynk.rustanddust.engine.SelectedTile; -import ch.asynk.rustanddust.engine.ObjectiveSet; -import ch.asynk.rustanddust.engine.OrderList; -import ch.asynk.rustanddust.engine.Orientation; import ch.asynk.rustanddust.engine.Meteorology; -import ch.asynk.rustanddust.engine.PathBuilder; -import ch.asynk.rustanddust.engine.gfx.Moveable; -import ch.asynk.rustanddust.engine.gfx.Animation; -import ch.asynk.rustanddust.engine.gfx.animations.AnimationSequence; -import ch.asynk.rustanddust.engine.gfx.animations.DiceAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.FireAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.TankFireAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.InfantryFireAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.PromoteAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.DestroyAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.SoundAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.RunnableAnimation; -import ch.asynk.rustanddust.engine.gfx.animations.MoveToAnimation.MoveToAnimationCb; - -import ch.asynk.rustanddust.ui.Position; +import ch.asynk.rustanddust.game.Unit; +import ch.asynk.rustanddust.game.Engagement; +import ch.asynk.rustanddust.game.map.Map4Commands; -public abstract class Map extends Board implements MoveToAnimationCb, ObjectiveSet.ObjectiveCb +public abstract class Map extends Map4Commands { - private final Ctrl ctrl; - - protected final HexSet moves; - protected final PathBuilder paths; - - protected final UnitList moveableUnits; - protected final UnitList targetUnits; - protected final UnitList assistUnits; - protected final UnitList breakthroughUnits; - protected final UnitList activatedUnits; - - protected final ObjectiveSet objectives; protected final Meteorology meteorology; - private final DestroyAnimation destroy; - private final Sound tankMoveSound; - private final Sound infantryMoveSound; - private Sound sound; - private long soundId = -1; - - private OrderList commands; - - public abstract void init(); - public abstract void turnDone(); - public abstract void actionDone(); - protected abstract void setup(); - protected abstract void resolveEngagement(Engagement e); - protected abstract int engagementCost(Engagement e); - public Map(final RustAndDust game, String map, String hex) { - super(game.factory, game.manager.get(map, Texture.class), - new SelectedTile(game.manager.get(hex, Texture.class), new float[] {.1f, .1f, .1f, .1f, .3f, .1f} )); - this.ctrl = game.ctrl; - this.destroy = new DestroyAnimation(); - this.tankMoveSound = game.manager.get("sounds/tank_move.mp3", Sound.class); - this.infantryMoveSound = game.manager.get("sounds/infantry_move.mp3", Sound.class); - DiceAnimation.init(game.manager.get("data/dice.png", Texture.class), 16, 9, game.manager.get("sounds/dice.mp3", Sound.class)); - PromoteAnimation.init(game.manager.get("data/hud.atlas", TextureAtlas.class), - game.manager.get("sounds/promote_us.mp3", Sound.class), - game.manager.get("sounds/promote_ge.mp3", Sound.class)); - FireAnimation.init( - game.manager.get("data/infantry_fire.png", Texture.class), 1, 8, - game.manager.get("data/tank_fire.png", Texture.class), 1, 8, - game.manager.get("data/explosions.png", Texture.class), 16, 8, - game.manager.get("sounds/infantry_fire.mp3", Sound.class), - game.manager.get("sounds/tank_fire.mp3", Sound.class), - game.manager.get("sounds/tank_fire_short.mp3", Sound.class), - game.manager.get("sounds/explosion.mp3", Sound.class), - game.manager.get("sounds/explosion_short.mp3", Sound.class) + super(game, + game.manager.get(map, Texture.class), + new SelectedTile(game.manager.get(hex, Texture.class), new float[] {.1f, .1f, .1f, .1f, .3f, .1f} ) ); - setup(); - - moves = new HexSet(this, 40); - paths = new PathBuilder(this, 10, 20, 5, 10); - - moveableUnits = new UnitList(6); - targetUnits = new UnitList(10); - assistUnits = new UnitList(6); - breakthroughUnits = new UnitList(4); - activatedUnits = new UnitList(7); - - objectives = new ObjectiveSet(this, 4); - meteorology = new Meteorology(); - commands = new OrderList(); - } - - @Override - public void dispose() - { - super.dispose(); - clearAll(); - destroy.dispose(); - paths.dispose(); - DiceAnimation.free(); - PromoteAnimation.free(); - FireAnimation.free(); - commands.dispose(); - Command.clearPool(); - Engagement.clearPool(); - } - - public void clearAll() - { - moves.clear(); - paths.clear(); - moveableUnits.clear(); - targetUnits.clear(); - assistUnits.clear(); - breakthroughUnits.clear(); - activatedUnits.clear(); - } - - public Hex getHexAt(float x, float y) - { - return (Hex) getTileAt(x, y); - } - - public Hex getHex(int col, int row) - { - return (Hex) getTile(col, row); - } - - public void addObjective(int col, int row, Army army) - { - addObjective(col, row, army, true); - } - - public void addHoldObjective(int col, int row, Army army) - { - addObjective(col, row, army, false); - } - - private void addObjective(int col, int row, Army army, boolean persistent) - { - Hex hex = getHex(col, row); - objectives.add(hex, army, persistent); - showObjective(hex, army, !persistent); - } - - private void claim(Hex hex, Army army) - { - showObjective(hex, objectives.claim(hex, army)); - } - - private void unclaim(Hex hex) - { - showObjective(hex, objectives.unclaim(hex)); - } - - public boolean movesContains(Hex hex) - { - return moves.contains(hex); - } - - public int movesCollect(Unit unit) - { - if (unit.canMove()) - return collectPossibleMoves(unit, moves.asTiles()); - - moves.clear(); - return 0; } - public void pathsClear() { paths.clear(); } - - public int pathsSize() { return paths.size(); } - - public void pathsInit(Unit unit) { paths.init(unit); } - - public void pathsInit(Unit unit, Hex hex) { paths.init(unit, hex); } - - public boolean pathsIsSet() { return paths.isSet(); } - - public boolean pathsCanExit(Orientation o) { return paths.canExit(o); } - - public void pathsSetExit(Orientation o) { paths.setExit(o); } - - public int pathsBuild(Hex hex) { return pathsBuild(hex); } - - public boolean pathsContains(Hex hex) { return paths.contains(hex); } - - public void pathsSetOrientation(Orientation o) { paths.orientation = o; } - - public Hex pathsTo() { return (Hex) paths.to; } - - public int pathsChooseOne() { return paths.choosePath(); } - - public int pathsToggleHex(Hex hex) + public void init() { - boolean enable = !hex.isOverlayEnabled(Hex.MOVE); - enableOverlayOn(hex, Hex.MOVE, enable); - return paths.toggleCtrlTile(hex); + actionDone(); } - public int collectTargets(Unit unit, UnitList foes) + public void turnDone() { - if (unit.canEngage()) - return collectPossibleTargets(unit, foes.asPawns(), targetUnits.asPawns()); + RustAndDust.debug("TurnDone", String.format(" Processed Commands : %d", commandsSize())); - targetUnits.clear(); - return 0; - } - - public int collectMoveable(Unit unit) - { - if (unit.canHQMove()) - collectMoveAssists(unit, moveableUnits.asPawns()); - else - moveableUnits.clear(); + if (objectives.modifiedCount() > 0) + throw new RuntimeException("objectives not cleared"); - if (unit.canMove()) - moveableUnits.add(unit); - - return moveableUnits.size(); + // FIXME do something with these Commands + commandsClear(); } - public int collectAssists(Unit unit, Unit target, UnitList units) + public void actionDone() { - int s = collectAttackAssists(unit, target, units.asPawns(), assistUnits.asPawns()); - activatedUnits.add(unit); - return s; + objectives.forget(); } - public boolean toggleAssist(Unit unit) - { - if (activatedUnits.contains(unit)) { - activatedUnits.remove(unit); - unit.hideAttack(); - unit.showAttackAssist(); - return false; - } else { - activatedUnits.add(unit); - unit.showAttack(); - unit.hideAttackAssist(); - return true; - } - } - - public void collectUpdate(Unit unit) - { - movesHide(); - unitsMoveableHide(); - movesCollect(unit); - collectMoveable(unit); - movesShow(); - unitsMoveableShow(); - activatedUnits.clear(); - } - - // -> implement MoveToAnimationCb - - @Override - public void moveToAnimationEnter(Moveable moveable, float x, float y, float r) - { - claim(getHexAt(x, y), (Army) moveable.getFaction()); - } - - @Override - public void moveToAnimationLeave(Moveable moveable, float x, float y, float r) + public void clearAll() { - unclaim(getHexAt(x, y)); + clearMoves(); + clearUnits(); } @Override - public void moveToAnimationDone(Moveable moveable, float x, float y, float r) - { - } - - // <- implement MoveToAnimationCb - - private int process(Unit unit, Move move) - { - RustAndDust.debug(" Move", String.format("%s %s", move.type, move.toString())); - - int r = 1; - - switch(move.type) { - case REGULAR: - initMove(unit); - movePawn(unit, move, this); - r = moveableUnits.size(); - break; - case EXIT: - initMove(unit); - movePawn(unit, move, this); - ctrl.player.unitWithdraw(unit); - r = moveableUnits.size(); - break; - case SET: - setPawnOnto(unit, move); - ctrl.player.unitEntry(unit); - claim((Hex) move.to, unit.getArmy()); - break; - case ENTER: - enterPawn(unit, move); - ctrl.player.unitEntry(unit); - claim((Hex) move.to, unit.getArmy()); - break; - default: - System.err.println(String.format("process wrong Move type %s", move.type)); - r = -1; - break; - } - - return r; - } - - private int promoteUnit(final Unit unit, final Player player) + protected int engagementCost(Engagement e) { - activatedUnits.add(unit); - - Hex hex = unit.getHex(); - AnimationSequence seq = AnimationSequence.get(2); - seq.addAnimation(PromoteAnimation.get((unit.getArmy() == Army.US), hex.getX(), hex.getY(), ctrl.cfg.fxVolume)); - seq.addAnimation ( RunnableAnimation.get(unit, new Runnable() { - @Override - public void run() { - player.promote(unit); - } - })); - addAnimation(seq); + if ((activatedUnits.size() == 1) && e.attacker.isA(Unit.UnitType.AT_GUN) && e.defender.isHardTarget()) + return 0; return 1; } - private int process(Command cmd) - { - RustAndDust.debug("Command", cmd.toString()); - - int r = 1; - - switch(cmd.type) { - case MOVE: - r = process(cmd.unit, cmd.move); - break; - case PROMOTE: - r = promoteUnit(cmd.unit, cmd.player); - break; - case ENGAGE: - resolveEngagement(cmd.engagement); - r = doEngagement(cmd.engagement); - break; - default: - System.err.println(String.format("process wrong Command type %s", cmd.type)); - r = -1; - break; - } - - if (r != -1) - commands.add(cmd); - - return r; - } - - protected int commandsSize() { return commands.size(); } - protected void commandsClear() { commands.dispose(); } - - // STATES ENTRY -> - - public void showOnBoard(final Unit unit, Hex to, Orientation o) - { - setPawnOnto(unit, to, o); - } - - public boolean setOnBoard(final Unit unit, Hex to, Orientation entry) - { - commands.dispose(unit); - return (process(getMoveCommand(unit, Move.getSet(unit, to, entry))) == 1); - } - - public boolean enterBoard(final Unit unit, Hex to, int allowedMoves) - { - Orientation entry = findBestEntry(unit, to, allowedMoves); - if (entry == Orientation.KEEP) - return false; - - return (process(getMoveCommand(unit, Move.getEnter(unit, to, entry))) == 1); - } - - public int exitBoard(final Unit unit) - { - return process(getMoveCommand(unit, paths.getExitMove())); - } - - public int moveUnit(final Unit unit) - { - return process(getMoveCommand(unit, paths.getMove())); - } - - public void revertMoves() - { - for (Unit unit: activatedUnits) { - RustAndDust.debug(" revertMove() " + unit); - revertLastPawnMove(unit); - commands.dispose(unit, Command.CommandType.MOVE); - } - activatedUnits.clear(); - objectives.revert(this); - } - - public void revertEnter(final Unit unit) - { - RustAndDust.debug(" revertEnter() "+ unit); - removePawn(unit); - objectives.revert(this); - ctrl.player.revertUnitEntry(unit); - commands.dispose(unit); - unit.reset(); - } - - public boolean engageUnit(final Unit unit, final Unit target) - { - attack(unit, target, true); - - Command cmd = Command.get(ctrl.player); - cmd.setEngage(unit, target); - return (process(cmd) == 1); - } - - public void promoteUnit(final Unit unit) - { - Command cmd = Command.get(ctrl.player); - cmd.setPromote(unit); - process(cmd); - } - - // STATES ENTRY <- - - private Command getMoveCommand(Unit unit, Move move) - { - Command cmd = Command.get(ctrl.player); - cmd.setMove(unit, move); - return cmd; - } - - private void initMove(Unit unit) - { - moveableUnits.remove(unit); - activatedUnits.add(unit); - playMoveSound(unit); - } - - private void playMoveSound(Unit unit) - { - if (unit.isA(Unit.UnitType.INFANTRY)) - sound = infantryMoveSound; - else - sound = tankMoveSound; - soundId = sound.play(ctrl.cfg.fxVolume); - } - @Override - protected void animationsOver() - { - if (soundId >= 0) { - addAnimation( SoundAnimation.get(SoundAnimation.Action.FADE_OUT, sound, soundId, ctrl.cfg.fxVolume, 0.5f)); - soundId = -1; - return; + protected void resolveEngagement(Engagement e) + { + int dice = e.d1 + e.d2; + + int distance = 0; + boolean mayReroll = false; + boolean night = meteorology.isNight(); + boolean flankAttack = false; + boolean terrainBonus = true; + + for (Unit unit : activatedUnits) { + if (unit != e.attacker) + e.addAssist(unit); + if (unit.isAce()) + mayReroll = true; + if (unit.isFlankAttack()) + flankAttack = true; + if (unit.preventDefenseOn(e.defender.getTile())) + terrainBonus = false; + if (night) { + if (distance < unit.attackDistance()) + distance = unit.attackDistance(); + } } - ctrl.animationsOver(); - } - private void addEngagementAnimation(Unit target) - { - FireAnimation.reset(); - Hex to = target.getHex(); - for (Unit u : activatedUnits) { - Hex from = u.getHex(); - float halfWidth = (u.getWidth() / 2f); - if (u.isA(Unit.UnitType.INFANTRY)) - addAnimation(InfantryFireAnimation.get(ctrl.cfg.fxVolume, from.getX(), from.getY(), to.getX(), to.getY(), halfWidth)); - else - addAnimation(TankFireAnimation.get(ctrl.cfg.fxVolume, from.getX(), from.getY(), to.getX(), to.getY(), halfWidth)); + int cnt = activatedUnits.size(); + int def = e.defender.getDefense(e.attacker.getTile()); + int flk = (flankAttack ? Unit.FLANK_ATTACK_BONUS : 0); + int tdf = (terrainBonus ? e.defender.getTile().defense() : 0); + int wdf = 0; + if (night) { + if (distance > 3) + wdf = 3; + else if (distance > 2) + wdf = 2; + else if (distance > 1) + wdf = 1; } - } - - private int doEngagement(Engagement e) - { - breakthroughUnits.clear(); - activatedUnits.clear(); - - activatedUnits.add(e.attacker); - for (Unit u : e.assists) - activatedUnits.add(u); - - for (Unit u : activatedUnits) { - u.engage(); - if (u.canBreak()) - breakthroughUnits.add(u); + int s1 = (dice + cnt + flk); + int s2 = (def + tdf + wdf); + + boolean success = false; + if (dice == 2) { + success = false; + } else if (dice == 12) { + success = true; + } else { + success = (s1 >= s2); } - - if (e.success) { - unclaim(e.defender.getHex()); - removePawn(e.defender); - destroy.set(2f, e.defender); - addAnimation(destroy); + if (!success && mayReroll) { + dice = e.d3 + e.d4; + s1 = (dice + cnt + flk); + if (dice == 2) { + success = false; + } else if (dice == 12) { + success = true; + } else { + success = (s1 >= s2); + } + } else { + e.d3 = 0; + e.d4 = 0; } - ctrl.hud.engagementSummary(e); - addEngagementAnimation(e.defender); - - if (engagementCost(e) == 0) - activatedUnits.clear(); - - return (e.success ? 1 : 0); - } - - public Unit unitsMoveableGet(int i) { return moveableUnits.get(i); } - - public void unitsTargetClear() { targetUnits.clear(); } - public void unitsActivatedClear() { activatedUnits.clear(); } - - public int unitsActivatedSize() { return activatedUnits.size(); } - public int unitsMoveableSize() { return moveableUnits.size(); } - public int unitsBreakThroughSize() { return breakthroughUnits.size(); } - - public boolean unitsTargetContains(Unit unit) { return targetUnits.contains(unit); } - public boolean unitsAssistContains(Unit unit) { return assistUnits.contains(unit); } - public boolean unitsMoveableContains(Unit unit) { return moveableUnits.contains(unit); } - public boolean unitsBreakThroughContains(Unit unit) { return breakthroughUnits.contains(unit); } - - public void unitsTargetShow() { unitsShowOverlay(targetUnits, Unit.TARGET, true); } - public void unitsTargetHide() { unitsShowOverlay(targetUnits, Unit.TARGET, false); } - public void unitsAssistShow() { unitsShowOverlay(assistUnits, Unit.MAY_FIRE, true); } - public void unitsAssistHide() { unitsShowOverlay(assistUnits, Unit.MAY_FIRE, false); unitsShowOverlay(assistUnits, Unit.FIRE, false); } - public void unitsMoveableShow() { unitsShowOverlay(moveableUnits, Unit.MOVE, true); } - public void unitsMoveableHide() { unitsShowOverlay(moveableUnits, Unit.MOVE, false); } - public void unitsBreakThroughShow() { unitsShowOverlay(breakthroughUnits, Unit.MOVE, true); } - public void unitsBreakThroughHide() { unitsShowOverlay(breakthroughUnits, Unit.MOVE, false); } - - private void unitsShowOverlay(UnitList units, int overlay, boolean on) - { - for (Unit unit : units) - unit.enableOverlay(overlay, on); - } - - public void movesShow() { moves.enable(Hex.AREA, true); } - public void movesHide() { moves.enable(Hex.AREA, false); } - public void pathsShow() { paths.enable(Hex.AREA, true); } - public void pathsHide() { paths.enable(Hex.AREA, false); } - public void pathShow(Hex dst) { paths.enable(Hex.MOVE, true); hexMoveShow(dst); } - public void pathHide(Hex dst) { paths.enable(Hex.MOVE, false); hexMoveHide(dst); } - - public void hexSelect(Hex hex) { selectedTile.set(hex); } - public void hexUnselect(Hex hex) { selectedTile.hide(); } - public void hexMoveShow(Hex hex) { enableOverlayOn(hex, Hex.MOVE, true); } - public void hexMoveHide(Hex hex) { enableOverlayOn(hex, Hex.MOVE, false); } - public void hexDirectionsShow(Hex hex) { enableOverlayOn(hex, Hex.DIRECTIONS, true); } - public void hexDirectionsHide(Hex hex) { enableOverlayOn(hex, Hex.DIRECTIONS, false); } - public void hexExitShow(Hex hex) { enableOverlayOn(hex, Hex.EXIT, true); } - public void hexExitHide(Hex hex) { enableOverlayOn(hex, Hex.EXIT, false); } - - public void showObjective(Hex hex, Army army, boolean hold) - { - if (hold) - enableOverlayOn(hex, Hex.OBJECTIVE_HOLD, true); - else - enableOverlayOn(hex, Hex.OBJECTIVE, true); - } - - - // -> implement ObjectiveSet.ObjectiveCb - - public void showObjective(Tile tile, Faction faction) - { - showObjective((Hex) tile, (Army) faction); - } - - // <- implement MoveToAnimationCb - - public void showObjective(Hex hex, Army army) - { - if (army == null) - army = Army.NONE; - switch(army) { - case GE: - enableOverlayOn(hex, Hex.OBJECTIVE_GE, true); - enableOverlayOn(hex, Hex.OBJECTIVE_US, false); - break; - case US: - enableOverlayOn(hex, Hex.OBJECTIVE_GE, false); - enableOverlayOn(hex, Hex.OBJECTIVE_US, true); - break; - case NONE: - default: - enableOverlayOn(hex, Hex.OBJECTIVE_GE, false); - enableOverlayOn(hex, Hex.OBJECTIVE_US, false); - break; - } + e.set(cnt, flk, def, tdf, wdf); + e.success = success; } } diff --git a/core/src/ch/asynk/rustanddust/game/battles/Map00.java b/core/src/ch/asynk/rustanddust/game/battles/Map00.java index a9126bd..da1b664 100644 --- a/core/src/ch/asynk/rustanddust/game/battles/Map00.java +++ b/core/src/ch/asynk/rustanddust/game/battles/Map00.java @@ -31,7 +31,6 @@ public class Map00 extends MapRules return cfg; } - @Override protected void setup() { getHex(6, 1).terrain = Hex.Terrain.HILLS; diff --git a/core/src/ch/asynk/rustanddust/game/map/Map0Hex.java b/core/src/ch/asynk/rustanddust/game/map/Map0Hex.java new file mode 100644 index 0000000..6ed0783 --- /dev/null +++ b/core/src/ch/asynk/rustanddust/game/map/Map0Hex.java @@ -0,0 +1,107 @@ +package ch.asynk.rustanddust.game.map; + +import com.badlogic.gdx.graphics.Texture; + +import ch.asynk.rustanddust.RustAndDust; +import ch.asynk.rustanddust.engine.Tile; +import ch.asynk.rustanddust.engine.Board; +import ch.asynk.rustanddust.engine.Faction; +import ch.asynk.rustanddust.engine.SelectedTile; +import ch.asynk.rustanddust.engine.ObjectiveSet; +import ch.asynk.rustanddust.game.Hex; +import ch.asynk.rustanddust.game.Army; + +public abstract class Map0Hex extends Board implements ObjectiveSet.ObjectiveCb +{ + protected final RustAndDust game; + protected final ObjectiveSet objectives; + + public Map0Hex(final RustAndDust game, Texture map, SelectedTile hex) + { + super(game.factory, map, hex); + + this.game = game; + objectives = new ObjectiveSet(this, 4); + } + + public Hex getHexAt(float x, float y) + { + return (Hex) getTileAt(x, y); + } + + public Hex getHex(int col, int row) + { + return (Hex) getTile(col, row); + } + + public void addObjective(int col, int row, Army army) + { + addObjective(col, row, army, true); + } + + public void addHoldObjective(int col, int row, Army army) + { + addObjective(col, row, army, false); + } + + private void addObjective(int col, int row, Army army, boolean persistent) + { + Hex hex = getHex(col, row); + objectives.add(hex, army, persistent); + showObjective(hex, army, !persistent); + } + + protected void claim(Hex hex, Army army) + { + showObjective(hex, objectives.claim(hex, army)); + } + + protected void unclaim(Hex hex) + { + showObjective(hex, objectives.unclaim(hex)); + } + + public void hexSelect(Hex hex) { selectedTile.set(hex); } + public void hexUnselect(Hex hex) { selectedTile.hide(); } + public void hexMoveShow(Hex hex) { enableOverlayOn(hex, Hex.MOVE, true); } + public void hexMoveHide(Hex hex) { enableOverlayOn(hex, Hex.MOVE, false); } + public void hexDirectionsShow(Hex hex) { enableOverlayOn(hex, Hex.DIRECTIONS, true); } + public void hexDirectionsHide(Hex hex) { enableOverlayOn(hex, Hex.DIRECTIONS, false); } + public void hexExitShow(Hex hex) { enableOverlayOn(hex, Hex.EXIT, true); } + public void hexExitHide(Hex hex) { enableOverlayOn(hex, Hex.EXIT, false); } + + protected void showObjective(Hex hex, Army army, boolean hold) + { + if (hold) + enableOverlayOn(hex, Hex.OBJECTIVE_HOLD, true); + else + enableOverlayOn(hex, Hex.OBJECTIVE, true); + } + + @Override + public void showObjective(Tile tile, Faction faction) + { + showObjective((Hex) tile, (Army) faction); + } + + protected void showObjective(Hex hex, Army army) + { + if (army == null) + army = Army.NONE; + switch(army) { + case GE: + enableOverlayOn(hex, Hex.OBJECTIVE_GE, true); + enableOverlayOn(hex, Hex.OBJECTIVE_US, false); + break; + case US: + enableOverlayOn(hex, Hex.OBJECTIVE_GE, false); + enableOverlayOn(hex, Hex.OBJECTIVE_US, true); + break; + case NONE: + default: + enableOverlayOn(hex, Hex.OBJECTIVE_GE, false); + enableOverlayOn(hex, Hex.OBJECTIVE_US, false); + break; + } + } +} diff --git a/core/src/ch/asynk/rustanddust/game/map/Map1Units.java b/core/src/ch/asynk/rustanddust/game/map/Map1Units.java new file mode 100644 index 0000000..7812d50 --- /dev/null +++ b/core/src/ch/asynk/rustanddust/game/map/Map1Units.java @@ -0,0 +1,117 @@ +package ch.asynk.rustanddust.game.map; + +import com.badlogic.gdx.graphics.Texture; + +import ch.asynk.rustanddust.RustAndDust; +import ch.asynk.rustanddust.engine.SelectedTile; +import ch.asynk.rustanddust.game.Unit; +import ch.asynk.rustanddust.game.UnitList; + +public abstract class Map1Units extends Map0Hex +{ + protected final UnitList moveableUnits; + protected final UnitList targetUnits; + protected final UnitList assistUnits; + protected final UnitList breakthroughUnits; + protected final UnitList activatedUnits; + + public Map1Units(final RustAndDust game, Texture map, SelectedTile hex) + { + super(game, map, hex); + + moveableUnits = new UnitList(6); + targetUnits = new UnitList(10); + assistUnits = new UnitList(6); + breakthroughUnits = new UnitList(4); + activatedUnits = new UnitList(7); + } + + @Override + public void dispose() + { + clearUnits(); + super.dispose(); + } + + public void clearUnits() + { + moveableUnits.clear(); + targetUnits.clear(); + assistUnits.clear(); + breakthroughUnits.clear(); + activatedUnits.clear(); + } + + public int collectMoveable(Unit unit) + { + if (unit.canHQMove()) + collectMoveAssists(unit, moveableUnits.asPawns()); + else + moveableUnits.clear(); + + if (unit.canMove()) + moveableUnits.add(unit); + + return moveableUnits.size(); + } + + public int collectTargets(Unit unit, UnitList foes) + { + if (unit.canEngage()) + return collectPossibleTargets(unit, foes.asPawns(), targetUnits.asPawns()); + + targetUnits.clear(); + return 0; + } + + public int collectAssists(Unit unit, Unit target, UnitList units) + { + int s = collectAttackAssists(unit, target, units.asPawns(), assistUnits.asPawns()); + activatedUnits.add(unit); + return s; + } + + public boolean toggleAssist(Unit unit) + { + if (activatedUnits.contains(unit)) { + activatedUnits.remove(unit); + unit.hideAttack(); + unit.showAttackAssist(); + return false; + } else { + activatedUnits.add(unit); + unit.showAttack(); + unit.hideAttackAssist(); + return true; + } + } + + public Unit unitsMoveableGet(int i) { return moveableUnits.get(i); } + + public void unitsTargetClear() { targetUnits.clear(); } + public void unitsActivatedClear() { activatedUnits.clear(); } + + public int unitsActivatedSize() { return activatedUnits.size(); } + public int unitsMoveableSize() { return moveableUnits.size(); } + public int unitsBreakThroughSize() { return breakthroughUnits.size(); } + + public boolean unitsTargetContains(Unit unit) { return targetUnits.contains(unit); } + public boolean unitsAssistContains(Unit unit) { return assistUnits.contains(unit); } + public boolean unitsMoveableContains(Unit unit) { return moveableUnits.contains(unit); } + public boolean unitsBreakThroughContains(Unit unit) { return breakthroughUnits.contains(unit); } + + public void unitsTargetShow() { unitsShowOverlay(targetUnits, Unit.TARGET, true); } + public void unitsTargetHide() { unitsShowOverlay(targetUnits, Unit.TARGET, false); } + public void unitsAssistShow() { unitsShowOverlay(assistUnits, Unit.MAY_FIRE, true); } + public void unitsAssistHide() { unitsShowOverlay(assistUnits, Unit.MAY_FIRE, false); unitsShowOverlay(assistUnits, Unit.FIRE, false); } + public void unitsMoveableShow() { unitsShowOverlay(moveableUnits, Unit.MOVE, true); } + public void unitsMoveableHide() { unitsShowOverlay(moveableUnits, Unit.MOVE, false); } + public void unitsBreakThroughShow() { unitsShowOverlay(breakthroughUnits, Unit.MOVE, true); } + public void unitsBreakThroughHide() { unitsShowOverlay(breakthroughUnits, Unit.MOVE, false); } + + private void unitsShowOverlay(UnitList units, int overlay, boolean on) + { + for (Unit unit : units) + unit.enableOverlay(overlay, on); + } +} diff --git a/core/src/ch/asynk/rustanddust/game/map/Map2Moves.java b/core/src/ch/asynk/rustanddust/game/map/Map2Moves.java new file mode 100644 index 0000000..e626655 --- /dev/null +++ b/core/src/ch/asynk/rustanddust/game/map/Map2Moves.java @@ -0,0 +1,91 @@ +package ch.asynk.rustanddust.game.map; + +import com.badlogic.gdx.graphics.Texture; + +import ch.asynk.rustanddust.RustAndDust; +import ch.asynk.rustanddust.engine.SelectedTile; +import ch.asynk.rustanddust.engine.Orientation; +import ch.asynk.rustanddust.engine.PathBuilder; +import ch.asynk.rustanddust.game.Map; +import ch.asynk.rustanddust.game.Unit; +import ch.asynk.rustanddust.game.Hex; +import ch.asynk.rustanddust.game.HexSet; + +public abstract class Map2Moves extends Map1Units +{ + protected final HexSet moves; + protected final PathBuilder paths; + + public Map2Moves(final RustAndDust game, Texture map, SelectedTile hex) + { + super(game, map, hex); + + moves = new HexSet(this, 40); + paths = new PathBuilder(this, 10, 20, 5, 10); + } + + @Override + public void dispose() + { + clearMoves(); + super.dispose(); + paths.dispose(); + } + + public void clearMoves() + { + moves.clear(); + paths.clear(); + } + + public boolean movesContains(Hex hex) + { + return moves.contains(hex); + } + + public int movesCollect(Unit unit) + { + if (unit.canMove()) + return collectPossibleMoves(unit, moves.asTiles()); + + moves.clear(); + return 0; + } + + public void collectUpdate(Unit unit) + { + movesHide(); + unitsMoveableHide(); + movesCollect(unit); + collectMoveable(unit); + movesShow(); + unitsMoveableShow(); + activatedUnits.clear(); + } + + public int pathsSize() { return paths.size(); } + public void pathsClear() { paths.clear(); } + public void pathsInit(Unit unit) { paths.init(unit); } + public void pathsInit(Unit unit, Hex hex) { paths.init(unit, hex); } + public int pathsBuild(Hex hex) { return pathsBuild(hex); } + public Hex pathsTo() { return (Hex) paths.to; } + public void pathsSetOrientation(Orientation o) { paths.orientation = o; } + public boolean pathsIsSet() { return paths.isSet(); } + public boolean pathsCanExit(Orientation o) { return paths.canExit(o); } + public void pathsSetExit(Orientation o) { paths.setExit(o); } + public boolean pathsContains(Hex hex) { return paths.contains(hex); } + public int pathsChooseOne() { return paths.choosePath(); } + public int pathsToggleHex(Hex hex) + { + boolean enable = !hex.isOverlayEnabled(Hex.MOVE); + enableOverlayOn(hex, Hex.MOVE, enable); + return paths.toggleCtrlTile(hex); + } + + public void movesShow() { moves.enable(Hex.AREA, true); } + public void movesHide() { moves.enable(Hex.AREA, false); } + public void pathsShow() { paths.enable(Hex.AREA, true); } + public void pathsHide() { paths.enable(Hex.AREA, false); } + public void pathShow(Hex dst) { paths.enable(Hex.MOVE, true); hexMoveShow(dst); } + public void pathHide(Hex dst) { paths.enable(Hex.MOVE, false); hexMoveHide(dst); } +} diff --git a/core/src/ch/asynk/rustanddust/game/map/Map3Animations.java b/core/src/ch/asynk/rustanddust/game/map/Map3Animations.java new file mode 100644 index 0000000..2b3badf --- /dev/null +++ b/core/src/ch/asynk/rustanddust/game/map/Map3Animations.java @@ -0,0 +1,143 @@ +package ch.asynk.rustanddust.game.map; + +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; + +import ch.asynk.rustanddust.RustAndDust; +import ch.asynk.rustanddust.engine.SelectedTile; +import ch.asynk.rustanddust.engine.gfx.Moveable; +import ch.asynk.rustanddust.engine.gfx.animations.AnimationSequence; +import ch.asynk.rustanddust.engine.gfx.animations.DiceAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.FireAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.TankFireAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.InfantryFireAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.PromoteAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.DestroyAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.SoundAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.RunnableAnimation; +import ch.asynk.rustanddust.engine.gfx.animations.MoveToAnimation.MoveToAnimationCb; +import ch.asynk.rustanddust.game.Hex; +import ch.asynk.rustanddust.game.Unit; +import ch.asynk.rustanddust.game.Ctrl; +import ch.asynk.rustanddust.game.Army; +import ch.asynk.rustanddust.game.Player; + +public abstract class Map3Animations extends Map2Moves implements MoveToAnimationCb +{ + protected final DestroyAnimation destroyAnimation; + private final Sound tankMoveSound; + private final Sound infantryMoveSound; + private Sound sound; + private long soundId = -1; + + public Map3Animations(final RustAndDust game, Texture map, SelectedTile hex) + { + super(game, map, hex); + + this.destroyAnimation = new DestroyAnimation(); + this.tankMoveSound = game.manager.get("sounds/tank_move.mp3", Sound.class); + this.infantryMoveSound = game.manager.get("sounds/infantry_move.mp3", Sound.class); + + DiceAnimation.init( + game.manager.get("data/dice.png", Texture.class), 16, 9, game.manager.get("sounds/dice.mp3", Sound.class) + ); + PromoteAnimation.init( + game.manager.get("data/hud.atlas", TextureAtlas.class), + game.manager.get("sounds/promote_us.mp3", Sound.class), + game.manager.get("sounds/promote_ge.mp3", Sound.class) + ); + FireAnimation.init( + game.manager.get("data/infantry_fire.png", Texture.class), 1, 8, + game.manager.get("data/tank_fire.png", Texture.class), 1, 8, + game.manager.get("data/explosions.png", Texture.class), 16, 8, + game.manager.get("sounds/infantry_fire.mp3", Sound.class), + game.manager.get("sounds/tank_fire.mp3", Sound.class), + game.manager.get("sounds/tank_fire_short.mp3", Sound.class), + game.manager.get("sounds/explosion.mp3", Sound.class), + game.manager.get("sounds/explosion_short.mp3", Sound.class) + ); + } + + @Override + public void dispose() + { + super.dispose(); + destroyAnimation.dispose(); + tankMoveSound.dispose(); + infantryMoveSound.dispose(); + DiceAnimation.free(); + PromoteAnimation.free(); + FireAnimation.free(); + } + + // -> implement MoveToAnimationCb + + @Override + public void moveToAnimationEnter(Moveable moveable, float x, float y, float r) + { + claim(getHexAt(x, y), (Army) moveable.getFaction()); + } + + @Override + public void moveToAnimationLeave(Moveable moveable, float x, float y, float r) + { + unclaim(getHexAt(x, y)); + } + + @Override + public void moveToAnimationDone(Moveable moveable, float x, float y, float r) + { + } + + // <- implement MoveToAnimationCb + + protected void addPromoteAnimation(final Unit unit, final Player player, final Runnable after) + { + Hex hex = unit.getHex(); + AnimationSequence seq = AnimationSequence.get(2); + seq.addAnimation(PromoteAnimation.get((unit.getArmy() == Army.US), hex.getX(), hex.getY(), game.config.fxVolume)); + seq.addAnimation(RunnableAnimation.get(unit, after)); + addAnimation(seq); + } + + protected void addDestroyAnimation(Unit unit) + { + destroyAnimation.set(2f, unit); + addAnimation(destroyAnimation); + } + + protected void addEngagementAnimation(Unit target) + { + FireAnimation.reset(); + Hex to = target.getHex(); + for (Unit u : activatedUnits) { + Hex from = u.getHex(); + float halfWidth = (u.getWidth() / 2f); + if (u.isA(Unit.UnitType.INFANTRY)) + addAnimation(InfantryFireAnimation.get(game.config.fxVolume, from.getX(), from.getY(), to.getX(), to.getY(), halfWidth)); + else + addAnimation(TankFireAnimation.get(game.config.fxVolume, from.getX(), from.getY(), to.getX(), to.getY(), halfWidth)); + } + } + + protected void playMoveSound(Unit unit) + { + if (unit.isA(Unit.UnitType.INFANTRY)) + sound = infantryMoveSound; + else + sound = tankMoveSound; + soundId = sound.play(game.config.fxVolume); + } + + @Override + protected void animationsOver() + { + if (soundId >= 0) { + addAnimation( SoundAnimation.get(SoundAnimation.Action.FADE_OUT, sound, soundId, game.config.fxVolume, 0.5f)); + soundId = -1; + return; + } + game.ctrl.animationsOver(); + } +} diff --git a/core/src/ch/asynk/rustanddust/game/map/Map4Commands.java b/core/src/ch/asynk/rustanddust/game/map/Map4Commands.java new file mode 100644 index 0000000..b17f1e3 --- /dev/null +++ b/core/src/ch/asynk/rustanddust/game/map/Map4Commands.java @@ -0,0 +1,236 @@ +package ch.asynk.rustanddust.game.map; + +import com.badlogic.gdx.graphics.Texture; + +import ch.asynk.rustanddust.RustAndDust; +import ch.asynk.rustanddust.engine.Move; +import ch.asynk.rustanddust.engine.SelectedTile; +import ch.asynk.rustanddust.engine.OrderList; +import ch.asynk.rustanddust.engine.Orientation; +import ch.asynk.rustanddust.game.Hex; +import ch.asynk.rustanddust.game.Unit; +import ch.asynk.rustanddust.game.Player; +import ch.asynk.rustanddust.game.Command; +import ch.asynk.rustanddust.game.Engagement; + +public abstract class Map4Commands extends Map3Animations +{ + private OrderList commands; + + protected abstract int engagementCost(Engagement e); + protected abstract void resolveEngagement(Engagement e); + + public Map4Commands(final RustAndDust game, Texture map, SelectedTile hex) + { + super(game, map, hex); + + commands = new OrderList(); + } + + @Override + public void dispose() + { + super.dispose(); + commands.dispose(); + Command.clearPool(); + Engagement.clearPool(); + } + + protected int commandsSize() { return commands.size(); } + protected void commandsClear() { commands.dispose(); } + + // STATES ENTRY -> + + public void showOnBoard(final Unit unit, Hex to, Orientation o) + { + setPawnOnto(unit, to, o); + } + + public boolean setOnBoard(final Unit unit, Hex to, Orientation entry) + { + commands.dispose(unit); + return (process(getMoveCommand(unit, Move.getSet(unit, to, entry))) == 1); + } + + public boolean enterBoard(final Unit unit, Hex to, int allowedMoves) + { + Orientation entry = findBestEntry(unit, to, allowedMoves); + if (entry == Orientation.KEEP) + return false; + + return (process(getMoveCommand(unit, Move.getEnter(unit, to, entry))) == 1); + } + + public int exitBoard(final Unit unit) + { + return process(getMoveCommand(unit, paths.getExitMove())); + } + + public int moveUnit(final Unit unit) + { + return process(getMoveCommand(unit, paths.getMove())); + } + + public void revertMoves() + { + for (Unit unit: activatedUnits) { + RustAndDust.debug(" revertMove() " + unit); + revertLastPawnMove(unit); + commands.dispose(unit, Command.CommandType.MOVE); + } + activatedUnits.clear(); + objectives.revert(this); + } + + public void revertEnter(final Unit unit) + { + RustAndDust.debug(" revertEnter() "+ unit); + removePawn(unit); + objectives.revert(this); + game.ctrl.player.revertUnitEntry(unit); + commands.dispose(unit); + unit.reset(); + } + + public boolean engageUnit(final Unit unit, final Unit target) + { + attack(unit, target, true); + + Command cmd = Command.get(game.ctrl.player); + cmd.setEngage(unit, target); + return (process(cmd) == 1); + } + + public void promoteUnit(final Unit unit) + { + Command cmd = Command.get(game.ctrl.player); + cmd.setPromote(unit); + process(cmd); + } + + // STATES ENTRY <- + + private Command getMoveCommand(Unit unit, Move move) + { + Command cmd = Command.get(game.ctrl.player); + cmd.setMove(unit, move); + return cmd; + } + + private void initMove(Unit unit) + { + moveableUnits.remove(unit); + activatedUnits.add(unit); + playMoveSound(unit); + } + + private int promoteUnit(final Unit unit, final Player player) + { + activatedUnits.add(unit); + addPromoteAnimation(unit, player, new Runnable() { + @Override + public void run() { + player.promote(unit); + } + }); + return 1; + } + + private int process(Command cmd) + { + RustAndDust.debug("Command", cmd.toString()); + + int r = 1; + + switch(cmd.type) { + case MOVE: + r = process(cmd.unit, cmd.move); + break; + case PROMOTE: + r = promoteUnit(cmd.unit, cmd.player); + break; + case ENGAGE: + r = doEngagement(cmd.engagement); + break; + default: + System.err.println(String.format("process wrong Command type %s", cmd.type)); + r = -1; + break; + } + + if (r != -1) + commands.add(cmd); + + return r; + } + + private int process(Unit unit, Move move) + { + RustAndDust.debug(" Move", String.format("%s %s", move.type, move.toString())); + + int r = 1; + + switch(move.type) { + case REGULAR: + initMove(unit); + movePawn(unit, move, this); + r = moveableUnits.size(); + break; + case EXIT: + initMove(unit); + movePawn(unit, move, this); + game.ctrl.player.unitWithdraw(unit); + r = moveableUnits.size(); + break; + case SET: + setPawnOnto(unit, move); + game.ctrl.player.unitEntry(unit); + claim((Hex) move.to, unit.getArmy()); + break; + case ENTER: + enterPawn(unit, move); + game.ctrl.player.unitEntry(unit); + claim((Hex) move.to, unit.getArmy()); + break; + default: + System.err.println(String.format("process wrong Move type %s", move.type)); + r = -1; + break; + } + + return r; + } + + private int doEngagement(Engagement e) + { + resolveEngagement(e); + + breakthroughUnits.clear(); + activatedUnits.clear(); + + activatedUnits.add(e.attacker); + for (Unit u : e.assists) + activatedUnits.add(u); + + for (Unit u : activatedUnits) { + u.engage(); + if (u.canBreak()) + breakthroughUnits.add(u); + } + + if (e.success) { + unclaim(e.defender.getHex()); + removePawn(e.defender); + addDestroyAnimation(e.defender); + } + + game.ctrl.hud.engagementSummary(e); + addEngagementAnimation(e.defender); + + if (engagementCost(e) == 0) + activatedUnits.clear(); + + return (e.success ? 1 : 0); + } + +} -- cgit v1.1-2-g2b99