Add build sounds and rough draft of build progress bar

This commit is contained in:
Retera 2020-11-13 20:00:33 -05:00
parent 4fbb7adeaf
commit 632576323c
10 changed files with 3641 additions and 3582 deletions

View File

@ -446,4 +446,8 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
super.add(childFrame); super.add(childFrame);
this.nameToFrame.put(childFrame.getName(), childFrame); this.nameToFrame.put(childFrame.getName(), childFrame);
} }
public Scene getUiScene() {
return uiScene;
}
} }

View File

@ -225,6 +225,11 @@ public class SplatModel {
} }
public void add(float x, float y, float z, float scale, float[] centerOffset) {
locations.add(new float[]{x - scale, y - scale, x + scale, y + scale, z});
compact(Gdx.gl30, centerOffset);
}
private static final class Batch { private static final class Batch {
private final int uvsOffset; private final int uvsOffset;
private final int vertexBuffer; private final int vertexBuffer;

View File

@ -323,8 +323,7 @@ public class War3MapViewer extends ModelViewer {
final LoadGenericCallback callback) { final LoadGenericCallback callback) {
if (this.mapMpq == null) { if (this.mapMpq == null) {
return loadGeneric(path, dataType, callback); return loadGeneric(path, dataType, callback);
} } else {
else {
return loadGeneric(path, dataType, callback, this.dataSource); return loadGeneric(path, dataType, callback, this.dataSource);
} }
} }
@ -355,22 +354,19 @@ public class War3MapViewer extends ModelViewer {
tilesetSource = new CompoundDataSource(Arrays.asList(compoundDataSource, tilesetSource = new CompoundDataSource(Arrays.asList(compoundDataSource,
new SubdirDataSource(compoundDataSource, tileset + ".mpq/"), new SubdirDataSource(compoundDataSource, tileset + ".mpq/"),
new SubdirDataSource(compoundDataSource, "_tilesets/" + tileset + ".w3mod/"))); new SubdirDataSource(compoundDataSource, "_tilesets/" + tileset + ".w3mod/")));
} } else {
else {
final byte[] mapData = IOUtils.toByteArray(mapStream); final byte[] mapData = IOUtils.toByteArray(mapStream);
sbc = new SeekableInMemoryByteChannel(mapData); sbc = new SeekableInMemoryByteChannel(mapData);
final DataSource internalMpqContentsDataSource = new MpqDataSource(new MPQArchive(sbc), sbc); final DataSource internalMpqContentsDataSource = new MpqDataSource(new MPQArchive(sbc), sbc);
tilesetSource = new CompoundDataSource( tilesetSource = new CompoundDataSource(
Arrays.asList(compoundDataSource, internalMpqContentsDataSource)); Arrays.asList(compoundDataSource, internalMpqContentsDataSource));
} }
} } catch (final IOException exc) {
catch (final IOException exc) {
tilesetSource = new CompoundDataSource( tilesetSource = new CompoundDataSource(
Arrays.asList(compoundDataSource, new SubdirDataSource(compoundDataSource, tileset + ".mpq/"), Arrays.asList(compoundDataSource, new SubdirDataSource(compoundDataSource, tileset + ".mpq/"),
new SubdirDataSource(compoundDataSource, "_tilesets/" + tileset + ".w3mod/"))); new SubdirDataSource(compoundDataSource, "_tilesets/" + tileset + ".w3mod/")));
} }
} } catch (final MPQException e) {
catch (final MPQException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
setDataSource(tilesetSource); setDataSource(tilesetSource);
@ -444,8 +440,7 @@ public class War3MapViewer extends ModelViewer {
modelInstance.setScene(War3MapViewer.this.worldScene); modelInstance.setScene(War3MapViewer.this.worldScene);
if (bounceIndex == 0) { if (bounceIndex == 0) {
SequenceUtils.randomBirthSequence(modelInstance); SequenceUtils.randomBirthSequence(modelInstance);
} } else {
else {
SequenceUtils.randomStandSequence(modelInstance); SequenceUtils.randomStandSequence(modelInstance);
} }
modelInstance.setLocation(x, y, height); modelInstance.setLocation(x, y, height);
@ -508,6 +503,14 @@ public class War3MapViewer extends ModelViewer {
damagedUnit.getY()); damagedUnit.getY());
} }
@Override
public void spawnUnitConstructionSound(CUnit constructingUnit, CUnit constructedStructure) {
UnitSound constructingBuilding = uiSounds.getSound(gameUI.getSkinField("ConstructingBuilding"));
if (constructingBuilding != null) {
constructingBuilding.play(worldScene.audioContext, constructedStructure.getX(), constructedStructure.getY());
}
}
@Override @Override
public void removeUnit(final CUnit unit) { public void removeUnit(final CUnit unit) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.remove(unit); final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.remove(unit);
@ -521,6 +524,14 @@ public class War3MapViewer extends ModelViewer {
.getBuildingPathingPixelMap(War3MapViewer.this.allObjectData.getUnits().get(rawcode)); .getBuildingPathingPixelMap(War3MapViewer.this.allObjectData.getUnits().get(rawcode));
} }
@Override
public void spawnUnitConstructionFinishSound(CUnit constructedStructure) {
UnitSound constructingBuilding = uiSounds.getSound(gameUI.getSkinField("JobDoneSound"));
if (constructingBuilding != null) {
constructingBuilding.play(worldScene.audioContext, constructedStructure.getX(), constructedStructure.getY());
}
}
@Override @Override
public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex, public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex,
final float x, final float y, final float facing) { final float x, final float y, final float facing) {
@ -532,8 +543,7 @@ public class War3MapViewer extends ModelViewer {
this.walkableObjectsTree = new Quadtree<>(this.terrain.getEntireMap()); this.walkableObjectsTree = new Quadtree<>(this.terrain.getEntireMap());
if (this.doodadsAndDestructiblesLoaded) { if (this.doodadsAndDestructiblesLoaded) {
this.loadDoodadsAndDestructibles(this.allObjectData); this.loadDoodadsAndDestructibles(this.allObjectData);
} } else {
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises"); throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
} }
@ -560,8 +570,7 @@ public class War3MapViewer extends ModelViewer {
public void loadAfterUI() throws IOException { public void loadAfterUI() throws IOException {
if (this.unitsAndItemsLoaded) { if (this.unitsAndItemsLoaded) {
this.loadUnitsAndItems(this.allObjectData); this.loadUnitsAndItems(this.allObjectData);
} } else {
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises"); throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
} }
@ -631,8 +640,7 @@ public class War3MapViewer extends ModelViewer {
bufferedImage = TgaFile.readTGA(pathingTexture, bufferedImage = TgaFile.readTGA(pathingTexture,
this.mapMpq.getResourceAsStream(pathingTexture)); this.mapMpq.getResourceAsStream(pathingTexture));
this.filePathToPathingMap.put(pathingTexture.toLowerCase(), bufferedImage); this.filePathToPathingMap.put(pathingTexture.toLowerCase(), bufferedImage);
} } catch (final Exception exc) {
catch (final Exception exc) {
exc.printStackTrace(); exc.printStackTrace();
} }
} }
@ -650,15 +658,13 @@ public class War3MapViewer extends ModelViewer {
String path; String path;
if (this.mapMpq.has(fileVar)) { if (this.mapMpq.has(fileVar)) {
path = fileVar; path = fileVar;
} } else {
else {
path = file; path = file;
} }
MdxModel model; MdxModel model;
if (this.mapMpq.has(path)) { if (this.mapMpq.has(path)) {
model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams); model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
} } else {
else {
model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams); model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams);
} }
@ -677,8 +683,7 @@ public class War3MapViewer extends ModelViewer {
renderDestructableBounds); renderDestructableBounds);
} }
this.doodads.add(renderDestructable); this.doodads.add(renderDestructable);
} } else {
else {
this.doodads.add(new RenderDoodad(this, model, row, doodad, type, maxPitch, maxRoll)); this.doodads.add(new RenderDoodad(this, model, row, doodad, type, maxPitch, maxRoll));
} }
} }
@ -711,14 +716,12 @@ public class War3MapViewer extends ModelViewer {
pathingTextureImage = TgaFile.readTGA(pathingTexture, pathingTextureImage = TgaFile.readTGA(pathingTexture,
this.mapMpq.getResourceAsStream(pathingTexture)); this.mapMpq.getResourceAsStream(pathingTexture));
this.filePathToPathingMap.put(pathingTexture.toLowerCase(), pathingTextureImage); this.filePathToPathingMap.put(pathingTexture.toLowerCase(), pathingTextureImage);
} } catch (final Exception exc) {
catch (final Exception exc) {
exc.printStackTrace(); exc.printStackTrace();
} }
} }
} }
} } else {
else {
pathingTextureImage = null; pathingTextureImage = null;
} }
if (pathingTextureImage != null) { if (pathingTextureImage != null) {
@ -756,6 +759,7 @@ public class War3MapViewer extends ModelViewer {
private void loadUnitsAndItems(final Warcraft3MapObjectData modifications) throws IOException { private void loadUnitsAndItems(final Warcraft3MapObjectData modifications) throws IOException {
final War3Map mpq = this.mapMpq; final War3Map mpq = this.mapMpq;
this.unitsReady = false;
this.soundsetNameToSoundset = new HashMap<>(); this.soundsetNameToSoundset = new HashMap<>();
@ -796,8 +800,7 @@ public class War3MapViewer extends ModelViewer {
// path = "Objects\\StartLocation\\StartLocation.mdx"; // path = "Objects\\StartLocation\\StartLocation.mdx";
type = null; /// ?????? type = null; /// ??????
this.startLocations[playerIndex] = new Vector2(unitX, unitY); this.startLocations[playerIndex] = new Vector2(unitX, unitY);
} } else {
else {
row = modifications.getUnits().get(unitId); row = modifications.getUnits().get(unitId);
if (row == null) { if (row == null) {
row = modifications.getItems().get(unitId); row = modifications.getItems().get(unitId);
@ -809,13 +812,18 @@ public class War3MapViewer extends ModelViewer {
path = path.substring(0, path.length() - 4); path = path.substring(0, path.length() - 4);
} }
final String unitShadow = "Shadow"; Element misc = miscData.get("Misc");
if ((unitShadow != null) && !"_".equals(unitShadow)) { String itemShadowFile = misc.getField("ItemShadowFile");
final String texture = "ReplaceableTextures\\Shadows\\" + unitShadow + ".blp"; int itemShadowWidth = misc.getFieldValue("ItemShadowSize", 0);
final float shadowX = 50; int itemShadowHeight = misc.getFieldValue("ItemShadowSize", 1);
final float shadowY = 50; int itemShadowX = misc.getFieldValue("ItemShadowOffset", 0);
final float shadowWidth = 128; int itemShadowY = misc.getFieldValue("ItemShadowOffset", 1);
final float shadowHeight = 128; if ((itemShadowFile != null) && !"_".equals(itemShadowFile)) {
final String texture = "ReplaceableTextures\\Shadows\\" + itemShadowFile + ".blp";
final float shadowX = itemShadowX;
final float shadowY = itemShadowY;
final float shadowWidth = itemShadowWidth;
final float shadowHeight = itemShadowHeight;
if (!this.terrain.splats.containsKey(texture)) { if (!this.terrain.splats.containsKey(texture)) {
final Splat splat = new Splat(); final Splat splat = new Splat();
splat.opacity = 0.5f; splat.opacity = 0.5f;
@ -824,14 +832,13 @@ public class War3MapViewer extends ModelViewer {
final float x = unitX - shadowX; final float x = unitX - shadowX;
final float y = unitY - shadowY; final float y = unitY - shadowY;
this.terrain.splats.get(texture).locations this.terrain.splats.get(texture).locations
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 }); .add(new float[]{x, y, x + shadowWidth, y + shadowHeight, 3});
unitShadowSplat = this.terrain.splats.get(texture); unitShadowSplat = this.terrain.splats.get(texture);
} }
path += ".mdx"; path += ".mdx";
} }
} } else {
else {
type = WorldEditorDataType.UNITS; type = WorldEditorDataType.UNITS;
path = getUnitModelPath(row); path = getUnitModelPath(row);
@ -849,14 +856,18 @@ public class War3MapViewer extends ModelViewer {
if (uberSplatInfo != null) { if (uberSplatInfo != null) {
final String texturePath = uberSplatInfo.getField("Dir") + "\\" + uberSplatInfo.getField("file") final String texturePath = uberSplatInfo.getField("Dir") + "\\" + uberSplatInfo.getField("file")
+ ".blp"; + ".blp";
final float s = uberSplatInfo.getFieldFloatValue("Scale");
if (unitsReady) {
this.terrain.addUberSplat(texturePath, unitX, unitY, 1, s);
} else {
if (!this.terrain.splats.containsKey(texturePath)) { if (!this.terrain.splats.containsKey(texturePath)) {
this.terrain.splats.put(texturePath, new Splat()); this.terrain.splats.put(texturePath, new Splat());
} }
final float x = unitX; final float x = unitX;
final float y = unitY; final float y = unitY;
final float s = uberSplatInfo.getFieldFloatValue("Scale");
this.terrain.splats.get(texturePath).locations this.terrain.splats.get(texturePath).locations
.add(new float[] { x - s, y - s, x + s, y + s, 1 }); .add(new float[]{x - s, y - s, x + s, y + s, 1});
}
} }
} }
@ -876,7 +887,7 @@ public class War3MapViewer extends ModelViewer {
final float x = unitX - shadowX; final float x = unitX - shadowX;
final float y = unitY - shadowY; final float y = unitY - shadowY;
this.terrain.splats.get(texture).locations this.terrain.splats.get(texture).locations
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 }); .add(new float[]{x, y, x + shadowWidth, y + shadowHeight, 3});
unitShadowSplat = this.terrain.splats.get(texture); unitShadowSplat = this.terrain.splats.get(texture);
} }
} }
@ -903,8 +914,7 @@ public class War3MapViewer extends ModelViewer {
final String portraitPath = path.substring(0, path.length() - 4) + "_portrait.mdx"; final String portraitPath = path.substring(0, path.length() - 4) + "_portrait.mdx";
if (this.dataSource.has(portraitPath)) { if (this.dataSource.has(portraitPath)) {
portraitModel = (MdxModel) this.load(portraitPath, this.mapPathSolver, this.solverParams); portraitModel = (MdxModel) this.load(portraitPath, this.mapPathSolver, this.solverParams);
} } else {
else {
portraitModel = model; portraitModel = model;
} }
if (type == WorldEditorDataType.UNITS) { if (type == WorldEditorDataType.UNITS) {
@ -925,8 +935,7 @@ public class War3MapViewer extends ModelViewer {
}); });
} }
return simulationUnit; return simulationUnit;
} } else {
else {
this.items this.items
.add(new RenderItem(this, model, row, unitX, unitY, unitZ, unitAngle, soundset, portraitModel)); // TODO .add(new RenderItem(this, model, row, unitX, unitY, unitZ, unitAngle, soundset, portraitModel)); // TODO
// store // store
@ -940,8 +949,7 @@ public class War3MapViewer extends ModelViewer {
}); });
} }
} }
} } else {
else {
System.err.println("Unknown unit ID: " + unitId); System.err.println("Unknown unit ID: " + unitId);
} }
return null; return null;
@ -972,16 +980,14 @@ public class War3MapViewer extends ModelViewer {
if (pathingTexture.toLowerCase().endsWith(".tga")) { if (pathingTexture.toLowerCase().endsWith(".tga")) {
buildingPathingPixelMap = TgaFile.readTGA(pathingTexture, buildingPathingPixelMap = TgaFile.readTGA(pathingTexture,
this.mapMpq.getResourceAsStream(pathingTexture)); this.mapMpq.getResourceAsStream(pathingTexture));
} } else {
else {
try (InputStream stream = this.mapMpq.getResourceAsStream(pathingTexture)) { try (InputStream stream = this.mapMpq.getResourceAsStream(pathingTexture)) {
buildingPathingPixelMap = ImageIO.read(stream); buildingPathingPixelMap = ImageIO.read(stream);
System.out.println("LOADING BLP PATHING: " + pathingTexture); System.out.println("LOADING BLP PATHING: " + pathingTexture);
} }
} }
this.filePathToPathingMap.put(pathingTexture.toLowerCase(), buildingPathingPixelMap); this.filePathToPathingMap.put(pathingTexture.toLowerCase(), buildingPathingPixelMap);
} } catch (final IOException exc) {
catch (final IOException exc) {
System.err.println("Failure to get pathing: " + exc.getClass() + ":" + exc.getMessage()); System.err.println("Failure to get pathing: " + exc.getClass() + ":" + exc.getMessage());
} }
} }
@ -1087,7 +1093,7 @@ public class War3MapViewer extends ModelViewer {
public void deselect() { public void deselect() {
if (!this.selModels.isEmpty()) { if (!this.selModels.isEmpty()) {
for (final SplatModel model : this.selModels) { for (final SplatModel model : this.selModels) {
this.terrain.removeSplatBatchModel(model); this.terrain.removeSplatBatchModel("selection");
} }
this.selModels.clear(); this.selModels.clear();
for (final RenderUnit unit : this.selected) { for (final RenderUnit unit : this.selected) {
@ -1127,8 +1133,8 @@ public class War3MapViewer extends ModelViewer {
final float y = unit.location[1]; final float y = unit.location[1];
System.out.println("Selecting a unit at " + x + "," + y); System.out.println("Selecting a unit at " + x + "," + y);
final float z = unit.row.getFieldAsFloat(UNIT_SELECT_HEIGHT, 0); final float z = unit.row.getFieldAsFloat(UNIT_SELECT_HEIGHT, 0);
splats.get(path).locations.add(new float[] { x - (selectionSize / 2), y - (selectionSize / 2), splats.get(path).locations.add(new float[]{x - (selectionSize / 2), y - (selectionSize / 2),
x + (selectionSize / 2), y + (selectionSize / 2), z + 5 }); x + (selectionSize / 2), y + (selectionSize / 2), z + 5});
splats.get(path).unitMapping.add(new Consumer<SplatModel.SplatMover>() { splats.get(path).unitMapping.add(new Consumer<SplatModel.SplatMover>() {
@Override @Override
public void accept(final SplatMover t) { public void accept(final SplatMover t) {
@ -1150,7 +1156,7 @@ public class War3MapViewer extends ModelViewer {
model.color[2] = 0; model.color[2] = 0;
model.color[3] = 1; model.color[3] = 1;
this.selModels.add(model); this.selModels.add(model);
this.terrain.addSplatBatchModel(model); this.terrain.addSplatBatchModel("selection", model);
} }
} }
@ -1167,8 +1173,7 @@ public class War3MapViewer extends ModelViewer {
this.walkableObjectsTree.intersect(rectangleHeap, this.walkablesIntersectionFinder.reset(gdxRayHeap)); this.walkableObjectsTree.intersect(rectangleHeap, this.walkablesIntersectionFinder.reset(gdxRayHeap));
if (this.walkablesIntersectionFinder.found) { if (this.walkablesIntersectionFinder.found) {
out.set(this.walkablesIntersectionFinder.intersection); out.set(this.walkablesIntersectionFinder.intersection);
} } else {
else {
out.z = Math.max(getWalkableRenderHeight(out.x, out.y), this.terrain.getGroundHeight(out.x, out.y)); out.z = Math.max(getWalkableRenderHeight(out.x, out.y), this.terrain.getGroundHeight(out.x, out.y));
} }
} }
@ -1210,16 +1215,13 @@ public class War3MapViewer extends ModelViewer {
final int idx = sel.indexOf(entity); final int idx = sel.indexOf(entity);
if (idx >= 0) { if (idx >= 0) {
sel.remove(idx); sel.remove(idx);
} } else {
else {
sel.add(entity); sel.add(entity);
} }
} } else {
else {
sel = Arrays.asList(entity); sel = Arrays.asList(entity);
} }
} } else {
else {
sel = Collections.emptyList(); sel = Collections.emptyList();
} }
this.doSelectUnit(sel); this.doSelectUnit(sel);
@ -1263,11 +1265,9 @@ public class War3MapViewer extends ModelViewer {
stringBuilder.append(line); stringBuilder.append(line);
stringBuilder.append("\n"); stringBuilder.append("\n");
} }
} } catch (final UnsupportedEncodingException e) {
catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} } catch (final IOException e) {
catch (final IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return new MappedData(stringBuilder.toString()); return new MappedData(stringBuilder.toString());
@ -1287,11 +1287,9 @@ public class War3MapViewer extends ModelViewer {
stringBuilder.append(line); stringBuilder.append(line);
stringBuilder.append("\n"); stringBuilder.append("\n");
} }
} } catch (final UnsupportedEncodingException e) {
catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} } catch (final IOException e) {
catch (final IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return stringBuilder.toString(); return stringBuilder.toString();
@ -1388,8 +1386,7 @@ public class War3MapViewer extends ModelViewer {
public SceneLightManager createLightManager(final boolean simple) { public SceneLightManager createLightManager(final boolean simple) {
if (simple) { if (simple) {
return new W3xScenePortraitLightManager(this, this.lightDirection); return new W3xScenePortraitLightManager(this, this.lightDirection);
} } else {
else {
return new W3xSceneWorldLightManager(this); return new W3xSceneWorldLightManager(this);
} }
} }

View File

@ -5,13 +5,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.Buffer; import java.nio.Buffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -54,7 +48,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.W3xShaders;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer; import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
public class Terrain { public class Terrain {
private static final String[] colorTags = { "R", "G", "B", "A" }; private static final String[] colorTags = {"R", "G", "B", "A"};
private static final float[] sizeHeap = new float[2]; private static final float[] sizeHeap = new float[2];
private static final Vector3 normalHeap1 = new Vector3(); private static final Vector3 normalHeap1 = new Vector3();
private static final Vector3 normalHeap2 = new Vector3(); private static final Vector3 normalHeap2 = new Vector3();
@ -70,7 +64,7 @@ public class Terrain {
public float waterIncreasePerFrame; public float waterIncreasePerFrame;
public float waterHeightOffset; public float waterHeightOffset;
// //
public List<GroundTexture> groundTextures = new ArrayList<>(); public List<GroundTexture> groundTextures = new ArrayList<>();
public List<UnloadedTexture> cliffTextures = new ArrayList<>(); public List<UnloadedTexture> cliffTextures = new ArrayList<>();
public RenderCorner[][] corners; public RenderCorner[][] corners;
@ -114,7 +108,7 @@ public class Terrain {
private final ShaderProgram uberSplatShader; private final ShaderProgram uberSplatShader;
public final DataTable uberSplatTable; public final DataTable uberSplatTable;
private final List<SplatModel> uberSplatModels; private final Map<String, SplatModel> uberSplatModels;
private int shadowMap; private int shadowMap;
public final Map<String, Splat> splats = new HashMap<>(); public final Map<String, Splat> splats = new HashMap<>();
public final Map<String, List<float[]>> shadows = new HashMap<>(); public final Map<String, List<float[]>> shadows = new HashMap<>();
@ -125,6 +119,8 @@ public class Terrain {
public final SoftwareGroundMesh softwareGroundMesh; public final SoftwareGroundMesh softwareGroundMesh;
private final int testArrayBuffer; private final int testArrayBuffer;
private final int testElementBuffer; private final int testElementBuffer;
private boolean initShadowsFinished = false;
private byte[] shadowData;
public Terrain(final War3MapW3e w3eFile, final War3MapWpm terrainPathing, final War3MapW3i w3iFile, public Terrain(final War3MapW3e w3eFile, final War3MapWpm terrainPathing, final War3MapW3i w3iFile,
final WebGL webGL, final DataSource dataSource, final WorldEditStrings worldEditStrings, final WebGL webGL, final DataSource dataSource, final WorldEditStrings worldEditStrings,
@ -181,8 +177,7 @@ public class Terrain {
this.waterHeightOffset = waterInfo.getFieldFloatValue("height"); this.waterHeightOffset = waterInfo.getFieldFloatValue("height");
this.waterTextureCount = waterInfo.getFieldValue("numTex"); this.waterTextureCount = waterInfo.getFieldValue("numTex");
this.waterIncreasePerFrame = waterInfo.getFieldValue("texRate") / 60f; this.waterIncreasePerFrame = waterInfo.getFieldValue("texRate") / 60f;
} } else {
else {
this.waterHeightOffset = 0; this.waterHeightOffset = 0;
this.waterTextureCount = 0; this.waterTextureCount = 0;
this.waterIncreasePerFrame = 0; this.waterIncreasePerFrame = 0;
@ -250,14 +245,12 @@ public class Terrain {
try (final InputStream tgaStream = dataSource.getResourceAsStream(tgaPath)) { try (final InputStream tgaStream = dataSource.getResourceAsStream(tgaPath)) {
if (tgaStream != null) { if (tgaStream != null) {
image = TgaFile.readTGA(tgaPath, tgaStream); image = TgaFile.readTGA(tgaPath, tgaStream);
} } else {
else {
throw new IllegalStateException( throw new IllegalStateException(
"Missing cliff texture: " + texDir + "\\" + texFile + texturesExt); "Missing cliff texture: " + texDir + "\\" + texFile + texturesExt);
} }
} }
} } else {
else {
image = ImageIO.read(imageStream); image = ImageIO.read(imageStream);
if (image == null) { if (image == null) {
throw new IllegalStateException( throw new IllegalStateException(
@ -402,12 +395,12 @@ public class Terrain {
// TODO collision bodies (?) // TODO collision bodies (?)
this.centerOffset = w3eFile.getCenterOffset(); this.centerOffset = w3eFile.getCenterOffset();
this.uberSplatModels = new ArrayList<>(); this.uberSplatModels = new LinkedHashMap<>();
this.mapBounds = w3iFile.getCameraBoundsComplements(); this.mapBounds = w3iFile.getCameraBoundsComplements();
this.shaderMapBounds = new float[] { (this.mapBounds[0] * 128.0f) + this.centerOffset[0], this.shaderMapBounds = new float[]{(this.mapBounds[0] * 128.0f) + this.centerOffset[0],
(this.mapBounds[2] * 128.0f) + this.centerOffset[1], (this.mapBounds[2] * 128.0f) + this.centerOffset[1],
((this.columns - this.mapBounds[1] - 1) * 128.0f) + this.centerOffset[0], ((this.columns - this.mapBounds[1] - 1) * 128.0f) + this.centerOffset[0],
((this.rows - this.mapBounds[3] - 1) * 128.0f) + this.centerOffset[1] }; ((this.rows - this.mapBounds[3] - 1) * 128.0f) + this.centerOffset[1]};
this.shaderMapBoundsRectangle = new Rectangle(this.shaderMapBounds[0], this.shaderMapBounds[1], this.shaderMapBoundsRectangle = new Rectangle(this.shaderMapBounds[0], this.shaderMapBounds[1],
this.shaderMapBounds[2] - this.shaderMapBounds[0], this.shaderMapBounds[3] - this.shaderMapBounds[1]); this.shaderMapBounds[2] - this.shaderMapBounds[0], this.shaderMapBounds[3] - this.shaderMapBounds[1]);
this.mapSize = w3eFile.getMapSize(); this.mapSize = w3eFile.getMapSize();
@ -442,7 +435,8 @@ public class Terrain {
float rampHeight = 0f; float rampHeight = 0f;
// Check if in one of the configurations the bottom_left is a ramp // Check if in one of the configurations the bottom_left is a ramp
XLoop: for (int xOffset = -1; xOffset <= 0; xOffset++) { XLoop:
for (int xOffset = -1; xOffset <= 0; xOffset++) {
for (int yOffset = -1; yOffset <= 0; yOffset++) { for (int yOffset = -1; yOffset <= 0; yOffset++) {
if (((i + xOffset) >= 0) && ((i + xOffset) < (this.columns - 1)) && ((j + yOffset) >= 0) if (((i + xOffset) >= 0) && ((i + xOffset) < (this.columns - 1)) && ((j + yOffset) >= 0)
&& ((j + yOffset) < (this.rows - 1))) { && ((j + yOffset) < (this.rows - 1))) {
@ -502,8 +496,8 @@ public class Terrain {
final int columns = this.mapSize[0]; final int columns = this.mapSize[0];
final int rows = this.mapSize[1]; final int rows = this.mapSize[1];
final String[] ramps = { "AAHL", "AALH", "ABHL", "AHLA", "ALHA", "ALHB", "BALH", "BHLA", "HAAL", "HBAL", "HLAA", final String[] ramps = {"AAHL", "AALH", "ABHL", "AHLA", "ALHA", "ALHB", "BALH", "BHLA", "HAAL", "HBAL", "HLAA",
"HLAB", "LAAH", "LABH", "LHAA", "LHBA" }; "HLAB", "LAAH", "LABH", "LHAA", "LHBA"};
// Adjust terrain height inside ramps (set rampAdjust) // Adjust terrain height inside ramps (set rampAdjust)
for (int y = 1; y < (rows - 1); ++y) { for (int y = 1; y < (rows - 1); ++y) {
@ -546,7 +540,7 @@ public class Terrain {
/// Updates the cliff and ramp meshes for an area /// Updates the cliff and ramp meshes for an area
private void updateCliffMeshes(final Rectangle area) throws IOException { private void updateCliffMeshes(final Rectangle area) throws IOException {
// Remove all existing cliff meshes in area // Remove all existing cliff meshes in area
for (int i = this.cliffs.size(); i-- > 0;) { for (int i = this.cliffs.size(); i-- > 0; ) {
final IVec3 pos = this.cliffs.get(i); final IVec3 pos = this.cliffs.get(i);
if (area.contains(pos.x, pos.y)) { if (area.contains(pos.x, pos.y)) {
this.cliffs.remove(i); this.cliffs.remove(i);
@ -617,7 +611,7 @@ public class Terrain {
this.pathToCliff.put(fileName, this.cliffMeshes.size() - 1); this.pathToCliff.put(fileName, this.cliffMeshes.size() - 1);
} }
for (int ji = this.cliffs.size(); ji-- > 0;) { for (int ji = this.cliffs.size(); ji-- > 0; ) {
final IVec3 pos = this.cliffs.get(ji); final IVec3 pos = this.cliffs.get(ji);
if ((pos.x == (i + ((bo ? 1 : 0) * (facingLeft ? 0 : 1)))) if ((pos.x == (i + ((bo ? 1 : 0) * (facingLeft ? 0 : 1))))
&& (pos.y == (j - ((br ? 1 : 0) * (facingDown ? 1 : 0))))) { && (pos.y == (j - ((br ? 1 : 0) * (facingDown ? 1 : 0))))) {
@ -707,8 +701,7 @@ public class Terrain {
uploadGroundTexture(); uploadGroundTexture();
try { try {
updateCliffMeshes(new Rectangle(i - 1, j - 1, 1, 1)); // TODO does this work? updateCliffMeshes(new Rectangle(i - 1, j - 1, 1, 1)); // TODO does this work?
} } catch (final IOException e) {
catch (final IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@ -722,8 +715,7 @@ public class Terrain {
uploadGroundTexture(); uploadGroundTexture();
try { try {
updateCliffMeshes(new Rectangle(0, 0, this.columns - 1, this.rows - 1)); updateCliffMeshes(new Rectangle(0, 0, this.columns - 1, this.rows - 1));
} } catch (final IOException e) {
catch (final IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@ -772,7 +764,8 @@ public class Terrain {
} }
private int realTileTexture(final int x, final int y) { private int realTileTexture(final int x, final int y) {
ILoop: for (int i = -1; i < 1; i++) { ILoop:
for (int i = -1; i < 1; i++) {
for (int j = -1; j < 1; j++) { for (int j = -1; j < 1; j++) {
if (((x + i) >= 0) && ((x + i) < this.columns) && ((y + j) >= 0) && ((y + j) < this.rows)) { if (((x + i) >= 0) && ((x + i) < this.columns) && ((y + j) >= 0) && ((y + j) < this.rows)) {
if (this.corners[x + i][y + j].cliff) { if (this.corners[x + i][y + j].cliff) {
@ -838,19 +831,15 @@ public class Terrain {
if (texture.extended) { if (texture.extended) {
if (variation <= 15) { if (variation <= 15) {
return (short) (16 + variation); return (short) (16 + variation);
} } else if (variation == 16) {
else if (variation == 16) {
return 15; return 15;
} } else {
else {
return 0; return 0;
} }
} } else {
else {
if (variation == 0) { if (variation == 0) {
return 0; return 0;
} } else {
else {
return 15; return 15;
} }
} }
@ -997,7 +986,7 @@ public class Terrain {
gl.glUniform1f(shader.getUniformLocation("u_lightTextureHeight"), terrainLightsTexture.getHeight()); gl.glUniform1f(shader.getUniformLocation("u_lightTextureHeight"), terrainLightsTexture.getHeight());
// Render the cliffs // Render the cliffs
for (final SplatModel splat : this.uberSplatModels) { for (final SplatModel splat : this.uberSplatModels.values()) {
splat.render(gl, shader); splat.render(gl, shader);
} }
} }
@ -1103,13 +1092,32 @@ public class Terrain {
} }
} }
public void addShadow(final String file, final float x, final float y) { public void addShadow(final String file, final float shadowX, final float shadowY) {
if (!this.shadows.containsKey(file)) { if (!this.shadows.containsKey(file)) {
final String path = "ReplaceableTextures\\Shadows\\" + file + ".blp"; final String path = "ReplaceableTextures\\Shadows\\" + file + ".blp";
this.shadows.put(file, new ArrayList<>()); this.shadows.put(file, new ArrayList<>());
this.shadowTextures.put(file, (Texture) this.viewer.load(path, PathSolver.DEFAULT, null)); this.shadowTextures.put(file, (Texture) this.viewer.load(path, PathSolver.DEFAULT, null));
} }
this.shadows.get(file).add(new float[] { x, y }); this.shadows.get(file).add(new float[]{shadowX, shadowY});
if (initShadowsFinished) {
final Texture texture = shadowTextures.get(file);
final int columns = (this.columns - 1) * 4;
final int rows = (this.rows - 1) * 4;
blitShadowData(columns, rows, shadowX, shadowY, texture);
GL30 gl = Gdx.gl30;
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.shadowMap);
gl.glTexImage2D(GL30.GL_TEXTURE_2D, 0, GL30.GL_R8, columns, rows, 0, GL30.GL_RED, GL30.GL_UNSIGNED_BYTE,
RenderMathUtils.wrap(shadowData));
}
}
public void blitShadowData(int columns, int rows, float shadowX, float shadowY, Texture texture) {
final int width = texture.getWidth();
final int height = texture.getHeight();
final int ox = (int) Math.round(width * 0.3);
final int oy = (int) Math.round(height * 0.7);
blitShadowDataLocation(columns, rows, (RawOpenGLTextureResource) texture, width, height, ox, oy, centerOffset, shadowX, shadowY);
} }
public void initShadows() throws IOException { public void initShadows() throws IOException {
@ -1119,7 +1127,7 @@ public class Terrain {
final int rows = (this.rows - 1) * 4; final int rows = (this.rows - 1) * 4;
final int shadowSize = columns * rows; final int shadowSize = columns * rows;
final byte[] shadowData = new byte[columns * rows]; shadowData = new byte[columns * rows];
if (this.viewer.mapMpq.has("war3map.shd")) { if (this.viewer.mapMpq.has("war3map.shd")) {
final byte[] buffer; final byte[] buffer;
@ -1141,21 +1149,7 @@ public class Terrain {
final int ox = (int) Math.round(width * 0.3); final int ox = (int) Math.round(width * 0.3);
final int oy = (int) Math.round(height * 0.7); final int oy = (int) Math.round(height * 0.7);
for (final float[] location : this.shadows.get(file)) { for (final float[] location : this.shadows.get(file)) {
final int x0 = (int) Math.floor((location[0] - centerOffset[0]) / 32.0) - ox; blitShadowDataLocation(columns, rows, (RawOpenGLTextureResource) texture, width, height, ox, oy, centerOffset, location[0], location[1]);
final int y0 = (int) Math.floor((location[1] - centerOffset[1]) / 32.0) + oy;
for (int y = 0; y < height; ++y) {
if (((y0 - y) < 0) || ((y0 - y) >= rows)) {
continue;
}
for (int x = 0; x < width; ++x) {
if (((x0 + x) < 0) || ((x0 + x) >= columns)) {
continue;
}
if (((RawOpenGLTextureResource) texture).getData().get((((y * width) + x) * 4) + 3) != 0) {
shadowData[((y0 - y) * columns) + x0 + x] = (byte) 128;
}
}
}
} }
} }
@ -1195,6 +1189,25 @@ public class Terrain {
gl.glTexParameteri(GL30.GL_TEXTURE_2D, GL30.GL_TEXTURE_WRAP_T, GL30.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL30.GL_TEXTURE_2D, GL30.GL_TEXTURE_WRAP_T, GL30.GL_CLAMP_TO_EDGE);
gl.glTexImage2D(GL30.GL_TEXTURE_2D, 0, GL30.GL_R8, columns, rows, 0, GL30.GL_RED, GL30.GL_UNSIGNED_BYTE, gl.glTexImage2D(GL30.GL_TEXTURE_2D, 0, GL30.GL_R8, columns, rows, 0, GL30.GL_RED, GL30.GL_UNSIGNED_BYTE,
RenderMathUtils.wrap(shadowData)); RenderMathUtils.wrap(shadowData));
this.initShadowsFinished = true;
}
public void blitShadowDataLocation(int columns, int rows, RawOpenGLTextureResource texture, int width, int height, int x01, int y01, float[] centerOffset, float v, float v2) {
final int x0 = (int) Math.floor((v - centerOffset[0]) / 32.0) - x01;
final int y0 = (int) Math.floor((v2 - centerOffset[1]) / 32.0) + y01;
for (int y = 0; y < height; ++y) {
if (((y0 - y) < 0) || ((y0 - y) >= rows)) {
continue;
}
for (int x = 0; x < width; ++x) {
if (((x0 + x) < 0) || ((x0 + x) >= columns)) {
continue;
}
if (texture.getData().get((((y * width) + x) * 4) + 3) != 0) {
shadowData[((y0 - y) * columns) + x0 + x] = (byte) 128;
}
}
}
} }
// public Vector3 groundNormal(final Vector3 out, int x, int y) { // public Vector3 groundNormal(final Vector3 out, int x, int y) {
@ -1277,8 +1290,7 @@ public class Terrain {
if ((sqX + sqY) < 1) { if ((sqX + sqY) < 1) {
height = bottomLeft + ((bottomRight - bottomLeft) * sqX) + ((topLeft - bottomLeft) * sqY); height = bottomLeft + ((bottomRight - bottomLeft) * sqX) + ((topLeft - bottomLeft) * sqY);
} } else {
else {
height = topRight + ((bottomRight - topRight) * (1 - sqY)) + ((topLeft - topRight) * (1 - sqX)); height = topRight + ((bottomRight - topRight) * (1 - sqY)) + ((topLeft - topRight) * (1 - sqX));
} }
@ -1305,8 +1317,7 @@ public class Terrain {
if ((sqX + sqY) < 1) { if ((sqX + sqY) < 1) {
height = bottomLeft + ((bottomRight - bottomLeft) * sqX) + ((topLeft - bottomLeft) * sqY); height = bottomLeft + ((bottomRight - bottomLeft) * sqX) + ((topLeft - bottomLeft) * sqY);
} } else {
else {
height = topRight + ((bottomRight - topRight) * (1 - sqY)) + ((topLeft - topRight) * (1 - sqX)); height = topRight + ((bottomRight - topRight) * (1 - sqY)) + ((topLeft - topRight) * (1 - sqX));
} }
@ -1331,16 +1342,26 @@ public class Terrain {
(Texture) this.viewer.load(path, PathSolver.DEFAULT, null), splat.locations, this.centerOffset, (Texture) this.viewer.load(path, PathSolver.DEFAULT, null), splat.locations, this.centerOffset,
splat.unitMapping, false); splat.unitMapping, false);
splatModel.color[3] = splat.opacity; splatModel.color[3] = splat.opacity;
this.uberSplatModels.add(splatModel); this.uberSplatModels.put(path, splatModel);
} }
} }
public void removeSplatBatchModel(final SplatModel model) { public void removeSplatBatchModel(String path) {
this.uberSplatModels.remove(model); this.uberSplatModels.remove(path);
} }
public void addSplatBatchModel(final SplatModel model) { public void addSplatBatchModel(String path, final SplatModel model) {
this.uberSplatModels.add(model); this.uberSplatModels.put(path, model);
}
public void addUberSplat(String path, float x, float y, float z, float scale) {
SplatModel splatModel = this.uberSplatModels.get(path);
if (splatModel == null) {
splatModel = new SplatModel(Gdx.gl30, (Texture) this.viewer.load(path, PathSolver.DEFAULT, null),
new ArrayList<>(), centerOffset, null, false);
this.uberSplatModels.put(path, splatModel);
}
splatModel.add(x, y, z, scale, centerOffset);
} }
public static final class SoftwareGroundMesh { public static final class SoftwareGroundMesh {

View File

@ -12,13 +12,10 @@ import com.etheller.warsmash.util.RenderMathUtils;
import com.etheller.warsmash.util.War3ID; import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance; import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel; import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens; import com.etheller.warsmash.viewer5.handlers.w3x.*;
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.AnimationTokens.SecondaryTag; import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover; import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSoundset;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
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.environment.PathingGrid.MovementType; import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
@ -39,6 +36,7 @@ public class RenderUnit {
private static final War3ID ORIENTATION_INTERPOLATION = War3ID.fromString("uori"); private static final War3ID ORIENTATION_INTERPOLATION = War3ID.fromString("uori");
private static final War3ID ANIM_PROPS = War3ID.fromString("uani"); private static final War3ID ANIM_PROPS = War3ID.fromString("uani");
private static final War3ID BLEND_TIME = War3ID.fromString("uble"); private static final War3ID BLEND_TIME = War3ID.fromString("uble");
private static final War3ID BUILD_SOUND_LABEL = War3ID.fromString("ubsl");
private static final float[] heapZ = new float[3]; private static final float[] heapZ = new float[3];
public final MdxComplexInstance instance; public final MdxComplexInstance instance;
public final MutableGameObject row; public final MutableGameObject row;
@ -66,6 +64,7 @@ public class RenderUnit {
private boolean corpse; private boolean corpse;
private boolean boneCorpse; private boolean boneCorpse;
private final RenderUnitTypeData typeData; private final RenderUnitTypeData typeData;
public UnitSound buildSound;
public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row, final float x, 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 float y, final float z, final int playerIndex, final UnitSoundset soundset,
@ -128,6 +127,7 @@ public class RenderUnit {
final float blendTime = row.getFieldAsFloat(BLEND_TIME, 0); final float blendTime = row.getFieldAsFloat(BLEND_TIME, 0);
instance.setBlendTime(blendTime * 1000.0f); instance.setBlendTime(blendTime * 1000.0f);
buildSound = map.getUiSounds().getSound(row.getFieldAsString(BUILD_SOUND_LABEL, 0));
} }
this.instance = instance; this.instance = instance;
@ -350,6 +350,9 @@ public class RenderUnit {
this.selectionCircle.move(dx, dy, map.terrain.centerOffset); this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
} }
this.unitAnimationListenerImpl.update(); this.unitAnimationListenerImpl.update();
if(!dead && simulationUnit.isConstructing()) {
instance.setFrameByRatio(simulationUnit.getConstructionProgress() / simulationUnit.getUnitType().getBuildTime());
}
} }
private float getGroundHeightSample(final float groundHeight, final MdxComplexInstance currentWalkableUnder, private float getGroundHeightSample(final float groundHeight, final MdxComplexInstance currentWalkableUnder,

View File

@ -223,6 +223,10 @@ public class CSimulation {
this.simulationRenderController.spawnUnitDamageSound(damagedUnit, weaponSound, armorType); this.simulationRenderController.spawnUnitDamageSound(damagedUnit, weaponSound, armorType);
} }
public void unitConstructedEvent(CUnit constructingUnit, CUnit constructedStructure) {
this.simulationRenderController.spawnUnitConstructionSound(constructingUnit, constructedStructure);
}
public CPlayer getPlayer(final int index) { public CPlayer getPlayer(final int index) {
return this.players.get(index); return this.players.get(index);
} }
@ -230,4 +234,8 @@ public class CSimulation {
public CommandErrorListener getCommandErrorListener() { public CommandErrorListener getCommandErrorListener() {
return this.commandErrorListener; return this.commandErrorListener;
} }
public void unitConstructFinishEvent(CUnit constructedStructure) {
this.simulationRenderController.spawnUnitConstructionFinishSound(constructedStructure);
}
} }

View File

@ -70,6 +70,8 @@ public class CUnit extends CWidget {
private transient CBehaviorFollow followBehavior; private transient CBehaviorFollow followBehavior;
private transient CBehaviorPatrol patrolBehavior; private transient CBehaviorPatrol patrolBehavior;
private transient CBehaviorStop stopBehavior; private transient CBehaviorStop stopBehavior;
private boolean constructing = false;
private float constructionProgress;
public CUnit(final int handleId, final int playerIndex, final float x, final float y, final float life, public CUnit(final int handleId, final int playerIndex, final float x, final float y, final float life,
final War3ID typeId, final float facing, final float mana, final int maximumLife, final int maximumMana, final War3ID typeId, final float facing, final float mana, final int maximumLife, final int maximumMana,
@ -199,6 +201,14 @@ public class CUnit extends CWidget {
return true; return true;
} }
} }
else if (constructing) {
constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME;
if (constructionProgress >= unitType.getBuildTime()) {
constructing = false;
game.unitConstructFinishEvent(this);
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
}
}
else if (this.currentBehavior != null) { else if (this.currentBehavior != null) {
final CBehavior lastBehavior = this.currentBehavior; final CBehavior lastBehavior = this.currentBehavior;
this.currentBehavior = this.currentBehavior.update(game); this.currentBehavior = this.currentBehavior.update(game);
@ -670,4 +680,22 @@ public class CUnit extends CWidget {
return getCurrentBehavior() instanceof CBehaviorMove; return getCurrentBehavior() instanceof CBehaviorMove;
} }
public void setConstructing(boolean constructing) {
this.constructing = constructing;
if (constructing) {
unitAnimationListener.playAnimation(true, PrimaryTag.BIRTH, SequenceUtils.EMPTY, 0.0f, true);
}
}
public void setConstructionProgress(float constructionProgress) {
this.constructionProgress = constructionProgress;
}
public boolean isConstructing() {
return constructing;
}
public float getConstructionProgress() {
return constructionProgress;
}
} }

View File

@ -35,8 +35,10 @@ public class CBehaviorOrcBuild extends CAbstractRangedPointTargetBehavior {
@Override @Override
protected CBehavior update(final CSimulation simulation, final boolean withinRange) { protected CBehavior update(final CSimulation simulation, final boolean withinRange) {
simulation.createUnit(this.orderId, this.unit.getPlayerIndex(), this.targetX, this.targetY, CUnit constructedStructure = simulation.createUnit(this.orderId, this.unit.getPlayerIndex(), this.targetX, this.targetY,
simulation.getGameplayConstants().getBuildingAngle()); simulation.getGameplayConstants().getBuildingAngle());
constructedStructure.setConstructing(true);
simulation.unitConstructedEvent(this.unit, constructedStructure);
return this.unit.pollNextOrderBehavior(simulation); return this.unit.pollNextOrderBehavior(simulation);
} }

View File

@ -21,7 +21,11 @@ public interface SimulationRenderController {
void spawnUnitDamageSound(CUnit damagedUnit, final String weaponSound, String armorType); void spawnUnitDamageSound(CUnit damagedUnit, final String weaponSound, String armorType);
void spawnUnitConstructionSound(CUnit constructingUnit, CUnit constructedStructure);
void removeUnit(CUnit unit); void removeUnit(CUnit unit);
BufferedImage getBuildingPathingPixelMap(War3ID rawcode); BufferedImage getBuildingPathingPixelMap(War3ID rawcode);
void spawnUnitConstructionFinishSound(CUnit constructedStructure);
} }

View File

@ -128,6 +128,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private StringFrame armorInfoPanelIconLevel; private StringFrame armorInfoPanelIconLevel;
private InfoPanelIconBackdrops damageBackdrops; private InfoPanelIconBackdrops damageBackdrops;
private InfoPanelIconBackdrops defenseBackdrops; private InfoPanelIconBackdrops defenseBackdrops;
private SpriteFrame buildTimeIndicator;
private final CommandCardIcon[][] commandCard = new CommandCardIcon[COMMAND_CARD_HEIGHT][COMMAND_CARD_WIDTH]; private final CommandCardIcon[][] commandCard = new CommandCardIcon[COMMAND_CARD_HEIGHT][COMMAND_CARD_WIDTH];
@ -195,18 +196,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
try { try {
minimapTexture = ImageUtils.getTextureNoColorCorrection(TgaFile.readTGA("war3mapMap.tga", minimapTexture = ImageUtils.getTextureNoColorCorrection(TgaFile.readTGA("war3mapMap.tga",
war3MapViewer.dataSource.getResourceAsStream("war3mapMap.tga"))); war3MapViewer.dataSource.getResourceAsStream("war3mapMap.tga")));
} } catch (final IOException e) {
catch (final IOException e) {
System.err.println("Could not load minimap TGA file"); System.err.println("Could not load minimap TGA file");
e.printStackTrace(); e.printStackTrace();
} }
} } else if (war3MapViewer.dataSource.has("war3mapMap.blp")) {
else if (war3MapViewer.dataSource.has("war3mapMap.blp")) {
try { try {
minimapTexture = ImageUtils minimapTexture = ImageUtils
.getTexture(ImageIO.read(war3MapViewer.dataSource.getResourceAsStream("war3mapMap.blp"))); .getTexture(ImageIO.read(war3MapViewer.dataSource.getResourceAsStream("war3mapMap.blp")));
} } catch (final IOException e) {
catch (final IOException e) {
System.err.println("Could not load minimap BLP file"); System.err.println("Could not load minimap BLP file");
e.printStackTrace(); e.printStackTrace();
} }
@ -233,14 +231,12 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.rootFrameListener.onCreate(this.rootFrame); this.rootFrameListener.onCreate(this.rootFrame);
try { try {
this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc"); this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
} } catch (final IOException exc) {
catch (final IOException exc) {
throw new IllegalStateException("Unable to load FrameDef.toc", exc); throw new IllegalStateException("Unable to load FrameDef.toc", exc);
} }
try { try {
this.rootFrame.loadTOCFile("UI\\FrameDef\\SmashFrameDef.toc"); this.rootFrame.loadTOCFile("UI\\FrameDef\\SmashFrameDef.toc");
} } catch (final IOException exc) {
catch (final IOException exc) {
throw new IllegalStateException("Unable to load SmashFrameDef.toc", exc); throw new IllegalStateException("Unable to load SmashFrameDef.toc", exc);
} }
this.damageBackdrops = new InfoPanelIconBackdrops(CAttackType.values(), this.rootFrame, "Damage", "Neutral"); this.damageBackdrops = new InfoPanelIconBackdrops(CAttackType.values(), this.rootFrame, "Damage", "Neutral");
@ -366,6 +362,13 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
commandButtonIndex++; commandButtonIndex++;
} }
} }
buildTimeIndicator = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
"SmashBuildProgressBar", this.rootFrame, "", 0);
buildTimeIndicator.addSetPoint(new SetPoint(FramePoint.CENTER, simpleClassValue, FramePoint.CENTER,
GameUI.convertX(this.uiViewport, -0.04f),
GameUI.convertY(this.uiViewport, -0.025f)));
this.rootFrame.setSpriteFrameModel(buildTimeIndicator, this.rootFrame.getSkinField("BuildTimeIndicator"));
buildTimeIndicator.setAnimationSpeed(0);
this.cursorFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", "SmashCursorFrame", this.rootFrame, this.cursorFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", "SmashCursorFrame", this.rootFrame,
"", 0); "", 0);
@ -397,8 +400,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
stringMsgActivationReceiver); stringMsgActivationReceiver);
if (!stringMsgActivationReceiver.isUseOk()) { if (!stringMsgActivationReceiver.isUseOk()) {
showCommandError(stringMsgActivationReceiver.getMessage()); showCommandError(stringMsgActivationReceiver.getMessage());
} } else {
else {
final BooleanAbilityTargetCheckReceiver<Void> noTargetReceiver = BooleanAbilityTargetCheckReceiver final BooleanAbilityTargetCheckReceiver<Void> noTargetReceiver = BooleanAbilityTargetCheckReceiver
.<Void>getInstance().reset(); .<Void>getInstance().reset();
abilityToUse.checkCanTargetNoTarget(this.war3MapViewer.simulation, abilityToUse.checkCanTargetNoTarget(this.war3MapViewer.simulation,
@ -406,16 +408,14 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (noTargetReceiver.isTargetable()) { if (noTargetReceiver.isTargetable()) {
this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(), this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(),
abilityHandleId, orderId, isShiftDown()); abilityHandleId, orderId, isShiftDown());
} } else {
else {
this.activeCommand = abilityToUse; this.activeCommand = abilityToUse;
this.activeCommandOrderId = orderId; this.activeCommandOrderId = orderId;
this.activeCommandUnit = this.selectedUnit; this.activeCommandUnit = this.selectedUnit;
clearAndRepopulateCommandCard(); clearAndRepopulateCommandCard();
} }
} }
} } else {
else {
this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(), this.unitOrderListener.issueImmediateOrder(this.selectedUnit.getSimulationUnit().getHandleId(),
abilityHandleId, orderId, isShiftDown()); abilityHandleId, orderId, isShiftDown());
} }
@ -431,8 +431,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.activeCommandUnit = null; this.activeCommandUnit = null;
this.activeCommand = null; this.activeCommand = null;
this.activeCommandOrderId = -1; this.activeCommandOrderId = -1;
} } else {
else {
this.subMenuOrderIdStack.add(orderId); this.subMenuOrderIdStack.add(orderId);
} }
clearAndRepopulateCommandCard(); clearAndRepopulateCommandCard();
@ -480,7 +479,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
final MdxModel model = (MdxModel) this.war3MapViewer.load(unitModelPath, final MdxModel model = (MdxModel) this.war3MapViewer.load(unitModelPath,
this.war3MapViewer.mapPathSolver, this.war3MapViewer.solverParams); this.war3MapViewer.mapPathSolver, this.war3MapViewer.solverParams);
this.cursorModelInstance = (MdxComplexInstance) model.addInstance(); this.cursorModelInstance = (MdxComplexInstance) model.addInstance();
this.cursorModelInstance.setVertexColor(new float[] { 1, 1, 1, 0.5f }); this.cursorModelInstance.setVertexColor(new float[]{1, 1, 1, 0.5f});
this.cursorModelInstance.rotate(RenderUnit.tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.cursorModelInstance.rotate(RenderUnit.tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z,
this.war3MapViewer.simulation.getGameplayConstants().getBuildingAngle())); this.war3MapViewer.simulation.getGameplayConstants().getBuildingAngle()));
this.cursorModelInstance.setAnimationSpeed(0f); this.cursorModelInstance.setAnimationSpeed(0f);
@ -503,8 +502,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (justLoaded) { if (justLoaded) {
this.cursorModelInstance.setScene(this.war3MapViewer.worldScene); this.cursorModelInstance.setScene(this.war3MapViewer.worldScene);
} }
} } else {
else {
if (this.cursorModelInstance != null) { if (this.cursorModelInstance != null) {
this.cursorModelInstance.detach(); this.cursorModelInstance.detach();
this.cursorModelInstance = null; this.cursorModelInstance = null;
@ -512,8 +510,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
this.cursorFrame.setSequence("Target"); this.cursorFrame.setSequence("Target");
} }
} } else {
else {
if (this.cursorModelInstance != null) { if (this.cursorModelInstance != null) {
this.cursorModelInstance.detach(); this.cursorModelInstance.detach();
this.cursorModelInstance = null; this.cursorModelInstance = null;
@ -522,35 +519,31 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (down) { if (down) {
if (left) { if (left) {
this.cursorFrame.setSequence("Scroll Down Left"); this.cursorFrame.setSequence("Scroll Down Left");
} } else if (right) {
else if (right) {
this.cursorFrame.setSequence("Scroll Down Right"); this.cursorFrame.setSequence("Scroll Down Right");
} } else {
else {
this.cursorFrame.setSequence("Scroll Down"); this.cursorFrame.setSequence("Scroll Down");
} }
} } else if (up) {
else if (up) {
if (left) { if (left) {
this.cursorFrame.setSequence("Scroll Up Left"); this.cursorFrame.setSequence("Scroll Up Left");
} } else if (right) {
else if (right) {
this.cursorFrame.setSequence("Scroll Up Right"); this.cursorFrame.setSequence("Scroll Up Right");
} } else {
else {
this.cursorFrame.setSequence("Scroll Up"); this.cursorFrame.setSequence("Scroll Up");
} }
} } else if (left) {
else if (left) {
this.cursorFrame.setSequence("Scroll Left"); this.cursorFrame.setSequence("Scroll Left");
} } else if (right) {
else if (right) {
this.cursorFrame.setSequence("Scroll Right"); this.cursorFrame.setSequence("Scroll Right");
} } else {
else {
this.cursorFrame.setSequence("Normal"); this.cursorFrame.setSequence("Normal");
} }
} }
if (this.buildTimeIndicator.isVisible() && this.selectedUnit != null) {
buildTimeIndicator.setFrameByRatio(Math.min(this.selectedUnit.getSimulationUnit().getConstructionProgress() /
this.selectedUnit.getSimulationUnit().getUnitType().getBuildTime(), 0.99f));
}
final float groundHeight = Math.max( final float groundHeight = Math.max(
this.war3MapViewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y), this.war3MapViewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y),
this.war3MapViewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y)); this.war3MapViewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y));
@ -617,8 +610,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
this.modelInstance = null; this.modelInstance = null;
this.portraitCameraManager.setModelInstance(null, null); this.portraitCameraManager.setModelInstance(null, null);
} } else {
else {
final MdxModel portraitModel = unit.portraitModel; final MdxModel portraitModel = unit.portraitModel;
if (portraitModel != null) { if (portraitModel != null) {
if (this.modelInstance != null) { if (this.modelInstance != null) {
@ -645,8 +637,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
this.portrait.setSelectedUnit(unit); this.portrait.setSelectedUnit(unit);
this.selectedUnit = unit; this.selectedUnit = unit;
clearCommandCard();
if (unit == null) { if (unit == null) {
clearCommandCard();
this.simpleNameValue.setText(""); this.simpleNameValue.setText("");
this.unitLifeText.setText(""); this.unitLifeText.setText("");
this.unitManaText.setText(""); this.unitManaText.setText("");
@ -658,8 +650,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.attack2InfoPanelIconLevel.setText(""); this.attack2InfoPanelIconLevel.setText("");
this.armorIcon.setVisible(false); this.armorIcon.setVisible(false);
this.armorInfoPanelIconLevel.setText(""); this.armorInfoPanelIconLevel.setText("");
} this.buildTimeIndicator.setVisible(false);
else { } else {
unit.getSimulationUnit().addStateListener(this); unit.getSimulationUnit().addStateListener(this);
this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName()); this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName());
String classText = null; String classText = null;
@ -675,8 +667,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
if (classText != null) { if (classText != null) {
this.simpleClassValue.setText(classText); this.simpleClassValue.setText(classText);
} } else {
else {
this.simpleClassValue.setText(""); this.simpleClassValue.setText("");
} }
this.unitLifeText.setText(FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getLife()) + " / " this.unitLifeText.setText(FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getLife()) + " / "
@ -685,17 +676,17 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (maximumMana > 0) { if (maximumMana > 0) {
this.unitManaText.setText( this.unitManaText.setText(
FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getMana()) + " / " + maximumMana); FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getMana()) + " / " + maximumMana);
} } else {
else {
this.unitManaText.setText(""); this.unitManaText.setText("");
} }
this.simpleBuildingActionLabel.setText(""); this.simpleBuildingActionLabel.setText("");
final boolean anyAttacks = unit.getSimulationUnit().getUnitType().getAttacks().size() > 0; final boolean anyAttacks = unit.getSimulationUnit().getUnitType().getAttacks().size() > 0;
boolean constructing = unit.getSimulationUnit().isConstructing();
final UIFrame localArmorIcon = this.armorIcon; final UIFrame localArmorIcon = this.armorIcon;
final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop; final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop;
final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue; final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue;
if (anyAttacks) { if (anyAttacks && !constructing) {
final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0); final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0);
this.attack1Icon.setVisible(attackOne.isShowUI()); this.attack1Icon.setVisible(attackOne.isShowUI());
this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType())); this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType()));
@ -705,8 +696,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.attack2Icon.setVisible(attackTwo.isShowUI()); this.attack2Icon.setVisible(attackTwo.isShowUI());
this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType())); this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType()));
this.attack2InfoPanelIconValue.setText(attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage()); this.attack2InfoPanelIconValue.setText(attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage());
} } else {
else {
this.attack2Icon.setVisible(false); this.attack2Icon.setVisible(false);
} }
@ -714,8 +704,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT, new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f))); GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f)));
this.armorIcon.positionBounds(this.uiViewport); this.armorIcon.positionBounds(this.uiViewport);
} } else {
else {
this.attack1Icon.setVisible(false); this.attack1Icon.setVisible(false);
this.attack2Icon.setVisible(false); this.attack2Icon.setVisible(false);
@ -724,7 +713,11 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.armorIcon.positionBounds(this.uiViewport); this.armorIcon.positionBounds(this.uiViewport);
} }
localArmorIcon.setVisible(true); localArmorIcon.setVisible(!constructing);
buildTimeIndicator.setVisible(constructing);
if (constructing) {
buildTimeIndicator.setSequence(0);
}
final Texture defenseTexture = this.defenseBackdrops final Texture defenseTexture = this.defenseBackdrops
.getTexture(unit.getSimulationUnit().getUnitType().getDefenseType()); .getTexture(unit.getSimulationUnit().getUnitType().getDefenseType());
if (defenseTexture == null) { if (defenseTexture == null) {
@ -733,8 +726,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
localArmorIconBackdrop.setTexture(defenseTexture); localArmorIconBackdrop.setTexture(defenseTexture);
localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense())); localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense()));
unit.populateCommandCard(this.war3MapViewer.simulation, this, this.war3MapViewer.getAbilityDataUI(), clearAndRepopulateCommandCard();
getSubMenuOrderId());
} }
} }
@ -788,8 +780,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
final Texture suffixTexture = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey)); final Texture suffixTexture = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey));
if (suffixTexture != null) { if (suffixTexture != null) {
this.damageBackdropTextures[index] = suffixTexture; this.damageBackdropTextures[index] = suffixTexture;
} } else {
else {
skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey(); skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey();
this.damageBackdropTextures[index] = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey)); this.damageBackdropTextures[index] = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey));
} }
@ -835,8 +826,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
public void lifeChanged() { public void lifeChanged() {
if (this.selectedUnit.getSimulationUnit().isDead()) { if (this.selectedUnit.getSimulationUnit().isDead()) {
selectUnit(null); selectUnit(null);
} } else {
else {
this.unitLifeText this.unitLifeText
.setText(FastNumberFormat.formatWholeNumber(this.selectedUnit.getSimulationUnit().getLife()) + " / " .setText(FastNumberFormat.formatWholeNumber(this.selectedUnit.getSimulationUnit().getLife()) + " / "
+ this.selectedUnit.getSimulationUnit().getMaximumLife()); + this.selectedUnit.getSimulationUnit().getMaximumLife());
@ -845,7 +835,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
@Override @Override
public void ordersChanged(final int abilityHandleId, final int orderId) { public void ordersChanged(final int abilityHandleId, final int orderId) {
clearAndRepopulateCommandCard(); selectUnit(selectedUnit);
} }
private void clearAndRepopulateCommandCard() { private void clearAndRepopulateCommandCard() {
@ -856,8 +846,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
final IconUI cancelUI = abilityDataUI.getCancelUI(); final IconUI cancelUI = abilityDataUI.getCancelUI();
this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0, this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0,
menuOrderId, 0, false, false, true); menuOrderId, 0, false, false, true);
} } else if (this.selectedUnit.getSimulationUnit().isConstructing()) {
else {
} else {
if (menuOrderId != 0) { if (menuOrderId != 0) {
final int exitOrderId = this.subMenuOrderIdStack.size() > 1 final int exitOrderId = this.subMenuOrderIdStack.size() > 1
? this.subMenuOrderIdStack.get(this.subMenuOrderIdStack.size() - 2) ? this.subMenuOrderIdStack.get(this.subMenuOrderIdStack.size() - 2)
@ -910,8 +901,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.activeCommand = null; this.activeCommand = null;
this.activeCommandOrderId = -1; this.activeCommandOrderId = -1;
clearAndRepopulateCommandCard(); clearAndRepopulateCommandCard();
} } else {
else {
final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY, final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY,
this.activeCommandUnitTargetFilter); this.activeCommandUnitTargetFilter);
final boolean shiftDown = isShiftDown(); final boolean shiftDown = isShiftDown();
@ -932,8 +922,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.activeCommandOrderId = -1; this.activeCommandOrderId = -1;
clearAndRepopulateCommandCard(); clearAndRepopulateCommandCard();
} }
} } else {
else {
this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY);
clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y); clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y);
@ -944,8 +933,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (target != null) { if (target != null) {
if (this.activeCommand instanceof CAbilityAttack) { if (this.activeCommand instanceof CAbilityAttack) {
this.war3MapViewer.showConfirmation(clickLocationTemp, 1, 0, 0); this.war3MapViewer.showConfirmation(clickLocationTemp, 1, 0, 0);
} } else {
else {
this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0); this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0);
} }
this.unitOrderListener.issuePointOrder( this.unitOrderListener.issuePointOrder(
@ -972,8 +960,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
} }
} }
} } else {
else {
if (button == Input.Buttons.RIGHT) { if (button == Input.Buttons.RIGHT) {
if (getSelectedUnit() != null) { if (getSelectedUnit() != null) {
final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY); final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY);
@ -1001,8 +988,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
this.selectedSoundCount = 0; this.selectedSoundCount = 0;
} }
} } else {
else {
this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY); this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY);
this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0); this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0);
clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y); clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y);
@ -1038,8 +1024,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
} }
} }
} } else {
else {
final List<RenderUnit> selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY, false); final List<RenderUnit> selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY, false);
if (!selectedUnits.isEmpty()) { if (!selectedUnits.isEmpty()) {
final RenderUnit unit = selectedUnits.get(0); final RenderUnit unit = selectedUnits.get(0);
@ -1050,16 +1035,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
} }
if (unit.soundset != null) { if (unit.soundset != null) {
UnitSound ackSoundToPlay = unit.soundset.what; UnitSound ackSoundToPlay = unit.soundset.what;
final int pissedSoundCount = unit.soundset.pissed.getSoundCount();
int soundIndex; int soundIndex;
final int pissedSoundCount = unit.soundset.pissed.getSoundCount();
if (unit.getSimulationUnit().isConstructing()) {
ackSoundToPlay = unit.buildSound;
soundIndex = 0;
} else {
if ((this.selectedSoundCount >= 3) && (pissedSoundCount > 0)) { if ((this.selectedSoundCount >= 3) && (pissedSoundCount > 0)) {
soundIndex = this.selectedSoundCount - 3; soundIndex = this.selectedSoundCount - 3;
ackSoundToPlay = unit.soundset.pissed; ackSoundToPlay = unit.soundset.pissed;
} } else {
else {
soundIndex = (int) (Math.random() * ackSoundToPlay.getSoundCount()); soundIndex = (int) (Math.random() * ackSoundToPlay.getSoundCount());
} }
if (ackSoundToPlay.playUnitResponse(this.war3MapViewer.worldScene.audioContext, unit, }
if (ackSoundToPlay != null && ackSoundToPlay.playUnitResponse(this.war3MapViewer.worldScene.audioContext, unit,
soundIndex)) { soundIndex)) {
this.selectedSoundCount++; this.selectedSoundCount++;
if ((this.selectedSoundCount - 3) >= pissedSoundCount) { if ((this.selectedSoundCount - 3) >= pissedSoundCount) {
@ -1074,14 +1063,12 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (playedNewSound) { if (playedNewSound) {
portraitTalk(); portraitTalk();
} }
} } else {
else {
selectUnit(null); selectUnit(null);
} }
} }
} }
} } else {
else {
if (clickedUIFrame instanceof CommandCardIcon) { if (clickedUIFrame instanceof CommandCardIcon) {
this.mouseDownUIFrame = (CommandCardIcon) clickedUIFrame; this.mouseDownUIFrame = (CommandCardIcon) clickedUIFrame;
this.mouseDownUIFrame.mouseDown(this.uiViewport); this.mouseDownUIFrame.mouseDown(this.uiViewport);