From cf9beb992371affb8998b4a7dadedd40eea04b18 Mon Sep 17 00:00:00 2001 From: Retera Date: Sun, 8 Nov 2020 18:16:32 -0500 Subject: [PATCH] Working with behaviors --- .../etheller/warsmash/WarsmashGdxMapGame.java | 11 +- .../viewer5/handlers/mdx/EventObjectSpn.java | 3 + .../viewer5/handlers/w3x/UnitSound.java | 3 + .../viewer5/handlers/w3x/War3MapViewer.java | 6 + .../handlers/w3x/simulation/CUnit.java | 32 +- .../w3x/simulation/abilities/CAbility.java | 3 + .../simulation/abilities/CAbilityAttack.java | 8 +- .../simulation/abilities/CAbilityGeneric.java | 5 + .../simulation/abilities/CAbilityMove.java | 5 + .../build/AbstractCAbilityBuild.java | 5 + .../abilities/build/CAbilityHumanBuild.java | 2 +- .../abilities/combat/CAbilityColdArrows.java | 13 +- .../behaviors/CAbstractRangedBehavior.java | 27 +- .../CAbstractRangedPointTargetBehavior.java | 35 + .../CAbstractRangedWidgetTargetBehavior.java | 39 + .../simulation/behaviors/CBehaviorAttack.java | 18 +- .../simulation/behaviors/CBehaviorFollow.java | 6 +- .../behaviors/build/CBehaviorBuild.java | 45 + .../w3x/simulation/players/CPlayer.java | 4 +- .../w3x/simulation/test/BaseBehavior.java | 5 + .../w3x/simulation/test/BaseState.java | 5 + .../w3x/simulation/test/IAbility.java | 28 + .../w3x/simulation/test/IBehavior.java | 5 + .../handlers/w3x/simulation/test/IState.java | 5 + .../test/ability/AttackAbility.java | 28 + .../simulation/test/ability/MoveAbility.java | 22 + .../test/behavior/AttackTarget.java | 22 + .../simulation/test/behavior/MoveToPoint.java | 45 + .../w3x/simulation/test/state/MoveState.java | 28 + .../util/SimulationRenderController.java | 3 + .../viewer5/handlers/w3x/ui/MeleeUI.java | 1936 +++++++++-------- .../warsmash/desktop/DesktopLauncher.java | 3 + 32 files changed, 1417 insertions(+), 988 deletions(-) create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedPointTargetBehavior.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedWidgetTargetBehavior.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorBuild.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseBehavior.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseState.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IAbility.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IBehavior.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IState.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/AttackAbility.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/MoveAbility.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/AttackTarget.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/MoveToPoint.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/state/MoveState.java diff --git a/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java b/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java index df38da2..0284e4e 100644 --- a/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java +++ b/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java @@ -55,6 +55,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI; import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener; public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor { + private static final boolean ENABLE_AUDIO = false; private static final boolean ENABLE_MUSIC = false; private DataSource codebase; private War3MapViewer viewer; @@ -124,8 +125,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv this.codebase = new CompoundDataSourceDescriptor(dataSourcesList).createDataSource(); this.viewer = new War3MapViewer(this.codebase, this); - this.viewer.worldScene.enableAudio(); - this.viewer.enableAudio(); + if (ENABLE_AUDIO) { + this.viewer.worldScene.enableAudio(); + this.viewer.enableAudio(); + } try { this.viewer.loadMap(this.warsmashIni.get("Map").getField("FilePath")); } @@ -157,7 +160,9 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv final Scene portraitScene = this.viewer.addSimpleScene(); this.uiScene = this.viewer.addSimpleScene(); this.uiScene.alpha = true; - this.uiScene.enableAudio(); + if (ENABLE_AUDIO) { + this.uiScene.enableAudio(); + } // this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3D_exp\\MainMenu3D_exp.mdx", diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/EventObjectSpn.java b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/EventObjectSpn.java index d59b650..9c58ef8 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/EventObjectSpn.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/EventObjectSpn.java @@ -38,6 +38,9 @@ public class EventObjectSpn extends EmittedObject= model.getSequences().get(0).getInterval()[1]) { this.health = 0; diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/UnitSound.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/UnitSound.java index 68a991e..f0f0585 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/UnitSound.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/UnitSound.java @@ -95,6 +95,9 @@ public final class UnitSound { return false; } + if (audioContext == null) { + return true; + } final AudioPanner panner = audioContext.createPanner(); final AudioBufferSource source = audioContext.createBufferSource(); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java index d46b562..8aab527 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java @@ -520,6 +520,12 @@ public class War3MapViewer extends ModelViewer { return War3MapViewer.this .getBuildingPathingPixelMap(War3MapViewer.this.allObjectData.getUnits().get(rawcode)); } + + @Override + public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex, + final float x, final float y, final float facing) { + return null; + } }, this.terrain.pathingGrid, this.terrain.getEntireMap(), this.seededRandom, w3iFile.getPlayers()); this.walkableObjectsTree = new Quadtree<>(this.terrain.getEntireMap()); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java index 3392af1..a9e9d98 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java @@ -6,7 +6,6 @@ import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; -import java.util.concurrent.CyclicBarrier; import com.badlogic.gdx.math.Rectangle; import com.etheller.warsmash.util.War3ID; @@ -28,6 +27,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrder; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IState; public class CUnit extends CWidget { private static final Rectangle tempRect = new Rectangle(); @@ -71,6 +72,8 @@ public class CUnit extends CWidget { private transient CBehaviorFollow followBehavior; private transient CBehaviorPatrol patrolBehavior; private transient CBehaviorStop stopBehavior; + private IBehavior behavior; + private IState state; public CUnit(final int handleId, final int playerIndex, final float x, final float y, final float life, final War3ID typeId, final float facing, final float mana, final int maximumLife, final int maximumMana, @@ -201,9 +204,9 @@ public class CUnit extends CWidget { } } else if (this.currentBehavior != null) { - CBehavior lastBehavior = this.currentBehavior; + final CBehavior lastBehavior = this.currentBehavior; this.currentBehavior = this.currentBehavior.update(game); - if(this.currentBehavior.getHighlightOrderId() != lastBehavior.getHighlightOrderId()) { + if (this.currentBehavior.getHighlightOrderId() != lastBehavior.getHighlightOrderId()) { this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId()); } } @@ -242,6 +245,17 @@ public class CUnit extends CWidget { if (isDead()) { return; } + + final CAbility ability = game.getAbility(order.getAbilityHandleId()); + if (ability != null) { + // Allow the ability to response to the order without actually placing itself in + // the queue, nor modifying (interrupting) the queue. + if (!ability.checkBeforeQueue(game, this, order.getOrderId())) { + this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId()); + return; + } + } + if (queue && (this.currentOrder != null)) { this.orderQueue.add(order); } @@ -595,7 +609,8 @@ public class CUnit extends CWidget { if (this.source.canReach(unit, this.source.acquisitionRange) && unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed()) && (this.source.distance(unit) >= this.source.getUnitType().getMinimumAttackRange())) { - this.source.currentBehavior = this.source.getAttackBehavior().reset(OrderIds.attack, attack, unit); + this.source.currentBehavior = this.source.getAttackBehavior().reset(OrderIds.attack, attack, + unit); return true; } } @@ -644,4 +659,13 @@ public class CUnit extends CWidget { final COrder order = this.orderQueue.poll(); return beginOrder(game, order); } + + public boolean isMoving() { + return getCurrentBehavior() instanceof CBehaviorMove; + } + + public void setBehavior(final IBehavior behavior) { + this.behavior = behavior; + this.state = behavior.resolveNext(); + } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbility.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbility.java index 7720194..3de15cc 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbility.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbility.java @@ -13,6 +13,9 @@ public interface CAbility extends CAbilityView { /* should fire when ability removed from unit */ void onRemove(CSimulation game, CUnit unit); + /* return false to not do anything, such as for toggling autocast */ + boolean checkBeforeQueue(CSimulation game, CUnit caster, int orderId); + CBehavior begin(CSimulation game, CUnit caster, int orderId, CWidget target); CBehavior begin(CSimulation game, CUnit caster, int orderId, Vector2 point); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java index a58c30f..e6d9e0f 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java @@ -10,11 +10,12 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IAbility; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType; -public class CAbilityAttack implements CAbility { +public class CAbilityAttack implements CAbility, IAbility { private final int handleId; public CAbilityAttack(final int handleId) { @@ -60,6 +61,11 @@ public class CAbilityAttack implements CAbility { } } + @Override + public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) { + return true; + } + @Override public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target, final AbilityTargetCheckReceiver receiver) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityGeneric.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityGeneric.java index 40ff01c..52946c3 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityGeneric.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityGeneric.java @@ -67,6 +67,11 @@ public class CAbilityGeneric implements CAbility { public void onRemove(final CSimulation game, final CUnit unit) { } + @Override + public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) { + return false; + } + @Override public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) { return caster.pollNextOrderBehavior(game); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityMove.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityMove.java index fb1fc05..64b1988 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityMove.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityMove.java @@ -85,6 +85,11 @@ public class CAbilityMove implements CAbility { } + @Override + public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) { + return true; + } + @Override public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) { return caster.getFollowBehavior().reset(OrderIds.move, (CUnit) target); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java index 387499c..a946d90 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java @@ -75,4 +75,9 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements final AbilityTargetCheckReceiver receiver) { receiver.orderIdNotAccepted(); } + + @Override + public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) { + return false; + } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java index 9eb3c64..d8764c9 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java @@ -43,7 +43,7 @@ public class CAbilityHumanBuild extends AbstractCAbilityBuild { @Override public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) { - // TODO Auto-generated method stub +// caster.getMoveBehavior().reset(point.x, point.y, ) return null; } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/combat/CAbilityColdArrows.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/combat/CAbilityColdArrows.java index 3a11ac4..742e0ae 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/combat/CAbilityColdArrows.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/combat/CAbilityColdArrows.java @@ -91,6 +91,18 @@ public class CAbilityColdArrows implements CAbility { public void onRemove(final CSimulation game, final CUnit unit) { } + @Override + public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) { + switch (orderId) { + case OrderIds.coldarrows: + case OrderIds.uncoldarrows: + this.autoCastActive = !this.autoCastActive; + return false; + default: + return true; + } + } + @Override public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) { CBehavior behavior = null; @@ -113,7 +125,6 @@ public class CAbilityColdArrows implements CAbility { @Override public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) { - this.autoCastActive = !this.autoCastActive; return caster.pollNextOrderBehavior(game); } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java index 809d097..bea9639 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java @@ -2,7 +2,6 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; public abstract class CAbstractRangedBehavior implements CRangedBehavior { protected final CUnit unit; @@ -12,28 +11,29 @@ public abstract class CAbstractRangedBehavior implements CRangedBehavior { } private boolean wasWithinPropWindow = false; - protected CWidget target; private boolean wasInRange = false; private CBehaviorMove moveBehavior; - protected final CAbstractRangedBehavior innerReset(final CWidget target) { + protected final CAbstractRangedBehavior innerReset() { this.wasWithinPropWindow = false; - this.target = target; this.wasInRange = false; + CBehaviorMove moveBehavior; if (!this.unit.isMovementDisabled()) { - if ((target instanceof CUnit) && !((CUnit) target).getUnitType().isBuilding()) { - this.moveBehavior = this.unit.getMoveBehavior().reset((CUnit) target, this); - } - else { - this.moveBehavior = this.unit.getMoveBehavior().reset(target.getX(), target.getY(), this); - } + moveBehavior = setupMoveBehavior(); } else { - this.moveBehavior = null; + moveBehavior = null; } + this.moveBehavior = moveBehavior; return this; } + protected abstract CBehaviorMove setupMoveBehavior(); + + protected abstract float getTargetX(); + + protected abstract float getTargetY(); + protected abstract CBehavior update(CSimulation simulation, boolean withinRange); protected abstract boolean checkTargetStillValid(CSimulation simulation); @@ -51,15 +51,14 @@ public abstract class CAbstractRangedBehavior implements CRangedBehavior { } this.wasInRange = false; resetBeforeMoving(simulation); - ; return this.unit.getMoveBehavior(); } this.wasInRange = true; if (!this.unit.isMovementDisabled()) { final float prevX = this.unit.getX(); final float prevY = this.unit.getY(); - final float deltaY = this.target.getY() - prevY; - final float deltaX = this.target.getX() - prevX; + final float deltaY = getTargetY() - prevY; + final float deltaX = getTargetX() - prevX; final double goalAngleRad = Math.atan2(deltaY, deltaX); float goalAngle = (float) Math.toDegrees(goalAngleRad); if (goalAngle < 0) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedPointTargetBehavior.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedPointTargetBehavior.java new file mode 100644 index 0000000..1064290 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedPointTargetBehavior.java @@ -0,0 +1,35 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; + +public abstract class CAbstractRangedPointTargetBehavior extends CAbstractRangedBehavior { + + protected float targetX; + protected float targetY; + + public CAbstractRangedPointTargetBehavior(final CUnit unit) { + super(unit); + } + + protected final CAbstractRangedBehavior innerReset(final float targetX, final float targetY) { + this.targetX = targetX; + this.targetY = targetY; + return innerReset(); + } + + @Override + protected float getTargetX() { + return this.targetX; + } + + @Override + protected float getTargetY() { + return this.targetY; + } + + @Override + protected CBehaviorMove setupMoveBehavior() { + return this.unit.getMoveBehavior().reset(this.targetX, this.targetY, this); + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedWidgetTargetBehavior.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedWidgetTargetBehavior.java new file mode 100644 index 0000000..3b1ff9c --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedWidgetTargetBehavior.java @@ -0,0 +1,39 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; + +public abstract class CAbstractRangedWidgetTargetBehavior extends CAbstractRangedBehavior { + + protected CWidget target; + + public CAbstractRangedWidgetTargetBehavior(final CUnit unit) { + super(unit); + } + + protected final CAbstractRangedBehavior innerReset(final CWidget target) { + this.target = target; + return innerReset(); + } + + @Override + protected float getTargetX() { + return this.target.getX(); + } + + @Override + protected float getTargetY() { + return this.target.getY(); + } + + @Override + protected CBehaviorMove setupMoveBehavior() { + if ((this.target instanceof CUnit) && !((CUnit) this.target).getUnitType().isBuilding()) { + return this.unit.getMoveBehavior().reset((CUnit) this.target, this); + } + else { + return this.unit.getMoveBehavior().reset(this.target.getX(), this.target.getY(), this); + } + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java index 8837938..bde7654 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java @@ -8,7 +8,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack; -public class CBehaviorAttack extends CAbstractRangedBehavior { +public class CBehaviorAttack extends CAbstractRangedWidgetTargetBehavior { private int highlightOrderId; @@ -21,7 +21,7 @@ public class CBehaviorAttack extends CAbstractRangedBehavior { private int backSwingTime; private int thisOrderCooldownEndTime; - public CBehaviorAttack reset(int highlightOrderId, final CUnitAttack unitAttack, final CWidget target) { + public CBehaviorAttack reset(final int highlightOrderId, final CUnitAttack unitAttack, final CWidget target) { this.highlightOrderId = highlightOrderId; super.innerReset(target); this.unitAttack = unitAttack; @@ -33,18 +33,18 @@ public class CBehaviorAttack extends CAbstractRangedBehavior { @Override public int getHighlightOrderId() { - return highlightOrderId; + return this.highlightOrderId; } @Override public boolean isWithinRange(final CSimulation simulation) { float range = this.unitAttack.getRange(); - if ((this.target instanceof CUnit) && (((CUnit) this.target).getCurrentBehavior() instanceof CBehaviorMove) - && (this.damagePointLaunchTime != 0 /* - * only apply range motion buffer if they were already in range and - * attacked - */)) { - range += this.unitAttack.getRangeMotionBuffer(); + if ((this.target instanceof CUnit) && (((CUnit) this.target).isMoving()) && (simulation + .getGameTurnTick() < this.unit.getCooldownEndTime() /* + * only apply range motion buffer if they were + * already in range and attacked + */)) { + range += this.unitAttack.getRangeMotionBuffer() + 1000; } return this.unit.canReach(this.target, range) && (this.unit.distance(this.target) >= this.unit.getUnitType().getMinimumAttackRange()); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java index 785195e..02c98dd 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java @@ -5,7 +5,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; -public class CBehaviorFollow extends CAbstractRangedBehavior { +public class CBehaviorFollow extends CAbstractRangedWidgetTargetBehavior { private int higlightOrderId; @@ -13,14 +13,14 @@ public class CBehaviorFollow extends CAbstractRangedBehavior { super(unit); } - public CBehavior reset(int higlightOrderId, final CUnit target) { + public CBehavior reset(final int higlightOrderId, final CUnit target) { this.higlightOrderId = higlightOrderId; return innerReset(target); } @Override public int getHighlightOrderId() { - return higlightOrderId; + return this.higlightOrderId; } @Override diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorBuild.java new file mode 100644 index 0000000..f407ad5 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorBuild.java @@ -0,0 +1,45 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedPointTargetBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; + +public class CBehaviorBuild extends CAbstractRangedPointTargetBehavior { + private int orderId; + + public CBehaviorBuild(final CUnit unit) { + super(unit); + } + + public CBehavior reset(final float targetX, final float targetY, final int orderId) { + this.orderId = orderId; + return innerReset(targetX, targetY); + } + + @Override + public boolean isWithinRange(final CSimulation simulation) { + return this.unit.distance(this.targetX, this.targetY) <= 23525; + } + + @Override + public int getHighlightOrderId() { + return this.orderId; + } + + @Override + protected CBehavior update(final CSimulation simulation, final boolean withinRange) { + return this; + } + + @Override + protected boolean checkTargetStillValid(final CSimulation simulation) { + return true; + } + + @Override + protected void resetBeforeMoving(final CSimulation simulation) { + + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java index cc3f424..93425ef 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java @@ -12,8 +12,8 @@ public class CPlayer { private final CRace race; private final float[] startLocation; private final EnumSet racePrefs; - private int gold; - private int lumber; + private int gold = 5000; + private int lumber = 5000; private final EnumSet[] alliances = new EnumSet[WarsmashConstants.MAX_PLAYERS]; public CPlayer(final int id, final CMapControl controlType, final String name, final CRace race, diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseBehavior.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseBehavior.java new file mode 100644 index 0000000..8db5d76 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseBehavior.java @@ -0,0 +1,5 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test; + +public abstract class BaseBehavior { + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseState.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseState.java new file mode 100644 index 0000000..3ea24f6 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/BaseState.java @@ -0,0 +1,5 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test; + +public abstract class BaseState implements IState { + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IAbility.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IAbility.java new file mode 100644 index 0000000..c8c82e6 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IAbility.java @@ -0,0 +1,28 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test; + +import java.awt.Point; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; + +/* + * IAbility + Execute(unit caster, int orderId, unit targetUnit, point targetPoint); + +IBehavior + ResolveNext(); + +IState + Execute(); + +abstract BaseState + ctor(unit unit, IBehavior behavior) + abstract Execute(); + +abstract BaseBehavior + ctor(unit unit) + + */ +public interface IAbility { + void execute(CUnit caster, int orderId, CWidget targetUnit, Point targetPoint); +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IBehavior.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IBehavior.java new file mode 100644 index 0000000..ff9e07e --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IBehavior.java @@ -0,0 +1,5 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test; + +public interface IBehavior { + IState resolveNext(); +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IState.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IState.java new file mode 100644 index 0000000..7c351ca --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/IState.java @@ -0,0 +1,5 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test; + +public interface IState { + void execute(); +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/AttackAbility.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/AttackAbility.java new file mode 100644 index 0000000..83d2ba1 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/AttackAbility.java @@ -0,0 +1,28 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.ability; + +import java.awt.Point; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IAbility; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.behavior.AttackTarget; + +public class AttackAbility implements IAbility { + + @Override + public void execute(final CUnit caster, final int orderId, final CWidget target, final Point targetPoint) { + if (target != null) { + new AttackTarget(caster, target); + } + else if (targetPoint != null) { + if (orderId == OrderIds.attackground) { + // TODO some stuff + } + else if (orderId == OrderIds.attack) { + + } + } + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/MoveAbility.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/MoveAbility.java new file mode 100644 index 0000000..e12eb86 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/ability/MoveAbility.java @@ -0,0 +1,22 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.ability; + +import java.awt.Point; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IAbility; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.behavior.MoveToPoint; + +public class MoveAbility implements IAbility { + + @Override + public void execute(final CUnit caster, final int orderId, final CWidget targetUnit, final Point targetPoint) { + if (targetUnit == null) { + caster.setBehavior(new MoveToPoint(caster, targetPoint)); + } + else { + + } + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/AttackTarget.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/AttackTarget.java new file mode 100644 index 0000000..639f53e --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/AttackTarget.java @@ -0,0 +1,22 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.behavior; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IState; + +public class AttackTarget implements IBehavior { + private final CUnit attackingUnit; + private final CWidget targetUnit; + + public AttackTarget(final CUnit attackingUnit, final CWidget targetUnit) { + this.attackingUnit = attackingUnit; + this.targetUnit = targetUnit; + } + + @Override + public IState resolveNext() { + return null; + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/MoveToPoint.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/MoveToPoint.java new file mode 100644 index 0000000..5e2cfa9 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/behavior/MoveToPoint.java @@ -0,0 +1,45 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.behavior; + +import java.awt.Point; +import java.awt.geom.Point2D; +import java.awt.geom.Point2D.Float; +import java.util.List; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.state.MoveState; + +public class MoveToPoint implements IBehavior { + + private final CSimulation simulation; + private final CUnit unit; + private final Point point; + private final MoveState moveState; + private final List waypointList; + + public MoveToPoint(final CSimulation simulation, final CUnit unit, final Point point) { + this.simulation = simulation; + this.unit = unit; + this.point = point; + this.waypointList = this.simulation.findNaiveSlowPath(unit, null, unit.getX(), unit.getY(), + new Point2D.Float(point.x, point.y), unit.getUnitType().getMovementType(), + unit.getUnitType().getCollisionSize(), true); + this.moveState = new MoveState(); + this.unit.setBehavior(this); + this.unit.setState(this.moveState); + resolveNext(); + } + + @Override + public void resolveNext() { + if (this.waypointList.isEmpty()) { + this.unit.setState(state); + } + else { + final Float firstWaypoint = this.waypointList.remove(0); + this.unit.setState(this.moveState.reset(this, this.unit, firstWaypoint.x, firstWaypoint.y)); + } + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/state/MoveState.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/state/MoveState.java new file mode 100644 index 0000000..b1758db --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/test/state/MoveState.java @@ -0,0 +1,28 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.state; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IState; + +public class MoveState implements IState { + public IBehavior behavior; + public CUnit unit; + public float targetX; + public float targetY; + + public MoveState reset(final IBehavior behavior, final CUnit unit, final float targetX, final float targetY) { + this.behavior = behavior; + this.unit = unit; + this.targetX = targetX; + this.targetY = targetY; + return this; + } + + @Override + public void execute() { + final float dx = this.targetX - this.unit.getX(); + final float dy = this.targetY - this.unit.getY(); + this.unit.setX(this.unit.getX(), collision); + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/SimulationRenderController.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/SimulationRenderController.java index ea07743..0052226 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/SimulationRenderController.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/SimulationRenderController.java @@ -14,6 +14,9 @@ public interface SimulationRenderController { CAttackProjectile createAttackProjectile(CSimulation simulation, float launchX, float launchY, float launchFacing, CUnit source, CUnitAttackMissile attack, CWidget target, float damage, int bounceIndex); + CUnit createUnit(CSimulation simulation, final War3ID typeId, final int playerIndex, final float x, final float y, + final float facing); + void createInstantAttackEffect(CSimulation cSimulation, CUnit source, CUnitAttackInstant attack, CWidget target); void spawnUnitDamageSound(CUnit damagedUnit, final String weaponSound, String armorType); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java index 9c7280f..433fd21 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java @@ -73,954 +73,990 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgAbili import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandCardCommandListener; public class MeleeUI implements CUnitStateListener, CommandButtonListener, CommandCardCommandListener { - public static final float DEFAULT_COMMAND_CARD_ICON_WIDTH = 0.039f; - public static final float DEFAULT_COMMAND_CARD_ICON_PRESSED_WIDTH = 0.037f; - private static final int COMMAND_CARD_WIDTH = 4; - private static final int COMMAND_CARD_HEIGHT = 3; - - private static final Vector2 screenCoordsVector = new Vector2(); - private static final Vector3 clickLocationTemp = new Vector3(); - private static final Vector2 clickLocationTemp2 = new Vector2(); - private final DataSource dataSource; - private final ExtendViewport uiViewport; - private final FreeTypeFontGenerator fontGenerator; - private final Scene uiScene; - private final Scene portraitScene; - private final GameCameraManager cameraManager; - private final War3MapViewer war3MapViewer; - private final RootFrameListener rootFrameListener; - private GameUI rootFrame; - private UIFrame consoleUI; - private UIFrame resourceBar; - private StringFrame resourceBarGoldText; - private StringFrame resourceBarLumberText; - private StringFrame resourceBarSupplyText; - private StringFrame resourceBarUpkeepText; - private SpriteFrame timeIndicator; - private UIFrame unitPortrait; - private StringFrame unitLifeText; - private StringFrame unitManaText; - private Portrait portrait; - private final Rectangle tempRect = new Rectangle(); - private final Vector2 projectionTemp1 = new Vector2(); - private final Vector2 projectionTemp2 = new Vector2(); - private UIFrame simpleInfoPanelUnitDetail; - private StringFrame simpleNameValue; - private StringFrame simpleClassValue; - private StringFrame simpleBuildingActionLabel; - private UIFrame attack1Icon; - private TextureFrame attack1IconBackdrop; - private StringFrame attack1InfoPanelIconValue; - private StringFrame attack1InfoPanelIconLevel; - private UIFrame attack2Icon; - private TextureFrame attack2IconBackdrop; - private StringFrame attack2InfoPanelIconValue; - private StringFrame attack2InfoPanelIconLevel; - private UIFrame armorIcon; - private TextureFrame armorIconBackdrop; - private StringFrame armorInfoPanelIconValue; - private StringFrame armorInfoPanelIconLevel; - private InfoPanelIconBackdrops damageBackdrops; - private InfoPanelIconBackdrops defenseBackdrops; - - private final CommandCardIcon[][] commandCard = new CommandCardIcon[COMMAND_CARD_HEIGHT][COMMAND_CARD_WIDTH]; - - private RenderUnit selectedUnit; - private final List subMenuOrderIdStack = new ArrayList<>(); - - // TODO remove this & replace with FDF - private final Texture activeButtonTexture; - private UIFrame inventoryCover; - private SpriteFrame cursorFrame; - private MeleeUIMinimap meleeUIMinimap; - private final CPlayerUnitOrderListener unitOrderListener; - private StringFrame errorMessageFrame; - - private CAbilityView activeCommand; - private int activeCommandOrderId; - private RenderUnit activeCommandUnit; - - private int selectedSoundCount = 0; - private final ActiveCommandUnitTargetFilter activeCommandUnitTargetFilter; - - // TODO these corrections are used for old hardcoded UI stuff, we should - // probably remove them later - private final float widthRatioCorrection; - private final float heightRatioCorrection; - private CommandCardIcon mouseDownUIFrame; - - public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport, - final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final Scene portraitScene, - final CameraPreset[] cameraPresets, final CameraRates cameraRates, final War3MapViewer war3MapViewer, - final RootFrameListener rootFrameListener, final CPlayerUnitOrderListener unitOrderListener) { - this.dataSource = dataSource; - this.uiViewport = uiViewport; - this.fontGenerator = fontGenerator; - this.uiScene = uiScene; - this.portraitScene = portraitScene; - this.war3MapViewer = war3MapViewer; - this.rootFrameListener = rootFrameListener; - this.unitOrderListener = unitOrderListener; - - this.cameraManager = new GameCameraManager(cameraPresets, cameraRates); - - this.cameraManager.setupCamera(war3MapViewer.worldScene); - if (this.war3MapViewer.startLocations[0] != null) { - this.cameraManager.target.x = this.war3MapViewer.startLocations[0].x; - this.cameraManager.target.y = this.war3MapViewer.startLocations[0].y; - } - - this.activeButtonTexture = ImageUtils.getBLPTexture(war3MapViewer.mapMpq, - "UI\\Widgets\\Console\\Human\\CommandButton\\human-activebutton.blp"); - this.activeCommandUnitTargetFilter = new ActiveCommandUnitTargetFilter(); - this.widthRatioCorrection = this.uiViewport.getMinWorldWidth() / 1600f; - this.heightRatioCorrection = this.uiViewport.getMinWorldHeight() / 1200f; - - } - - private MeleeUIMinimap createMinimap(final War3MapViewer war3MapViewer) { - final Rectangle minimapDisplayArea = new Rectangle(18.75f * this.widthRatioCorrection, - 13.75f * this.heightRatioCorrection, 278.75f * this.widthRatioCorrection, - 276.25f * this.heightRatioCorrection); - Texture minimapTexture = null; - if (war3MapViewer.dataSource.has("war3mapMap.tga")) { - try { - minimapTexture = ImageUtils.getTextureNoColorCorrection(TgaFile.readTGA("war3mapMap.tga", - war3MapViewer.dataSource.getResourceAsStream("war3mapMap.tga"))); - } catch (final IOException e) { - System.err.println("Could not load minimap TGA file"); - e.printStackTrace(); - } - } else if (war3MapViewer.dataSource.has("war3mapMap.blp")) { - try { - minimapTexture = ImageUtils - .getTexture(ImageIO.read(war3MapViewer.dataSource.getResourceAsStream("war3mapMap.blp"))); - } catch (final IOException e) { - System.err.println("Could not load minimap BLP file"); - e.printStackTrace(); - } - } - final Texture[] teamColors = new Texture[WarsmashConstants.MAX_PLAYERS]; - for (int i = 0; i < teamColors.length; i++) { - teamColors[i] = ImageUtils.getBLPTexture(war3MapViewer.dataSource, - "ReplaceableTextures\\" + ReplaceableIds.getPathString(1) + ReplaceableIds.getIdString(i) + ".blp"); - } - final Rectangle playableMapArea = war3MapViewer.terrain.getPlayableMapArea(); - return new MeleeUIMinimap(minimapDisplayArea, playableMapArea, minimapTexture, teamColors); - } - - /** - * Called "main" because this was originally written in JASS so that maps could - * override it, and I may convert it back to the JASS at some point. - */ - public void main() { - // ================================= - // Load skins and templates - // ================================= - this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 0), this.uiViewport, - this.fontGenerator, this.uiScene, this.war3MapViewer); - this.rootFrameListener.onCreate(this.rootFrame); - try { - this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc"); - } catch (final IOException exc) { - throw new IllegalStateException("Unable to load FrameDef.toc", exc); - } - try { - this.rootFrame.loadTOCFile("UI\\FrameDef\\SmashFrameDef.toc"); - } catch (final IOException exc) { - throw new IllegalStateException("Unable to load SmashFrameDef.toc", exc); - } - this.damageBackdrops = new InfoPanelIconBackdrops(CAttackType.values(), this.rootFrame, "Damage", "Neutral"); - this.defenseBackdrops = new InfoPanelIconBackdrops(CDefenseType.values(), this.rootFrame, "Armor", "Neutral"); - - // ================================= - // Load major UI components - // ================================= - // Console UI is the background with the racial theme - this.consoleUI = this.rootFrame.createSimpleFrame("ConsoleUI", this.rootFrame, 0); - this.consoleUI.setSetAllPoints(true); - - // Resource bar is a 3 part bar with Gold, Lumber, and Food. - // Its template does not specify where to put it, so we must - // put it in the "TOPRIGHT" corner. - this.resourceBar = this.rootFrame.createSimpleFrame("ResourceBarFrame", this.consoleUI, 0); - this.resourceBar.addSetPoint(new SetPoint(FramePoint.TOPRIGHT, this.consoleUI, FramePoint.TOPRIGHT, 0, 0)); - this.resourceBarGoldText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarGoldText", 0); - this.resourceBarGoldText.setText("500"); - this.resourceBarLumberText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarLumberText", 0); - this.resourceBarLumberText.setText("150"); - this.resourceBarSupplyText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarSupplyText", 0); - this.resourceBarSupplyText.setText("12/100"); - this.resourceBarUpkeepText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarUpkeepText", 0); - this.resourceBarUpkeepText.setText("No Upkeep"); - this.resourceBarUpkeepText.setColor(Color.GREEN); - - // Create the Time Indicator (clock) - this.timeIndicator = (SpriteFrame) this.rootFrame.createFrame("TimeOfDayIndicator", this.rootFrame, 0, 0); - this.timeIndicator.setSequence(0); // play the stand - this.timeIndicator.setAnimationSpeed(0.0f); // do not advance automatically - - // Create the unit portrait stuff - this.portrait = new Portrait(this.war3MapViewer, this.portraitScene); - positionPortrait(); - this.unitPortrait = this.rootFrame.createSimpleFrame("UnitPortrait", this.consoleUI, 0); - this.unitLifeText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitHitPointText", 0); - this.unitManaText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitManaPointText", 0); - - this.simpleInfoPanelUnitDetail = this.rootFrame.createSimpleFrame("SimpleInfoPanelUnitDetail", this.consoleUI, - 0); - this.simpleInfoPanelUnitDetail - .addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f))); - this.simpleInfoPanelUnitDetail.setWidth(GameUI.convertY(this.uiViewport, 0.180f)); - this.simpleInfoPanelUnitDetail.setHeight(GameUI.convertY(this.uiViewport, 0.105f)); - this.simpleNameValue = (StringFrame) this.rootFrame.getFrameByName("SimpleNameValue", 0); - this.simpleClassValue = (StringFrame) this.rootFrame.getFrameByName("SimpleClassValue", 0); - this.simpleBuildingActionLabel = (StringFrame) this.rootFrame.getFrameByName("SimpleBuildingActionLabel", 0); - - this.attack1Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail, - 0); - this.attack1Icon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, - FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f))); - this.attack1IconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 0); - this.attack1InfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 0); - this.attack1InfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 0); - - this.attack2Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail, - 1); - this.attack2Icon - .addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT, - GameUI.convertX(this.uiViewport, 0.1f), GameUI.convertY(this.uiViewport, -0.030125f))); - this.attack2IconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 1); - this.attack2InfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 1); - this.attack2InfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 1); - - this.armorIcon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconArmor", this.simpleInfoPanelUnitDetail, - 1); - this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT, - GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f))); - this.armorIconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 0); - this.armorInfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 0); - this.armorInfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 0); - - this.inventoryCover = this.rootFrame.createSimpleFrame("SmashConsoleInventoryCover", this.rootFrame, 0); - - this.errorMessageFrame = this.rootFrame.createStringFrame("SmashErrorMessageFrame", this.consoleUI, - new Color(0xFFFFCC00), TextJustify.LEFT, TextJustify.MIDDLE, 0.014f); - this.errorMessageFrame.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT, - GameUI.convertX(this.uiViewport, 0.275f), GameUI.convertY(this.uiViewport, 0.275f))); - this.errorMessageFrame.setWidth(GameUI.convertX(this.uiViewport, 0.25f)); - - int commandButtonIndex = 0; - for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) { - for (int i = 0; i < COMMAND_CARD_WIDTH; i++) { - final CommandCardIcon commandCardIcon = new CommandCardIcon("SmashCommandButton_" + commandButtonIndex, - this.rootFrame, this); - this.rootFrame.add(commandCardIcon); - final TextureFrame iconFrame = this.rootFrame.createTextureFrame( - "SmashCommandButton_" + (commandButtonIndex) + "_Icon", this.rootFrame, false, null); - final TextureFrame activeHighlightFrame = this.rootFrame.createTextureFrame( - "SmashCommandButton_" + (commandButtonIndex) + "_ActiveHighlight", this.rootFrame, true, null, - FilterMode.ADDALPHA); - final SpriteFrame cooldownFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", - "SmashCommandButton_" + (commandButtonIndex) + "_Cooldown", this.rootFrame, "", 0); - final SpriteFrame autocastFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", - "SmashCommandButton_" + (commandButtonIndex) + "_Autocast", this.rootFrame, "", 0); - commandCardIcon.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT, - GameUI.convertX(this.uiViewport, 0.6175f + (0.0434f * i)), - GameUI.convertY(this.uiViewport, 0.095f - (0.044f * j)))); - commandCardIcon.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - commandCardIcon.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - iconFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); - iconFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - iconFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - iconFrame.setTexture(ImageUtils.DEFAULT_ICON_PATH, this.rootFrame); - activeHighlightFrame - .addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); - activeHighlightFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - activeHighlightFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - activeHighlightFrame.setTexture("CommandButtonActiveHighlight", this.rootFrame); - cooldownFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); - this.rootFrame.setSpriteFrameModel(cooldownFrame, this.rootFrame.getSkinField("CommandButtonCooldown")); - cooldownFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - cooldownFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - autocastFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); - this.rootFrame.setSpriteFrameModel(autocastFrame, this.rootFrame.getSkinField("CommandButtonAutocast")); - autocastFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - autocastFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); - commandCardIcon.set(iconFrame, activeHighlightFrame, cooldownFrame, autocastFrame); - this.commandCard[j][i] = commandCardIcon; - commandCardIcon.setCommandButton(null); - commandButtonIndex++; - } - } - - this.cursorFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", "SmashCursorFrame", this.rootFrame, - "", 0); - this.rootFrame.setSpriteFrameModel(this.cursorFrame, this.rootFrame.getSkinField("Cursor")); - this.cursorFrame.setSequence("Normal"); - this.cursorFrame.setZDepth(1.0f); - Gdx.input.setCursorCatched(true); - - this.meleeUIMinimap = createMinimap(this.war3MapViewer); - - this.rootFrame.positionBounds(this.uiViewport); - selectUnit(null); - } - - @Override - public void startUsingAbility(final int abilityHandleId, final int orderId) { - // TODO not O(N) - CAbilityView abilityToUse = null; - for (final CAbility ability : this.selectedUnit.getSimulationUnit().getAbilities()) { - if (ability.getHandleId() == abilityHandleId) { - abilityToUse = ability; - break; - } - } - if (abilityToUse != null) { - final StringMsgAbilityActivationReceiver stringMsgActivationReceiver = StringMsgAbilityActivationReceiver - .getInstance().reset(); - abilityToUse.checkCanUse(this.war3MapViewer.simulation, this.selectedUnit.getSimulationUnit(), orderId, - stringMsgActivationReceiver); - if (!stringMsgActivationReceiver.isUseOk()) { - showCommandError(stringMsgActivationReceiver.getMessage()); - } else { - final BooleanAbilityTargetCheckReceiver noTargetReceiver = BooleanAbilityTargetCheckReceiver - .getInstance().reset(); - abilityToUse.checkCanTargetNoTarget(this.war3MapViewer.simulation, - this.selectedUnit.getSimulationUnit(), orderId, noTargetReceiver); - if (noTargetReceiver.isTargetable()) { - this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(), - abilityHandleId, orderId, isShiftDown()); - } else { - this.activeCommand = abilityToUse; - this.activeCommandOrderId = orderId; - this.activeCommandUnit = this.selectedUnit; - clearAndRepopulateCommandCard(); - } - } - } else { - this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(), - abilityHandleId, orderId, isShiftDown()); - } - } - - @Override - public void openMenu(final int orderId) { - if (orderId == 0) { - subMenuOrderIdStack.clear(); - this.activeCommandUnit = null; - this.activeCommand = null; - this.activeCommandOrderId = -1; - } else { - this.subMenuOrderIdStack.add(orderId); - } - clearAndRepopulateCommandCard(); - } - - public void showCommandError(final String message) { - this.errorMessageFrame.setText(message); - } - - public void update(final float deltaTime) { - this.portrait.update(); - - int mouseX = Gdx.input.getX(); - int mouseY = Gdx.input.getY(); - final int minX = this.uiViewport.getScreenX(); - final int maxX = minX + this.uiViewport.getScreenWidth(); - final int minY = this.uiViewport.getScreenY(); - final int maxY = minY + this.uiViewport.getScreenHeight(); - final boolean left = mouseX <= (minX + 3); - final boolean right = mouseX >= (maxX - 3); - final boolean up = mouseY <= (minY + 3); - final boolean down = mouseY >= (maxY - 3); - this.cameraManager.applyVelocity(deltaTime, up, down, left, right); - - mouseX = Math.max(minX, Math.min(maxX, mouseX)); - mouseY = Math.max(minY, Math.min(maxY, mouseY)); - if (Gdx.input.isCursorCatched()) { - Gdx.input.setCursorPosition(mouseX, mouseY); - } - - screenCoordsVector.set(mouseX, mouseY); - this.uiViewport.unproject(screenCoordsVector); - this.cursorFrame.setFramePointX(FramePoint.LEFT, screenCoordsVector.x); - this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y); - - if (this.activeCommand != null) { - this.cursorFrame.setSequence("Target"); - } else if (down) { - if (left) { - this.cursorFrame.setSequence("Scroll Down Left"); - } else if (right) { - this.cursorFrame.setSequence("Scroll Down Right"); - } else { - this.cursorFrame.setSequence("Scroll Down"); - } - } else if (up) { - if (left) { - this.cursorFrame.setSequence("Scroll Up Left"); - } else if (right) { - this.cursorFrame.setSequence("Scroll Up Right"); - } else { - this.cursorFrame.setSequence("Scroll Up"); - } - } else if (left) { - this.cursorFrame.setSequence("Scroll Left"); - } else if (right) { - this.cursorFrame.setSequence("Scroll Right"); - } else { - this.cursorFrame.setSequence("Normal"); - } - final float groundHeight = Math.max( - this.war3MapViewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y), - this.war3MapViewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y)); - this.cameraManager.updateTargetZ(groundHeight); - this.cameraManager.updateCamera(); - } - - public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) { - this.rootFrame.render(batch, font20, glyphLayout); - if (this.selectedUnit != null) { - font20.setColor(Color.WHITE); - - } - - this.meleeUIMinimap.render(batch, this.war3MapViewer.units); - this.timeIndicator.setFrameByRatio(this.war3MapViewer.simulation.getGameTimeOfDay() - / this.war3MapViewer.simulation.getGameplayConstants().getGameDayHours()); - } - - public void portraitTalk() { - this.portrait.talk(); - } - - private final class ActiveCommandUnitTargetFilter implements CUnitFilterFunction { - @Override - public boolean call(final CUnit unit) { - final BooleanAbilityTargetCheckReceiver targetReceiver = BooleanAbilityTargetCheckReceiver - .getInstance(); - MeleeUI.this.activeCommand.checkCanTarget(MeleeUI.this.war3MapViewer.simulation, - MeleeUI.this.activeCommandUnit.getSimulationUnit(), MeleeUI.this.activeCommandOrderId, unit, - targetReceiver); - return targetReceiver.isTargetable(); - } - } - - private static final class Portrait { - private MdxComplexInstance modelInstance; - private final PortraitCameraManager portraitCameraManager; - private final Scene portraitScene; - - public Portrait(final War3MapViewer war3MapViewer, final Scene portraitScene) { - this.portraitScene = portraitScene; - this.portraitCameraManager = new PortraitCameraManager(); - this.portraitCameraManager.setupCamera(this.portraitScene); - this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48)); - } - - public void update() { - this.portraitCameraManager.updateCamera(); - if ((this.modelInstance != null) - && (this.modelInstance.sequenceEnded || (this.modelInstance.sequence == -1))) { - SequenceUtils.randomSequence(this.modelInstance, PrimaryTag.PORTRAIT, SequenceUtils.EMPTY, true); - } - } - - public void talk() { - SequenceUtils.randomSequence(this.modelInstance, PrimaryTag.PORTRAIT, SequenceUtils.TALK, true); - } - - public void setSelectedUnit(final RenderUnit unit) { - if (unit == null) { - if (this.modelInstance != null) { - this.portraitScene.removeInstance(this.modelInstance); - } - this.modelInstance = null; - this.portraitCameraManager.setModelInstance(null, null); - } else { - final MdxModel portraitModel = unit.portraitModel; - if (portraitModel != null) { - if (this.modelInstance != null) { - this.portraitScene.removeInstance(this.modelInstance); - } - this.modelInstance = (MdxComplexInstance) portraitModel.addInstance(); - this.portraitCameraManager.setModelInstance(this.modelInstance, portraitModel); - this.modelInstance.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP); - this.modelInstance.setScene(this.portraitScene); - this.modelInstance.setVertexColor(unit.instance.vertexColor); - this.modelInstance.setTeamColor(unit.playerIndex); - } - } - } - } - - public void selectUnit(RenderUnit unit) { - this.subMenuOrderIdStack.clear(); - if ((unit != null) && unit.getSimulationUnit().isDead()) { - unit = null; - } - if (this.selectedUnit != null) { - this.selectedUnit.getSimulationUnit().removeStateListener(this); - } - this.portrait.setSelectedUnit(unit); - this.selectedUnit = unit; - clearCommandCard(); - if (unit == null) { - this.simpleNameValue.setText(""); - this.unitLifeText.setText(""); - this.unitManaText.setText(""); - this.simpleClassValue.setText(""); - this.simpleBuildingActionLabel.setText(""); - this.attack1Icon.setVisible(false); - this.attack2Icon.setVisible(false); - this.attack1InfoPanelIconLevel.setText(""); - this.attack2InfoPanelIconLevel.setText(""); - this.armorIcon.setVisible(false); - this.armorInfoPanelIconLevel.setText(""); - } else { - unit.getSimulationUnit().addStateListener(this); - this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName()); - String classText = null; - for (final CUnitClassification classification : unit.getSimulationUnit().getClassifications()) { - if ((classification == CUnitClassification.MECHANICAL) - && unit.getSimulationUnit().getUnitType().isBuilding()) { - // buildings dont display MECHANICAL - continue; - } - if (classification.getDisplayName() != null) { - classText = classification.getDisplayName(); - } - } - if (classText != null) { - this.simpleClassValue.setText(classText); - } else { - this.simpleClassValue.setText(""); - } - this.unitLifeText.setText(FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getLife()) + " / " - + unit.getSimulationUnit().getMaximumLife()); - final int maximumMana = unit.getSimulationUnit().getMaximumMana(); - if (maximumMana > 0) { - this.unitManaText.setText( - FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getMana()) + " / " + maximumMana); - } else { - this.unitManaText.setText(""); - } - this.simpleBuildingActionLabel.setText(""); - - final boolean anyAttacks = unit.getSimulationUnit().getUnitType().getAttacks().size() > 0; - final UIFrame localArmorIcon = this.armorIcon; - final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop; - final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue; - if (anyAttacks) { - final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0); - this.attack1Icon.setVisible(attackOne.isShowUI()); - this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType())); - this.attack1InfoPanelIconValue.setText(attackOne.getMinDamage() + " - " + attackOne.getMaxDamage()); - if (unit.getSimulationUnit().getUnitType().getAttacks().size() > 1) { - final CUnitAttack attackTwo = unit.getSimulationUnit().getUnitType().getAttacks().get(1); - this.attack2Icon.setVisible(attackTwo.isShowUI()); - this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType())); - this.attack2InfoPanelIconValue.setText(attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage()); - } else { - this.attack2Icon.setVisible(false); - } - - this.armorIcon.addSetPoint( - new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT, - GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f))); - this.armorIcon.positionBounds(this.uiViewport); - } else { - this.attack1Icon.setVisible(false); - this.attack2Icon.setVisible(false); - - this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, - FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f))); - this.armorIcon.positionBounds(this.uiViewport); - } - - localArmorIcon.setVisible(true); - final Texture defenseTexture = this.defenseBackdrops - .getTexture(unit.getSimulationUnit().getUnitType().getDefenseType()); - if (defenseTexture == null) { - throw new RuntimeException( - unit.getSimulationUnit().getUnitType().getDefenseType() + " can't find texture!"); - } - localArmorIconBackdrop.setTexture(defenseTexture); - localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense())); - unit.populateCommandCard(this.war3MapViewer.simulation, this, this.war3MapViewer.getAbilityDataUI(), - getSubMenuOrderId()); - } - } - - private void clearCommandCard() { - for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) { - for (int i = 0; i < COMMAND_CARD_WIDTH; i++) { - this.commandCard[j][i].setCommandButton(null); - } - } - } - - @Override - public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon, - final int abilityHandleId, final int orderId, final int autoCastId, final boolean active, - final boolean autoCastActive, final boolean menuButton) { - final int x = Math.max(0, Math.min(COMMAND_CARD_WIDTH - 1, buttonPositionX)); - final int y = Math.max(0, Math.min(COMMAND_CARD_HEIGHT - 1, buttonPositionY)); - this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId, autoCastId, active, autoCastActive, - menuButton); - } - - public void resize(final Rectangle viewport) { - this.cameraManager.resize(viewport); - positionPortrait(); - } - - public void positionPortrait() { - this.projectionTemp1.x = 422 * this.widthRatioCorrection; - this.projectionTemp1.y = 57 * this.heightRatioCorrection; - this.projectionTemp2.x = (422 + 167) * this.widthRatioCorrection; - this.projectionTemp2.y = (57 + 170) * this.heightRatioCorrection; - this.uiViewport.project(this.projectionTemp1); - this.uiViewport.project(this.projectionTemp2); - - this.tempRect.x = this.projectionTemp1.x + this.uiViewport.getScreenX(); - this.tempRect.y = this.projectionTemp1.y + this.uiViewport.getScreenY(); - this.tempRect.width = this.projectionTemp2.x - this.projectionTemp1.x; - this.tempRect.height = this.projectionTemp2.y - this.projectionTemp1.y; - this.portrait.portraitScene.camera.viewport(this.tempRect); - } - - private static final class InfoPanelIconBackdrops { - private final Texture[] damageBackdropTextures; - - public InfoPanelIconBackdrops(final CodeKeyType[] attackTypes, final GameUI gameUI, final String prefix, - final String suffix) { - this.damageBackdropTextures = new Texture[attackTypes.length]; - for (int index = 0; index < attackTypes.length; index++) { - final CodeKeyType attackType = attackTypes[index]; - String skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey() + suffix; - final Texture suffixTexture = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey)); - if (suffixTexture != null) { - this.damageBackdropTextures[index] = suffixTexture; - } else { - skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey(); - this.damageBackdropTextures[index] = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey)); - } - } - } - - public Texture getTexture(final CodeKeyType attackType) { - if (attackType != null) { - final int ordinal = attackType.ordinal(); - if ((ordinal >= 0) && (ordinal < this.damageBackdropTextures.length)) { - return this.damageBackdropTextures[ordinal]; - } - } - return this.damageBackdropTextures[0]; - } - - private static String getSuffix(final CAttackType attackType) { - switch (attackType) { - case CHAOS: - return "Chaos"; - case HERO: - return "Hero"; - case MAGIC: - return "Magic"; - case NORMAL: - return "Normal"; - case PIERCE: - return "Pierce"; - case SIEGE: - return "Siege"; - case SPELLS: - return "Magic"; - case UNKNOWN: - return "Unknown"; - default: - throw new IllegalArgumentException("Unknown attack type: " + attackType); - } - - } - } - - @Override - public void lifeChanged() { - if (this.selectedUnit.getSimulationUnit().isDead()) { - selectUnit(null); - } else { - this.unitLifeText - .setText(FastNumberFormat.formatWholeNumber(this.selectedUnit.getSimulationUnit().getLife()) + " / " - + this.selectedUnit.getSimulationUnit().getMaximumLife()); - } - } - - @Override - public void ordersChanged(final int abilityHandleId, final int orderId) { - clearAndRepopulateCommandCard(); - } - - private void clearAndRepopulateCommandCard() { - clearCommandCard(); - final AbilityDataUI abilityDataUI = this.war3MapViewer.getAbilityDataUI(); - final int menuOrderId = getSubMenuOrderId(); - if (this.activeCommand != null) { - final IconUI cancelUI = abilityDataUI.getCancelUI(); - this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0, - menuOrderId, 0, false, false, true); - } else { - if (menuOrderId != 0) { - final int exitOrderId = this.subMenuOrderIdStack.size() > 1 - ? this.subMenuOrderIdStack.get(this.subMenuOrderIdStack.size() - 2) - : 0; - final IconUI cancelUI = abilityDataUI.getCancelUI(); - this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0, - exitOrderId, 0, false, false, true); - } - this.selectedUnit.populateCommandCard(this.war3MapViewer.simulation, this, abilityDataUI, menuOrderId); - } - } - - private int getSubMenuOrderId() { - return this.subMenuOrderIdStack.isEmpty() ? 0 - : this.subMenuOrderIdStack.get(this.subMenuOrderIdStack.size() - 1); - } - - public RenderUnit getSelectedUnit() { - return this.selectedUnit; - } - - public boolean keyDown(final int keycode) { - return this.cameraManager.keyDown(keycode); - } - - public boolean keyUp(final int keycode) { - return this.cameraManager.keyUp(keycode); - } - - public void scrolled(final int amount) { - this.cameraManager.scrolled(amount); - } - - public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) { - screenCoordsVector.set(screenX, screenY); - this.uiViewport.unproject(screenCoordsVector); - if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) { - final Vector2 worldPoint = this.meleeUIMinimap.getWorldPointFromScreen(screenCoordsVector.x, - screenCoordsVector.y); - this.cameraManager.target.x = worldPoint.x; - this.cameraManager.target.y = worldPoint.y; - return true; - } - final UIFrame clickedUIFrame = this.rootFrame.touchDown(screenCoordsVector.x, screenCoordsVector.y, button); - if (clickedUIFrame == null) { - // try to interact with world - if (this.activeCommand != null) { - if (button == Input.Buttons.RIGHT) { - this.activeCommandUnit = null; - this.activeCommand = null; - this.activeCommandOrderId = -1; - clearAndRepopulateCommandCard(); - } else { - final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY, - this.activeCommandUnitTargetFilter); - final boolean shiftDown = isShiftDown(); - if (rayPickUnit != null) { - this.unitOrderListener.issueTargetOrder( - this.activeCommandUnit.getSimulationUnit().getHandleId(), - this.activeCommand.getHandleId(), this.activeCommandOrderId, - rayPickUnit.getSimulationUnit().getHandleId(), shiftDown); - if (getSelectedUnit().soundset.yesAttack - .playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { - portraitTalk(); - } - this.selectedSoundCount = 0; - if (!shiftDown) { - this.activeCommandUnit = null; - this.activeCommand = null; - this.activeCommandOrderId = -1; - clearAndRepopulateCommandCard(); - } - } else { - this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); - clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y); - - this.activeCommand.checkCanTarget(this.war3MapViewer.simulation, - this.activeCommandUnit.getSimulationUnit(), this.activeCommandOrderId, - clickLocationTemp2, PointAbilityTargetCheckReceiver.INSTANCE); - final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget(); - if (target != null) { - if (this.activeCommand instanceof CAbilityAttack) { - this.war3MapViewer.showConfirmation(clickLocationTemp, 1, 0, 0); - } else { - this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0); - } - this.unitOrderListener.issuePointOrder( - this.activeCommandUnit.getSimulationUnit().getHandleId(), - this.activeCommand.getHandleId(), this.activeCommandOrderId, clickLocationTemp2.x, - clickLocationTemp2.y, shiftDown); - if (getSelectedUnit().soundset.yes - .playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { - portraitTalk(); - } - this.selectedSoundCount = 0; - if (!shiftDown) { - this.activeCommandUnit = null; - this.activeCommand = null; - this.activeCommandOrderId = -1; - clearAndRepopulateCommandCard(); - } - - } - } - } - } else { - if (button == Input.Buttons.RIGHT) { - if (getSelectedUnit() != null) { - final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY); - if ((rayPickUnit != null) && !rayPickUnit.getSimulationUnit().isDead()) { - boolean ordered = false; - for (final RenderUnit unit : this.war3MapViewer.selected) { - for (final CAbility ability : unit.getSimulationUnit().getAbilities()) { - ability.checkCanTarget(this.war3MapViewer.simulation, unit.getSimulationUnit(), - OrderIds.smart, rayPickUnit.getSimulationUnit(), - CWidgetAbilityTargetCheckReceiver.INSTANCE); - final CWidget targetWidget = CWidgetAbilityTargetCheckReceiver.INSTANCE.getTarget(); - if (targetWidget != null) { - this.unitOrderListener.issueTargetOrder(unit.getSimulationUnit().getHandleId(), - ability.getHandleId(), OrderIds.smart, targetWidget.getHandleId(), - isShiftDown()); - ordered = true; - } - } - - } - if (ordered) { - if (getSelectedUnit().soundset.yesAttack.playUnitResponse( - this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { - portraitTalk(); - } - this.selectedSoundCount = 0; - } - } else { - this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); - this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0); - clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y); - - boolean ordered = false; - for (final RenderUnit unit : this.war3MapViewer.selected) { - for (final CAbility ability : unit.getSimulationUnit().getAbilities()) { - ability.checkCanUse(this.war3MapViewer.simulation, unit.getSimulationUnit(), - OrderIds.smart, BooleanAbilityActivationReceiver.INSTANCE); - if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) { - ability.checkCanTarget(this.war3MapViewer.simulation, unit.getSimulationUnit(), - OrderIds.smart, clickLocationTemp2, - PointAbilityTargetCheckReceiver.INSTANCE); - final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget(); - if (target != null) { - this.unitOrderListener.issuePointOrder( - unit.getSimulationUnit().getHandleId(), ability.getHandleId(), - OrderIds.smart, clickLocationTemp2.x, clickLocationTemp2.y, - isShiftDown()); - ordered = true; - } - } - } - - } - - if (ordered) { - if (getSelectedUnit().soundset.yes.playUnitResponse( - this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { - portraitTalk(); - } - this.selectedSoundCount = 0; - } - } - } - } else { - final List selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY, false); - if (!selectedUnits.isEmpty()) { - final RenderUnit unit = selectedUnits.get(0); - final boolean selectionChanged = getSelectedUnit() != unit; - boolean playedNewSound = false; - if (selectionChanged) { - this.selectedSoundCount = 0; - } - if (unit.soundset != null) { - UnitSound ackSoundToPlay = unit.soundset.what; - final int pissedSoundCount = unit.soundset.pissed.getSoundCount(); - int soundIndex; - if ((this.selectedSoundCount >= 3) && (pissedSoundCount > 0)) { - soundIndex = this.selectedSoundCount - 3; - ackSoundToPlay = unit.soundset.pissed; - } else { - soundIndex = (int) (Math.random() * ackSoundToPlay.getSoundCount()); - } - if (ackSoundToPlay.playUnitResponse(this.war3MapViewer.worldScene.audioContext, unit, - soundIndex)) { - this.selectedSoundCount++; - if ((this.selectedSoundCount - 3) >= pissedSoundCount) { - this.selectedSoundCount = 0; - } - playedNewSound = true; - } - } - if (selectionChanged) { - selectUnit(unit); - } - if (playedNewSound) { - portraitTalk(); - } - } else { - selectUnit(null); - } - } - } - } else { - if (clickedUIFrame instanceof CommandCardIcon) { - this.mouseDownUIFrame = (CommandCardIcon) clickedUIFrame; - this.mouseDownUIFrame.mouseDown(this.uiViewport); - } - } - return false; - } - - public boolean touchUp(final int screenX, final int screenY, final float worldScreenY, final int button) { - screenCoordsVector.set(screenX, screenY); - this.uiViewport.unproject(screenCoordsVector); - final UIFrame clickedUIFrame = this.rootFrame.touchUp(screenCoordsVector.x, screenCoordsVector.y, button); - if (this.mouseDownUIFrame != null) { - if (clickedUIFrame == this.mouseDownUIFrame) { - this.mouseDownUIFrame.onClick(button); - this.war3MapViewer.getUiSounds().getSound("InterfaceClick").play(this.uiScene.audioContext, 0, 0); - } - this.mouseDownUIFrame.mouseUp(this.uiViewport); - } - this.mouseDownUIFrame = null; - return false; - } - - private static boolean isShiftDown() { - return Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT); - } - - public boolean touchDragged(final int screenX, final int screenY, final float worldScreenY, final int pointer) { - screenCoordsVector.set(screenX, screenY); - this.uiViewport.unproject(screenCoordsVector); - - if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) { - final Vector2 worldPoint = this.meleeUIMinimap.getWorldPointFromScreen(screenCoordsVector.x, - screenCoordsVector.y); - this.cameraManager.target.x = worldPoint.x; - this.cameraManager.target.y = worldPoint.y; - } - return false; - } - - public float getHeightRatioCorrection() { - return this.heightRatioCorrection; - } + public static final float DEFAULT_COMMAND_CARD_ICON_WIDTH = 0.039f; + public static final float DEFAULT_COMMAND_CARD_ICON_PRESSED_WIDTH = 0.037f; + private static final int COMMAND_CARD_WIDTH = 4; + private static final int COMMAND_CARD_HEIGHT = 3; + + private static final Vector2 screenCoordsVector = new Vector2(); + private static final Vector3 clickLocationTemp = new Vector3(); + private static final Vector2 clickLocationTemp2 = new Vector2(); + private final DataSource dataSource; + private final ExtendViewport uiViewport; + private final FreeTypeFontGenerator fontGenerator; + private final Scene uiScene; + private final Scene portraitScene; + private final GameCameraManager cameraManager; + private final War3MapViewer war3MapViewer; + private final RootFrameListener rootFrameListener; + private GameUI rootFrame; + private UIFrame consoleUI; + private UIFrame resourceBar; + private StringFrame resourceBarGoldText; + private StringFrame resourceBarLumberText; + private StringFrame resourceBarSupplyText; + private StringFrame resourceBarUpkeepText; + private SpriteFrame timeIndicator; + private UIFrame unitPortrait; + private StringFrame unitLifeText; + private StringFrame unitManaText; + private Portrait portrait; + private final Rectangle tempRect = new Rectangle(); + private final Vector2 projectionTemp1 = new Vector2(); + private final Vector2 projectionTemp2 = new Vector2(); + private UIFrame simpleInfoPanelUnitDetail; + private StringFrame simpleNameValue; + private StringFrame simpleClassValue; + private StringFrame simpleBuildingActionLabel; + private UIFrame attack1Icon; + private TextureFrame attack1IconBackdrop; + private StringFrame attack1InfoPanelIconValue; + private StringFrame attack1InfoPanelIconLevel; + private UIFrame attack2Icon; + private TextureFrame attack2IconBackdrop; + private StringFrame attack2InfoPanelIconValue; + private StringFrame attack2InfoPanelIconLevel; + private UIFrame armorIcon; + private TextureFrame armorIconBackdrop; + private StringFrame armorInfoPanelIconValue; + private StringFrame armorInfoPanelIconLevel; + private InfoPanelIconBackdrops damageBackdrops; + private InfoPanelIconBackdrops defenseBackdrops; + + private final CommandCardIcon[][] commandCard = new CommandCardIcon[COMMAND_CARD_HEIGHT][COMMAND_CARD_WIDTH]; + + private RenderUnit selectedUnit; + private final List subMenuOrderIdStack = new ArrayList<>(); + + // TODO remove this & replace with FDF + private final Texture activeButtonTexture; + private UIFrame inventoryCover; + private SpriteFrame cursorFrame; + private MeleeUIMinimap meleeUIMinimap; + private final CPlayerUnitOrderListener unitOrderListener; + private StringFrame errorMessageFrame; + + private CAbilityView activeCommand; + private int activeCommandOrderId; + private RenderUnit activeCommandUnit; + + private int selectedSoundCount = 0; + private final ActiveCommandUnitTargetFilter activeCommandUnitTargetFilter; + + // TODO these corrections are used for old hardcoded UI stuff, we should + // probably remove them later + private final float widthRatioCorrection; + private final float heightRatioCorrection; + private CommandCardIcon mouseDownUIFrame; + + public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport, + final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final Scene portraitScene, + final CameraPreset[] cameraPresets, final CameraRates cameraRates, final War3MapViewer war3MapViewer, + final RootFrameListener rootFrameListener, final CPlayerUnitOrderListener unitOrderListener) { + this.dataSource = dataSource; + this.uiViewport = uiViewport; + this.fontGenerator = fontGenerator; + this.uiScene = uiScene; + this.portraitScene = portraitScene; + this.war3MapViewer = war3MapViewer; + this.rootFrameListener = rootFrameListener; + this.unitOrderListener = unitOrderListener; + + this.cameraManager = new GameCameraManager(cameraPresets, cameraRates); + + this.cameraManager.setupCamera(war3MapViewer.worldScene); + if (this.war3MapViewer.startLocations[0] != null) { + this.cameraManager.target.x = this.war3MapViewer.startLocations[0].x; + this.cameraManager.target.y = this.war3MapViewer.startLocations[0].y; + } + + this.activeButtonTexture = ImageUtils.getBLPTexture(war3MapViewer.mapMpq, + "UI\\Widgets\\Console\\Human\\CommandButton\\human-activebutton.blp"); + this.activeCommandUnitTargetFilter = new ActiveCommandUnitTargetFilter(); + this.widthRatioCorrection = this.uiViewport.getMinWorldWidth() / 1600f; + this.heightRatioCorrection = this.uiViewport.getMinWorldHeight() / 1200f; + + } + + private MeleeUIMinimap createMinimap(final War3MapViewer war3MapViewer) { + final Rectangle minimapDisplayArea = new Rectangle(18.75f * this.widthRatioCorrection, + 13.75f * this.heightRatioCorrection, 278.75f * this.widthRatioCorrection, + 276.25f * this.heightRatioCorrection); + Texture minimapTexture = null; + if (war3MapViewer.dataSource.has("war3mapMap.tga")) { + try { + minimapTexture = ImageUtils.getTextureNoColorCorrection(TgaFile.readTGA("war3mapMap.tga", + war3MapViewer.dataSource.getResourceAsStream("war3mapMap.tga"))); + } + catch (final IOException e) { + System.err.println("Could not load minimap TGA file"); + e.printStackTrace(); + } + } + else if (war3MapViewer.dataSource.has("war3mapMap.blp")) { + try { + minimapTexture = ImageUtils + .getTexture(ImageIO.read(war3MapViewer.dataSource.getResourceAsStream("war3mapMap.blp"))); + } + catch (final IOException e) { + System.err.println("Could not load minimap BLP file"); + e.printStackTrace(); + } + } + final Texture[] teamColors = new Texture[WarsmashConstants.MAX_PLAYERS]; + for (int i = 0; i < teamColors.length; i++) { + teamColors[i] = ImageUtils.getBLPTexture(war3MapViewer.dataSource, + "ReplaceableTextures\\" + ReplaceableIds.getPathString(1) + ReplaceableIds.getIdString(i) + ".blp"); + } + final Rectangle playableMapArea = war3MapViewer.terrain.getPlayableMapArea(); + return new MeleeUIMinimap(minimapDisplayArea, playableMapArea, minimapTexture, teamColors); + } + + /** + * Called "main" because this was originally written in JASS so that maps could + * override it, and I may convert it back to the JASS at some point. + */ + public void main() { + // ================================= + // Load skins and templates + // ================================= + this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 0), this.uiViewport, + this.fontGenerator, this.uiScene, this.war3MapViewer); + this.rootFrameListener.onCreate(this.rootFrame); + try { + this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc"); + } + catch (final IOException exc) { + throw new IllegalStateException("Unable to load FrameDef.toc", exc); + } + try { + this.rootFrame.loadTOCFile("UI\\FrameDef\\SmashFrameDef.toc"); + } + catch (final IOException exc) { + throw new IllegalStateException("Unable to load SmashFrameDef.toc", exc); + } + this.damageBackdrops = new InfoPanelIconBackdrops(CAttackType.values(), this.rootFrame, "Damage", "Neutral"); + this.defenseBackdrops = new InfoPanelIconBackdrops(CDefenseType.values(), this.rootFrame, "Armor", "Neutral"); + + // ================================= + // Load major UI components + // ================================= + // Console UI is the background with the racial theme + this.consoleUI = this.rootFrame.createSimpleFrame("ConsoleUI", this.rootFrame, 0); + this.consoleUI.setSetAllPoints(true); + + // Resource bar is a 3 part bar with Gold, Lumber, and Food. + // Its template does not specify where to put it, so we must + // put it in the "TOPRIGHT" corner. + this.resourceBar = this.rootFrame.createSimpleFrame("ResourceBarFrame", this.consoleUI, 0); + this.resourceBar.addSetPoint(new SetPoint(FramePoint.TOPRIGHT, this.consoleUI, FramePoint.TOPRIGHT, 0, 0)); + this.resourceBarGoldText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarGoldText", 0); + this.resourceBarGoldText.setText("500"); + this.resourceBarLumberText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarLumberText", 0); + this.resourceBarLumberText.setText("150"); + this.resourceBarSupplyText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarSupplyText", 0); + this.resourceBarSupplyText.setText("12/100"); + this.resourceBarUpkeepText = (StringFrame) this.rootFrame.getFrameByName("ResourceBarUpkeepText", 0); + this.resourceBarUpkeepText.setText("No Upkeep"); + this.resourceBarUpkeepText.setColor(Color.GREEN); + + // Create the Time Indicator (clock) + this.timeIndicator = (SpriteFrame) this.rootFrame.createFrame("TimeOfDayIndicator", this.rootFrame, 0, 0); + this.timeIndicator.setSequence(0); // play the stand + this.timeIndicator.setAnimationSpeed(0.0f); // do not advance automatically + + // Create the unit portrait stuff + this.portrait = new Portrait(this.war3MapViewer, this.portraitScene); + positionPortrait(); + this.unitPortrait = this.rootFrame.createSimpleFrame("UnitPortrait", this.consoleUI, 0); + this.unitLifeText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitHitPointText", 0); + this.unitManaText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitManaPointText", 0); + + this.simpleInfoPanelUnitDetail = this.rootFrame.createSimpleFrame("SimpleInfoPanelUnitDetail", this.consoleUI, + 0); + this.simpleInfoPanelUnitDetail + .addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f))); + this.simpleInfoPanelUnitDetail.setWidth(GameUI.convertY(this.uiViewport, 0.180f)); + this.simpleInfoPanelUnitDetail.setHeight(GameUI.convertY(this.uiViewport, 0.105f)); + this.simpleNameValue = (StringFrame) this.rootFrame.getFrameByName("SimpleNameValue", 0); + this.simpleClassValue = (StringFrame) this.rootFrame.getFrameByName("SimpleClassValue", 0); + this.simpleBuildingActionLabel = (StringFrame) this.rootFrame.getFrameByName("SimpleBuildingActionLabel", 0); + + this.attack1Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail, + 0); + this.attack1Icon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, + FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f))); + this.attack1IconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 0); + this.attack1InfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 0); + this.attack1InfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 0); + + this.attack2Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail, + 1); + this.attack2Icon + .addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT, + GameUI.convertX(this.uiViewport, 0.1f), GameUI.convertY(this.uiViewport, -0.030125f))); + this.attack2IconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 1); + this.attack2InfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 1); + this.attack2InfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 1); + + this.armorIcon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconArmor", this.simpleInfoPanelUnitDetail, + 1); + this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT, + GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f))); + this.armorIconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 0); + this.armorInfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 0); + this.armorInfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 0); + + this.inventoryCover = this.rootFrame.createSimpleFrame("SmashConsoleInventoryCover", this.rootFrame, 0); + + this.errorMessageFrame = this.rootFrame.createStringFrame("SmashErrorMessageFrame", this.consoleUI, + new Color(0xFFFFCC00), TextJustify.LEFT, TextJustify.MIDDLE, 0.014f); + this.errorMessageFrame.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT, + GameUI.convertX(this.uiViewport, 0.275f), GameUI.convertY(this.uiViewport, 0.275f))); + this.errorMessageFrame.setWidth(GameUI.convertX(this.uiViewport, 0.25f)); + + int commandButtonIndex = 0; + for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) { + for (int i = 0; i < COMMAND_CARD_WIDTH; i++) { + final CommandCardIcon commandCardIcon = new CommandCardIcon("SmashCommandButton_" + commandButtonIndex, + this.rootFrame, this); + this.rootFrame.add(commandCardIcon); + final TextureFrame iconFrame = this.rootFrame.createTextureFrame( + "SmashCommandButton_" + (commandButtonIndex) + "_Icon", this.rootFrame, false, null); + final TextureFrame activeHighlightFrame = this.rootFrame.createTextureFrame( + "SmashCommandButton_" + (commandButtonIndex) + "_ActiveHighlight", this.rootFrame, true, null, + FilterMode.ADDALPHA); + final SpriteFrame cooldownFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", + "SmashCommandButton_" + (commandButtonIndex) + "_Cooldown", this.rootFrame, "", 0); + final SpriteFrame autocastFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", + "SmashCommandButton_" + (commandButtonIndex) + "_Autocast", this.rootFrame, "", 0); + commandCardIcon.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT, + GameUI.convertX(this.uiViewport, 0.6175f + (0.0434f * i)), + GameUI.convertY(this.uiViewport, 0.095f - (0.044f * j)))); + commandCardIcon.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + commandCardIcon.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + iconFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); + iconFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + iconFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + iconFrame.setTexture(ImageUtils.DEFAULT_ICON_PATH, this.rootFrame); + activeHighlightFrame + .addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); + activeHighlightFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + activeHighlightFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + activeHighlightFrame.setTexture("CommandButtonActiveHighlight", this.rootFrame); + cooldownFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); + this.rootFrame.setSpriteFrameModel(cooldownFrame, this.rootFrame.getSkinField("CommandButtonCooldown")); + cooldownFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + cooldownFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + autocastFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); + this.rootFrame.setSpriteFrameModel(autocastFrame, this.rootFrame.getSkinField("CommandButtonAutocast")); + autocastFrame.setWidth(GameUI.convertX(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + autocastFrame.setHeight(GameUI.convertY(this.uiViewport, DEFAULT_COMMAND_CARD_ICON_WIDTH)); + commandCardIcon.set(iconFrame, activeHighlightFrame, cooldownFrame, autocastFrame); + this.commandCard[j][i] = commandCardIcon; + commandCardIcon.setCommandButton(null); + commandButtonIndex++; + } + } + + this.cursorFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", "SmashCursorFrame", this.rootFrame, + "", 0); + this.rootFrame.setSpriteFrameModel(this.cursorFrame, this.rootFrame.getSkinField("Cursor")); + this.cursorFrame.setSequence("Normal"); + this.cursorFrame.setZDepth(1.0f); + Gdx.input.setCursorCatched(true); + + this.meleeUIMinimap = createMinimap(this.war3MapViewer); + + this.rootFrame.positionBounds(this.uiViewport); + selectUnit(null); + } + + @Override + public void startUsingAbility(final int abilityHandleId, final int orderId) { + // TODO not O(N) + CAbilityView abilityToUse = null; + for (final CAbility ability : this.selectedUnit.getSimulationUnit().getAbilities()) { + if (ability.getHandleId() == abilityHandleId) { + abilityToUse = ability; + break; + } + } + if (abilityToUse != null) { + final StringMsgAbilityActivationReceiver stringMsgActivationReceiver = StringMsgAbilityActivationReceiver + .getInstance().reset(); + abilityToUse.checkCanUse(this.war3MapViewer.simulation, this.selectedUnit.getSimulationUnit(), orderId, + stringMsgActivationReceiver); + if (!stringMsgActivationReceiver.isUseOk()) { + showCommandError(stringMsgActivationReceiver.getMessage()); + } + else { + final BooleanAbilityTargetCheckReceiver noTargetReceiver = BooleanAbilityTargetCheckReceiver + .getInstance().reset(); + abilityToUse.checkCanTargetNoTarget(this.war3MapViewer.simulation, + this.selectedUnit.getSimulationUnit(), orderId, noTargetReceiver); + if (noTargetReceiver.isTargetable()) { + this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(), + abilityHandleId, orderId, isShiftDown()); + } + else { + this.activeCommand = abilityToUse; + this.activeCommandOrderId = orderId; + this.activeCommandUnit = this.selectedUnit; + clearAndRepopulateCommandCard(); + } + } + } + else { + this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(), + abilityHandleId, orderId, isShiftDown()); + } + } + + @Override + public void openMenu(final int orderId) { + if (orderId == 0) { + this.subMenuOrderIdStack.clear(); + this.activeCommandUnit = null; + this.activeCommand = null; + this.activeCommandOrderId = -1; + } + else { + this.subMenuOrderIdStack.add(orderId); + } + clearAndRepopulateCommandCard(); + } + + public void showCommandError(final String message) { + this.errorMessageFrame.setText(message); + } + + public void update(final float deltaTime) { + this.portrait.update(); + + int mouseX = Gdx.input.getX(); + int mouseY = Gdx.input.getY(); + final int minX = this.uiViewport.getScreenX(); + final int maxX = minX + this.uiViewport.getScreenWidth(); + final int minY = this.uiViewport.getScreenY(); + final int maxY = minY + this.uiViewport.getScreenHeight(); + final boolean left = mouseX <= (minX + 3); + final boolean right = mouseX >= (maxX - 3); + final boolean up = mouseY <= (minY + 3); + final boolean down = mouseY >= (maxY - 3); + this.cameraManager.applyVelocity(deltaTime, up, down, left, right); + + mouseX = Math.max(minX, Math.min(maxX, mouseX)); + mouseY = Math.max(minY, Math.min(maxY, mouseY)); + if (Gdx.input.isCursorCatched()) { + Gdx.input.setCursorPosition(mouseX, mouseY); + } + + screenCoordsVector.set(mouseX, mouseY); + this.uiViewport.unproject(screenCoordsVector); + this.cursorFrame.setFramePointX(FramePoint.LEFT, screenCoordsVector.x); + this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y); + + if (this.activeCommand != null) { + this.cursorFrame.setSequence("Target"); + } + else if (down) { + if (left) { + this.cursorFrame.setSequence("Scroll Down Left"); + } + else if (right) { + this.cursorFrame.setSequence("Scroll Down Right"); + } + else { + this.cursorFrame.setSequence("Scroll Down"); + } + } + else if (up) { + if (left) { + this.cursorFrame.setSequence("Scroll Up Left"); + } + else if (right) { + this.cursorFrame.setSequence("Scroll Up Right"); + } + else { + this.cursorFrame.setSequence("Scroll Up"); + } + } + else if (left) { + this.cursorFrame.setSequence("Scroll Left"); + } + else if (right) { + this.cursorFrame.setSequence("Scroll Right"); + } + else { + this.cursorFrame.setSequence("Normal"); + } + final float groundHeight = Math.max( + this.war3MapViewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y), + this.war3MapViewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y)); + this.cameraManager.updateTargetZ(groundHeight); + this.cameraManager.updateCamera(); + } + + public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) { + this.rootFrame.render(batch, font20, glyphLayout); + if (this.selectedUnit != null) { + font20.setColor(Color.WHITE); + + } + + this.meleeUIMinimap.render(batch, this.war3MapViewer.units); + this.timeIndicator.setFrameByRatio(this.war3MapViewer.simulation.getGameTimeOfDay() + / this.war3MapViewer.simulation.getGameplayConstants().getGameDayHours()); + } + + public void portraitTalk() { + this.portrait.talk(); + } + + private final class ActiveCommandUnitTargetFilter implements CUnitFilterFunction { + @Override + public boolean call(final CUnit unit) { + final BooleanAbilityTargetCheckReceiver targetReceiver = BooleanAbilityTargetCheckReceiver + .getInstance(); + MeleeUI.this.activeCommand.checkCanTarget(MeleeUI.this.war3MapViewer.simulation, + MeleeUI.this.activeCommandUnit.getSimulationUnit(), MeleeUI.this.activeCommandOrderId, unit, + targetReceiver); + return targetReceiver.isTargetable(); + } + } + + private static final class Portrait { + private MdxComplexInstance modelInstance; + private final PortraitCameraManager portraitCameraManager; + private final Scene portraitScene; + + public Portrait(final War3MapViewer war3MapViewer, final Scene portraitScene) { + this.portraitScene = portraitScene; + this.portraitCameraManager = new PortraitCameraManager(); + this.portraitCameraManager.setupCamera(this.portraitScene); + this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48)); + } + + public void update() { + this.portraitCameraManager.updateCamera(); + if ((this.modelInstance != null) + && (this.modelInstance.sequenceEnded || (this.modelInstance.sequence == -1))) { + SequenceUtils.randomSequence(this.modelInstance, PrimaryTag.PORTRAIT, SequenceUtils.EMPTY, true); + } + } + + public void talk() { + SequenceUtils.randomSequence(this.modelInstance, PrimaryTag.PORTRAIT, SequenceUtils.TALK, true); + } + + public void setSelectedUnit(final RenderUnit unit) { + if (unit == null) { + if (this.modelInstance != null) { + this.portraitScene.removeInstance(this.modelInstance); + } + this.modelInstance = null; + this.portraitCameraManager.setModelInstance(null, null); + } + else { + final MdxModel portraitModel = unit.portraitModel; + if (portraitModel != null) { + if (this.modelInstance != null) { + this.portraitScene.removeInstance(this.modelInstance); + } + this.modelInstance = (MdxComplexInstance) portraitModel.addInstance(); + this.portraitCameraManager.setModelInstance(this.modelInstance, portraitModel); + this.modelInstance.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP); + this.modelInstance.setScene(this.portraitScene); + this.modelInstance.setVertexColor(unit.instance.vertexColor); + this.modelInstance.setTeamColor(unit.playerIndex); + } + } + } + } + + public void selectUnit(RenderUnit unit) { + this.subMenuOrderIdStack.clear(); + if ((unit != null) && unit.getSimulationUnit().isDead()) { + unit = null; + } + if (this.selectedUnit != null) { + this.selectedUnit.getSimulationUnit().removeStateListener(this); + } + this.portrait.setSelectedUnit(unit); + this.selectedUnit = unit; + clearCommandCard(); + if (unit == null) { + this.simpleNameValue.setText(""); + this.unitLifeText.setText(""); + this.unitManaText.setText(""); + this.simpleClassValue.setText(""); + this.simpleBuildingActionLabel.setText(""); + this.attack1Icon.setVisible(false); + this.attack2Icon.setVisible(false); + this.attack1InfoPanelIconLevel.setText(""); + this.attack2InfoPanelIconLevel.setText(""); + this.armorIcon.setVisible(false); + this.armorInfoPanelIconLevel.setText(""); + } + else { + unit.getSimulationUnit().addStateListener(this); + this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName()); + String classText = null; + for (final CUnitClassification classification : unit.getSimulationUnit().getClassifications()) { + if ((classification == CUnitClassification.MECHANICAL) + && unit.getSimulationUnit().getUnitType().isBuilding()) { + // buildings dont display MECHANICAL + continue; + } + if (classification.getDisplayName() != null) { + classText = classification.getDisplayName(); + } + } + if (classText != null) { + this.simpleClassValue.setText(classText); + } + else { + this.simpleClassValue.setText(""); + } + this.unitLifeText.setText(FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getLife()) + " / " + + unit.getSimulationUnit().getMaximumLife()); + final int maximumMana = unit.getSimulationUnit().getMaximumMana(); + if (maximumMana > 0) { + this.unitManaText.setText( + FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getMana()) + " / " + maximumMana); + } + else { + this.unitManaText.setText(""); + } + this.simpleBuildingActionLabel.setText(""); + + final boolean anyAttacks = unit.getSimulationUnit().getUnitType().getAttacks().size() > 0; + final UIFrame localArmorIcon = this.armorIcon; + final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop; + final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue; + if (anyAttacks) { + final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0); + this.attack1Icon.setVisible(attackOne.isShowUI()); + this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType())); + this.attack1InfoPanelIconValue.setText(attackOne.getMinDamage() + " - " + attackOne.getMaxDamage()); + if (unit.getSimulationUnit().getUnitType().getAttacks().size() > 1) { + final CUnitAttack attackTwo = unit.getSimulationUnit().getUnitType().getAttacks().get(1); + this.attack2Icon.setVisible(attackTwo.isShowUI()); + this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType())); + this.attack2InfoPanelIconValue.setText(attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage()); + } + else { + this.attack2Icon.setVisible(false); + } + + this.armorIcon.addSetPoint( + new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT, + GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f))); + this.armorIcon.positionBounds(this.uiViewport); + } + else { + this.attack1Icon.setVisible(false); + this.attack2Icon.setVisible(false); + + this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, + FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f))); + this.armorIcon.positionBounds(this.uiViewport); + } + + localArmorIcon.setVisible(true); + final Texture defenseTexture = this.defenseBackdrops + .getTexture(unit.getSimulationUnit().getUnitType().getDefenseType()); + if (defenseTexture == null) { + throw new RuntimeException( + unit.getSimulationUnit().getUnitType().getDefenseType() + " can't find texture!"); + } + localArmorIconBackdrop.setTexture(defenseTexture); + localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense())); + unit.populateCommandCard(this.war3MapViewer.simulation, this, this.war3MapViewer.getAbilityDataUI(), + getSubMenuOrderId()); + } + } + + private void clearCommandCard() { + for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) { + for (int i = 0; i < COMMAND_CARD_WIDTH; i++) { + this.commandCard[j][i].setCommandButton(null); + } + } + } + + @Override + public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon, + final int abilityHandleId, final int orderId, final int autoCastId, final boolean active, + final boolean autoCastActive, final boolean menuButton) { + final int x = Math.max(0, Math.min(COMMAND_CARD_WIDTH - 1, buttonPositionX)); + final int y = Math.max(0, Math.min(COMMAND_CARD_HEIGHT - 1, buttonPositionY)); + this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId, autoCastId, active, autoCastActive, + menuButton); + } + + public void resize(final Rectangle viewport) { + this.cameraManager.resize(viewport); + positionPortrait(); + } + + public void positionPortrait() { + this.projectionTemp1.x = 422 * this.widthRatioCorrection; + this.projectionTemp1.y = 57 * this.heightRatioCorrection; + this.projectionTemp2.x = (422 + 167) * this.widthRatioCorrection; + this.projectionTemp2.y = (57 + 170) * this.heightRatioCorrection; + this.uiViewport.project(this.projectionTemp1); + this.uiViewport.project(this.projectionTemp2); + + this.tempRect.x = this.projectionTemp1.x + this.uiViewport.getScreenX(); + this.tempRect.y = this.projectionTemp1.y + this.uiViewport.getScreenY(); + this.tempRect.width = this.projectionTemp2.x - this.projectionTemp1.x; + this.tempRect.height = this.projectionTemp2.y - this.projectionTemp1.y; + this.portrait.portraitScene.camera.viewport(this.tempRect); + } + + private static final class InfoPanelIconBackdrops { + private final Texture[] damageBackdropTextures; + + public InfoPanelIconBackdrops(final CodeKeyType[] attackTypes, final GameUI gameUI, final String prefix, + final String suffix) { + this.damageBackdropTextures = new Texture[attackTypes.length]; + for (int index = 0; index < attackTypes.length; index++) { + final CodeKeyType attackType = attackTypes[index]; + String skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey() + suffix; + final Texture suffixTexture = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey)); + if (suffixTexture != null) { + this.damageBackdropTextures[index] = suffixTexture; + } + else { + skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey(); + this.damageBackdropTextures[index] = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey)); + } + } + } + + public Texture getTexture(final CodeKeyType attackType) { + if (attackType != null) { + final int ordinal = attackType.ordinal(); + if ((ordinal >= 0) && (ordinal < this.damageBackdropTextures.length)) { + return this.damageBackdropTextures[ordinal]; + } + } + return this.damageBackdropTextures[0]; + } + + private static String getSuffix(final CAttackType attackType) { + switch (attackType) { + case CHAOS: + return "Chaos"; + case HERO: + return "Hero"; + case MAGIC: + return "Magic"; + case NORMAL: + return "Normal"; + case PIERCE: + return "Pierce"; + case SIEGE: + return "Siege"; + case SPELLS: + return "Magic"; + case UNKNOWN: + return "Unknown"; + default: + throw new IllegalArgumentException("Unknown attack type: " + attackType); + } + + } + } + + @Override + public void lifeChanged() { + if (this.selectedUnit.getSimulationUnit().isDead()) { + selectUnit(null); + } + else { + this.unitLifeText + .setText(FastNumberFormat.formatWholeNumber(this.selectedUnit.getSimulationUnit().getLife()) + " / " + + this.selectedUnit.getSimulationUnit().getMaximumLife()); + } + } + + @Override + public void ordersChanged(final int abilityHandleId, final int orderId) { + clearAndRepopulateCommandCard(); + } + + private void clearAndRepopulateCommandCard() { + clearCommandCard(); + final AbilityDataUI abilityDataUI = this.war3MapViewer.getAbilityDataUI(); + final int menuOrderId = getSubMenuOrderId(); + if (this.activeCommand != null) { + final IconUI cancelUI = abilityDataUI.getCancelUI(); + this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0, + menuOrderId, 0, false, false, true); + } + else { + if (menuOrderId != 0) { + final int exitOrderId = this.subMenuOrderIdStack.size() > 1 + ? this.subMenuOrderIdStack.get(this.subMenuOrderIdStack.size() - 2) + : 0; + final IconUI cancelUI = abilityDataUI.getCancelUI(); + this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0, + exitOrderId, 0, false, false, true); + } + this.selectedUnit.populateCommandCard(this.war3MapViewer.simulation, this, abilityDataUI, menuOrderId); + } + } + + private int getSubMenuOrderId() { + return this.subMenuOrderIdStack.isEmpty() ? 0 + : this.subMenuOrderIdStack.get(this.subMenuOrderIdStack.size() - 1); + } + + public RenderUnit getSelectedUnit() { + return this.selectedUnit; + } + + public boolean keyDown(final int keycode) { + return this.cameraManager.keyDown(keycode); + } + + public boolean keyUp(final int keycode) { + return this.cameraManager.keyUp(keycode); + } + + public void scrolled(final int amount) { + this.cameraManager.scrolled(amount); + } + + public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) { + screenCoordsVector.set(screenX, screenY); + this.uiViewport.unproject(screenCoordsVector); + if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) { + final Vector2 worldPoint = this.meleeUIMinimap.getWorldPointFromScreen(screenCoordsVector.x, + screenCoordsVector.y); + this.cameraManager.target.x = worldPoint.x; + this.cameraManager.target.y = worldPoint.y; + return true; + } + final UIFrame clickedUIFrame = this.rootFrame.touchDown(screenCoordsVector.x, screenCoordsVector.y, button); + if (clickedUIFrame == null) { + // try to interact with world + if (this.activeCommand != null) { + if (button == Input.Buttons.RIGHT) { + this.activeCommandUnit = null; + this.activeCommand = null; + this.activeCommandOrderId = -1; + clearAndRepopulateCommandCard(); + } + else { + final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY, + this.activeCommandUnitTargetFilter); + final boolean shiftDown = isShiftDown(); + if (rayPickUnit != null) { + this.unitOrderListener.issueTargetOrder( + this.activeCommandUnit.getSimulationUnit().getHandleId(), + this.activeCommand.getHandleId(), this.activeCommandOrderId, + rayPickUnit.getSimulationUnit().getHandleId(), shiftDown); + if (getSelectedUnit().soundset.yesAttack + .playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { + portraitTalk(); + } + this.selectedSoundCount = 0; + if (!shiftDown) { + this.activeCommandUnit = null; + this.activeCommand = null; + this.activeCommandOrderId = -1; + clearAndRepopulateCommandCard(); + } + } + else { + this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); + clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y); + + this.activeCommand.checkCanTarget(this.war3MapViewer.simulation, + this.activeCommandUnit.getSimulationUnit(), this.activeCommandOrderId, + clickLocationTemp2, PointAbilityTargetCheckReceiver.INSTANCE); + final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget(); + if (target != null) { + if (this.activeCommand instanceof CAbilityAttack) { + this.war3MapViewer.showConfirmation(clickLocationTemp, 1, 0, 0); + } + else { + this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0); + } + this.unitOrderListener.issuePointOrder( + this.activeCommandUnit.getSimulationUnit().getHandleId(), + this.activeCommand.getHandleId(), this.activeCommandOrderId, clickLocationTemp2.x, + clickLocationTemp2.y, shiftDown); + if (getSelectedUnit().soundset.yes + .playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { + portraitTalk(); + } + this.selectedSoundCount = 0; + if (!shiftDown) { + this.activeCommandUnit = null; + this.activeCommand = null; + this.activeCommandOrderId = -1; + clearAndRepopulateCommandCard(); + } + + } + } + } + } + else { + if (button == Input.Buttons.RIGHT) { + if (getSelectedUnit() != null) { + final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY); + if ((rayPickUnit != null) && !rayPickUnit.getSimulationUnit().isDead()) { + boolean ordered = false; + for (final RenderUnit unit : this.war3MapViewer.selected) { + for (final CAbility ability : unit.getSimulationUnit().getAbilities()) { + ability.checkCanTarget(this.war3MapViewer.simulation, unit.getSimulationUnit(), + OrderIds.smart, rayPickUnit.getSimulationUnit(), + CWidgetAbilityTargetCheckReceiver.INSTANCE); + final CWidget targetWidget = CWidgetAbilityTargetCheckReceiver.INSTANCE.getTarget(); + if (targetWidget != null) { + this.unitOrderListener.issueTargetOrder(unit.getSimulationUnit().getHandleId(), + ability.getHandleId(), OrderIds.smart, targetWidget.getHandleId(), + isShiftDown()); + ordered = true; + } + } + + } + if (ordered) { + if (getSelectedUnit().soundset.yesAttack.playUnitResponse( + this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { + portraitTalk(); + } + this.selectedSoundCount = 0; + } + } + else { + this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); + this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0); + clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y); + + boolean ordered = false; + for (final RenderUnit unit : this.war3MapViewer.selected) { + for (final CAbility ability : unit.getSimulationUnit().getAbilities()) { + ability.checkCanUse(this.war3MapViewer.simulation, unit.getSimulationUnit(), + OrderIds.smart, BooleanAbilityActivationReceiver.INSTANCE); + if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) { + ability.checkCanTarget(this.war3MapViewer.simulation, unit.getSimulationUnit(), + OrderIds.smart, clickLocationTemp2, + PointAbilityTargetCheckReceiver.INSTANCE); + final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget(); + if (target != null) { + this.unitOrderListener.issuePointOrder( + unit.getSimulationUnit().getHandleId(), ability.getHandleId(), + OrderIds.smart, clickLocationTemp2.x, clickLocationTemp2.y, + isShiftDown()); + ordered = true; + } + } + } + + } + + if (ordered) { + if (getSelectedUnit().soundset.yes.playUnitResponse( + this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) { + portraitTalk(); + } + this.selectedSoundCount = 0; + } + } + } + } + else { + final List selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY, false); + if (!selectedUnits.isEmpty()) { + final RenderUnit unit = selectedUnits.get(0); + final boolean selectionChanged = getSelectedUnit() != unit; + boolean playedNewSound = false; + if (selectionChanged) { + this.selectedSoundCount = 0; + } + if (unit.soundset != null) { + UnitSound ackSoundToPlay = unit.soundset.what; + final int pissedSoundCount = unit.soundset.pissed.getSoundCount(); + int soundIndex; + if ((this.selectedSoundCount >= 3) && (pissedSoundCount > 0)) { + soundIndex = this.selectedSoundCount - 3; + ackSoundToPlay = unit.soundset.pissed; + } + else { + soundIndex = (int) (Math.random() * ackSoundToPlay.getSoundCount()); + } + if (ackSoundToPlay.playUnitResponse(this.war3MapViewer.worldScene.audioContext, unit, + soundIndex)) { + this.selectedSoundCount++; + if ((this.selectedSoundCount - 3) >= pissedSoundCount) { + this.selectedSoundCount = 0; + } + playedNewSound = true; + } + } + if (selectionChanged) { + selectUnit(unit); + } + if (playedNewSound) { + portraitTalk(); + } + } + else { + selectUnit(null); + } + } + } + } + else { + if (clickedUIFrame instanceof CommandCardIcon) { + this.mouseDownUIFrame = (CommandCardIcon) clickedUIFrame; + this.mouseDownUIFrame.mouseDown(this.uiViewport); + } + } + return false; + } + + public boolean touchUp(final int screenX, final int screenY, final float worldScreenY, final int button) { + screenCoordsVector.set(screenX, screenY); + this.uiViewport.unproject(screenCoordsVector); + final UIFrame clickedUIFrame = this.rootFrame.touchUp(screenCoordsVector.x, screenCoordsVector.y, button); + if (this.mouseDownUIFrame != null) { + if (clickedUIFrame == this.mouseDownUIFrame) { + this.mouseDownUIFrame.onClick(button); + this.war3MapViewer.getUiSounds().getSound("InterfaceClick").play(this.uiScene.audioContext, 0, 0); + } + this.mouseDownUIFrame.mouseUp(this.uiViewport); + } + this.mouseDownUIFrame = null; + return false; + } + + private static boolean isShiftDown() { + return Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT); + } + + public boolean touchDragged(final int screenX, final int screenY, final float worldScreenY, final int pointer) { + screenCoordsVector.set(screenX, screenY); + this.uiViewport.unproject(screenCoordsVector); + + if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) { + final Vector2 worldPoint = this.meleeUIMinimap.getWorldPointFromScreen(screenCoordsVector.x, + screenCoordsVector.y); + this.cameraManager.target.x = worldPoint.x; + this.cameraManager.target.y = worldPoint.y; + } + return false; + } + + public float getHeightRatioCorrection() { + return this.heightRatioCorrection; + } } diff --git a/desktop/src/com/etheller/warsmash/desktop/DesktopLauncher.java b/desktop/src/com/etheller/warsmash/desktop/DesktopLauncher.java index 9caaca2..c53e166 100644 --- a/desktop/src/com/etheller/warsmash/desktop/DesktopLauncher.java +++ b/desktop/src/com/etheller/warsmash/desktop/DesktopLauncher.java @@ -64,6 +64,9 @@ public class DesktopLauncher { Extensions.soundLengthExtension = new SoundLengthExtension() { @Override public float getDuration(final Sound sound) { + if (sound == null) { + return 1; + } return ((OpenALSound) sound).duration(); } };