diff --git a/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java b/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java index 71542ff..11872d9 100644 --- a/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java +++ b/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java @@ -10,7 +10,6 @@ import java.util.List; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Input; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.graphics.Color; @@ -26,8 +25,6 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFont import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Rectangle; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.utils.viewport.ExtendViewport; import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor; import com.etheller.warsmash.datasources.DataSource; @@ -50,17 +47,15 @@ import com.etheller.warsmash.viewer5.Scene; import com.etheller.warsmash.viewer5.TextureMapper; import com.etheller.warsmash.viewer5.handlers.ModelHandler; import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel; -import com.etheller.warsmash.viewer5.handlers.w3x.UnitSound; import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer; import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraPreset; import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraRates; -import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayerUnitOrderExecutor; 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_MUSIC = false; - private static final Vector3 clickLocationTemp = new Vector3(); - private static final Vector2 clickLocationTemp2 = new Vector2(); private DataSource codebase; private War3MapViewer viewer; private final Rectangle tempRect = new Rectangle(); @@ -73,8 +68,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv private ExtendViewport uiViewport; private GlyphLayout glyphLayout; - private int selectedSoundCount = 0; - private Texture solidGreenTexture; private ShapeRenderer shapeRenderer; @@ -227,7 +220,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv music.play(); } } - }); + }, new CPlayerUnitOrderExecutor(this.viewer.simulation, new CommandErrorListener() { + @Override + public void showCommandError(final String message) { + WarsmashGdxMapGame.this.meleeUI.showCommandError(message); + } + })); final ModelInstance libgdxContentInstance = new LibGDXContentLayerModel(null, this.viewer, "", this.viewer.mapPathSolver, "").addInstance(); libgdxContentInstance.setScene(this.uiScene); @@ -361,85 +359,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv @Override public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) { final float worldScreenY = getHeight() - screenY; - System.out.println(screenX + "," + screenY); - clickLocationTemp2.x = screenX; - clickLocationTemp2.y = screenY; - this.uiViewport.unproject(clickLocationTemp2); - - if (this.meleeUI.touchDown(clickLocationTemp2.x, clickLocationTemp2.y, button)) { + if (this.meleeUI.touchDown(screenX, screenY, worldScreenY, button)) { return false; } - if (button == Input.Buttons.RIGHT) { - final RenderUnit rayPickUnit = this.viewer.rayPickUnit(screenX, worldScreenY); - if (this.meleeUI.getSelectedUnit() != null) { - if ((rayPickUnit != null) && (rayPickUnit.playerIndex != this.meleeUI.getSelectedUnit().playerIndex) - && !rayPickUnit.getSimulationUnit().isDead()) { - if (this.viewer.orderSmart(rayPickUnit)) { - if (this.meleeUI.getSelectedUnit().soundset.yesAttack.playUnitResponse( - this.viewer.worldScene.audioContext, this.meleeUI.getSelectedUnit())) { - this.meleeUI.portraitTalk(); - } - this.selectedSoundCount = 0; - } - } - else { - this.viewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); - System.out.println(clickLocationTemp); - this.viewer.showConfirmation(clickLocationTemp, 0, 1, 0); - final int x = (int) ((clickLocationTemp.x - this.viewer.terrain.centerOffset[0]) / 128); - final int y = (int) ((clickLocationTemp.y - this.viewer.terrain.centerOffset[1]) / 128); - System.out.println(x + "," + y); - this.viewer.terrain.logRomp(x, y); - if (this.viewer.orderSmart(clickLocationTemp.x, clickLocationTemp.y)) { - if (this.meleeUI.getSelectedUnit().soundset.yes.playUnitResponse( - this.viewer.worldScene.audioContext, this.meleeUI.getSelectedUnit())) { - this.meleeUI.portraitTalk(); - } - this.selectedSoundCount = 0; - } - } - } - } - else { - final List selectedUnits = this.viewer.selectUnit(screenX, worldScreenY, false); - if (!selectedUnits.isEmpty()) { - final RenderUnit unit = selectedUnits.get(0); - final boolean selectionChanged = this.meleeUI.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.viewer.worldScene.audioContext, unit, soundIndex)) { - this.selectedSoundCount++; - if ((this.selectedSoundCount - 3) >= pissedSoundCount) { - this.selectedSoundCount = 0; - } - playedNewSound = true; - } - } - if (selectionChanged) { - this.meleeUI.selectUnit(unit); - } - if (playedNewSound) { - this.meleeUI.portraitTalk(); - } - } - else { - this.meleeUI.selectUnit(null); - } - } return false; } diff --git a/core/src/com/etheller/warsmash/parsers/fdf/GameUI.java b/core/src/com/etheller/warsmash/parsers/fdf/GameUI.java index 1d0be0c..04a54bb 100644 --- a/core/src/com/etheller/warsmash/parsers/fdf/GameUI.java +++ b/core/src/com/etheller/warsmash/parsers/fdf/GameUI.java @@ -211,6 +211,19 @@ public final class GameUI extends AbstractUIFrame implements UIFrame { return textureFrame; } + public StringFrame createStringFrame(final String name, final UIFrame parent, final Color color, + final TextJustify justifyH, final TextJustify justifyV, final float fdfFontSize) { + this.fontParam.size = (int) convertY(this.viewport, fdfFontSize); + if (this.fontParam.size == 0) { + this.fontParam.size = 24; + } + final BitmapFont frameFont = this.fontGenerator.generateFont(this.fontParam); + final StringFrame stringFrame = new StringFrame(name, parent, color, justifyH, justifyV, frameFont); + this.nameToFrame.put(name, stringFrame); + add(stringFrame); + return stringFrame; + } + public UIFrame inflate(final FrameDefinition frameDefinition, final UIFrame parent, final FrameDefinition parentDefinitionIfAvailable) { UIFrame inflatedFrame = null; 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 1a797b9..80984af 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java @@ -81,17 +81,16 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataU 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.CUnitClassification; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitFilterFunction; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackInstant; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissile; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CWidgetAbilityTargetCheckReceiver; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.PointAbilityTargetCheckReceiver; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController; import mpq.MPQArchive; @@ -1135,6 +1134,10 @@ public class War3MapViewer extends ModelViewer { } public RenderUnit rayPickUnit(final float x, final float y) { + return rayPickUnit(x, y, CUnitFilterFunction.ACCEPT_ALL); + } + + public RenderUnit rayPickUnit(final float x, final float y, final CUnitFilterFunction filter) { final float[] ray = rayHeap; mousePosHeap.set(x, y); this.worldScene.camera.screenToWorldRay(ray, mousePosHeap); @@ -1146,7 +1149,11 @@ public class War3MapViewer extends ModelViewer { final MdxComplexInstance instance = unit.instance; if (instance.isVisible(this.worldScene.camera) && instance.intersectRayWithCollision(gdxRayHeap, intersectionHeap, unit.getSimulationUnit().getUnitType().isBuilding())) { - entity = unit; + if (filter.call(unit.getSimulationUnit())) { + if ((entity == null) || (entity.instance.depth > instance.depth)) { + entity = unit; + } + } } } return entity; @@ -1235,41 +1242,6 @@ public class War3MapViewer extends ModelViewer { return (numElements < 0) ? 1 : (numElements >= MAXIMUM_ACCEPTED) ? MAXIMUM_ACCEPTED : numElements + 1; } - public boolean orderSmart(final float x, final float y) { - mousePosHeap.x = x; - mousePosHeap.y = y; - boolean ordered = false; - for (final RenderUnit unit : this.selected) { - for (final CAbility ability : unit.getSimulationUnit().getAbilities()) { - if (ability instanceof CAbilityMove) { - ability.checkCanUse(this.simulation, unit.getSimulationUnit(), OrderIds.smart, - BooleanAbilityActivationReceiver.INSTANCE); - if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) { - ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap, - PointAbilityTargetCheckReceiver.INSTANCE); - final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget(); - if (target != null) { - ability.onOrder(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap, - false); - ordered = true; - } - else { - System.err.println("Target not valid."); - } - } - else { - System.err.println("Ability not ok to use."); - } - } - else { - System.err.println("Ability not move."); - } - } - - } - return ordered; - } - public boolean orderSmart(final RenderUnit target) { boolean ordered = false; for (final RenderUnit unit : this.selected) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandButtonListener.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandButtonListener.java index 04c2414..89a82a9 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandButtonListener.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandButtonListener.java @@ -34,5 +34,5 @@ public interface CommandButtonListener { // int getButtonPositionY(); // // int getOrderId(); - void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int orderId); + void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int abilityHandleId, int orderId); } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandCardPopulatingAbilityVisitor.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandCardPopulatingAbilityVisitor.java index a919955..c0aeb88 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandCardPopulatingAbilityVisitor.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/commandbuttons/CommandCardPopulatingAbilityVisitor.java @@ -46,6 +46,6 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor handleIdToUnit = new HashMap<>(); + private final Map handleIdToAbility = new HashMap<>(); public CSimulation(final DataTable miscData, final MutableObjectData parsedUnitData, final MutableObjectData parsedAbilityData, final SimulationRenderController simulationRenderController, @@ -106,10 +111,22 @@ public class CSimulation { final CUnit unit = this.unitData.create(this, playerIndex, typeId, x, y, facing, buildingPathingPixelMap, this.simulationRenderController, this.handleIdAllocator); this.units.add(unit); + this.handleIdToUnit.put(unit.getHandleId(), unit); + for (final CAbility ability : unit.getAbilities()) { + this.handleIdToAbility.put(ability.getHandleId(), ability); + } this.worldCollision.addUnit(unit); return unit; } + public CUnit getUnit(final int handleId) { + return this.handleIdToUnit.get(handleId); + } + + public CAbility getAbility(final int handleId) { + return this.handleIdToAbility.get(handleId); + } + public CAttackProjectile createProjectile(final CUnit source, final float launchX, final float launchY, final float launchFacing, final CUnitAttackMissile attack, final CWidget target, final float damage, final int bounceIndex) { @@ -142,6 +159,10 @@ public class CSimulation { final CUnit unit = unitIterator.next(); if (unit.update(this)) { unitIterator.remove(); + for (final CAbility ability : unit.getAbilities()) { + this.handleIdToAbility.remove(ability.getHandleId()); + } + this.handleIdToUnit.remove(unit.getHandleId()); this.simulationRenderController.removeUnit(unit); } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnitFilterFunction.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnitFilterFunction.java new file mode 100644 index 0000000..6cbc073 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnitFilterFunction.java @@ -0,0 +1,12 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation; + +public interface CUnitFilterFunction { + boolean call(CUnit unit); + + CUnitFilterFunction ACCEPT_ALL = new CUnitFilterFunction() { + @Override + public boolean call(final CUnit unit) { + return true; + } + }; +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerController.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerController.java deleted file mode 100644 index fc482c1..0000000 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerController.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players; - -public interface CPlayerController { - boolean issueTargetOrder(int unitHandleId, int orderId, int targetHandleId); - - boolean issuePointOrder(int unitHandleId, int orderId, float x, float y); - - boolean issueImmediateOrder(int unitHandleId, int orderId); -} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerUnitOrderExecutor.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerUnitOrderExecutor.java new file mode 100644 index 0000000..ea56443 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerUnitOrderExecutor.java @@ -0,0 +1,101 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players; + +import com.badlogic.gdx.math.Vector2; +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; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgAbilityActivationReceiver; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgTargetCheckReceiver; +import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener; + +public class CPlayerUnitOrderExecutor implements CPlayerUnitOrderListener { + private final CSimulation game; + private final CommandErrorListener errorListener; + private final StringMsgTargetCheckReceiver targetCheckReceiver = new StringMsgTargetCheckReceiver<>(); + private final StringMsgAbilityActivationReceiver abilityActivationReceiver = new StringMsgAbilityActivationReceiver(); + + private StringMsgTargetCheckReceiver targetCheckReceiver() { + return (StringMsgTargetCheckReceiver) this.targetCheckReceiver.reset(); + } + + public CPlayerUnitOrderExecutor(final CSimulation game, final CommandErrorListener errorListener) { + this.game = game; + this.errorListener = errorListener; + } + + @Override + public boolean issueTargetOrder(final int unitHandleId, final int abilityHandleId, final int orderId, + final int targetHandleId, final boolean queue) { + final CUnit unit = this.game.getUnit(unitHandleId); + final CAbility ability = this.game.getAbility(abilityHandleId); + ability.checkCanUse(this.game, unit, orderId, this.abilityActivationReceiver.reset()); + if (this.abilityActivationReceiver.isUseOk()) { + final CUnit target = this.game.getUnit(targetHandleId); + final StringMsgTargetCheckReceiver targetReceiver = this.targetCheckReceiver(); + ability.checkCanTarget(this.game, unit, orderId, target, targetReceiver); + if (targetReceiver.getTarget() != null) { + ability.onOrder(this.game, unit, orderId, target, queue); + return true; + } + else { + this.errorListener.showCommandError(targetReceiver.getMessage()); + return false; + } + } + else { + this.errorListener.showCommandError(this.abilityActivationReceiver.getMessage()); + return false; + } + } + + @Override + public boolean issuePointOrder(final int unitHandleId, final int abilityHandleId, final int orderId, final float x, + final float y, final boolean queue) { + final CUnit unit = this.game.getUnit(unitHandleId); + final CAbility ability = this.game.getAbility(abilityHandleId); + ability.checkCanUse(this.game, unit, orderId, this.abilityActivationReceiver.reset()); + if (this.abilityActivationReceiver.isUseOk()) { + final Vector2 target = new Vector2(x, y); + final StringMsgTargetCheckReceiver targetReceiver = this.targetCheckReceiver(); + ability.checkCanTarget(this.game, unit, orderId, target, targetReceiver); + if (targetReceiver.getTarget() != null) { + ability.onOrder(this.game, unit, orderId, target, queue); + return true; + } + else { + this.errorListener.showCommandError(targetReceiver.getMessage()); + return false; + } + } + else { + this.errorListener.showCommandError(this.abilityActivationReceiver.getMessage()); + return false; + } + } + + @Override + public boolean issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId, + final boolean queue) { + final CUnit unit = this.game.getUnit(unitHandleId); + final CAbility ability = this.game.getAbility(abilityHandleId); + ability.checkCanUse(this.game, unit, orderId, this.abilityActivationReceiver.reset()); + if (this.abilityActivationReceiver.isUseOk()) { + final StringMsgTargetCheckReceiver targetReceiver = this.targetCheckReceiver(); + ability.checkCanTargetNoTarget(this.game, unit, orderId, targetReceiver); + if (targetReceiver.getTarget() != null) { + ability.onOrderNoTarget(this.game, unit, orderId, queue); + return true; + } + else { + this.errorListener.showCommandError(targetReceiver.getMessage()); + return false; + } + } + else { + this.errorListener.showCommandError(this.abilityActivationReceiver.getMessage()); + return false; + } + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerUnitOrderListener.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerUnitOrderListener.java new file mode 100644 index 0000000..a0d420a --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayerUnitOrderListener.java @@ -0,0 +1,12 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players; + +public interface CPlayerUnitOrderListener { + boolean issueTargetOrder(int unitHandleId, int abilityHandleId, int orderId, int targetHandleId, boolean queue); + + boolean issuePointOrder(int unitHandleId, int abilityHandleId, int orderId, float x, float y, boolean queue); + + // Below: used for "DROP ITEM AT POINT" ???? +// boolean issueTargetAndPointOrder(int unitHandleId, int orderId, int targetHandleId, float x, float y); + + boolean issueImmediateOrder(int unitHandleId, int abilityHandleId, int orderId, boolean queue); +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/BooleanAbilityTargetCheckReceiver.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/BooleanAbilityTargetCheckReceiver.java new file mode 100644 index 0000000..ab1a986 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/BooleanAbilityTargetCheckReceiver.java @@ -0,0 +1,66 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util; + +public final class BooleanAbilityTargetCheckReceiver implements AbilityTargetCheckReceiver { + private static final BooleanAbilityTargetCheckReceiver INSTANCE = new BooleanAbilityTargetCheckReceiver<>(); + + public static BooleanAbilityTargetCheckReceiver getInstance() { + return (BooleanAbilityTargetCheckReceiver) INSTANCE; + } + + private boolean targetable = false; + + public boolean isTargetable() { + return this.targetable; + } + + public BooleanAbilityTargetCheckReceiver reset() { + this.targetable = false; + return this; + } + + @Override + public void targetOk(final TARGET_TYPE target) { + this.targetable = true; + } + + @Override + public void mustTargetTeamType(final TeamType correctType) { + this.targetable = false; + } + + @Override + public void mustTargetType(final TargetType correctType) { + this.targetable = false; + } + + @Override + public void targetOutsideRange(final double howMuch) { + this.targetable = false; + } + + @Override + public void notAnActiveAbility() { + this.targetable = false; + } + + @Override + public void targetNotVisible() { + this.targetable = false; + } + + @Override + public void targetTooComplicated() { + this.targetable = false; + } + + @Override + public void targetNotInPlayableMap() { + this.targetable = false; + } + + @Override + public void orderIdNotAccepted() { + this.targetable = false; + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/StringMsgAbilityActivationReceiver.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/StringMsgAbilityActivationReceiver.java new file mode 100644 index 0000000..d9d77bb --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/StringMsgAbilityActivationReceiver.java @@ -0,0 +1,57 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util; + +public class StringMsgAbilityActivationReceiver implements AbilityActivationReceiver { + private static final StringMsgAbilityActivationReceiver INSTANCE = new StringMsgAbilityActivationReceiver(); + + public static StringMsgAbilityActivationReceiver getInstance() { + return INSTANCE; + } + + private String message; + private boolean useOk = false; + + public StringMsgAbilityActivationReceiver reset() { + this.message = null; + this.useOk = false; + return this; + } + + public String getMessage() { + return this.message; + } + + public boolean isUseOk() { + return this.useOk; + } + + @Override + public void useOk() { + this.useOk = true; + } + + @Override + public void notEnoughResources(final ResourceType resource, final int amount) { + this.message = "NOTEXTERN: Requires " + amount + " " + resource.name().toLowerCase() + "."; + } + + @Override + public void notAnActiveAbility() { + this.message = "NOTEXTERN: Not an active ability."; + } + + @Override + public void missingRequirement(final String name) { + this.message = "NOTEXTERN: Requires " + name; + } + + @Override + public void cargoCapacityUnavailable() { + this.message = "NOTEXTERN: Cargo capacity unavailable."; + } + + @Override + public void casterMovementDisabled() { + this.message = "NOTEXTERN: Caster movement disabled."; + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/StringMsgTargetCheckReceiver.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/StringMsgTargetCheckReceiver.java new file mode 100644 index 0000000..1622261 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/util/StringMsgTargetCheckReceiver.java @@ -0,0 +1,96 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util; + +public final class StringMsgTargetCheckReceiver implements AbilityTargetCheckReceiver { + private static final StringMsgTargetCheckReceiver INSTANCE = new StringMsgTargetCheckReceiver<>(); + + public static StringMsgTargetCheckReceiver getInstance() { + return (StringMsgTargetCheckReceiver) INSTANCE; + } + + private TARGET_TYPE target; + private String message; + + public TARGET_TYPE getTarget() { + return this.target; + } + + public String getMessage() { + return this.message; + } + + public StringMsgTargetCheckReceiver reset() { + this.target = null; + this.message = null; + return this; + } + + @Override + public void targetOk(final TARGET_TYPE target) { + this.target = target; + } + + @Override + public void mustTargetTeamType(final TeamType correctType) { + switch (correctType) { + case ALLIED: + this.message = "NOTEXTERN: Must target an allied unit."; + break; + case ENEMY: + this.message = "NOTEXTERN: Must target an enemy unit."; + break; + case PLAYER_UNITS: + this.message = "NOTEXTERN: Unable to target a unit you do not control."; + break; + default: + this.message = "NOTEXTERN: Must target team type: " + correctType; + } + } + + @Override + public void mustTargetType(final TargetType correctType) { + switch (correctType) { + case POINT: + this.message = "NOTEXTERN: Must target a point."; + break; + case UNIT: + this.message = "NOTEXTERN: Must target a unit."; + break; + case UNIT_OR_POINT: + this.message = "NOTEXTERN: Must target a unit or point."; + break; + default: + this.message = "NOTEXTERN: Must target type: " + correctType; + } + } + + @Override + public void targetOutsideRange(final double howMuch) { + this.message = "NOTEXTERN: Target is outside range."; + } + + @Override + public void notAnActiveAbility() { + this.message = "NOTEXTERN: Not an active ability."; + } + + @Override + public void targetNotVisible() { + this.message = "NOTEXTERN: Target is not visible."; + } + + @Override + public void targetTooComplicated() { + this.message = "NOTEXTERN: Target is too complicated."; + } + + @Override + public void targetNotInPlayableMap() { + this.message = "NOTEXTERN: Target is not within the designed combat area."; + } + + @Override + public void orderIdNotAccepted() { + this.message = "NOTEXTERN: OrderID not accepted."; + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/CommandCardIcon.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/CommandCardIcon.java index 2449cb6..fc7cbd3 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/CommandCardIcon.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/CommandCardIcon.java @@ -1,5 +1,6 @@ package com.etheller.warsmash.viewer5.handlers.w3x.ui; +import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.GlyphLayout; @@ -11,6 +12,7 @@ import com.etheller.warsmash.parsers.fdf.frames.TextureFrame; import com.etheller.warsmash.parsers.fdf.frames.UIFrame; import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButton; +import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandCardCommandListener; public class CommandCardIcon extends AbstractRenderableFrame { @@ -18,9 +20,14 @@ public class CommandCardIcon extends AbstractRenderableFrame { private SpriteFrame cooldownFrame; private SpriteFrame autocastFrame; private CommandButton commandButton; + private int abilityHandleId; + private int orderId; + private final CommandCardCommandListener commandCardCommandListener; - public CommandCardIcon(final String name, final UIFrame parent) { + public CommandCardIcon(final String name, final UIFrame parent, + final CommandCardCommandListener commandCardCommandListener) { super(name, parent); + this.commandCardCommandListener = commandCardCommandListener; } public void set(final TextureFrame iconFrame, final SpriteFrame cooldownFrame, final SpriteFrame autocastFrame) { @@ -57,11 +64,13 @@ public class CommandCardIcon extends AbstractRenderableFrame { } } - public void setCommandButtonData(final Texture texture, final int orderId) { + public void setCommandButtonData(final Texture texture, final int abilityHandleId, final int orderId) { this.iconFrame.setVisible(true); this.cooldownFrame.setVisible(false); this.autocastFrame.setVisible(false); this.iconFrame.setTexture(texture); + this.abilityHandleId = abilityHandleId; + this.orderId = orderId; } @Override @@ -81,6 +90,12 @@ public class CommandCardIcon extends AbstractRenderableFrame { @Override public UIFrame touchDown(final float screenX, final float screenY, final int button) { if (this.renderBounds.contains(screenX, screenY)) { + if (button == Input.Buttons.LEFT) { + this.commandCardCommandListener.startUsingAbility(this.abilityHandleId, this.orderId); + } + else if (button == Input.Buttons.RIGHT) { + this.commandCardCommandListener.toggleAutoCastAbility(this.abilityHandleId); + } return this; } return null; 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 1c57b9a..8ae6024 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 @@ -1,10 +1,12 @@ package com.etheller.warsmash.viewer5.handlers.w3x.ui; import java.io.IOException; +import java.util.List; import javax.imageio.ImageIO; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; @@ -13,11 +15,13 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.utils.viewport.Viewport; import com.etheller.warsmash.datasources.DataSource; import com.etheller.warsmash.parsers.fdf.GameUI; import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition; import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint; +import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify; import com.etheller.warsmash.parsers.fdf.frames.SetPoint; import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame; import com.etheller.warsmash.parsers.fdf.frames.StringFrame; @@ -34,6 +38,7 @@ import com.etheller.warsmash.viewer5.handlers.mdx.ReplaceableIds; import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode; import com.etheller.warsmash.viewer5.handlers.tga.TgaFile; import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils; +import com.etheller.warsmash.viewer5.handlers.w3x.UnitSound; import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer; import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraPreset; import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraRates; @@ -41,18 +46,34 @@ import com.etheller.warsmash.viewer5.handlers.w3x.camera.GameCameraManager; import com.etheller.warsmash.viewer5.handlers.w3x.camera.PortraitCameraManager; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButtonListener; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitFilterFunction; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityView; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CodeKeyType; 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.CPlayerUnitOrderListener; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityTargetCheckReceiver; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CWidgetAbilityTargetCheckReceiver; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.PointAbilityTargetCheckReceiver; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgAbilityActivationReceiver; +import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandCardCommandListener; -public class MeleeUI implements CUnitStateListener, CommandButtonListener { +public class MeleeUI implements CUnitStateListener, CommandButtonListener, CommandCardCommandListener { 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 Viewport uiViewport; private final FreeTypeFontGenerator fontGenerator; @@ -104,11 +125,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { 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; public MeleeUI(final DataSource dataSource, final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final Scene portraitScene, final CameraPreset[] cameraPresets, - final CameraRates cameraRates, final War3MapViewer war3MapViewer, - final RootFrameListener rootFrameListener) { + final CameraRates cameraRates, final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener, + final CPlayerUnitOrderListener unitOrderListener) { this.dataSource = dataSource; this.uiViewport = uiViewport; this.fontGenerator = fontGenerator; @@ -116,6 +146,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { this.portraitScene = portraitScene; this.war3MapViewer = war3MapViewer; this.rootFrameListener = rootFrameListener; + this.unitOrderListener = unitOrderListener; this.cameraManager = new GameCameraManager(cameraPresets, cameraRates); @@ -127,6 +158,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { this.activeButtonTexture = ImageUtils.getBLPTexture(war3MapViewer.mapMpq, "UI\\Widgets\\Console\\Human\\CommandButton\\human-activebutton.blp"); + this.activeCommandUnitTargetFilter = new ActiveCommandUnitTargetFilter(); } @@ -170,7 +202,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { // ================================= // Load skins and templates // ================================= - this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 3), this.uiViewport, + 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 { @@ -259,11 +291,17 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { 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.rootFrame, this); this.rootFrame.add(commandCardIcon); final TextureFrame iconFrame = this.rootFrame.createTextureFrame( "SmashCommandButton_" + (commandButtonIndex) + "_Icon", this.rootFrame, false, null); @@ -271,17 +309,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { "SmashCommandButton_" + (commandButtonIndex) + "_Cooldown", this.rootFrame, "", 0); final SpriteFrame autocastFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", "SmashCommandButton_" + (commandButtonIndex) + "_Autocast", this.rootFrame, "", 0); - iconFrame.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT, + 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, 0.039f)); + commandCardIcon.setHeight(GameUI.convertY(this.uiViewport, 0.039f)); + iconFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0)); iconFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f)); iconFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f)); iconFrame.setTexture(ImageUtils.DEFAULT_ICON_PATH, this.rootFrame); - cooldownFrame.addSetPoint(new SetPoint(FramePoint.CENTER, iconFrame, FramePoint.CENTER, 0, 0)); + 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, 0.039f)); cooldownFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f)); - autocastFrame.addSetPoint(new SetPoint(FramePoint.CENTER, iconFrame, FramePoint.CENTER, 0, 0)); + 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, 0.039f)); autocastFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f)); @@ -305,6 +346,51 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { 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; + } + } + } + } + + public void showCommandError(final String message) { + this.errorMessageFrame.setText(message); + } + + @Override + public void toggleAutoCastAbility(final int abilityHandleId) { + + } + public void update(final float deltaTime) { this.portrait.update(); @@ -329,7 +415,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { this.cursorFrame.setFramePointX(FramePoint.LEFT, screenCoordsVector.x); this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y); - if (down) { + if (this.activeCommand != null) { + this.cursorFrame.setSequence("Target"); + } + else if (down) { if (left) { this.cursorFrame.setSequence("Scroll Down Left"); } @@ -383,6 +472,17 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { 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, unit, + MeleeUI.this.activeCommandOrderId, unit, targetReceiver); + return targetReceiver.isTargetable(); + } + } + private static final class Portrait { private MdxComplexInstance modelInstance; private final PortraitCameraManager portraitCameraManager; @@ -539,11 +639,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { @Override public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon, - final int orderId) { + final int abilityHandleId, final int orderId) { 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, orderId); - + this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId); } public void resize(final Rectangle viewport) { @@ -649,17 +748,191 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener { this.cameraManager.scrolled(amount); } - public boolean touchDown(final float screenX, final float screenY, final int button) { - if (this.meleeUIMinimap.containsMouse(screenX, screenY)) { - final Vector2 worldPoint = this.meleeUIMinimap.getWorldPointFromScreen(screenX, screenY); + 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; } - screenCoordsVector.set(screenX, screenY); - this.uiViewport.unproject(screenCoordsVector); - this.rootFrame.touchDown(GameUI.unconvertX(this.uiViewport, screenCoordsVector.x), - GameUI.unconvertY(this.uiViewport, screenCoordsVector.y), button); + 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; + } + else { + final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY, + this.activeCommandUnitTargetFilter); + final boolean shiftDown = isShiftDown(); + if (rayPickUnit != null) { + if (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; + } + } + } + else { + this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); + 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); + } + if (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; + } + } + } + } + } + } + else { + if (button == Input.Buttons.RIGHT) { + final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY); + if (getSelectedUnit() != null) { + if ((rayPickUnit != null) && (rayPickUnit.playerIndex != getSelectedUnit().playerIndex) + && !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); + } + } + } + } return false; } + + private static boolean isShiftDown() { + return Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT); + } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/ActiveCommand.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/ActiveCommand.java new file mode 100644 index 0000000..269d9bd --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/ActiveCommand.java @@ -0,0 +1,8 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.ui.command; + +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; + +public interface ActiveCommand { + boolean finish(CSimulation simulation, CUnit selectedUnit, float mouseScreenX, float mouseScreenY); +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/CommandCardCommandListener.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/CommandCardCommandListener.java new file mode 100644 index 0000000..2f0ea28 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/CommandCardCommandListener.java @@ -0,0 +1,7 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.ui.command; + +public interface CommandCardCommandListener { + void startUsingAbility(int abilityHandleId, int orderId); + + void toggleAutoCastAbility(int abilityHandleId); +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/CommandErrorListener.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/CommandErrorListener.java new file mode 100644 index 0000000..0da222f --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/command/CommandErrorListener.java @@ -0,0 +1,5 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.ui.command; + +public interface CommandErrorListener { + void showCommandError(String message); +}