Make UI icons clickable

This commit is contained in:
Retera 2020-10-24 01:10:37 -04:00
parent e919f35904
commit 2173c993bc
18 changed files with 728 additions and 156 deletions

View File

@ -10,7 +10,6 @@ import java.util.List;
import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color; 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.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle; 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.badlogic.gdx.utils.viewport.ExtendViewport;
import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor; import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor;
import com.etheller.warsmash.datasources.DataSource; 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.TextureMapper;
import com.etheller.warsmash.viewer5.handlers.ModelHandler; import com.etheller.warsmash.viewer5.handlers.ModelHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel; 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.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraPreset; 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.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.MeleeUI;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor { public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
private static final boolean ENABLE_MUSIC = false; 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 DataSource codebase;
private War3MapViewer viewer; private War3MapViewer viewer;
private final Rectangle tempRect = new Rectangle(); private final Rectangle tempRect = new Rectangle();
@ -73,8 +68,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private ExtendViewport uiViewport; private ExtendViewport uiViewport;
private GlyphLayout glyphLayout; private GlyphLayout glyphLayout;
private int selectedSoundCount = 0;
private Texture solidGreenTexture; private Texture solidGreenTexture;
private ShapeRenderer shapeRenderer; private ShapeRenderer shapeRenderer;
@ -227,7 +220,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
music.play(); 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, "", final ModelInstance libgdxContentInstance = new LibGDXContentLayerModel(null, this.viewer, "",
this.viewer.mapPathSolver, "").addInstance(); this.viewer.mapPathSolver, "").addInstance();
libgdxContentInstance.setScene(this.uiScene); libgdxContentInstance.setScene(this.uiScene);
@ -361,85 +359,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
@Override @Override
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) { public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
final float worldScreenY = getHeight() - screenY; final float worldScreenY = getHeight() - screenY;
System.out.println(screenX + "," + screenY);
clickLocationTemp2.x = screenX; if (this.meleeUI.touchDown(screenX, screenY, worldScreenY, button)) {
clickLocationTemp2.y = screenY;
this.uiViewport.unproject(clickLocationTemp2);
if (this.meleeUI.touchDown(clickLocationTemp2.x, clickLocationTemp2.y, button)) {
return false; 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<RenderUnit> 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; return false;
} }

View File

@ -211,6 +211,19 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return textureFrame; 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, public UIFrame inflate(final FrameDefinition frameDefinition, final UIFrame parent,
final FrameDefinition parentDefinitionIfAvailable) { final FrameDefinition parentDefinitionIfAvailable) {
UIFrame inflatedFrame = null; UIFrame inflatedFrame = null;

View File

@ -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.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; 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.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.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; 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.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.CUnitAttackInstant;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissile; 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.combat.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; 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.BooleanAbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CWidgetAbilityTargetCheckReceiver; 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 com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
import mpq.MPQArchive; import mpq.MPQArchive;
@ -1135,6 +1134,10 @@ public class War3MapViewer extends ModelViewer {
} }
public RenderUnit rayPickUnit(final float x, final float y) { 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; final float[] ray = rayHeap;
mousePosHeap.set(x, y); mousePosHeap.set(x, y);
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap); this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
@ -1146,7 +1149,11 @@ public class War3MapViewer extends ModelViewer {
final MdxComplexInstance instance = unit.instance; final MdxComplexInstance instance = unit.instance;
if (instance.isVisible(this.worldScene.camera) && instance.intersectRayWithCollision(gdxRayHeap, if (instance.isVisible(this.worldScene.camera) && instance.intersectRayWithCollision(gdxRayHeap,
intersectionHeap, unit.getSimulationUnit().getUnitType().isBuilding())) { intersectionHeap, unit.getSimulationUnit().getUnitType().isBuilding())) {
entity = unit; if (filter.call(unit.getSimulationUnit())) {
if ((entity == null) || (entity.instance.depth > instance.depth)) {
entity = unit;
}
}
} }
} }
return entity; return entity;
@ -1235,41 +1242,6 @@ public class War3MapViewer extends ModelViewer {
return (numElements < 0) ? 1 : (numElements >= MAXIMUM_ACCEPTED) ? MAXIMUM_ACCEPTED : numElements + 1; 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) { public boolean orderSmart(final RenderUnit target) {
boolean ordered = false; boolean ordered = false;
for (final RenderUnit unit : this.selected) { for (final RenderUnit unit : this.selected) {

View File

@ -34,5 +34,5 @@ public interface CommandButtonListener {
// int getButtonPositionY(); // int getButtonPositionY();
// //
// int getOrderId(); // int getOrderId();
void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int orderId); void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int abilityHandleId, int orderId);
} }

View File

@ -46,6 +46,6 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
private void addCommandButton(final IconUI iconUI, final int handleId, final int orderId) { private void addCommandButton(final IconUI iconUI, final int handleId, final int orderId) {
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(), this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
iconUI.getIcon(), orderId); iconUI.getIcon(), handleId, orderId);
} }
} }

View File

@ -3,8 +3,10 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Random; import java.util.Random;
import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Rectangle;
@ -14,6 +16,7 @@ import com.etheller.warsmash.units.manager.MutableObjectData;
import com.etheller.warsmash.util.War3ID; import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.util.WarsmashConstants; import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid; import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackInstant; 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.attacks.CUnitAttackMissile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
@ -42,6 +45,8 @@ public class CSimulation {
private final CGameplayConstants gameplayConstants; private final CGameplayConstants gameplayConstants;
private final Random seededRandom; private final Random seededRandom;
private float currentGameDayTimeElapsed; private float currentGameDayTimeElapsed;
private final Map<Integer, CUnit> handleIdToUnit = new HashMap<>();
private final Map<Integer, CAbility> handleIdToAbility = new HashMap<>();
public CSimulation(final DataTable miscData, final MutableObjectData parsedUnitData, public CSimulation(final DataTable miscData, final MutableObjectData parsedUnitData,
final MutableObjectData parsedAbilityData, final SimulationRenderController simulationRenderController, 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, final CUnit unit = this.unitData.create(this, playerIndex, typeId, x, y, facing, buildingPathingPixelMap,
this.simulationRenderController, this.handleIdAllocator); this.simulationRenderController, this.handleIdAllocator);
this.units.add(unit); 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); this.worldCollision.addUnit(unit);
return 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, 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 float launchFacing, final CUnitAttackMissile attack, final CWidget target, final float damage,
final int bounceIndex) { final int bounceIndex) {
@ -142,6 +159,10 @@ public class CSimulation {
final CUnit unit = unitIterator.next(); final CUnit unit = unitIterator.next();
if (unit.update(this)) { if (unit.update(this)) {
unitIterator.remove(); unitIterator.remove();
for (final CAbility ability : unit.getAbilities()) {
this.handleIdToAbility.remove(ability.getHandleId());
}
this.handleIdToUnit.remove(unit.getHandleId());
this.simulationRenderController.removeUnit(unit); this.simulationRenderController.removeUnit(unit);
} }
} }

View File

@ -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;
}
};
}

View File

@ -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);
}

View File

@ -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 <T> StringMsgTargetCheckReceiver<T> targetCheckReceiver() {
return (StringMsgTargetCheckReceiver<T>) 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<CWidget> targetReceiver = this.<CWidget>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<Vector2> targetReceiver = this.<Vector2>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<Void> targetReceiver = this.<Void>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;
}
}
}

View File

@ -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);
}

View File

@ -0,0 +1,66 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
public final class BooleanAbilityTargetCheckReceiver<TARGET_TYPE> implements AbilityTargetCheckReceiver<TARGET_TYPE> {
private static final BooleanAbilityTargetCheckReceiver<?> INSTANCE = new BooleanAbilityTargetCheckReceiver<>();
public static <T> BooleanAbilityTargetCheckReceiver<T> getInstance() {
return (BooleanAbilityTargetCheckReceiver<T>) INSTANCE;
}
private boolean targetable = false;
public boolean isTargetable() {
return this.targetable;
}
public BooleanAbilityTargetCheckReceiver<TARGET_TYPE> 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;
}
}

View File

@ -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.";
}
}

View File

@ -0,0 +1,96 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
public final class StringMsgTargetCheckReceiver<TARGET_TYPE> implements AbilityTargetCheckReceiver<TARGET_TYPE> {
private static final StringMsgTargetCheckReceiver<?> INSTANCE = new StringMsgTargetCheckReceiver<>();
public static <T> StringMsgTargetCheckReceiver<T> getInstance() {
return (StringMsgTargetCheckReceiver<T>) INSTANCE;
}
private TARGET_TYPE target;
private String message;
public TARGET_TYPE getTarget() {
return this.target;
}
public String getMessage() {
return this.message;
}
public StringMsgTargetCheckReceiver<TARGET_TYPE> 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.";
}
}

View File

@ -1,5 +1,6 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui; package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout; 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.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag; 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.rendersim.commandbuttons.CommandButton;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandCardCommandListener;
public class CommandCardIcon extends AbstractRenderableFrame { public class CommandCardIcon extends AbstractRenderableFrame {
@ -18,9 +20,14 @@ public class CommandCardIcon extends AbstractRenderableFrame {
private SpriteFrame cooldownFrame; private SpriteFrame cooldownFrame;
private SpriteFrame autocastFrame; private SpriteFrame autocastFrame;
private CommandButton commandButton; 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); super(name, parent);
this.commandCardCommandListener = commandCardCommandListener;
} }
public void set(final TextureFrame iconFrame, final SpriteFrame cooldownFrame, final SpriteFrame autocastFrame) { 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.iconFrame.setVisible(true);
this.cooldownFrame.setVisible(false); this.cooldownFrame.setVisible(false);
this.autocastFrame.setVisible(false); this.autocastFrame.setVisible(false);
this.iconFrame.setTexture(texture); this.iconFrame.setTexture(texture);
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
} }
@Override @Override
@ -81,6 +90,12 @@ public class CommandCardIcon extends AbstractRenderableFrame {
@Override @Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) { public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (this.renderBounds.contains(screenX, screenY)) { 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 this;
} }
return null; return null;

View File

@ -1,10 +1,12 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui; package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont; 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.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.Viewport; import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.datasources.DataSource; import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI; import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition; import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint; 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.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame; import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame; 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.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.tga.TgaFile; import com.etheller.warsmash.viewer5.handlers.tga.TgaFile;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils; 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.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraPreset; 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.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.camera.PortraitCameraManager;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit; 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.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.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.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.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType; 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.CodeKeyType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack; 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_WIDTH = 4;
private static final int COMMAND_CARD_HEIGHT = 3; private static final int COMMAND_CARD_HEIGHT = 3;
private static final Vector2 screenCoordsVector = new Vector2(); 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 DataSource dataSource;
private final Viewport uiViewport; private final Viewport uiViewport;
private final FreeTypeFontGenerator fontGenerator; private final FreeTypeFontGenerator fontGenerator;
@ -104,11 +125,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
private UIFrame inventoryCover; private UIFrame inventoryCover;
private SpriteFrame cursorFrame; private SpriteFrame cursorFrame;
private MeleeUIMinimap meleeUIMinimap; 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, public MeleeUI(final DataSource dataSource, final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator,
final Scene uiScene, final Scene portraitScene, final CameraPreset[] cameraPresets, final Scene uiScene, final Scene portraitScene, final CameraPreset[] cameraPresets,
final CameraRates cameraRates, final War3MapViewer war3MapViewer, final CameraRates cameraRates, final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener,
final RootFrameListener rootFrameListener) { final CPlayerUnitOrderListener unitOrderListener) {
this.dataSource = dataSource; this.dataSource = dataSource;
this.uiViewport = uiViewport; this.uiViewport = uiViewport;
this.fontGenerator = fontGenerator; this.fontGenerator = fontGenerator;
@ -116,6 +146,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
this.portraitScene = portraitScene; this.portraitScene = portraitScene;
this.war3MapViewer = war3MapViewer; this.war3MapViewer = war3MapViewer;
this.rootFrameListener = rootFrameListener; this.rootFrameListener = rootFrameListener;
this.unitOrderListener = unitOrderListener;
this.cameraManager = new GameCameraManager(cameraPresets, cameraRates); this.cameraManager = new GameCameraManager(cameraPresets, cameraRates);
@ -127,6 +158,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
this.activeButtonTexture = ImageUtils.getBLPTexture(war3MapViewer.mapMpq, this.activeButtonTexture = ImageUtils.getBLPTexture(war3MapViewer.mapMpq,
"UI\\Widgets\\Console\\Human\\CommandButton\\human-activebutton.blp"); "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 // 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.fontGenerator, this.uiScene, this.war3MapViewer);
this.rootFrameListener.onCreate(this.rootFrame); this.rootFrameListener.onCreate(this.rootFrame);
try { try {
@ -259,11 +291,17 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
this.inventoryCover = this.rootFrame.createSimpleFrame("SmashConsoleInventoryCover", this.rootFrame, 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; int commandButtonIndex = 0;
for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) { for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) {
for (int i = 0; i < COMMAND_CARD_WIDTH; i++) { for (int i = 0; i < COMMAND_CARD_WIDTH; i++) {
final CommandCardIcon commandCardIcon = new CommandCardIcon("SmashCommandButton_" + commandButtonIndex, final CommandCardIcon commandCardIcon = new CommandCardIcon("SmashCommandButton_" + commandButtonIndex,
this.rootFrame); this.rootFrame, this);
this.rootFrame.add(commandCardIcon); this.rootFrame.add(commandCardIcon);
final TextureFrame iconFrame = this.rootFrame.createTextureFrame( final TextureFrame iconFrame = this.rootFrame.createTextureFrame(
"SmashCommandButton_" + (commandButtonIndex) + "_Icon", this.rootFrame, false, null); "SmashCommandButton_" + (commandButtonIndex) + "_Icon", this.rootFrame, false, null);
@ -271,17 +309,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
"SmashCommandButton_" + (commandButtonIndex) + "_Cooldown", this.rootFrame, "", 0); "SmashCommandButton_" + (commandButtonIndex) + "_Cooldown", this.rootFrame, "", 0);
final SpriteFrame autocastFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", final SpriteFrame autocastFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
"SmashCommandButton_" + (commandButtonIndex) + "_Autocast", this.rootFrame, "", 0); "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.convertX(this.uiViewport, 0.6175f + (0.0434f * i)),
GameUI.convertY(this.uiViewport, 0.095f - (0.044f * j)))); 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.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
iconFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f)); iconFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
iconFrame.setTexture(ImageUtils.DEFAULT_ICON_PATH, this.rootFrame); 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")); this.rootFrame.setSpriteFrameModel(cooldownFrame, this.rootFrame.getSkinField("CommandButtonCooldown"));
cooldownFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f)); cooldownFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
cooldownFrame.setHeight(GameUI.convertY(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")); this.rootFrame.setSpriteFrameModel(autocastFrame, this.rootFrame.getSkinField("CommandButtonAutocast"));
autocastFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f)); autocastFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
autocastFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f)); autocastFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
@ -305,6 +346,51 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
selectUnit(null); 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<Void> noTargetReceiver = BooleanAbilityTargetCheckReceiver
.<Void>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) { public void update(final float deltaTime) {
this.portrait.update(); this.portrait.update();
@ -329,7 +415,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
this.cursorFrame.setFramePointX(FramePoint.LEFT, screenCoordsVector.x); this.cursorFrame.setFramePointX(FramePoint.LEFT, screenCoordsVector.x);
this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y); this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y);
if (down) { if (this.activeCommand != null) {
this.cursorFrame.setSequence("Target");
}
else if (down) {
if (left) { if (left) {
this.cursorFrame.setSequence("Scroll Down Left"); this.cursorFrame.setSequence("Scroll Down Left");
} }
@ -383,6 +472,17 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
this.portrait.talk(); this.portrait.talk();
} }
private final class ActiveCommandUnitTargetFilter implements CUnitFilterFunction {
@Override
public boolean call(final CUnit unit) {
final BooleanAbilityTargetCheckReceiver<CWidget> targetReceiver = BooleanAbilityTargetCheckReceiver
.<CWidget>getInstance();
MeleeUI.this.activeCommand.checkCanTarget(MeleeUI.this.war3MapViewer.simulation, unit,
MeleeUI.this.activeCommandOrderId, unit, targetReceiver);
return targetReceiver.isTargetable();
}
}
private static final class Portrait { private static final class Portrait {
private MdxComplexInstance modelInstance; private MdxComplexInstance modelInstance;
private final PortraitCameraManager portraitCameraManager; private final PortraitCameraManager portraitCameraManager;
@ -539,11 +639,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
@Override @Override
public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon, 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 x = Math.max(0, Math.min(COMMAND_CARD_WIDTH - 1, buttonPositionX));
final int y = Math.max(0, Math.min(COMMAND_CARD_HEIGHT - 1, buttonPositionY)); 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) { public void resize(final Rectangle viewport) {
@ -649,17 +748,191 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener {
this.cameraManager.scrolled(amount); this.cameraManager.scrolled(amount);
} }
public boolean touchDown(final float screenX, final float screenY, final int button) { public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) {
if (this.meleeUIMinimap.containsMouse(screenX, screenY)) { screenCoordsVector.set(screenX, screenY);
final Vector2 worldPoint = this.meleeUIMinimap.getWorldPointFromScreen(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.x = worldPoint.x;
this.cameraManager.target.y = worldPoint.y; this.cameraManager.target.y = worldPoint.y;
return true; return true;
} }
screenCoordsVector.set(screenX, screenY); final UIFrame clickedUIFrame = this.rootFrame.touchDown(screenCoordsVector.x, screenCoordsVector.y, button);
this.uiViewport.unproject(screenCoordsVector); if (clickedUIFrame == null) {
this.rootFrame.touchDown(GameUI.unconvertX(this.uiViewport, screenCoordsVector.x), // try to interact with world
GameUI.unconvertY(this.uiViewport, screenCoordsVector.y), button); 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<RenderUnit> 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; return false;
} }
private static boolean isShiftDown() {
return Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT);
}
} }

View File

@ -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);
}

View File

@ -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);
}

View File

@ -0,0 +1,5 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui.command;
public interface CommandErrorListener {
void showCommandError(String message);
}