From 4fbb7adeaf47b884f16f9b93dfe9a15383116473 Mon Sep 17 00:00:00 2001 From: Retera Date: Tue, 10 Nov 2020 22:44:22 -0500 Subject: [PATCH] Build behavior first draft --- .../etheller/warsmash/WarsmashGdxMapGame.java | 4 +- .../viewer5/handlers/w3x/War3MapViewer.java | 364 ++++++++++-------- .../handlers/w3x/rendersim/RenderItem.java | 16 +- .../handlers/w3x/rendersim/RenderUnit.java | 16 +- .../w3x/simulation/CGameplayConstants.java | 13 + .../handlers/w3x/simulation/CSimulation.java | 11 +- .../handlers/w3x/simulation/CUnit.java | 90 +++-- .../simulation/abilities/CAbilityAttack.java | 3 +- .../build/AbstractCAbilityBuild.java | 2 +- .../abilities/build/CAbilityOrcBuild.java | 6 +- .../simulation/behaviors/CBehaviorAttack.java | 8 +- .../simulation/behaviors/CBehaviorMove.java | 2 +- ...aviorBuild.java => CBehaviorOrcBuild.java} | 24 +- .../handlers/w3x/ui/CommandCardIcon.java | 4 +- .../viewer5/handlers/w3x/ui/MeleeUI.java | 126 ++++-- .../command/CommandCardCommandListener.java | 2 +- 16 files changed, 411 insertions(+), 280 deletions(-) rename core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/{CBehaviorBuild.java => CBehaviorOrcBuild.java} (51%) diff --git a/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java b/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java index 0284e4e..ac61fe3 100644 --- a/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java +++ b/core/src/com/etheller/warsmash/WarsmashGdxMapGame.java @@ -55,8 +55,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI; import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener; public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor { - private static final boolean ENABLE_AUDIO = false; - private static final boolean ENABLE_MUSIC = false; + private static final boolean ENABLE_AUDIO = true; + private static final boolean ENABLE_MUSIC = true; private DataSource codebase; private War3MapViewer viewer; private final Rectangle tempRect = new Rectangle(); 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 8aab527..abca5c8 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java @@ -524,7 +524,8 @@ public class War3MapViewer extends ModelViewer { @Override public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex, final float x, final float y, final float facing) { - return null; + return createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y, 0f, playerIndex, + (float) Math.toRadians(facing)); } }, this.terrain.pathingGrid, this.terrain.getEntireMap(), this.seededRandom, w3iFile.getPlayers()); @@ -756,176 +757,21 @@ public class War3MapViewer extends ModelViewer { private void loadUnitsAndItems(final Warcraft3MapObjectData modifications) throws IOException { final War3Map mpq = this.mapMpq; + this.soundsetNameToSoundset = new HashMap<>(); + if (this.dataSource.has("war3mapUnits.doo")) { final War3MapUnitsDoo dooFile = mpq.readUnits(); - final Map soundsetNameToSoundset = new HashMap<>(); - // Collect the units and items data. - UnitSoundset soundset = null; for (final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit : dooFile.getUnits()) { - MutableGameObject row = null; - String path = null; - Splat unitShadowSplat = null; - BufferedImage buildingPathingPixelMap = null; + final War3ID unitId = unit.getId(); + final float unitX = unit.getLocation()[0]; + final float unitY = unit.getLocation()[1]; + final float unitZ = unit.getLocation()[2]; + final int playerIndex = unit.getPlayer(); + final float unitAngle = unit.getAngle(); - // Hardcoded? - WorldEditorDataType type = null; - if (sloc.equals(unit.getId())) { -// path = "Objects\\StartLocation\\StartLocation.mdx"; - type = null; /// ?????? - this.startLocations[unit.getPlayer()] = new Vector2(unit.getLocation()[0], unit.getLocation()[1]); - } - else { - row = modifications.getUnits().get(unit.getId()); - if (row == null) { - row = modifications.getItems().get(unit.getId()); - if (row != null) { - type = WorldEditorDataType.ITEM; - path = row.getFieldAsString(ITEM_FILE, 0); - - if (path.toLowerCase().endsWith(".mdl") || path.toLowerCase().endsWith(".mdx")) { - path = path.substring(0, path.length() - 4); - } - - final String unitShadow = "Shadow"; - if ((unitShadow != null) && !"_".equals(unitShadow)) { - final String texture = "ReplaceableTextures\\Shadows\\" + unitShadow + ".blp"; - final float shadowX = 50; - final float shadowY = 50; - final float shadowWidth = 128; - final float shadowHeight = 128; - if (!this.terrain.splats.containsKey(texture)) { - final Splat splat = new Splat(); - splat.opacity = 0.5f; - this.terrain.splats.put(texture, splat); - } - final float x = unit.getLocation()[0] - shadowX; - final float y = unit.getLocation()[1] - shadowY; - this.terrain.splats.get(texture).locations - .add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 }); - unitShadowSplat = this.terrain.splats.get(texture); - } - - path += ".mdx"; - } - } - else { - type = WorldEditorDataType.UNITS; - path = row.getFieldAsString(UNIT_FILE, 0); - - if (path.toLowerCase().endsWith(".mdl") || path.toLowerCase().endsWith(".mdx")) { - path = path.substring(0, path.length() - 4); - } - if ((row.readSLKTagInt("fileVerFlags") == 2) && this.dataSource.has(path + "_V1.mdx")) { - path += "_V1"; - } - - path += ".mdx"; - - final String uberSplat = row.getFieldAsString(UBER_SPLAT, 0); - if (uberSplat != null) { - final Element uberSplatInfo = this.terrain.uberSplatTable.get(uberSplat); - if (uberSplatInfo != null) { - final String texturePath = uberSplatInfo.getField("Dir") + "\\" - + uberSplatInfo.getField("file") + ".blp"; - if (!this.terrain.splats.containsKey(texturePath)) { - this.terrain.splats.put(texturePath, new Splat()); - } - final float x = unit.getLocation()[0]; - final float y = unit.getLocation()[1]; - final float s = uberSplatInfo.getFieldFloatValue("Scale"); - this.terrain.splats.get(texturePath).locations - .add(new float[] { x - s, y - s, x + s, y + s, 1 }); - } - } - - final String unitShadow = row.getFieldAsString(UNIT_SHADOW, 0); - if ((unitShadow != null) && !"_".equals(unitShadow)) { - final String texture = "ReplaceableTextures\\Shadows\\" + unitShadow + ".blp"; - final float shadowX = row.getFieldAsFloat(UNIT_SHADOW_X, 0); - final float shadowY = row.getFieldAsFloat(UNIT_SHADOW_Y, 0); - final float shadowWidth = row.getFieldAsFloat(UNIT_SHADOW_W, 0); - final float shadowHeight = row.getFieldAsFloat(UNIT_SHADOW_H, 0); - if (this.mapMpq.has(texture)) { - if (!this.terrain.splats.containsKey(texture)) { - final Splat splat = new Splat(); - splat.opacity = 0.5f; - this.terrain.splats.put(texture, splat); - } - final float x = unit.getLocation()[0] - shadowX; - final float y = unit.getLocation()[1] - shadowY; - this.terrain.splats.get(texture).locations - .add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 }); - unitShadowSplat = this.terrain.splats.get(texture); - } - } - - final String buildingShadow = row.getFieldAsString(BUILDING_SHADOW, 0); - if ((buildingShadow != null) && !"_".equals(buildingShadow)) { - this.terrain.addShadow(buildingShadow, unit.getLocation()[0], unit.getLocation()[1]); - } - buildingPathingPixelMap = getBuildingPathingPixelMap(row); - if (buildingPathingPixelMap != null) { - this.terrain.pathingGrid.blitPathingOverlayTexture(unit.getLocation()[0], - unit.getLocation()[1], (int) Math.toDegrees(unit.getAngle()), - buildingPathingPixelMap); - } - - final String soundName = row.getFieldAsString(UNIT_SOUNDSET, 0); - UnitSoundset unitSoundset = soundsetNameToSoundset.get(soundName); - if (unitSoundset == null) { - unitSoundset = new UnitSoundset(this.dataSource, this.unitAckSoundsTable, soundName); - soundsetNameToSoundset.put(soundName, unitSoundset); - } - soundset = unitSoundset; - } - } - - if (path != null) { - final MdxModel model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams); - MdxModel portraitModel; - final String portraitPath = path.substring(0, path.length() - 4) + "_portrait.mdx"; - if (this.dataSource.has(portraitPath)) { - portraitModel = (MdxModel) this.load(portraitPath, this.mapPathSolver, this.solverParams); - } - else { - portraitModel = model; - } - if (type == WorldEditorDataType.UNITS) { - final float angle = (float) Math.toDegrees(unit.getAngle()); - final CUnit simulationUnit = this.simulation.createUnit(row.getAlias(), unit.getPlayer(), - unit.getLocation()[0], unit.getLocation()[1], angle, buildingPathingPixelMap); - final RenderUnitTypeData typeData = getUnitTypeData(unit.getId(), row); - final RenderUnit renderUnit = new RenderUnit(this, model, row, unit, soundset, portraitModel, - simulationUnit, typeData); - this.unitToRenderPeer.put(simulationUnit, renderUnit); - this.units.add(renderUnit); - if (unitShadowSplat != null) { - unitShadowSplat.unitMapping.add(new Consumer() { - @Override - public void accept(final SplatMover t) { - renderUnit.shadow = t; - } - }); - } - } - else { - this.items.add(new RenderItem(this, model, row, unit, soundset, portraitModel)); // TODO store - // somewhere - if (unitShadowSplat != null) { - unitShadowSplat.unitMapping.add(new Consumer() { - @Override - public void accept(final SplatMover t) { - - } - }); - } - } - } - else { - System.err.println("Unknown unit ID: " + unit.getId()); - } + createNewUnit(modifications, unitId, unitX, unitY, unitZ, playerIndex, unitAngle); } } @@ -935,6 +781,187 @@ public class War3MapViewer extends ModelViewer { this.anyReady = true; } + private CUnit createNewUnit(final Warcraft3MapObjectData modifications, final War3ID unitId, float unitX, + float unitY, final float unitZ, final int playerIndex, final float unitAngle) { + UnitSoundset soundset = null; + MutableGameObject row = null; + String path = null; + Splat unitShadowSplat = null; + BufferedImage buildingPathingPixelMap = null; + final float unitVertexScale = 1.0f; + + // Hardcoded? + WorldEditorDataType type = null; + if (sloc.equals(unitId)) { +// path = "Objects\\StartLocation\\StartLocation.mdx"; + type = null; /// ?????? + this.startLocations[playerIndex] = new Vector2(unitX, unitY); + } + else { + row = modifications.getUnits().get(unitId); + if (row == null) { + row = modifications.getItems().get(unitId); + if (row != null) { + type = WorldEditorDataType.ITEM; + path = row.getFieldAsString(ITEM_FILE, 0); + + if (path.toLowerCase().endsWith(".mdl") || path.toLowerCase().endsWith(".mdx")) { + path = path.substring(0, path.length() - 4); + } + + final String unitShadow = "Shadow"; + if ((unitShadow != null) && !"_".equals(unitShadow)) { + final String texture = "ReplaceableTextures\\Shadows\\" + unitShadow + ".blp"; + final float shadowX = 50; + final float shadowY = 50; + final float shadowWidth = 128; + final float shadowHeight = 128; + if (!this.terrain.splats.containsKey(texture)) { + final Splat splat = new Splat(); + splat.opacity = 0.5f; + this.terrain.splats.put(texture, splat); + } + final float x = unitX - shadowX; + final float y = unitY - shadowY; + this.terrain.splats.get(texture).locations + .add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 }); + unitShadowSplat = this.terrain.splats.get(texture); + } + + path += ".mdx"; + } + } + else { + type = WorldEditorDataType.UNITS; + path = getUnitModelPath(row); + + buildingPathingPixelMap = getBuildingPathingPixelMap(row); + if (buildingPathingPixelMap != null) { + unitX = Math.round(unitX / 64f) * 64f; + unitY = Math.round(unitY / 64f) * 64f; + this.terrain.pathingGrid.blitPathingOverlayTexture(unitX, unitY, (int) Math.toDegrees(unitAngle), + buildingPathingPixelMap); + } + + final String uberSplat = row.getFieldAsString(UBER_SPLAT, 0); + if (uberSplat != null) { + final Element uberSplatInfo = this.terrain.uberSplatTable.get(uberSplat); + if (uberSplatInfo != null) { + final String texturePath = uberSplatInfo.getField("Dir") + "\\" + uberSplatInfo.getField("file") + + ".blp"; + if (!this.terrain.splats.containsKey(texturePath)) { + this.terrain.splats.put(texturePath, new Splat()); + } + final float x = unitX; + final float y = unitY; + final float s = uberSplatInfo.getFieldFloatValue("Scale"); + this.terrain.splats.get(texturePath).locations + .add(new float[] { x - s, y - s, x + s, y + s, 1 }); + } + } + + final String unitShadow = row.getFieldAsString(UNIT_SHADOW, 0); + if ((unitShadow != null) && !"_".equals(unitShadow)) { + final String texture = "ReplaceableTextures\\Shadows\\" + unitShadow + ".blp"; + final float shadowX = row.getFieldAsFloat(UNIT_SHADOW_X, 0); + final float shadowY = row.getFieldAsFloat(UNIT_SHADOW_Y, 0); + final float shadowWidth = row.getFieldAsFloat(UNIT_SHADOW_W, 0); + final float shadowHeight = row.getFieldAsFloat(UNIT_SHADOW_H, 0); + if (this.mapMpq.has(texture)) { + if (!this.terrain.splats.containsKey(texture)) { + final Splat splat = new Splat(); + splat.opacity = 0.5f; + this.terrain.splats.put(texture, splat); + } + final float x = unitX - shadowX; + final float y = unitY - shadowY; + this.terrain.splats.get(texture).locations + .add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 }); + unitShadowSplat = this.terrain.splats.get(texture); + } + } + + final String buildingShadow = row.getFieldAsString(BUILDING_SHADOW, 0); + if ((buildingShadow != null) && !"_".equals(buildingShadow)) { + this.terrain.addShadow(buildingShadow, unitX, unitY); + } + + final String soundName = row.getFieldAsString(UNIT_SOUNDSET, 0); + UnitSoundset unitSoundset = this.soundsetNameToSoundset.get(soundName); + if (unitSoundset == null) { + unitSoundset = new UnitSoundset(this.dataSource, this.unitAckSoundsTable, soundName); + this.soundsetNameToSoundset.put(soundName, unitSoundset); + } + soundset = unitSoundset; + + } + } + + if (path != null) { + final MdxModel model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams); + MdxModel portraitModel; + final String portraitPath = path.substring(0, path.length() - 4) + "_portrait.mdx"; + if (this.dataSource.has(portraitPath)) { + portraitModel = (MdxModel) this.load(portraitPath, this.mapPathSolver, this.solverParams); + } + else { + portraitModel = model; + } + if (type == WorldEditorDataType.UNITS) { + final float angle = (float) Math.toDegrees(unitAngle); + final CUnit simulationUnit = this.simulation.createUnit(row.getAlias(), playerIndex, unitX, unitY, + angle, buildingPathingPixelMap); + final RenderUnitTypeData typeData = getUnitTypeData(unitId, row); + final RenderUnit renderUnit = new RenderUnit(this, model, row, unitX, unitY, unitZ, playerIndex, + soundset, portraitModel, simulationUnit, typeData); + this.unitToRenderPeer.put(simulationUnit, renderUnit); + this.units.add(renderUnit); + if (unitShadowSplat != null) { + unitShadowSplat.unitMapping.add(new Consumer() { + @Override + public void accept(final SplatMover t) { + renderUnit.shadow = t; + } + }); + } + return simulationUnit; + } + else { + this.items + .add(new RenderItem(this, model, row, unitX, unitY, unitZ, unitAngle, soundset, portraitModel)); // TODO + // store + // somewhere + if (unitShadowSplat != null) { + unitShadowSplat.unitMapping.add(new Consumer() { + @Override + public void accept(final SplatMover t) { + + } + }); + } + } + } + else { + System.err.println("Unknown unit ID: " + unitId); + } + return null; + } + + public String getUnitModelPath(final MutableGameObject row) { + String path; + path = row.getFieldAsString(UNIT_FILE, 0); + + if (path.toLowerCase().endsWith(".mdl") || path.toLowerCase().endsWith(".mdx")) { + path = path.substring(0, path.length() - 4); + } + if ((row.readSLKTagInt("fileVerFlags") == 2) && this.dataSource.has(path + "_V1.mdx")) { + path += "_V1"; + } + + path += ".mdx"; + return path; + } + private BufferedImage getBuildingPathingPixelMap(final MutableGameObject row) { BufferedImage buildingPathingPixelMap = null; final String pathingTexture = row.getFieldAsString(UNIT_PATHING, 0); @@ -962,7 +989,7 @@ public class War3MapViewer extends ModelViewer { return buildingPathingPixelMap; } - private RenderUnitTypeData getUnitTypeData(final War3ID key, final MutableGameObject row) { + public RenderUnitTypeData getUnitTypeData(final War3ID key, final MutableGameObject row) { RenderUnitTypeData unitTypeData = this.unitIdToTypeData.get(key); if (unitTypeData == null) { unitTypeData = new RenderUnitTypeData(row.getFieldAsFloat(MAX_PITCH, 0), row.getFieldAsFloat(MAX_ROLL, 0), @@ -1295,6 +1322,7 @@ public class War3MapViewer extends ModelViewer { private WorldEditStrings worldEditStrings; private Warcraft3MapObjectData allObjectData; private AbilityDataUI abilityDataUI; + private Map soundsetNameToSoundset; /** * Returns a power of two size for the given target capacity. @@ -1388,6 +1416,10 @@ public class War3MapViewer extends ModelViewer { return this.uiSounds; } + public Warcraft3MapObjectData getAllObjectData() { + return this.allObjectData; + } + public float getWalkableRenderHeight(final float x, final float y) { this.walkableObjectsTree.intersect(x, y, this.walkablesIntersector.reset(x, y)); return this.walkablesIntersector.z; diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderItem.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderItem.java index f90d0e1..ac7169c 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderItem.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderItem.java @@ -20,23 +20,19 @@ public class RenderItem { public float radius; public UnitSoundset soundset; public final MdxModel portraitModel; - public int playerIndex; - public RenderItem(final War3MapViewer map, final MdxModel model, final MutableGameObject row, - final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit, final UnitSoundset soundset, + public RenderItem(final War3MapViewer map, final MdxModel model, final MutableGameObject row, final float x, + final float y, final float z, final float angle, final UnitSoundset soundset, final MdxModel portraitModel) { this.portraitModel = portraitModel; final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance(); - final float[] location = unit.getLocation(); - System.arraycopy(location, 0, this.location, 0, 3); - instance.move(location); - final float angle = unit.getAngle(); + this.location[0] = x; + this.location[1] = y; + this.location[2] = z; + instance.move(this.location); // instance.localRotation.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle); instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle)); - instance.scale(unit.getScale()); - this.playerIndex = unit.getPlayer(); - instance.setTeamColor(this.playerIndex); instance.setScene(map.worldScene); if (row != null) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderUnit.java index 05143df..e6368ba 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/rendersim/RenderUnit.java @@ -30,7 +30,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitAnimationListe import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; public class RenderUnit { - private static final Quaternion tempQuat = new Quaternion(); + public static final Quaternion tempQuat = new Quaternion(); private static final War3ID RED = War3ID.fromString("uclr"); private static final War3ID GREEN = War3ID.fromString("uclg"); private static final War3ID BLUE = War3ID.fromString("uclb"); @@ -67,25 +67,25 @@ public class RenderUnit { private boolean boneCorpse; private final RenderUnitTypeData typeData; - public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row, - final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit, final UnitSoundset soundset, + public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row, final float x, + final float y, final float z, final int playerIndex, final UnitSoundset soundset, final MdxModel portraitModel, final CUnit simulationUnit, final RenderUnitTypeData typeData) { this.portraitModel = portraitModel; this.simulationUnit = simulationUnit; this.typeData = typeData; final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance(); - final float[] location = unit.getLocation(); - System.arraycopy(location, 0, this.location, 0, 3); - instance.move(location); + this.location[0] = x; + this.location[1] = y; + this.location[2] = z; + instance.move(this.location); this.facing = simulationUnit.getFacing(); final float angle = (float) Math.toRadians(this.facing); // instance.localRotation.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle); this.x = simulationUnit.getX(); this.y = simulationUnit.getY(); instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle)); - instance.scale(unit.getScale()); - this.playerIndex = unit.getPlayer() & 0xFFFF; + this.playerIndex = playerIndex & 0xFFFF; instance.setTeamColor(this.playerIndex); instance.setScene(map.worldScene); this.unitAnimationListenerImpl = new UnitAnimationListenerImpl(instance); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CGameplayConstants.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CGameplayConstants.java index 9b70d09..4d18759 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CGameplayConstants.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CGameplayConstants.java @@ -24,6 +24,8 @@ public class CGameplayConstants { private final float gameDayHours; private final float gameDayLength; private final float structureDecayTime; + private final float buildingAngle; + private final float rootAngle; public CGameplayConstants(final DataTable parsedDataTable) { final Element miscData = parsedDataTable.get("Misc"); @@ -41,6 +43,9 @@ public class CGameplayConstants { this.gameDayHours = miscData.getFieldFloatValue("DayHours"); this.gameDayLength = miscData.getFieldFloatValue("DayLength"); + this.buildingAngle = miscData.getFieldFloatValue("BuildingAngle"); + this.rootAngle = miscData.getFieldFloatValue("RootAngle"); + final CDefenseType[] defenseTypeOrder = { CDefenseType.SMALL, CDefenseType.MEDIUM, CDefenseType.LARGE, CDefenseType.FORT, CDefenseType.NORMAL, CDefenseType.HERO, CDefenseType.DIVINE, CDefenseType.NONE, }; this.damageBonusTable = new float[CAttackType.values().length][defenseTypeOrder.length]; @@ -111,4 +116,12 @@ public class CGameplayConstants { public float getStructureDecayTime() { return this.structureDecayTime; } + + public float getBuildingAngle() { + return this.buildingAngle; + } + + public float getRootAngle() { + return this.rootAngle; + } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CSimulation.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CSimulation.java index c035c9c..2e29414 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CSimulation.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CSimulation.java @@ -34,6 +34,7 @@ public class CSimulation { private final CAbilityData abilityData; private final CUnitData unitData; private final List units; + private final List newUnits; private final List players; private final List projectiles; private final List newProjectiles; @@ -60,6 +61,7 @@ public class CSimulation { this.abilityData = new CAbilityData(parsedAbilityData); this.unitData = new CUnitData(parsedUnitData, this.abilityData); this.units = new ArrayList<>(); + this.newUnits = new ArrayList<>(); this.projectiles = new ArrayList<>(); this.newProjectiles = new ArrayList<>(); this.handleIdAllocator = new HandleIdAllocator(); @@ -119,7 +121,7 @@ public class CSimulation { final float facing, final BufferedImage buildingPathingPixelMap) { final CUnit unit = this.unitData.create(this, playerIndex, typeId, x, y, facing, buildingPathingPixelMap, this.simulationRenderController, this.handleIdAllocator); - this.units.add(unit); + this.newUnits.add(unit); this.handleIdToUnit.put(unit.getHandleId(), unit); for (final CAbility ability : unit.getAbilities()) { this.handleIdToAbility.put(ability.getHandleId(), ability); @@ -128,6 +130,11 @@ public class CSimulation { return unit; } + public CUnit createUnit(final War3ID typeId, final int playerIndex, final float x, final float y, + final float facing) { + return this.simulationRenderController.createUnit(this, typeId, playerIndex, x, y, facing); + } + public CUnit getUnit(final int handleId) { return this.handleIdToUnit.get(handleId); } @@ -175,6 +182,8 @@ public class CSimulation { this.simulationRenderController.removeUnit(unit); } } + this.units.addAll(this.newUnits); + this.newUnits.clear(); final Iterator projectileIterator = this.projectiles.iterator(); while (projectileIterator.hasNext()) { final CAttackProjectile projectile = projectileIterator.next(); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java index 0baebe2..8eb6864 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java @@ -462,53 +462,63 @@ public class CUnit extends CWidget { final CUnit targetUnit = (CUnit) target; final CUnitType targetUnitType = targetUnit.getUnitType(); if (targetUnitType.isBuilding() && (targetUnitType.getBuildingPathingPixelMap() != null)) { - final float relativeOffsetX = getX() - target.getX(); - final float relativeOffsetY = getY() - target.getY(); - final int rotation = ((int) targetUnit.getFacing() + 450) % 360; final BufferedImage buildingPathingPixelMap = targetUnitType.getBuildingPathingPixelMap(); - final int gridWidth = ((rotation % 180) != 0) ? buildingPathingPixelMap.getHeight() - : buildingPathingPixelMap.getWidth(); - final int gridHeight = ((rotation % 180) != 0) ? buildingPathingPixelMap.getWidth() - : buildingPathingPixelMap.getHeight(); - final int relativeGridX = (int) Math.floor(relativeOffsetX / 32f) + (gridWidth / 2); - final int relativeGridY = (int) Math.floor(relativeOffsetY / 32f) + (gridHeight / 2); - final int rangeInCells = (int) Math.floor(range / 32f); - final int rangeInCellsSquare = rangeInCells * rangeInCells; - int minCheckX = relativeGridX - rangeInCells; - int minCheckY = relativeGridY - rangeInCells; - int maxCheckX = relativeGridX + rangeInCells; - int maxCheckY = relativeGridY + rangeInCells; - if ((minCheckX < gridWidth) && (maxCheckX >= 0)) { - if ((minCheckY < gridHeight) && (maxCheckY >= 0)) { - if (minCheckX < 0) { - minCheckX = 0; - } - if (minCheckY < 0) { - minCheckY = 0; - } - if (maxCheckX > (gridWidth - 1)) { - maxCheckX = gridWidth - 1; - } - if (maxCheckY > (gridHeight - 1)) { - maxCheckY = gridHeight - 1; - } - for (int checkX = minCheckX; checkX <= maxCheckX; checkX++) { - for (int checkY = minCheckY; checkY <= maxCheckY; checkY++) { - final int dx = relativeGridX - checkX; - final int dy = relativeGridY - checkY; - if (((dx * dx) + (dy * dy)) <= rangeInCellsSquare) { - if (((getRGBFromPixelData(buildingPathingPixelMap, checkX, checkY, rotation) - & 0xFF0000) >>> 16) > 127) { - return true; - } - } + final float targetX = target.getX(); + final float targetY = target.getY(); + if (canReachToPathing(range, targetUnit.getFacing(), buildingPathingPixelMap, targetX, targetY)) { + return true; + } + } + } + return distance <= range; + } + + public boolean canReachToPathing(final float range, final float rotationForPathing, + final BufferedImage buildingPathingPixelMap, final float targetX, final float targetY) { + final int rotation = ((int) rotationForPathing + 450) % 360; + final float relativeOffsetX = getX() - targetX; + final float relativeOffsetY = getY() - targetY; + final int gridWidth = ((rotation % 180) != 0) ? buildingPathingPixelMap.getHeight() + : buildingPathingPixelMap.getWidth(); + final int gridHeight = ((rotation % 180) != 0) ? buildingPathingPixelMap.getWidth() + : buildingPathingPixelMap.getHeight(); + final int relativeGridX = (int) Math.floor(relativeOffsetX / 32f) + (gridWidth / 2); + final int relativeGridY = (int) Math.floor(relativeOffsetY / 32f) + (gridHeight / 2); + final int rangeInCells = (int) Math.floor(range / 32f); + final int rangeInCellsSquare = rangeInCells * rangeInCells; + int minCheckX = relativeGridX - rangeInCells; + int minCheckY = relativeGridY - rangeInCells; + int maxCheckX = relativeGridX + rangeInCells; + int maxCheckY = relativeGridY + rangeInCells; + if ((minCheckX < gridWidth) && (maxCheckX >= 0)) { + if ((minCheckY < gridHeight) && (maxCheckY >= 0)) { + if (minCheckX < 0) { + minCheckX = 0; + } + if (minCheckY < 0) { + minCheckY = 0; + } + if (maxCheckX > (gridWidth - 1)) { + maxCheckX = gridWidth - 1; + } + if (maxCheckY > (gridHeight - 1)) { + maxCheckY = gridHeight - 1; + } + for (int checkX = minCheckX; checkX <= maxCheckX; checkX++) { + for (int checkY = minCheckY; checkY <= maxCheckY; checkY++) { + final int dx = relativeGridX - checkX; + final int dy = relativeGridY - checkY; + if (((dx * dx) + (dy * dy)) <= rangeInCellsSquare) { + if (((getRGBFromPixelData(buildingPathingPixelMap, checkX, checkY, rotation) + & 0xFF0000) >>> 16) > 127) { + return true; } } } } } } - return distance <= range; + return false; } private int getRGBFromPixelData(final BufferedImage buildingPathingPixelMap, final int checkX, final int checkY, diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java index e6d9e0f..cbe2994 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/CAbilityAttack.java @@ -10,12 +10,11 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.test.IAbility; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType; -public class CAbilityAttack implements CAbility, IAbility { +public class CAbilityAttack implements CAbility { private final int handleId; public CAbilityAttack(final int handleId) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java index a946d90..487a78f 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/AbstractCAbilityBuild.java @@ -78,6 +78,6 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements @Override public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) { - return false; + return true; } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityOrcBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityOrcBuild.java index 79678f3..c10fa33 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityOrcBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityOrcBuild.java @@ -9,9 +9,11 @@ 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.CAbilityVisitor; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build.CBehaviorOrcBuild; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; public class CAbilityOrcBuild extends AbstractCAbilityBuild { + private CBehaviorOrcBuild buildBehavior; public CAbilityOrcBuild(final int handleId, final List structuresBuilt) { super(handleId, structuresBuilt); @@ -24,6 +26,7 @@ public class CAbilityOrcBuild extends AbstractCAbilityBuild { @Override public void onAdd(final CSimulation game, final CUnit unit) { + this.buildBehavior = new CBehaviorOrcBuild(unit); } @Override @@ -37,8 +40,7 @@ public class CAbilityOrcBuild extends AbstractCAbilityBuild { @Override public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) { - // TODO Auto-generated method stub - return null; + return this.buildBehavior.reset(point.x, point.y, orderId, getBaseOrderId()); } @Override diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java index bde7654..15b59ca 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java @@ -39,12 +39,8 @@ public class CBehaviorAttack extends CAbstractRangedWidgetTargetBehavior { @Override public boolean isWithinRange(final CSimulation simulation) { float range = this.unitAttack.getRange(); - if ((this.target instanceof CUnit) && (((CUnit) this.target).isMoving()) && (simulation - .getGameTurnTick() < this.unit.getCooldownEndTime() /* - * only apply range motion buffer if they were - * already in range and attacked - */)) { - range += this.unitAttack.getRangeMotionBuffer() + 1000; + if (simulation.getGameTurnTick() < this.unit.getCooldownEndTime()) { + range += this.unitAttack.getRangeMotionBuffer(); } return this.unit.canReach(this.target, range) && (this.unit.distance(this.target) >= this.unit.getUnitType().getMinimumAttackRange()); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java index 1f3efc3..6e1e995 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java @@ -88,7 +88,7 @@ public class CBehaviorMove implements CBehavior { @Override public CBehavior update(final CSimulation simulation) { if ((this.rangedBehavior != null) && this.rangedBehavior.isWithinRange(simulation)) { - return this.rangedBehavior; + return this.rangedBehavior.update(simulation); } final float prevX = this.unit.getX(); final float prevY = this.unit.getY(); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java similarity index 51% rename from core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorBuild.java rename to core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java index f407ad5..38dd56d 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java @@ -1,35 +1,43 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build; +import com.etheller.warsmash.util.War3ID; 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.CUnitType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedPointTargetBehavior; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; -public class CBehaviorBuild extends CAbstractRangedPointTargetBehavior { - private int orderId; +public class CBehaviorOrcBuild extends CAbstractRangedPointTargetBehavior { + private int highlightOrderId; + private War3ID orderId; - public CBehaviorBuild(final CUnit unit) { + public CBehaviorOrcBuild(final CUnit unit) { super(unit); } - public CBehavior reset(final float targetX, final float targetY, final int orderId) { - this.orderId = orderId; + public CBehavior reset(final float targetX, final float targetY, final int orderId, final int highlightOrderId) { + this.highlightOrderId = highlightOrderId; + this.orderId = new War3ID(orderId); return innerReset(targetX, targetY); } @Override public boolean isWithinRange(final CSimulation simulation) { - return this.unit.distance(this.targetX, this.targetY) <= 23525; + final CUnitType unitType = simulation.getUnitData().getUnitType(this.orderId); + return this.unit.canReachToPathing(0, simulation.getGameplayConstants().getBuildingAngle(), + unitType.getBuildingPathingPixelMap(), this.targetX, this.targetY); } @Override public int getHighlightOrderId() { - return this.orderId; + return this.highlightOrderId; } @Override protected CBehavior update(final CSimulation simulation, final boolean withinRange) { - return this; + simulation.createUnit(this.orderId, this.unit.getPlayerIndex(), this.targetX, this.targetY, + simulation.getGameplayConstants().getBuildingAngle()); + return this.unit.pollNextOrderBehavior(simulation); } @Override 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 6d2f033..12cc1d8 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 @@ -137,11 +137,11 @@ public class CommandCardIcon extends AbstractRenderableFrame { this.commandCardCommandListener.openMenu(this.orderId); } else { - this.commandCardCommandListener.startUsingAbility(this.abilityHandleId, this.orderId); + this.commandCardCommandListener.startUsingAbility(this.abilityHandleId, this.orderId, false); } } else if (button == Input.Buttons.RIGHT) { - this.commandCardCommandListener.startUsingAbility(this.abilityHandleId, this.autoCastOrderId); + this.commandCardCommandListener.startUsingAbility(this.abilityHandleId, this.autoCastOrderId, true); } } 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 433fd21..0f72e55 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,5 +1,6 @@ package com.etheller.warsmash.viewer5.handlers.w3x.ui; +import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -30,8 +31,11 @@ import com.etheller.warsmash.parsers.fdf.frames.TextureFrame; import com.etheller.warsmash.parsers.fdf.frames.UIFrame; import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener; import com.etheller.warsmash.parsers.mdlx.Layer.FilterMode; +import com.etheller.warsmash.units.manager.MutableObjectData; import com.etheller.warsmash.util.FastNumberFormat; import com.etheller.warsmash.util.ImageUtils; +import com.etheller.warsmash.util.RenderMathUtils; +import com.etheller.warsmash.util.War3ID; import com.etheller.warsmash.util.WarsmashConstants; import com.etheller.warsmash.viewer5.Scene; import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance; @@ -55,10 +59,12 @@ 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.CUnitType; 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.abilities.build.AbstractCAbilityBuild; 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; @@ -139,6 +145,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma private CAbilityView activeCommand; private int activeCommandOrderId; private RenderUnit activeCommandUnit; + private MdxComplexInstance cursorModelInstance = null; + private BufferedImage cursorModelPathing; private int selectedSoundCount = 0; private final ActiveCommandUnitTargetFilter activeCommandUnitTargetFilter; @@ -373,7 +381,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma } @Override - public void startUsingAbility(final int abilityHandleId, final int orderId) { + public void startUsingAbility(final int abilityHandleId, final int orderId, final boolean rightClick) { // TODO not O(N) CAbilityView abilityToUse = null; for (final CAbility ability : this.selectedUnit.getSimulationUnit().getAbilities()) { @@ -411,6 +419,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(), abilityHandleId, orderId, isShiftDown()); } + if (rightClick) { + this.war3MapViewer.getUiSounds().getSound("AutoCastButtonClick").play(this.uiScene.audioContext, 0, 0); + } } @Override @@ -434,8 +445,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma public void update(final float deltaTime) { this.portrait.update(); - int mouseX = Gdx.input.getX(); - int mouseY = Gdx.input.getY(); + final int baseMouseX = Gdx.input.getX(); + int mouseX = baseMouseX; + final int baseMouseY = Gdx.input.getY(); + int mouseY = baseMouseY; final int minX = this.uiViewport.getScreenX(); final int maxX = minX + this.uiViewport.getScreenWidth(); final int minY = this.uiViewport.getScreenY(); @@ -458,38 +471,85 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y); if (this.activeCommand != null) { - this.cursorFrame.setSequence("Target"); - } - else if (down) { - if (left) { - this.cursorFrame.setSequence("Scroll Down Left"); - } - else if (right) { - this.cursorFrame.setSequence("Scroll Down Right"); + if (this.activeCommand instanceof AbstractCAbilityBuild) { + boolean justLoaded = false; + if (this.cursorModelInstance == null) { + final MutableObjectData unitData = this.war3MapViewer.getAllObjectData().getUnits(); + final War3ID buildingTypeId = new War3ID(this.activeCommandOrderId); + final String unitModelPath = this.war3MapViewer.getUnitModelPath(unitData.get(buildingTypeId)); + final MdxModel model = (MdxModel) this.war3MapViewer.load(unitModelPath, + this.war3MapViewer.mapPathSolver, this.war3MapViewer.solverParams); + this.cursorModelInstance = (MdxComplexInstance) model.addInstance(); + this.cursorModelInstance.setVertexColor(new float[] { 1, 1, 1, 0.5f }); + this.cursorModelInstance.rotate(RenderUnit.tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, + this.war3MapViewer.simulation.getGameplayConstants().getBuildingAngle())); + this.cursorModelInstance.setAnimationSpeed(0f); + justLoaded = true; + final CUnitType buildingUnitType = this.war3MapViewer.simulation.getUnitData() + .getUnitType(buildingTypeId); + this.cursorModelPathing = buildingUnitType.getBuildingPathingPixelMap(); + } + this.war3MapViewer.getClickLocation(clickLocationTemp, baseMouseX, + Gdx.graphics.getHeight() - baseMouseY); + if (this.cursorModelPathing != null) { + clickLocationTemp.x = Math.round(clickLocationTemp.x / 64f) * 64f; + clickLocationTemp.y = Math.round(clickLocationTemp.y / 64f) * 64f; + clickLocationTemp.z = this.war3MapViewer.terrain.getGroundHeight(clickLocationTemp.x, + clickLocationTemp.y); + } + this.cursorModelInstance.setLocation(clickLocationTemp); + SequenceUtils.randomSequence(this.cursorModelInstance, PrimaryTag.STAND); + this.cursorFrame.setVisible(false); + if (justLoaded) { + this.cursorModelInstance.setScene(this.war3MapViewer.worldScene); + } } else { - this.cursorFrame.setSequence("Scroll Down"); + if (this.cursorModelInstance != null) { + this.cursorModelInstance.detach(); + this.cursorModelInstance = null; + this.cursorFrame.setVisible(true); + } + this.cursorFrame.setSequence("Target"); } } - else if (up) { - if (left) { - this.cursorFrame.setSequence("Scroll Up Left"); - } - else if (right) { - this.cursorFrame.setSequence("Scroll Up Right"); - } - else { - this.cursorFrame.setSequence("Scroll Up"); - } - } - else if (left) { - this.cursorFrame.setSequence("Scroll Left"); - } - else if (right) { - this.cursorFrame.setSequence("Scroll Right"); - } else { - this.cursorFrame.setSequence("Normal"); + if (this.cursorModelInstance != null) { + this.cursorModelInstance.detach(); + this.cursorModelInstance = null; + this.cursorFrame.setVisible(true); + } + if (down) { + if (left) { + this.cursorFrame.setSequence("Scroll Down Left"); + } + else if (right) { + this.cursorFrame.setSequence("Scroll Down Right"); + } + else { + this.cursorFrame.setSequence("Scroll Down"); + } + } + else if (up) { + if (left) { + this.cursorFrame.setSequence("Scroll Up Left"); + } + else if (right) { + this.cursorFrame.setSequence("Scroll Up Right"); + } + else { + this.cursorFrame.setSequence("Scroll Up"); + } + } + else if (left) { + this.cursorFrame.setSequence("Scroll Left"); + } + else if (right) { + this.cursorFrame.setSequence("Scroll Right"); + } + else { + this.cursorFrame.setSequence("Normal"); + } } final float groundHeight = Math.max( this.war3MapViewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y), @@ -866,6 +926,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma } this.selectedSoundCount = 0; if (!shiftDown) { + this.subMenuOrderIdStack.clear(); this.activeCommandUnit = null; this.activeCommand = null; this.activeCommandOrderId = -1; @@ -896,7 +957,12 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma portraitTalk(); } this.selectedSoundCount = 0; + if (this.activeCommand instanceof AbstractCAbilityBuild) { + this.war3MapViewer.getUiSounds().getSound("PlaceBuildingDefault") + .play(this.uiScene.audioContext, 0, 0); + } if (!shiftDown) { + this.subMenuOrderIdStack.clear(); this.activeCommandUnit = null; this.activeCommand = null; this.activeCommandOrderId = -1; 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 index 02ef4a4..36dc718 100644 --- 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 @@ -1,7 +1,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.ui.command; public interface CommandCardCommandListener { - void startUsingAbility(int abilityHandleId, int orderId); + void startUsingAbility(int abilityHandleId, int orderId, boolean rightClick); void openMenu(int orderId); }