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);
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 final int uvsOffset;
private final int vertexBuffer;

View File

@ -323,8 +323,7 @@ public class War3MapViewer extends ModelViewer {
final LoadGenericCallback callback) {
if (this.mapMpq == null) {
return loadGeneric(path, dataType, callback);
}
else {
} else {
return loadGeneric(path, dataType, callback, this.dataSource);
}
}
@ -355,22 +354,19 @@ public class War3MapViewer extends ModelViewer {
tilesetSource = new CompoundDataSource(Arrays.asList(compoundDataSource,
new SubdirDataSource(compoundDataSource, tileset + ".mpq/"),
new SubdirDataSource(compoundDataSource, "_tilesets/" + tileset + ".w3mod/")));
}
else {
} else {
final byte[] mapData = IOUtils.toByteArray(mapStream);
sbc = new SeekableInMemoryByteChannel(mapData);
final DataSource internalMpqContentsDataSource = new MpqDataSource(new MPQArchive(sbc), sbc);
tilesetSource = new CompoundDataSource(
Arrays.asList(compoundDataSource, internalMpqContentsDataSource));
}
}
catch (final IOException exc) {
} catch (final IOException exc) {
tilesetSource = new CompoundDataSource(
Arrays.asList(compoundDataSource, new SubdirDataSource(compoundDataSource, tileset + ".mpq/"),
new SubdirDataSource(compoundDataSource, "_tilesets/" + tileset + ".w3mod/")));
}
}
catch (final MPQException e) {
} catch (final MPQException e) {
throw new RuntimeException(e);
}
setDataSource(tilesetSource);
@ -444,8 +440,7 @@ public class War3MapViewer extends ModelViewer {
modelInstance.setScene(War3MapViewer.this.worldScene);
if (bounceIndex == 0) {
SequenceUtils.randomBirthSequence(modelInstance);
}
else {
} else {
SequenceUtils.randomStandSequence(modelInstance);
}
modelInstance.setLocation(x, y, height);
@ -508,6 +503,14 @@ public class War3MapViewer extends ModelViewer {
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
public void removeUnit(final CUnit 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));
}
@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
public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex,
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());
if (this.doodadsAndDestructiblesLoaded) {
this.loadDoodadsAndDestructibles(this.allObjectData);
}
else {
} else {
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 {
if (this.unitsAndItemsLoaded) {
this.loadUnitsAndItems(this.allObjectData);
}
else {
} else {
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,
this.mapMpq.getResourceAsStream(pathingTexture));
this.filePathToPathingMap.put(pathingTexture.toLowerCase(), bufferedImage);
}
catch (final Exception exc) {
} catch (final Exception exc) {
exc.printStackTrace();
}
}
@ -650,15 +658,13 @@ public class War3MapViewer extends ModelViewer {
String path;
if (this.mapMpq.has(fileVar)) {
path = fileVar;
}
else {
} else {
path = file;
}
MdxModel model;
if (this.mapMpq.has(path)) {
model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
}
else {
} else {
model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams);
}
@ -677,8 +683,7 @@ public class War3MapViewer extends ModelViewer {
renderDestructableBounds);
}
this.doodads.add(renderDestructable);
}
else {
} else {
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,
this.mapMpq.getResourceAsStream(pathingTexture));
this.filePathToPathingMap.put(pathingTexture.toLowerCase(), pathingTextureImage);
}
catch (final Exception exc) {
} catch (final Exception exc) {
exc.printStackTrace();
}
}
}
}
else {
} else {
pathingTextureImage = null;
}
if (pathingTextureImage != null) {
@ -756,6 +759,7 @@ public class War3MapViewer extends ModelViewer {
private void loadUnitsAndItems(final Warcraft3MapObjectData modifications) throws IOException {
final War3Map mpq = this.mapMpq;
this.unitsReady = false;
this.soundsetNameToSoundset = new HashMap<>();
@ -796,8 +800,7 @@ public class War3MapViewer extends ModelViewer {
// path = "Objects\\StartLocation\\StartLocation.mdx";
type = null; /// ??????
this.startLocations[playerIndex] = new Vector2(unitX, unitY);
}
else {
} else {
row = modifications.getUnits().get(unitId);
if (row == null) {
row = modifications.getItems().get(unitId);
@ -809,13 +812,18 @@ public class War3MapViewer extends ModelViewer {
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;
Element misc = miscData.get("Misc");
String itemShadowFile = misc.getField("ItemShadowFile");
int itemShadowWidth = misc.getFieldValue("ItemShadowSize", 0);
int itemShadowHeight = misc.getFieldValue("ItemShadowSize", 1);
int itemShadowX = misc.getFieldValue("ItemShadowOffset", 0);
int itemShadowY = misc.getFieldValue("ItemShadowOffset", 1);
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)) {
final Splat splat = new Splat();
splat.opacity = 0.5f;
@ -830,8 +838,7 @@ public class War3MapViewer extends ModelViewer {
path += ".mdx";
}
}
else {
} else {
type = WorldEditorDataType.UNITS;
path = getUnitModelPath(row);
@ -849,16 +856,20 @@ public class War3MapViewer extends ModelViewer {
if (uberSplatInfo != null) {
final String texturePath = uberSplatInfo.getField("Dir") + "\\" + uberSplatInfo.getField("file")
+ ".blp";
final float s = uberSplatInfo.getFieldFloatValue("Scale");
if (unitsReady) {
this.terrain.addUberSplat(texturePath, unitX, unitY, 1, s);
} else {
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)) {
@ -903,8 +914,7 @@ public class War3MapViewer extends ModelViewer {
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 {
} else {
portraitModel = model;
}
if (type == WorldEditorDataType.UNITS) {
@ -925,8 +935,7 @@ public class War3MapViewer extends ModelViewer {
});
}
return simulationUnit;
}
else {
} else {
this.items
.add(new RenderItem(this, model, row, unitX, unitY, unitZ, unitAngle, soundset, portraitModel)); // TODO
// store
@ -940,8 +949,7 @@ public class War3MapViewer extends ModelViewer {
});
}
}
}
else {
} else {
System.err.println("Unknown unit ID: " + unitId);
}
return null;
@ -972,16 +980,14 @@ public class War3MapViewer extends ModelViewer {
if (pathingTexture.toLowerCase().endsWith(".tga")) {
buildingPathingPixelMap = TgaFile.readTGA(pathingTexture,
this.mapMpq.getResourceAsStream(pathingTexture));
}
else {
} else {
try (InputStream stream = this.mapMpq.getResourceAsStream(pathingTexture)) {
buildingPathingPixelMap = ImageIO.read(stream);
System.out.println("LOADING BLP PATHING: " + pathingTexture);
}
}
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());
}
}
@ -1087,7 +1093,7 @@ public class War3MapViewer extends ModelViewer {
public void deselect() {
if (!this.selModels.isEmpty()) {
for (final SplatModel model : this.selModels) {
this.terrain.removeSplatBatchModel(model);
this.terrain.removeSplatBatchModel("selection");
}
this.selModels.clear();
for (final RenderUnit unit : this.selected) {
@ -1150,7 +1156,7 @@ public class War3MapViewer extends ModelViewer {
model.color[2] = 0;
model.color[3] = 1;
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));
if (this.walkablesIntersectionFinder.found) {
out.set(this.walkablesIntersectionFinder.intersection);
}
else {
} else {
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);
if (idx >= 0) {
sel.remove(idx);
}
else {
} else {
sel.add(entity);
}
}
else {
} else {
sel = Arrays.asList(entity);
}
}
else {
} else {
sel = Collections.emptyList();
}
this.doSelectUnit(sel);
@ -1263,11 +1265,9 @@ public class War3MapViewer extends ModelViewer {
stringBuilder.append(line);
stringBuilder.append("\n");
}
}
catch (final UnsupportedEncodingException e) {
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
catch (final IOException e) {
} catch (final IOException e) {
throw new RuntimeException(e);
}
return new MappedData(stringBuilder.toString());
@ -1287,11 +1287,9 @@ public class War3MapViewer extends ModelViewer {
stringBuilder.append(line);
stringBuilder.append("\n");
}
}
catch (final UnsupportedEncodingException e) {
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
catch (final IOException e) {
} catch (final IOException e) {
throw new RuntimeException(e);
}
return stringBuilder.toString();
@ -1388,8 +1386,7 @@ public class War3MapViewer extends ModelViewer {
public SceneLightManager createLightManager(final boolean simple) {
if (simple) {
return new W3xScenePortraitLightManager(this, this.lightDirection);
}
else {
} else {
return new W3xSceneWorldLightManager(this);
}
}

View File

@ -5,13 +5,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.Buffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;
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.*;
import java.util.function.Consumer;
import javax.imageio.ImageIO;
@ -114,7 +108,7 @@ public class Terrain {
private final ShaderProgram uberSplatShader;
public final DataTable uberSplatTable;
private final List<SplatModel> uberSplatModels;
private final Map<String, SplatModel> uberSplatModels;
private int shadowMap;
public final Map<String, Splat> splats = new HashMap<>();
public final Map<String, List<float[]>> shadows = new HashMap<>();
@ -125,6 +119,8 @@ public class Terrain {
public final SoftwareGroundMesh softwareGroundMesh;
private final int testArrayBuffer;
private final int testElementBuffer;
private boolean initShadowsFinished = false;
private byte[] shadowData;
public Terrain(final War3MapW3e w3eFile, final War3MapWpm terrainPathing, final War3MapW3i w3iFile,
final WebGL webGL, final DataSource dataSource, final WorldEditStrings worldEditStrings,
@ -181,8 +177,7 @@ public class Terrain {
this.waterHeightOffset = waterInfo.getFieldFloatValue("height");
this.waterTextureCount = waterInfo.getFieldValue("numTex");
this.waterIncreasePerFrame = waterInfo.getFieldValue("texRate") / 60f;
}
else {
} else {
this.waterHeightOffset = 0;
this.waterTextureCount = 0;
this.waterIncreasePerFrame = 0;
@ -250,14 +245,12 @@ public class Terrain {
try (final InputStream tgaStream = dataSource.getResourceAsStream(tgaPath)) {
if (tgaStream != null) {
image = TgaFile.readTGA(tgaPath, tgaStream);
}
else {
} else {
throw new IllegalStateException(
"Missing cliff texture: " + texDir + "\\" + texFile + texturesExt);
}
}
}
else {
} else {
image = ImageIO.read(imageStream);
if (image == null) {
throw new IllegalStateException(
@ -402,7 +395,7 @@ public class Terrain {
// TODO collision bodies (?)
this.centerOffset = w3eFile.getCenterOffset();
this.uberSplatModels = new ArrayList<>();
this.uberSplatModels = new LinkedHashMap<>();
this.mapBounds = w3iFile.getCameraBoundsComplements();
this.shaderMapBounds = new float[]{(this.mapBounds[0] * 128.0f) + this.centerOffset[0],
(this.mapBounds[2] * 128.0f) + this.centerOffset[1],
@ -442,7 +435,8 @@ public class Terrain {
float rampHeight = 0f;
// 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++) {
if (((i + xOffset) >= 0) && ((i + xOffset) < (this.columns - 1)) && ((j + yOffset) >= 0)
&& ((j + yOffset) < (this.rows - 1))) {
@ -707,8 +701,7 @@ public class Terrain {
uploadGroundTexture();
try {
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);
}
}
@ -722,8 +715,7 @@ public class Terrain {
uploadGroundTexture();
try {
updateCliffMeshes(new Rectangle(0, 0, this.columns - 1, this.rows - 1));
}
catch (final IOException e) {
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
@ -772,7 +764,8 @@ public class Terrain {
}
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++) {
if (((x + i) >= 0) && ((x + i) < this.columns) && ((y + j) >= 0) && ((y + j) < this.rows)) {
if (this.corners[x + i][y + j].cliff) {
@ -838,19 +831,15 @@ public class Terrain {
if (texture.extended) {
if (variation <= 15) {
return (short) (16 + variation);
}
else if (variation == 16) {
} else if (variation == 16) {
return 15;
}
else {
} else {
return 0;
}
}
else {
} else {
if (variation == 0) {
return 0;
}
else {
} else {
return 15;
}
}
@ -997,7 +986,7 @@ public class Terrain {
gl.glUniform1f(shader.getUniformLocation("u_lightTextureHeight"), terrainLightsTexture.getHeight());
// Render the cliffs
for (final SplatModel splat : this.uberSplatModels) {
for (final SplatModel splat : this.uberSplatModels.values()) {
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)) {
final String path = "ReplaceableTextures\\Shadows\\" + file + ".blp";
this.shadows.put(file, new ArrayList<>());
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 {
@ -1119,7 +1127,7 @@ public class Terrain {
final int rows = (this.rows - 1) * 4;
final int shadowSize = columns * rows;
final byte[] shadowData = new byte[columns * rows];
shadowData = new byte[columns * rows];
if (this.viewer.mapMpq.has("war3map.shd")) {
final byte[] buffer;
@ -1141,21 +1149,7 @@ public class Terrain {
final int ox = (int) Math.round(width * 0.3);
final int oy = (int) Math.round(height * 0.7);
for (final float[] location : this.shadows.get(file)) {
final int x0 = (int) Math.floor((location[0] - centerOffset[0]) / 32.0) - ox;
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;
}
}
}
blitShadowDataLocation(columns, rows, (RawOpenGLTextureResource) texture, width, height, ox, oy, centerOffset, location[0], location[1]);
}
}
@ -1195,6 +1189,25 @@ public class Terrain {
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,
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) {
@ -1277,8 +1290,7 @@ public class Terrain {
if ((sqX + sqY) < 1) {
height = bottomLeft + ((bottomRight - bottomLeft) * sqX) + ((topLeft - bottomLeft) * sqY);
}
else {
} else {
height = topRight + ((bottomRight - topRight) * (1 - sqY)) + ((topLeft - topRight) * (1 - sqX));
}
@ -1305,8 +1317,7 @@ public class Terrain {
if ((sqX + sqY) < 1) {
height = bottomLeft + ((bottomRight - bottomLeft) * sqX) + ((topLeft - bottomLeft) * sqY);
}
else {
} else {
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,
splat.unitMapping, false);
splatModel.color[3] = splat.opacity;
this.uberSplatModels.add(splatModel);
this.uberSplatModels.put(path, splatModel);
}
}
public void removeSplatBatchModel(final SplatModel model) {
this.uberSplatModels.remove(model);
public void removeSplatBatchModel(String path) {
this.uberSplatModels.remove(path);
}
public void addSplatBatchModel(final SplatModel model) {
this.uberSplatModels.add(model);
public void addSplatBatchModel(String path, final SplatModel 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 {

View File

@ -12,13 +12,10 @@ import com.etheller.warsmash.util.RenderMathUtils;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
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.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.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.MovementType;
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 ANIM_PROPS = War3ID.fromString("uani");
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];
public final MdxComplexInstance instance;
public final MutableGameObject row;
@ -66,6 +64,7 @@ public class RenderUnit {
private boolean corpse;
private boolean boneCorpse;
private final RenderUnitTypeData typeData;
public UnitSound buildSound;
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,
@ -128,6 +127,7 @@ public class RenderUnit {
final float blendTime = row.getFieldAsFloat(BLEND_TIME, 0);
instance.setBlendTime(blendTime * 1000.0f);
buildSound = map.getUiSounds().getSound(row.getFieldAsString(BUILD_SOUND_LABEL, 0));
}
this.instance = instance;
@ -350,6 +350,9 @@ public class RenderUnit {
this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
}
this.unitAnimationListenerImpl.update();
if(!dead && simulationUnit.isConstructing()) {
instance.setFrameByRatio(simulationUnit.getConstructionProgress() / simulationUnit.getUnitType().getBuildTime());
}
}
private float getGroundHeightSample(final float groundHeight, final MdxComplexInstance currentWalkableUnder,

View File

@ -223,6 +223,10 @@ public class CSimulation {
this.simulationRenderController.spawnUnitDamageSound(damagedUnit, weaponSound, armorType);
}
public void unitConstructedEvent(CUnit constructingUnit, CUnit constructedStructure) {
this.simulationRenderController.spawnUnitConstructionSound(constructingUnit, constructedStructure);
}
public CPlayer getPlayer(final int index) {
return this.players.get(index);
}
@ -230,4 +234,8 @@ public class CSimulation {
public CommandErrorListener getCommandErrorListener() {
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 CBehaviorPatrol patrolBehavior;
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,
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;
}
}
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) {
final CBehavior lastBehavior = this.currentBehavior;
this.currentBehavior = this.currentBehavior.update(game);
@ -670,4 +680,22 @@ public class CUnit extends CWidget {
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
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());
constructedStructure.setConstructing(true);
simulation.unitConstructedEvent(this.unit, constructedStructure);
return this.unit.pollNextOrderBehavior(simulation);
}

View File

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