mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
First draft of build queue, better working structures built list
This commit is contained in:
parent
4ffd0c3283
commit
f589afdf46
@ -56,7 +56,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListene
|
||||
|
||||
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
|
||||
private static final boolean ENABLE_AUDIO = true;
|
||||
private static final boolean ENABLE_MUSIC = true;
|
||||
private static final boolean ENABLE_MUSIC = false;
|
||||
private DataSource codebase;
|
||||
private War3MapViewer viewer;
|
||||
private final Rectangle tempRect = new Rectangle();
|
||||
|
@ -276,7 +276,9 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|
||||
case Frame:
|
||||
if ("SIMPLEFRAME".equals(frameDefinition.getFrameType())) {
|
||||
final SimpleFrame simpleFrame = new SimpleFrame(frameDefinition.getName(), parent);
|
||||
// TODO: we should not need to put ourselves in this map 2x
|
||||
// TODO: we should not need to put ourselves in this map 2x, but we do
|
||||
// since there are nested inflate calls happening before the general case
|
||||
// mapping
|
||||
this.nameToFrame.put(frameDefinition.getName(), simpleFrame);
|
||||
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
|
||||
simpleFrame.add(inflate(childDefinition, simpleFrame, frameDefinition));
|
||||
@ -315,7 +317,13 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|
||||
}
|
||||
break;
|
||||
case Layer:
|
||||
// NOT HANDLED YET
|
||||
final SimpleFrame simpleFrame = new SimpleFrame(frameDefinition.getName(), parent);
|
||||
simpleFrame.setSetAllPoints(true);
|
||||
this.nameToFrame.put(frameDefinition.getName(), simpleFrame);
|
||||
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
|
||||
simpleFrame.add(inflate(childDefinition, simpleFrame, frameDefinition));
|
||||
}
|
||||
inflatedFrame = simpleFrame;
|
||||
break;
|
||||
case String:
|
||||
final Float textLength = frameDefinition.getFloat("TextLength");
|
||||
|
@ -307,8 +307,8 @@ public abstract class AbstractRenderableFrame implements UIFrame {
|
||||
}
|
||||
}
|
||||
if (DEBUG_LOG) {
|
||||
System.out.println(
|
||||
getClass().getSimpleName() + ":" + this.name + " finishing position bounds: " + this.renderBounds);
|
||||
System.out.println(getClass().getSimpleName() + ":" + this.name + ":" + hashCode()
|
||||
+ " finishing position bounds: " + this.renderBounds);
|
||||
}
|
||||
innerPositionBounds(viewport);
|
||||
}
|
||||
|
@ -5,4 +5,6 @@ public class WarsmashConstants {
|
||||
public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
|
||||
public static final float SIMULATION_STEP_TIME = 1 / 20f;
|
||||
public static final int PORT_NUMBER = 6115;
|
||||
public static final float BUILDING_CONSTRUCT_START_LIFE = 0.1f;
|
||||
public static final int BUILD_QUEUE_SIZE = 7;
|
||||
}
|
||||
|
@ -225,9 +225,19 @@ 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});
|
||||
public SplatMover add(final float x, final float y, final float w, final float h, final float zDepthUpward,
|
||||
final float[] centerOffset) {
|
||||
this.locations.add(new float[] { x, y, w, h, zDepthUpward });
|
||||
final SplatMover splatMover;
|
||||
if (this.splatInstances != null) {
|
||||
splatMover = new SplatMover(this);
|
||||
this.splatInstances.add(splatMover);
|
||||
}
|
||||
else {
|
||||
splatMover = null;
|
||||
}
|
||||
compact(Gdx.gl30, centerOffset);
|
||||
return splatMover;
|
||||
}
|
||||
|
||||
private static final class Batch {
|
||||
@ -413,5 +423,12 @@ public class SplatModel {
|
||||
gl.glBufferSubData(GL30.GL_ARRAY_BUFFER, this.uvsOffset + ((this.startOffset / 3) * 2),
|
||||
4 * 2 * this.uvs.size(), RenderMathUtils.wrap(this.uvs));
|
||||
}
|
||||
|
||||
public void show(final float[] centerOffset) {
|
||||
// It tries to only update if it is located at a new position... but here we are
|
||||
// forcing it visible again by putting the position outside the map
|
||||
this.ix0 = this.ix1 = this.iy0 = this.iy1 = Integer.MIN_VALUE;
|
||||
move(0, 0, centerOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,8 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
|
||||
import com.etheller.warsmash.viewer5.handlers.tga.TgaFile;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.BuildingShadow;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.RemovablePathingMapInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.Terrain;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.Terrain.Splat;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderAttackInstant;
|
||||
@ -97,6 +99,7 @@ import mpq.MPQException;
|
||||
|
||||
public class War3MapViewer extends ModelViewer {
|
||||
private static final War3ID UNIT_FILE = War3ID.fromString("umdl");
|
||||
private static final War3ID UNIT_SPECIAL = War3ID.fromString("uspa");
|
||||
private static final War3ID UBER_SPLAT = War3ID.fromString("uubs");
|
||||
private static final War3ID UNIT_SHADOW = War3ID.fromString("ushu");
|
||||
private static final War3ID UNIT_SHADOW_X = War3ID.fromString("ushx");
|
||||
@ -553,6 +556,35 @@ public class War3MapViewer extends ModelViewer {
|
||||
return createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y, 0f, playerIndex,
|
||||
(float) Math.toRadians(facing));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnBuildingDeathEffect(final CUnit source) {
|
||||
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
|
||||
if (renderUnit.specialArtModel != null) {
|
||||
final MdxComplexInstance modelInstance = (MdxComplexInstance) renderUnit.specialArtModel
|
||||
.addInstance();
|
||||
modelInstance.setTeamColor(source.getPlayerIndex());
|
||||
modelInstance.setLocation(renderUnit.location);
|
||||
modelInstance.setScene(War3MapViewer.this.worldScene);
|
||||
SequenceUtils.randomBirthSequence(modelInstance);
|
||||
War3MapViewer.this.projectiles
|
||||
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this,
|
||||
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing())));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnUnitReadySound(final CUnit trainedUnit) {
|
||||
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(trainedUnit);
|
||||
renderPeer.soundset.ready.playUnitResponse(War3MapViewer.this.worldScene.audioContext,
|
||||
renderPeer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unitRepositioned(final CUnit cUnit) {
|
||||
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(cUnit);
|
||||
renderPeer.repositioned(War3MapViewer.this);
|
||||
}
|
||||
}, this.terrain.pathingGrid, this.terrain.getEntireMap(), this.seededRandom, w3iFile.getPlayers());
|
||||
|
||||
this.walkableObjectsTree = new Quadtree<>(this.terrain.getEntireMap());
|
||||
@ -664,7 +696,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
}
|
||||
if (bufferedImage != null) {
|
||||
this.terrain.pathingGrid.blitPathingOverlayTexture(doodad.getLocation()[0],
|
||||
this.terrain.pathingGrid.blitRemovablePathingOverlayTexture(doodad.getLocation()[0],
|
||||
doodad.getLocation()[1], (int) Math.toDegrees(doodad.getAngle()), bufferedImage);
|
||||
}
|
||||
}
|
||||
@ -814,8 +846,13 @@ public class War3MapViewer extends ModelViewer {
|
||||
MutableGameObject row = null;
|
||||
String path = null;
|
||||
Splat unitShadowSplat = null;
|
||||
SplatMover unitShadowSplatDynamicIngame = null;
|
||||
Splat buildingUberSplat = null;
|
||||
SplatMover buildingUberSplatDynamicIngame = null;
|
||||
BufferedImage buildingPathingPixelMap = null;
|
||||
final float unitVertexScale = 1.0f;
|
||||
RemovablePathingMapInstance pathingInstance = null;
|
||||
BuildingShadow buildingShadowInstance = null;
|
||||
|
||||
// Hardcoded?
|
||||
WorldEditorDataType type = null;
|
||||
@ -871,8 +908,8 @@ public class War3MapViewer extends ModelViewer {
|
||||
if (buildingPathingPixelMap != null) {
|
||||
unitX = Math.round(unitX / 64f) * 64f;
|
||||
unitY = Math.round(unitY / 64f) * 64f;
|
||||
this.terrain.pathingGrid.blitPathingOverlayTexture(unitX, unitY, (int) Math.toDegrees(unitAngle),
|
||||
buildingPathingPixelMap);
|
||||
pathingInstance = this.terrain.pathingGrid.blitRemovablePathingOverlayTexture(unitX, unitY,
|
||||
(int) Math.toDegrees(unitAngle), buildingPathingPixelMap);
|
||||
}
|
||||
|
||||
final String uberSplat = row.getFieldAsString(UBER_SPLAT, 0);
|
||||
@ -883,7 +920,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
+ ".blp";
|
||||
final float s = uberSplatInfo.getFieldFloatValue("Scale");
|
||||
if (this.unitsReady) {
|
||||
this.terrain.addUberSplat(texturePath, unitX, unitY, 1, s);
|
||||
buildingUberSplatDynamicIngame = this.terrain.addUberSplat(texturePath, unitX, unitY, 1, s);
|
||||
}
|
||||
else {
|
||||
if (!this.terrain.splats.containsKey(texturePath)) {
|
||||
@ -891,8 +928,8 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
final float x = unitX;
|
||||
final float y = unitY;
|
||||
this.terrain.splats.get(texturePath).locations
|
||||
.add(new float[] { x - s, y - s, x + s, y + s, 1 });
|
||||
buildingUberSplat = this.terrain.splats.get(texturePath);
|
||||
buildingUberSplat.locations.add(new float[] { x - s, y - s, x + s, y + s, 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -905,22 +942,28 @@ public class War3MapViewer extends ModelViewer {
|
||||
final float shadowWidth = row.getFieldAsFloat(UNIT_SHADOW_W, 0);
|
||||
final float shadowHeight = row.getFieldAsFloat(UNIT_SHADOW_H, 0);
|
||||
if (this.mapMpq.has(texture)) {
|
||||
if (!this.terrain.splats.containsKey(texture)) {
|
||||
final Splat splat = new Splat();
|
||||
splat.opacity = 0.5f;
|
||||
this.terrain.splats.put(texture, splat);
|
||||
}
|
||||
final float x = unitX - shadowX;
|
||||
final float y = unitY - shadowY;
|
||||
this.terrain.splats.get(texture).locations
|
||||
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 });
|
||||
unitShadowSplat = this.terrain.splats.get(texture);
|
||||
if (this.unitsReady) {
|
||||
unitShadowSplatDynamicIngame = this.terrain.addUnitShadowSplat(texture, x, y,
|
||||
x + shadowWidth, y + shadowHeight, 3, 0.5f);
|
||||
}
|
||||
else {
|
||||
if (!this.terrain.splats.containsKey(texture)) {
|
||||
final Splat splat = new Splat();
|
||||
splat.opacity = 0.5f;
|
||||
this.terrain.splats.put(texture, splat);
|
||||
}
|
||||
this.terrain.splats.get(texture).locations
|
||||
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 });
|
||||
unitShadowSplat = this.terrain.splats.get(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String buildingShadow = row.getFieldAsString(BUILDING_SHADOW, 0);
|
||||
if ((buildingShadow != null) && !"_".equals(buildingShadow)) {
|
||||
this.terrain.addShadow(buildingShadow, unitX, unitY);
|
||||
buildingShadowInstance = this.terrain.addShadow(buildingShadow, unitX, unitY);
|
||||
}
|
||||
|
||||
final String soundName = row.getFieldAsString(UNIT_SOUNDSET, 0);
|
||||
@ -935,6 +978,21 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
|
||||
if (path != null) {
|
||||
final String unitSpecialArtPath = row.getFieldAsString(UNIT_SPECIAL, 0);
|
||||
MdxModel specialArtModel;
|
||||
if (unitSpecialArtPath != null) {
|
||||
try {
|
||||
specialArtModel = (MdxModel) this.load(mdx(unitSpecialArtPath), this.mapPathSolver,
|
||||
this.solverParams);
|
||||
}
|
||||
catch (final Exception exc) {
|
||||
exc.printStackTrace();
|
||||
specialArtModel = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
specialArtModel = null;
|
||||
}
|
||||
final MdxModel model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
|
||||
MdxModel portraitModel;
|
||||
final String portraitPath = path.substring(0, path.length() - 4) + "_portrait.mdx";
|
||||
@ -947,10 +1005,10 @@ public class War3MapViewer extends ModelViewer {
|
||||
if (type == WorldEditorDataType.UNITS) {
|
||||
final float angle = (float) Math.toDegrees(unitAngle);
|
||||
final CUnit simulationUnit = this.simulation.createUnit(row.getAlias(), playerIndex, unitX, unitY,
|
||||
angle, buildingPathingPixelMap);
|
||||
angle, buildingPathingPixelMap, pathingInstance, buildingShadowInstance);
|
||||
final RenderUnitTypeData typeData = getUnitTypeData(unitId, row);
|
||||
final RenderUnit renderUnit = new RenderUnit(this, model, row, unitX, unitY, unitZ, playerIndex,
|
||||
soundset, portraitModel, simulationUnit, typeData);
|
||||
soundset, portraitModel, simulationUnit, typeData, specialArtModel);
|
||||
this.unitToRenderPeer.put(simulationUnit, renderUnit);
|
||||
this.units.add(renderUnit);
|
||||
if (unitShadowSplat != null) {
|
||||
@ -961,6 +1019,20 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (unitShadowSplatDynamicIngame != null) {
|
||||
renderUnit.shadow = unitShadowSplatDynamicIngame;
|
||||
}
|
||||
if (buildingUberSplat != null) {
|
||||
buildingUberSplat.unitMapping.add(new Consumer<SplatModel.SplatMover>() {
|
||||
@Override
|
||||
public void accept(final SplatMover t) {
|
||||
renderUnit.uberSplat = t;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (buildingUberSplatDynamicIngame != null) {
|
||||
renderUnit.uberSplat = buildingUberSplatDynamicIngame;
|
||||
}
|
||||
return simulationUnit;
|
||||
}
|
||||
else {
|
||||
@ -976,6 +1048,8 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (unitShadowSplatDynamicIngame != null) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1222,24 +1296,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
|
||||
public List<RenderUnit> selectUnit(final float x, final float y, final boolean toggle) {
|
||||
System.out.println("world: " + x + "," + y);
|
||||
final float[] ray = rayHeap;
|
||||
mousePosHeap.set(x, y);
|
||||
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
||||
gdxRayHeap.set(ray[0], ray[1], ray[2], ray[3] - ray[0], ray[4] - ray[1], ray[5] - ray[2]);
|
||||
gdxRayHeap.direction.nor();// needed for libgdx
|
||||
|
||||
RenderUnit entity = null;
|
||||
for (final RenderUnit unit : this.units) {
|
||||
final MdxComplexInstance instance = unit.instance;
|
||||
if (instance.isVisible(this.worldScene.camera)
|
||||
&& instance.intersectRayWithCollision(gdxRayHeap, intersectionHeap,
|
||||
unit.getSimulationUnit().getUnitType().isBuilding(), false)
|
||||
&& !unit.getSimulationUnit().isDead()) {
|
||||
if ((entity == null) || (entity.instance.depth > instance.depth)) {
|
||||
entity = unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
final RenderUnit entity = rayPickUnit(x, y, CUnitFilterFunction.ACCEPT_ALL_LIVING);
|
||||
List<RenderUnit> sel;
|
||||
if (entity != null) {
|
||||
if (toggle) {
|
||||
@ -1277,8 +1334,8 @@ public class War3MapViewer extends ModelViewer {
|
||||
RenderUnit entity = null;
|
||||
for (final RenderUnit unit : this.units) {
|
||||
final MdxComplexInstance instance = unit.instance;
|
||||
if (instance.isVisible(this.worldScene.camera) && instance.intersectRayWithCollision(gdxRayHeap,
|
||||
intersectionHeap, unit.getSimulationUnit().getUnitType().isBuilding(), false)) {
|
||||
if (instance.shown() && instance.isVisible(this.worldScene.camera) && instance.intersectRayWithCollision(
|
||||
gdxRayHeap, intersectionHeap, unit.getSimulationUnit().getUnitType().isBuilding(), false)) {
|
||||
if (filter.call(unit.getSimulationUnit()) && (intersectionHeap.z > this.terrain
|
||||
.getGroundHeight(intersectionHeap.x, intersectionHeap.y))) {
|
||||
if ((entity == null) || (entity.instance.depth > instance.depth)) {
|
||||
@ -1438,7 +1495,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
public void setGameUI(final GameUI gameUI) {
|
||||
this.gameUI = gameUI;
|
||||
this.abilityDataUI = new AbilityDataUI(this.allObjectData.getAbilities(), this.allObjectData.getUnits(),
|
||||
gameUI);
|
||||
this.allObjectData.getUpgrades(), gameUI);
|
||||
}
|
||||
|
||||
public GameUI getGameUI() {
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.environment;
|
||||
|
||||
public interface BuildingShadow {
|
||||
void remove();
|
||||
|
||||
void move(float x, float y);
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.environment;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.etheller.warsmash.parsers.w3x.wpm.War3MapWpm;
|
||||
@ -20,18 +23,20 @@ public class PathingGrid {
|
||||
private final short[] dynamicPathingOverlay; // for buildings and trees
|
||||
private final int[] pathingGridSizes;
|
||||
private final float[] centerOffset;
|
||||
private final List<RemovablePathingMapInstance> dynamicPathingInstances;
|
||||
|
||||
public PathingGrid(final War3MapWpm terrainPathing, final float[] centerOffset) {
|
||||
this.centerOffset = centerOffset;
|
||||
this.pathingGrid = terrainPathing.getPathing();
|
||||
this.pathingGridSizes = terrainPathing.getSize();
|
||||
this.dynamicPathingOverlay = new short[this.pathingGrid.length];
|
||||
this.dynamicPathingInstances = new ArrayList<>();
|
||||
}
|
||||
|
||||
// this blit function is basically copied from HiveWE, maybe remember to mention
|
||||
// that in credits as well:
|
||||
// https://github.com/stijnherfst/HiveWE/blob/master/Base/PathingMap.cpp
|
||||
public void blitPathingOverlayTexture(final float positionX, final float positionY, final int rotationInput,
|
||||
private void blitPathingOverlayTexture(final float positionX, final float positionY, final int rotationInput,
|
||||
final BufferedImage pathingTextureTga) {
|
||||
final int rotation = (rotationInput + 450) % 360;
|
||||
final int divW = ((rotation % 180) != 0) ? pathingTextureTga.getHeight() : pathingTextureTga.getWidth();
|
||||
@ -80,6 +85,15 @@ public class PathingGrid {
|
||||
}
|
||||
}
|
||||
|
||||
public RemovablePathingMapInstance blitRemovablePathingOverlayTexture(final float positionX, final float positionY,
|
||||
final int rotationInput, final BufferedImage pathingTextureTga) {
|
||||
final RemovablePathingMapInstance removablePathingMapInstance = new RemovablePathingMapInstance(positionX,
|
||||
positionY, rotationInput, pathingTextureTga);
|
||||
removablePathingMapInstance.blit();
|
||||
this.dynamicPathingInstances.add(removablePathingMapInstance);
|
||||
return removablePathingMapInstance;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return this.pathingGridSizes[0];
|
||||
}
|
||||
@ -294,4 +308,31 @@ public class PathingGrid {
|
||||
this.preventionFlag = preventionFlag;
|
||||
}
|
||||
}
|
||||
|
||||
public final class RemovablePathingMapInstance {
|
||||
private final float positionX;
|
||||
private final float positionY;
|
||||
private final int rotationInput;
|
||||
private final BufferedImage pathingTextureTga;
|
||||
|
||||
public RemovablePathingMapInstance(final float positionX, final float positionY, final int rotationInput,
|
||||
final BufferedImage pathingTextureTga) {
|
||||
this.positionX = positionX;
|
||||
this.positionY = positionY;
|
||||
this.rotationInput = rotationInput;
|
||||
this.pathingTextureTga = pathingTextureTga;
|
||||
}
|
||||
|
||||
private void blit() {
|
||||
blitPathingOverlayTexture(this.positionX, this.positionY, this.rotationInput, this.pathingTextureTga);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
PathingGrid.this.dynamicPathingInstances.remove(this);
|
||||
Arrays.fill(PathingGrid.this.dynamicPathingOverlay, (short) 0);
|
||||
for (final RemovablePathingMapInstance instance : PathingGrid.this.dynamicPathingInstances) {
|
||||
instance.blit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -52,8 +52,6 @@ public class RenderUnit {
|
||||
public SplatMover shadow;
|
||||
public SplatMover selectionCircle;
|
||||
|
||||
private float x;
|
||||
private float y;
|
||||
private float facing;
|
||||
|
||||
private boolean swimming;
|
||||
@ -67,13 +65,17 @@ public class RenderUnit {
|
||||
private boolean corpse;
|
||||
private boolean boneCorpse;
|
||||
private final RenderUnitTypeData typeData;
|
||||
public final MdxModel specialArtModel;
|
||||
public SplatMover uberSplat;
|
||||
|
||||
public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row, final float x,
|
||||
final float y, final float z, final int playerIndex, final UnitSoundset soundset,
|
||||
final MdxModel portraitModel, final CUnit simulationUnit, final RenderUnitTypeData typeData) {
|
||||
final MdxModel portraitModel, final CUnit simulationUnit, final RenderUnitTypeData typeData,
|
||||
final MdxModel specialArtModel) {
|
||||
this.portraitModel = portraitModel;
|
||||
this.simulationUnit = simulationUnit;
|
||||
this.typeData = typeData;
|
||||
this.specialArtModel = specialArtModel;
|
||||
final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance();
|
||||
|
||||
this.location[0] = x;
|
||||
@ -83,8 +85,6 @@ public class RenderUnit {
|
||||
this.facing = simulationUnit.getFacing();
|
||||
final float angle = (float) Math.toRadians(this.facing);
|
||||
// instance.localRotation.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle);
|
||||
this.x = simulationUnit.getX();
|
||||
this.y = simulationUnit.getY();
|
||||
instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle));
|
||||
this.playerIndex = playerIndex & 0xFFFF;
|
||||
instance.setTeamColor(this.playerIndex);
|
||||
@ -139,9 +139,11 @@ public class RenderUnit {
|
||||
|
||||
public void populateCommandCard(final CSimulation game, final CommandButtonListener commandButtonListener,
|
||||
final AbilityDataUI abilityDataUI, final int subMenuOrderId) {
|
||||
final CommandCardPopulatingAbilityVisitor commandCardPopulatingVisitor = CommandCardPopulatingAbilityVisitor.INSTANCE
|
||||
.reset(game, this.simulationUnit, commandButtonListener, abilityDataUI, subMenuOrderId,
|
||||
this.simulationUnit.isConstructing());
|
||||
for (final CAbility ability : this.simulationUnit.getAbilities()) {
|
||||
ability.visit(CommandCardPopulatingAbilityVisitor.INSTANCE.reset(game, this.simulationUnit,
|
||||
commandButtonListener, abilityDataUI, subMenuOrderId));
|
||||
ability.visit(commandCardPopulatingVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,48 +163,48 @@ public class RenderUnit {
|
||||
}
|
||||
else {
|
||||
this.instance.show();
|
||||
if (wasHidden) {
|
||||
if (this.shadow != null) {
|
||||
this.shadow.show(map.terrain.centerOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
final float prevX = this.location[0];
|
||||
final float prevY = this.location[1];
|
||||
final float simulationX = this.simulationUnit.getX();
|
||||
final float simulationY = this.simulationUnit.getY();
|
||||
if (wasHidden) {
|
||||
this.x = simulationX;
|
||||
this.y = simulationY;
|
||||
}
|
||||
final float deltaTime = Gdx.graphics.getDeltaTime();
|
||||
final float simDx = simulationX - this.x;
|
||||
final float simDy = simulationY - this.y;
|
||||
final float simDx = simulationX - this.location[0];
|
||||
final float simDy = simulationY - this.location[1];
|
||||
final float distanceToSimulation = (float) Math.sqrt((simDx * simDx) + (simDy * simDy));
|
||||
final int speed = this.simulationUnit.getSpeed();
|
||||
final float speedDelta = speed * deltaTime;
|
||||
if ((distanceToSimulation > speedDelta) && (deltaTime < 1.0)) {
|
||||
// The 1.0 here says that after 1 second of lag, units just teleport to show
|
||||
// where they actually are
|
||||
this.x += (speedDelta * simDx) / distanceToSimulation;
|
||||
this.y += (speedDelta * simDy) / distanceToSimulation;
|
||||
this.location[0] += (speedDelta * simDx) / distanceToSimulation;
|
||||
this.location[1] += (speedDelta * simDy) / distanceToSimulation;
|
||||
}
|
||||
else {
|
||||
this.x = simulationX;
|
||||
this.y = simulationY;
|
||||
this.location[0] = simulationX;
|
||||
this.location[1] = simulationY;
|
||||
}
|
||||
final float x = this.x;
|
||||
final float dx = x - this.location[0];
|
||||
this.location[0] = x;
|
||||
final float y = this.y;
|
||||
final float dy = y - this.location[1];
|
||||
this.location[1] = y;
|
||||
final float dx = this.location[0] - prevX;
|
||||
final float dy = this.location[1] - prevY;
|
||||
final float groundHeight;
|
||||
final MovementType movementType = this.simulationUnit.getUnitType().getMovementType();
|
||||
final short terrainPathing = map.terrain.pathingGrid.getPathing(x, y);
|
||||
final short terrainPathing = map.terrain.pathingGrid.getPathing(this.location[0], this.location[1]);
|
||||
boolean swimming = (movementType == MovementType.AMPHIBIOUS)
|
||||
&& PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.SWIMMABLE)
|
||||
&& !PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.WALKABLE);
|
||||
final float groundHeightTerrain = map.terrain.getGroundHeight(x, y);
|
||||
final float groundHeightTerrain = map.terrain.getGroundHeight(this.location[0], this.location[1]);
|
||||
float groundHeightTerrainAndWater;
|
||||
MdxComplexInstance currentWalkableUnder;
|
||||
final boolean standingOnWater = (swimming) || (movementType == MovementType.FLOAT)
|
||||
|| (movementType == MovementType.FLY) || (movementType == MovementType.HOVER);
|
||||
if (standingOnWater) {
|
||||
groundHeightTerrainAndWater = Math.max(groundHeightTerrain, map.terrain.getWaterHeight(x, y));
|
||||
groundHeightTerrainAndWater = Math.max(groundHeightTerrain,
|
||||
map.terrain.getWaterHeight(this.location[0], this.location[1]));
|
||||
}
|
||||
else {
|
||||
// land units will have their feet pass under the surface of the water
|
||||
@ -214,8 +216,8 @@ public class RenderUnit {
|
||||
currentWalkableUnder = null;
|
||||
}
|
||||
else {
|
||||
currentWalkableUnder = map.getHighestWalkableUnder(x, y);
|
||||
War3MapViewer.gdxRayHeap.set(x, y, 4096, 0, 0, -8192);
|
||||
currentWalkableUnder = map.getHighestWalkableUnder(this.location[0], this.location[1]);
|
||||
War3MapViewer.gdxRayHeap.set(this.location[0], this.location[1], 4096, 0, 0, -8192);
|
||||
if ((currentWalkableUnder != null)
|
||||
&& currentWalkableUnder.intersectRayWithCollision(War3MapViewer.gdxRayHeap,
|
||||
War3MapViewer.intersectionHeap, true, true)
|
||||
@ -244,6 +246,10 @@ public class RenderUnit {
|
||||
this.shadow.destroy(Gdx.gl30, map.terrain.centerOffset);
|
||||
this.shadow = null;
|
||||
}
|
||||
if (this.uberSplat != null) {
|
||||
this.uberSplat.destroy(Gdx.gl30, map.terrain.centerOffset);
|
||||
this.uberSplat = null;
|
||||
}
|
||||
if (this.selectionCircle != null) {
|
||||
this.selectionCircle.destroy(Gdx.gl30, map.terrain.centerOffset);
|
||||
this.selectionCircle = null;
|
||||
@ -311,15 +317,15 @@ public class RenderUnit {
|
||||
final float maxRoll = this.typeData.getMaxRoll();
|
||||
final float sampleRadius = this.typeData.getElevationSampleRadius();
|
||||
float pitch, roll;
|
||||
final float pitchSampleForwardX = x + (sampleRadius * (float) Math.cos(facingRadians));
|
||||
final float pitchSampleForwardY = y + (sampleRadius * (float) Math.sin(facingRadians));
|
||||
final float pitchSampleBackwardX = x - (sampleRadius * (float) Math.cos(facingRadians));
|
||||
final float pitchSampleBackwardY = y - (sampleRadius * (float) Math.sin(facingRadians));
|
||||
final float pitchSampleForwardX = this.location[0] + (sampleRadius * (float) Math.cos(facingRadians));
|
||||
final float pitchSampleForwardY = this.location[1] + (sampleRadius * (float) Math.sin(facingRadians));
|
||||
final float pitchSampleBackwardX = this.location[0] - (sampleRadius * (float) Math.cos(facingRadians));
|
||||
final float pitchSampleBackwardY = this.location[1] - (sampleRadius * (float) Math.sin(facingRadians));
|
||||
final double leftOfFacingAngle = facingRadians + (Math.PI / 2);
|
||||
final float rollSampleForwardX = x + (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
||||
final float rollSampleForwardY = y + (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
||||
final float rollSampleBackwardX = x - (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
||||
final float rollSampleBackwardY = y - (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
||||
final float rollSampleForwardX = this.location[0] + (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
||||
final float rollSampleForwardY = this.location[1] + (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
||||
final float rollSampleBackwardX = this.location[0] - (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
||||
final float rollSampleBackwardY = this.location[1] - (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
||||
final float pitchSampleGroundHeight1;
|
||||
final float pitchSampleGroundHeight2;
|
||||
final float rollSampleGroundHeight1;
|
||||
@ -504,4 +510,21 @@ public class RenderUnit {
|
||||
this.allowRarityVariations = allowRarityVariations;
|
||||
}
|
||||
}
|
||||
|
||||
public void repositioned(final War3MapViewer map) {
|
||||
final float prevX = this.location[0];
|
||||
final float prevY = this.location[1];
|
||||
final float simulationX = this.simulationUnit.getX();
|
||||
final float simulationY = this.simulationUnit.getY();
|
||||
final float dx = simulationX - prevX;
|
||||
final float dy = simulationY - prevY;
|
||||
if (this.shadow != null) {
|
||||
this.shadow.move(dx, dy, map.terrain.centerOffset);
|
||||
}
|
||||
if (this.selectionCircle != null) {
|
||||
this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
|
||||
}
|
||||
this.location[0] = this.simulationUnit.getX();
|
||||
this.location[1] = this.simulationUnit.getY();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
@ -26,8 +28,14 @@ public class AbilityDataUI {
|
||||
private static final War3ID UNIT_ICON_NORMAL_Y = War3ID.fromString("ubpy");
|
||||
private static final War3ID UNIT_ICON_NORMAL = War3ID.fromString("uico");
|
||||
|
||||
private static final War3ID UPGRADE_ICON_NORMAL_X = War3ID.fromString("gbpx");
|
||||
private static final War3ID UPGRADE_ICON_NORMAL_Y = War3ID.fromString("gbpy");
|
||||
private static final War3ID UPGRADE_ICON_NORMAL = War3ID.fromString("gar1");
|
||||
private static final War3ID UPGRADE_LEVELS = War3ID.fromString("glvl");
|
||||
|
||||
private final Map<War3ID, AbilityIconUI> rawcodeToUI = new HashMap<>();
|
||||
private final Map<War3ID, IconUI> rawcodeToUnitUI = new HashMap<>();
|
||||
private final Map<War3ID, List<IconUI>> rawcodeToUpgradeUI = new HashMap<>();
|
||||
private final IconUI moveUI;
|
||||
private final IconUI stopUI;
|
||||
private final IconUI holdPosUI;
|
||||
@ -41,8 +49,10 @@ public class AbilityDataUI {
|
||||
private final IconUI buildNeutralUI;
|
||||
private final IconUI buildNagaUI;
|
||||
private final IconUI cancelUI;
|
||||
private final IconUI cancelBuildUI;
|
||||
|
||||
public AbilityDataUI(final MutableObjectData abilityData, final MutableObjectData unitData, final GameUI gameUI) {
|
||||
public AbilityDataUI(final MutableObjectData abilityData, final MutableObjectData unitData,
|
||||
final MutableObjectData upgradeData, final GameUI gameUI) {
|
||||
final String disabledPrefix = gameUI.getSkinField("CommandButtonDisabledArtPath");
|
||||
for (final War3ID alias : abilityData.keySet()) {
|
||||
final MutableGameObject abilityTypeData = abilityData.get(alias);
|
||||
@ -75,6 +85,21 @@ public class AbilityDataUI {
|
||||
final Texture iconNormalDisabled = gameUI.loadTexture(disable(iconNormalPath, disabledPrefix));
|
||||
this.rawcodeToUnitUI.put(alias, new IconUI(iconNormal, iconNormalDisabled, iconNormalX, iconNormalY));
|
||||
}
|
||||
for (final War3ID alias : upgradeData.keySet()) {
|
||||
final MutableGameObject upgradeTypeData = upgradeData.get(alias);
|
||||
final int upgradeLevels = upgradeTypeData.getFieldAsInteger(UPGRADE_LEVELS, 0);
|
||||
final int iconNormalX = upgradeTypeData.getFieldAsInteger(UPGRADE_ICON_NORMAL_X, 0);
|
||||
final int iconNormalY = upgradeTypeData.getFieldAsInteger(UPGRADE_ICON_NORMAL_Y, 0);
|
||||
final List<IconUI> upgradeIconsByLevel = new ArrayList<>();
|
||||
for (int i = 0; i < upgradeLevels; i++) {
|
||||
final String iconNormalPath = gameUI
|
||||
.trySkinField(upgradeTypeData.getFieldAsString(UPGRADE_ICON_NORMAL, i));
|
||||
final Texture iconNormal = gameUI.loadTexture(iconNormalPath);
|
||||
final Texture iconNormalDisabled = gameUI.loadTexture(disable(iconNormalPath, disabledPrefix));
|
||||
upgradeIconsByLevel.add(new IconUI(iconNormal, iconNormalDisabled, iconNormalX, iconNormalY));
|
||||
}
|
||||
this.rawcodeToUpgradeUI.put(alias, upgradeIconsByLevel);
|
||||
}
|
||||
this.moveUI = createBuiltInIconUI(gameUI, "CmdMove", disabledPrefix);
|
||||
this.stopUI = createBuiltInIconUI(gameUI, "CmdStop", disabledPrefix);
|
||||
this.holdPosUI = createBuiltInIconUI(gameUI, "CmdHoldPos", disabledPrefix);
|
||||
@ -88,6 +113,7 @@ public class AbilityDataUI {
|
||||
this.buildNeutralUI = createBuiltInIconUI(gameUI, "CmdBuild", disabledPrefix);
|
||||
this.attackGroundUI = createBuiltInIconUI(gameUI, "CmdAttackGround", disabledPrefix);
|
||||
this.cancelUI = createBuiltInIconUI(gameUI, "CmdCancel", disabledPrefix);
|
||||
this.cancelBuildUI = createBuiltInIconUI(gameUI, "CmdCancelBuild", disabledPrefix);
|
||||
}
|
||||
|
||||
private IconUI createBuiltInIconUI(final GameUI gameUI, final String key, final String disabledPrefix) {
|
||||
@ -108,6 +134,19 @@ public class AbilityDataUI {
|
||||
return this.rawcodeToUnitUI.get(rawcode);
|
||||
}
|
||||
|
||||
public IconUI getUpgradeUI(final War3ID rawcode, final int level) {
|
||||
final List<IconUI> upgradeUI = this.rawcodeToUpgradeUI.get(rawcode);
|
||||
if (upgradeUI != null) {
|
||||
if (level < upgradeUI.size()) {
|
||||
return upgradeUI.get(level);
|
||||
}
|
||||
else {
|
||||
return upgradeUI.get(upgradeUI.size() - 1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String disable(final String path, final String disabledPrefix) {
|
||||
final int slashIndex = path.lastIndexOf('\\');
|
||||
String name = path;
|
||||
@ -169,4 +208,8 @@ public class AbilityDataUI {
|
||||
return this.cancelUI;
|
||||
}
|
||||
|
||||
public IconUI getCancelBuildUI() {
|
||||
return this.cancelBuildUI;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityG
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.AbstractCAbilityBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityHumanBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityNagaBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityNeutralBuild;
|
||||
@ -18,7 +19,9 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityOrcBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityUndeadBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat.CAbilityColdArrows;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
|
||||
|
||||
public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void> {
|
||||
public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor();
|
||||
@ -29,22 +32,24 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
private AbilityDataUI abilityDataUI;
|
||||
private int menuBaseOrderId;
|
||||
private boolean hasStop;
|
||||
private boolean underConstruction;
|
||||
|
||||
public CommandCardPopulatingAbilityVisitor reset(final CSimulation game, final CUnit unit,
|
||||
final CommandButtonListener commandButtonListener, final AbilityDataUI abilityDataUI,
|
||||
final int menuBaseOrderId) {
|
||||
final int menuBaseOrderId, final boolean underConstruction) {
|
||||
this.game = game;
|
||||
this.unit = unit;
|
||||
this.commandButtonListener = commandButtonListener;
|
||||
this.abilityDataUI = abilityDataUI;
|
||||
this.menuBaseOrderId = menuBaseOrderId;
|
||||
this.underConstruction = underConstruction;
|
||||
this.hasStop = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityAttack ability) {
|
||||
if (this.menuBaseOrderId == 0) {
|
||||
if ((this.menuBaseOrderId == 0) && !this.underConstruction) {
|
||||
addCommandButton(ability, this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack, 0,
|
||||
false, false);
|
||||
if (!this.hasStop) {
|
||||
@ -57,7 +62,7 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityMove ability) {
|
||||
if (this.menuBaseOrderId == 0) {
|
||||
if ((this.menuBaseOrderId == 0) && !this.underConstruction) {
|
||||
addCommandButton(ability, this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move, 0, false,
|
||||
false);
|
||||
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition,
|
||||
@ -74,7 +79,7 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityGeneric ability) {
|
||||
if (this.menuBaseOrderId == 0) {
|
||||
if ((this.menuBaseOrderId == 0) && !this.underConstruction) {
|
||||
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(),
|
||||
ability.getHandleId(), 0, 0, false, false);
|
||||
}
|
||||
@ -83,7 +88,7 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityColdArrows ability) {
|
||||
if (this.menuBaseOrderId == 0) {
|
||||
if ((this.menuBaseOrderId == 0) && !this.underConstruction) {
|
||||
final boolean autoCastActive = ability.isAutoCastActive();
|
||||
int autoCastId;
|
||||
if (autoCastActive) {
|
||||
@ -135,7 +140,7 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
}
|
||||
|
||||
private void handleBuildMenu(final AbstractCAbilityBuild ability, final IconUI buildUI) {
|
||||
if (this.menuBaseOrderId == ability.getBaseOrderId()) {
|
||||
if ((this.menuBaseOrderId == ability.getBaseOrderId()) && !this.underConstruction) {
|
||||
for (final War3ID unitType : ability.getStructuresBuilt()) {
|
||||
final IconUI unitUI = this.abilityDataUI.getUnitUI(unitType);
|
||||
if (unitUI != null) {
|
||||
@ -155,4 +160,33 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
|
||||
iconUI.getIcon(), handleId, orderId, autoCastOrderId, active, autoCastActive, menuButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityBuildInProgress ability) {
|
||||
if (this.menuBaseOrderId == 0) {
|
||||
addCommandButton(ability, this.abilityDataUI.getCancelBuildUI(), ability.getHandleId(), OrderIds.cancel, 0,
|
||||
false, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityQueue ability) {
|
||||
if ((this.menuBaseOrderId == 0) && !this.underConstruction) {
|
||||
for (final War3ID unitType : ability.getUnitsTrained()) {
|
||||
final IconUI unitUI = this.abilityDataUI.getUnitUI(unitType);
|
||||
if (unitUI != null) {
|
||||
addCommandButton(ability, unitUI, ability.getHandleId(), unitType.getValue(), 0, false, false);
|
||||
}
|
||||
}
|
||||
for (final War3ID unitType : ability.getResearchesAvailable()) {
|
||||
final CPlayer player = this.game.getPlayer(this.unit.getPlayerIndex());
|
||||
final IconUI unitUI = this.abilityDataUI.getUpgradeUI(unitType, player.getTechtreeUnlocked(unitType));
|
||||
if (unitUI != null) {
|
||||
addCommandButton(ability, unitUI, ability.getHandleId(), unitType.getValue(), 0, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ import com.etheller.warsmash.units.DataTable;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData;
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.BuildingShadow;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.RemovablePathingMapInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackInstant;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissile;
|
||||
@ -59,7 +61,7 @@ public class CSimulation {
|
||||
this.simulationRenderController = simulationRenderController;
|
||||
this.pathingGrid = pathingGrid;
|
||||
this.abilityData = new CAbilityData(parsedAbilityData);
|
||||
this.unitData = new CUnitData(parsedUnitData, this.abilityData);
|
||||
this.unitData = new CUnitData(parsedUnitData, this.abilityData, this.simulationRenderController);
|
||||
this.units = new ArrayList<>();
|
||||
this.newUnits = new ArrayList<>();
|
||||
this.projectiles = new ArrayList<>();
|
||||
@ -118,14 +120,12 @@ public class CSimulation {
|
||||
}
|
||||
|
||||
public CUnit createUnit(final War3ID typeId, final int playerIndex, final float x, final float y,
|
||||
final float facing, final BufferedImage buildingPathingPixelMap) {
|
||||
final float facing, final BufferedImage buildingPathingPixelMap,
|
||||
final RemovablePathingMapInstance pathingInstance, final BuildingShadow buildingShadowInstance) {
|
||||
final CUnit unit = this.unitData.create(this, playerIndex, typeId, x, y, facing, buildingPathingPixelMap,
|
||||
this.simulationRenderController, this.handleIdAllocator);
|
||||
this.handleIdAllocator, pathingInstance, buildingShadowInstance);
|
||||
this.newUnits.add(unit);
|
||||
this.handleIdToUnit.put(unit.getHandleId(), unit);
|
||||
for (final CAbility ability : unit.getAbilities()) {
|
||||
this.handleIdToAbility.put(ability.getHandleId(), ability);
|
||||
}
|
||||
this.worldCollision.addUnit(unit);
|
||||
return unit;
|
||||
}
|
||||
@ -143,6 +143,10 @@ public class CSimulation {
|
||||
return this.handleIdToAbility.get(handleId);
|
||||
}
|
||||
|
||||
protected void onAbilityAddedToUnit(final CUnit unit, final CAbility ability) {
|
||||
this.handleIdToAbility.put(ability.getHandleId(), ability);
|
||||
}
|
||||
|
||||
public CAttackProjectile createProjectile(final CUnit source, final float launchX, final float launchY,
|
||||
final float launchFacing, final CUnitAttackMissile attack, final CWidget target, final float damage,
|
||||
final int bounceIndex) {
|
||||
@ -223,7 +227,7 @@ public class CSimulation {
|
||||
this.simulationRenderController.spawnUnitDamageSound(damagedUnit, weaponSound, armorType);
|
||||
}
|
||||
|
||||
public void unitConstructedEvent(CUnit constructingUnit, CUnit constructedStructure) {
|
||||
public void unitConstructedEvent(final CUnit constructingUnit, final CUnit constructedStructure) {
|
||||
this.simulationRenderController.spawnUnitConstructionSound(constructingUnit, constructedStructure);
|
||||
}
|
||||
|
||||
@ -235,7 +239,23 @@ public class CSimulation {
|
||||
return this.commandErrorListener;
|
||||
}
|
||||
|
||||
public void unitConstructFinishEvent(CUnit constructedStructure) {
|
||||
public void unitConstructFinishEvent(final CUnit constructedStructure) {
|
||||
this.simulationRenderController.spawnUnitConstructionFinishSound(constructedStructure);
|
||||
}
|
||||
}
|
||||
|
||||
public void createBuildingDeathEffect(final CUnit cUnit) {
|
||||
this.simulationRenderController.spawnBuildingDeathEffect(cUnit);
|
||||
}
|
||||
|
||||
public HandleIdAllocator getHandleIdAllocator() {
|
||||
return this.handleIdAllocator;
|
||||
}
|
||||
|
||||
public void unitTrainedEvent(final CUnit trainingUnit, final CUnit trainedUnit) {
|
||||
this.simulationRenderController.spawnUnitReadySound(trainedUnit);
|
||||
}
|
||||
|
||||
public void unitRepositioned(final CUnit cUnit) {
|
||||
this.simulationRenderController.unitRepositioned(cUnit);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
@ -12,8 +13,11 @@ import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.BuildingShadow;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.RemovablePathingMapInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener.CUnitStateNotifier;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttack;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorFollow;
|
||||
@ -49,6 +53,8 @@ public class CUnit extends CWidget {
|
||||
private final CUnitType unitType;
|
||||
|
||||
private Rectangle collisionRectangle;
|
||||
private RemovablePathingMapInstance pathingInstance;
|
||||
private BuildingShadow buildingShadowInstance;
|
||||
|
||||
private final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
|
||||
|
||||
@ -75,10 +81,13 @@ public class CUnit extends CWidget {
|
||||
private boolean hidden = false;
|
||||
private boolean updating = true;
|
||||
private CUnit workerInside;
|
||||
private final War3ID[] buildQueue = new War3ID[WarsmashConstants.BUILD_QUEUE_SIZE];
|
||||
private final QueueItemType[] buildQueueTypes = new QueueItemType[WarsmashConstants.BUILD_QUEUE_SIZE];
|
||||
|
||||
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 int speed, final int defense, final CUnitType unitType) {
|
||||
final int speed, final int defense, final CUnitType unitType,
|
||||
final RemovablePathingMapInstance pathingInstance, final BuildingShadow buildingShadowInstance) {
|
||||
super(handleId, x, y, life);
|
||||
this.playerIndex = playerIndex;
|
||||
this.typeId = typeId;
|
||||
@ -88,6 +97,8 @@ public class CUnit extends CWidget {
|
||||
this.maximumMana = maximumMana;
|
||||
this.speed = speed;
|
||||
this.defense = defense;
|
||||
this.pathingInstance = pathingInstance;
|
||||
this.buildingShadowInstance = buildingShadowInstance;
|
||||
this.flyHeight = unitType.getDefaultFlyingHeight();
|
||||
this.unitType = unitType;
|
||||
this.classifications.addAll(unitType.getClassifications());
|
||||
@ -107,6 +118,7 @@ public class CUnit extends CWidget {
|
||||
|
||||
public void add(final CSimulation simulation, final CAbility ability) {
|
||||
this.abilities.add(ability);
|
||||
simulation.onAbilityAddedToUnit(this, ability);
|
||||
ability.onAdd(simulation, this);
|
||||
}
|
||||
|
||||
@ -207,33 +219,87 @@ public class CUnit extends CWidget {
|
||||
else if (this.updating) {
|
||||
if (this.constructing) {
|
||||
this.constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME;
|
||||
if (this.constructionProgress >= this.unitType.getBuildTime()) {
|
||||
final int buildTime = this.unitType.getBuildTime();
|
||||
final float healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / buildTime)
|
||||
* (this.maximumLife * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE));
|
||||
setLife(game, Math.min(this.life + healthGain, this.maximumLife));
|
||||
if (this.constructionProgress >= buildTime) {
|
||||
this.constructing = false;
|
||||
if (this.workerInside != null) {
|
||||
this.workerInside.setHidden(false);
|
||||
this.workerInside.setUpdating(true);
|
||||
this.workerInside.nudgeAround(game, this);
|
||||
this.workerInside = null;
|
||||
this.constructionProgress = 0;
|
||||
popoutWorker(game);
|
||||
final Iterator<CAbility> abilityIterator = this.abilities.iterator();
|
||||
while (abilityIterator.hasNext()) {
|
||||
final CAbility ability = abilityIterator.next();
|
||||
if (ability instanceof CAbilityBuildInProgress) {
|
||||
abilityIterator.remove();
|
||||
}
|
||||
}
|
||||
game.unitConstructFinishEvent(this);
|
||||
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
|
||||
}
|
||||
}
|
||||
else if (this.currentBehavior != null) {
|
||||
final CBehavior lastBehavior = this.currentBehavior;
|
||||
this.currentBehavior = this.currentBehavior.update(game);
|
||||
if (this.currentBehavior.getHighlightOrderId() != lastBehavior.getHighlightOrderId()) {
|
||||
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
|
||||
}
|
||||
}
|
||||
else {
|
||||
// check to auto acquire targets
|
||||
autoAcquireAttackTargets(game);
|
||||
final War3ID queuedRawcode = this.buildQueue[0];
|
||||
if (queuedRawcode != null) {
|
||||
// queue step forward
|
||||
this.constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME;
|
||||
if (this.buildQueueTypes[0] == QueueItemType.UNIT) {
|
||||
final CUnitType trainedUnitType = game.getUnitData().getUnitType(queuedRawcode);
|
||||
if (this.constructionProgress >= trainedUnitType.getBuildTime()) {
|
||||
this.constructionProgress = 0;
|
||||
final CUnit trainedUnit = game.createUnit(queuedRawcode, this.playerIndex, getX(), getY(),
|
||||
game.getGameplayConstants().getBuildingAngle());
|
||||
// nudge the trained unit out around us
|
||||
trainedUnit.nudgeAround(game, this);
|
||||
game.unitTrainedEvent(this, trainedUnit);
|
||||
for (int i = 0; i < (this.buildQueue.length - 1); i++) {
|
||||
this.buildQueue[i] = this.buildQueue[i + 1];
|
||||
this.buildQueueTypes[i] = this.buildQueueTypes[i + 1];
|
||||
}
|
||||
this.buildQueue[this.buildQueue.length - 1] = null;
|
||||
this.buildQueueTypes[this.buildQueue.length - 1] = null;
|
||||
this.stateNotifier.queueChanged();
|
||||
}
|
||||
}
|
||||
else if (this.buildQueueTypes[0] == QueueItemType.RESEARCH) {
|
||||
final CUnitType trainedUnitType = game.getUnitData().getUnitType(queuedRawcode);
|
||||
if (this.constructionProgress >= trainedUnitType.getBuildTime()) {
|
||||
this.constructionProgress = 0;
|
||||
for (int i = 0; i < (this.buildQueue.length - 1); i++) {
|
||||
this.buildQueue[i] = this.buildQueue[i + 1];
|
||||
this.buildQueueTypes[i] = this.buildQueueTypes[i + 1];
|
||||
}
|
||||
this.buildQueue[this.buildQueue.length - 1] = null;
|
||||
this.buildQueueTypes[this.buildQueue.length - 1] = null;
|
||||
this.stateNotifier.queueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.currentBehavior != null) {
|
||||
final CBehavior lastBehavior = this.currentBehavior;
|
||||
this.currentBehavior = this.currentBehavior.update(game);
|
||||
if (this.currentBehavior.getHighlightOrderId() != lastBehavior.getHighlightOrderId()) {
|
||||
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
|
||||
}
|
||||
}
|
||||
else {
|
||||
// check to auto acquire targets
|
||||
autoAcquireAttackTargets(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void popoutWorker(final CSimulation game) {
|
||||
if (this.workerInside != null) {
|
||||
this.workerInside.setHidden(false);
|
||||
this.workerInside.setUpdating(true);
|
||||
this.workerInside.nudgeAround(game, this);
|
||||
this.workerInside = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void autoAcquireAttackTargets(final CSimulation game) {
|
||||
if (!this.unitType.getAttacks().isEmpty()) {
|
||||
if (this.collisionRectangle != null) {
|
||||
@ -452,7 +518,7 @@ public class CUnit extends CWidget {
|
||||
simulation.unitDamageEvent(this, weaponType, this.unitType.getArmorType());
|
||||
this.stateNotifier.lifeChanged();
|
||||
if (isDead()) {
|
||||
if (!wasDead && !this.unitType.isBuilding()) {
|
||||
if (!wasDead) {
|
||||
kill(simulation);
|
||||
}
|
||||
}
|
||||
@ -474,7 +540,21 @@ public class CUnit extends CWidget {
|
||||
private void kill(final CSimulation simulation) {
|
||||
this.currentBehavior = null;
|
||||
this.orderQueue.clear();
|
||||
this.deathTurnTick = simulation.getGameTurnTick();
|
||||
if (this.constructing) {
|
||||
simulation.createBuildingDeathEffect(this);
|
||||
}
|
||||
else {
|
||||
this.deathTurnTick = simulation.getGameTurnTick();
|
||||
}
|
||||
if (this.pathingInstance != null) {
|
||||
this.pathingInstance.remove();
|
||||
this.pathingInstance = null;
|
||||
}
|
||||
if (this.buildingShadowInstance != null) {
|
||||
this.buildingShadowInstance.remove();
|
||||
this.buildingShadowInstance = null;
|
||||
}
|
||||
popoutWorker(simulation);
|
||||
}
|
||||
|
||||
public boolean canReach(final CWidget target, final float range) {
|
||||
@ -753,5 +833,62 @@ public class CUnit extends CWidget {
|
||||
}
|
||||
setX(x, simulation.getWorldCollision());
|
||||
setY(y, simulation.getWorldCollision());
|
||||
simulation.unitRepositioned(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLife(final CSimulation simulation, final float life) {
|
||||
final boolean wasDead = isDead();
|
||||
super.setLife(simulation, life);
|
||||
if (isDead() && !wasDead) {
|
||||
kill(simulation);
|
||||
}
|
||||
this.stateNotifier.lifeChanged();
|
||||
}
|
||||
|
||||
private void queue(final War3ID rawcode, final QueueItemType queueItemType) {
|
||||
for (int i = 0; i < this.buildQueue.length; i++) {
|
||||
if (this.buildQueue[i] == null) {
|
||||
this.buildQueue[i] = rawcode;
|
||||
this.buildQueueTypes[i] = queueItemType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public War3ID[] getBuildQueue() {
|
||||
return this.buildQueue;
|
||||
}
|
||||
|
||||
public QueueItemType[] getBuildQueueTypes() {
|
||||
return this.buildQueueTypes;
|
||||
}
|
||||
|
||||
public float getBuildQueueTimeRemaining(final CSimulation simulation) {
|
||||
if (this.buildQueueTypes[0] == null) {
|
||||
return 0;
|
||||
}
|
||||
switch (this.buildQueueTypes[0]) {
|
||||
case RESEARCH:
|
||||
return 999; // TODO
|
||||
case UNIT:
|
||||
final CUnitType trainedUnitType = simulation.getUnitData().getUnitType(this.buildQueue[0]);
|
||||
return trainedUnitType.getBuildTime();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void queueTrainingUnit(final War3ID rawcode) {
|
||||
queue(rawcode, QueueItemType.UNIT);
|
||||
}
|
||||
|
||||
public void queueResearch(final War3ID rawcode) {
|
||||
queue(rawcode, QueueItemType.RESEARCH);
|
||||
}
|
||||
|
||||
public static enum QueueItemType {
|
||||
UNIT,
|
||||
RESEARCH;
|
||||
}
|
||||
}
|
||||
|
@ -9,4 +9,11 @@ public interface CUnitFilterFunction {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CUnitFilterFunction ACCEPT_ALL_LIVING = new CUnitFilterFunction() {
|
||||
@Override
|
||||
public boolean call(final CUnit unit) {
|
||||
return !unit.isDead();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ public interface CUnitStateListener {
|
||||
|
||||
void ordersChanged(int abilityHandleId, int orderId);
|
||||
|
||||
void queueChanged();
|
||||
|
||||
public static final class CUnitStateNotifier extends SubscriberSetNotifier<CUnitStateListener>
|
||||
implements CUnitStateListener {
|
||||
@Override
|
||||
@ -22,5 +24,12 @@ public interface CUnitStateListener {
|
||||
listener.ordersChanged(abilityHandleId, orderId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueChanged() {
|
||||
for (final CUnitStateListener listener : set) {
|
||||
listener.queueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ public class CUnitType {
|
||||
private final float defaultAcquisitionRange;
|
||||
private final float minimumAttackRange;
|
||||
private final List<War3ID> structuresBuilt;
|
||||
private final List<War3ID> unitsTrained;
|
||||
private final List<War3ID> researchesAvailable;
|
||||
private final CUnitRace unitRace;
|
||||
private final int goldCost;
|
||||
private final int lumberCost;
|
||||
@ -49,7 +51,8 @@ public class CUnitType {
|
||||
final boolean raise, final boolean decay, final CDefenseType defenseType, final float impactZ,
|
||||
final BufferedImage buildingPathingPixelMap, final float deathTime, final EnumSet<CTargetType> targetedAs,
|
||||
final float defaultAcquisitionRange, final float minimumAttackRange, final List<War3ID> structuresBuilt,
|
||||
final CUnitRace unitRace, final int goldCost, final int lumberCost, final int buildTime) {
|
||||
final List<War3ID> unitsTrained, final List<War3ID> researchesAvailable, final CUnitRace unitRace,
|
||||
final int goldCost, final int lumberCost, final int buildTime) {
|
||||
this.name = name;
|
||||
this.building = isBldg;
|
||||
this.movementType = movementType;
|
||||
@ -68,6 +71,8 @@ public class CUnitType {
|
||||
this.defaultAcquisitionRange = defaultAcquisitionRange;
|
||||
this.minimumAttackRange = minimumAttackRange;
|
||||
this.structuresBuilt = structuresBuilt;
|
||||
this.unitsTrained = unitsTrained;
|
||||
this.researchesAvailable = researchesAvailable;
|
||||
this.unitRace = unitRace;
|
||||
this.goldCost = goldCost;
|
||||
this.lumberCost = lumberCost;
|
||||
@ -146,6 +151,14 @@ public class CUnitType {
|
||||
return this.structuresBuilt;
|
||||
}
|
||||
|
||||
public List<War3ID> getUnitsTrained() {
|
||||
return this.unitsTrained;
|
||||
}
|
||||
|
||||
public List<War3ID> getResearchesAvailable() {
|
||||
return this.researchesAvailable;
|
||||
}
|
||||
|
||||
public CUnitRace getRace() {
|
||||
return this.unitRace;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public abstract class CWidget {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void setLife(final float life) {
|
||||
public void setLife(final CSimulation simulation, final float life) {
|
||||
this.life = life;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
|
||||
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityHumanBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityNagaBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityNeutralBuild;
|
||||
@ -7,6 +8,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityOrcBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityUndeadBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat.CAbilityColdArrows;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
|
||||
|
||||
/**
|
||||
* A visitor for the lowest level inherent types of an ability. It's a bit of a
|
||||
@ -36,4 +38,8 @@ public interface CAbilityVisitor<T> {
|
||||
T accept(CAbilityNagaBuild ability);
|
||||
|
||||
T accept(CAbilityNeutralBuild ability);
|
||||
|
||||
T accept(CAbilityBuildInProgress ability);
|
||||
|
||||
T accept(CAbilityQueue ability);
|
||||
}
|
||||
|
@ -33,22 +33,29 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements
|
||||
@Override
|
||||
public void checkCanUse(final CSimulation game, final CUnit unit, final int orderId,
|
||||
final AbilityActivationReceiver receiver) {
|
||||
final CUnitType unitType = game.getUnitData().getUnitType(new War3ID(orderId));
|
||||
if (unitType != null) {
|
||||
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||
if (player.getGold() >= unitType.getGoldCost()) {
|
||||
if (player.getLumber() >= unitType.getLumberCost()) {
|
||||
receiver.useOk();
|
||||
final War3ID orderIdAsRawtype = new War3ID(orderId);
|
||||
if (this.structuresBuilt.contains(orderIdAsRawtype)) {
|
||||
final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype);
|
||||
if (unitType != null) {
|
||||
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||
if (player.getGold() >= unitType.getGoldCost()) {
|
||||
if (player.getLumber() >= unitType.getLumberCost()) {
|
||||
receiver.useOk();
|
||||
}
|
||||
else {
|
||||
receiver.notEnoughResources(ResourceType.LUMBER);
|
||||
}
|
||||
}
|
||||
else {
|
||||
receiver.notEnoughResources(ResourceType.LUMBER);
|
||||
receiver.notEnoughResources(ResourceType.GOLD);
|
||||
}
|
||||
}
|
||||
else {
|
||||
receiver.notEnoughResources(ResourceType.GOLD);
|
||||
receiver.useOk();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/// ???
|
||||
receiver.useOk();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.AbstractCAbility;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
|
||||
|
||||
public class CAbilityBuildInProgress extends AbstractCAbility {
|
||||
|
||||
public CAbilityBuildInProgress(final int handleId) {
|
||||
super(handleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdd(final CSimulation game, final CUnit unit) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(final CSimulation game, final CUnit unit) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) {
|
||||
caster.setLife(game, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanUse(final CSimulation game, final CUnit unit, final int orderId,
|
||||
final AbilityActivationReceiver receiver) {
|
||||
receiver.useOk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
|
||||
final AbilityTargetCheckReceiver<CWidget> receiver) {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target,
|
||||
final AbilityTargetCheckReceiver<Vector2> receiver) {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
|
||||
final AbilityTargetCheckReceiver<Void> receiver) {
|
||||
if (orderId == OrderIds.cancel) {
|
||||
receiver.targetOk(null);
|
||||
}
|
||||
else {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(final CAbilityVisitor<T> visitor) {
|
||||
return visitor.accept(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.AbstractCAbility;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
|
||||
|
||||
public final class CAbilityQueue extends AbstractCAbility {
|
||||
private final Set<War3ID> unitsTrained;
|
||||
private final Set<War3ID> researchesAvailable;
|
||||
|
||||
public CAbilityQueue(final int handleId, final List<War3ID> unitsTrained, final List<War3ID> researchesAvailable) {
|
||||
super(handleId);
|
||||
this.unitsTrained = new LinkedHashSet<>(unitsTrained);
|
||||
this.researchesAvailable = new LinkedHashSet<>(researchesAvailable);
|
||||
}
|
||||
|
||||
public Set<War3ID> getUnitsTrained() {
|
||||
return this.unitsTrained;
|
||||
}
|
||||
|
||||
public Set<War3ID> getResearchesAvailable() {
|
||||
return this.researchesAvailable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanUse(final CSimulation game, final CUnit unit, final int orderId,
|
||||
final AbilityActivationReceiver receiver) {
|
||||
final War3ID orderIdAsRawtype = new War3ID(orderId);
|
||||
if (this.unitsTrained.contains(orderIdAsRawtype) || this.researchesAvailable.contains(orderIdAsRawtype)) {
|
||||
final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype);
|
||||
if (unitType != null) {
|
||||
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||
if (player.getGold() >= unitType.getGoldCost()) {
|
||||
if (player.getLumber() >= unitType.getLumberCost()) {
|
||||
receiver.useOk();
|
||||
}
|
||||
else {
|
||||
receiver.notEnoughResources(ResourceType.LUMBER);
|
||||
}
|
||||
}
|
||||
else {
|
||||
receiver.notEnoughResources(ResourceType.GOLD);
|
||||
}
|
||||
}
|
||||
else {
|
||||
receiver.useOk();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/// ???
|
||||
receiver.useOk();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
|
||||
final AbilityTargetCheckReceiver<CWidget> receiver) {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target,
|
||||
final AbilityTargetCheckReceiver<Vector2> receiver) {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
|
||||
final AbilityTargetCheckReceiver<Void> receiver) {
|
||||
if (this.unitsTrained.contains(new War3ID(orderId)) || this.researchesAvailable.contains(new War3ID(orderId))) {
|
||||
receiver.targetOk(null);
|
||||
}
|
||||
else {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdd(final CSimulation game, final CUnit unit) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(final CSimulation game, final CUnit unit) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
|
||||
final War3ID rawcode = new War3ID(orderId);
|
||||
if (this.unitsTrained.contains(rawcode)) {
|
||||
caster.queueTrainingUnit(rawcode);
|
||||
}
|
||||
else if (this.researchesAvailable.contains(rawcode)) {
|
||||
caster.queueResearch(rawcode);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(final CAbilityVisitor<T> visitor) {
|
||||
return visitor.accept(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.upgrade;
|
||||
|
||||
public class CAbilityUpgrade {
|
||||
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build;
|
||||
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedPointTargetBehavior;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||
|
||||
@ -39,6 +41,9 @@ public class CBehaviorOrcBuild extends CAbstractRangedPointTargetBehavior {
|
||||
this.targetY, simulation.getGameplayConstants().getBuildingAngle());
|
||||
constructedStructure.setConstructing(true);
|
||||
constructedStructure.setWorkerInside(this.unit);
|
||||
constructedStructure.setLife(simulation,
|
||||
constructedStructure.getMaximumLife() * WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE);
|
||||
constructedStructure.add(simulation, new CAbilityBuildInProgress(simulation.getHandleIdAllocator().createId()));
|
||||
this.unit.setHidden(true);
|
||||
this.unit.setUpdating(false);
|
||||
simulation.unitConstructedEvent(this.unit, constructedStructure);
|
||||
|
@ -10,12 +10,15 @@ import java.util.Map;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.BuildingShadow;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.RemovablePathingMapInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.HandleIdAllocator;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityHumanBuild;
|
||||
@ -24,6 +27,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityNightElfBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityOrcBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityUndeadBuild;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
||||
@ -128,6 +132,8 @@ public class CUnitData {
|
||||
private static final War3ID ABILITIES_NORMAL = War3ID.fromString("uabi");
|
||||
|
||||
private static final War3ID STRUCTURES_BUILT = War3ID.fromString("ubui");
|
||||
private static final War3ID UNITS_TRAINED = War3ID.fromString("utra");
|
||||
private static final War3ID RESEARCHES_AVAILABLE = War3ID.fromString("ures");
|
||||
private static final War3ID UNIT_RACE = War3ID.fromString("urac");
|
||||
|
||||
private static final War3ID GOLD_COST = War3ID.fromString("ugol");
|
||||
@ -137,17 +143,19 @@ public class CUnitData {
|
||||
private final MutableObjectData unitData;
|
||||
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
|
||||
private final CAbilityData abilityData;
|
||||
private SimulationRenderController simulationRenderController;
|
||||
private final SimulationRenderController simulationRenderController;
|
||||
|
||||
public CUnitData(final MutableObjectData unitData, final CAbilityData abilityData) {
|
||||
public CUnitData(final MutableObjectData unitData, final CAbilityData abilityData,
|
||||
final SimulationRenderController simulationRenderController) {
|
||||
this.unitData = unitData;
|
||||
this.abilityData = abilityData;
|
||||
this.simulationRenderController = simulationRenderController;
|
||||
}
|
||||
|
||||
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
|
||||
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
|
||||
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
|
||||
this.simulationRenderController = simulationRenderController;
|
||||
final HandleIdAllocator handleIdAllocator, final RemovablePathingMapInstance pathingInstance,
|
||||
final BuildingShadow buildingShadowInstance) {
|
||||
final MutableGameObject unitType = this.unitData.get(typeId);
|
||||
final int handleId = handleIdAllocator.createId();
|
||||
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
|
||||
@ -160,7 +168,7 @@ public class CUnitData {
|
||||
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
|
||||
|
||||
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
|
||||
speed, defense, unitTypeInstance);
|
||||
speed, defense, unitTypeInstance, pathingInstance, buildingShadowInstance);
|
||||
if (speed > 0) {
|
||||
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
|
||||
}
|
||||
@ -193,9 +201,17 @@ public class CUnitData {
|
||||
break;
|
||||
}
|
||||
}
|
||||
final List<War3ID> unitsTrained = unitTypeInstance.getUnitsTrained();
|
||||
final List<War3ID> researchesAvailable = unitTypeInstance.getResearchesAvailable();
|
||||
if (!unitsTrained.isEmpty() || !researchesAvailable.isEmpty()) {
|
||||
unit.add(simulation, new CAbilityQueue(handleIdAllocator.createId(), unitsTrained, researchesAvailable));
|
||||
}
|
||||
for (final String ability : abilityList.split(",")) {
|
||||
if ((ability.length() > 0) && !"_".equals(ability)) {
|
||||
unit.add(simulation, this.abilityData.createAbility(ability, handleIdAllocator.createId()));
|
||||
final CAbility createAbility = this.abilityData.createAbility(ability, handleIdAllocator.createId());
|
||||
if (createAbility != null) {
|
||||
unit.add(simulation, createAbility);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unit;
|
||||
@ -338,6 +354,24 @@ public class CUnitData {
|
||||
final int lumberCost = unitType.getFieldAsInteger(LUMBER_COST, 0);
|
||||
final int buildTime = unitType.getFieldAsInteger(BUILD_TIME, 0);
|
||||
|
||||
final String unitsTrainedString = unitType.getFieldAsString(UNITS_TRAINED, 0);
|
||||
final String[] unitsTrainedStringItems = unitsTrainedString.trim().split(",");
|
||||
final List<War3ID> unitsTrained = new ArrayList<>();
|
||||
for (final String unitsTrainedStringItem : unitsTrainedStringItems) {
|
||||
if (unitsTrainedStringItem.length() == 4) {
|
||||
unitsTrained.add(War3ID.fromString(unitsTrainedStringItem));
|
||||
}
|
||||
}
|
||||
|
||||
final String researchesAvailableString = unitType.getFieldAsString(RESEARCHES_AVAILABLE, 0);
|
||||
final String[] researchesAvailableStringItems = researchesAvailableString.trim().split(",");
|
||||
final List<War3ID> researchesAvailable = new ArrayList<>();
|
||||
for (final String researchesAvailableStringItem : researchesAvailableStringItems) {
|
||||
if (researchesAvailableStringItem.length() == 4) {
|
||||
researchesAvailable.add(War3ID.fromString(researchesAvailableStringItem));
|
||||
}
|
||||
}
|
||||
|
||||
final String structuresBuiltString = unitType.getFieldAsString(STRUCTURES_BUILT, 0);
|
||||
final String[] structuresBuiltStringItems = structuresBuiltString.split(",");
|
||||
final List<War3ID> structuresBuilt = new ArrayList<>();
|
||||
@ -352,8 +386,8 @@ public class CUnitData {
|
||||
|
||||
unitTypeInstance = new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize, classifications,
|
||||
attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime,
|
||||
targetedAs, acquisitionRange, minimumAttackRange, structuresBuilt, unitRace, goldCost, lumberCost,
|
||||
buildTime);
|
||||
targetedAs, acquisitionRange, minimumAttackRange, structuresBuilt, unitsTrained,
|
||||
researchesAvailable, unitRace, goldCost, lumberCost, buildTime);
|
||||
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
||||
}
|
||||
return unitTypeInstance;
|
||||
|
@ -1,7 +1,10 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
|
||||
public class CPlayer {
|
||||
@ -15,6 +18,7 @@ public class CPlayer {
|
||||
private int gold = 5000;
|
||||
private int lumber = 5000;
|
||||
private final EnumSet<CAllianceType>[] alliances = new EnumSet[WarsmashConstants.MAX_PLAYERS];
|
||||
private final Map<War3ID, Integer> rawcodeToTechtreeUnlocked = new HashMap<>();
|
||||
|
||||
public CPlayer(final int id, final CMapControl controlType, final String name, final CRace race,
|
||||
final float[] startLocation) {
|
||||
@ -106,4 +110,12 @@ public class CPlayer {
|
||||
public void setColorIndex(final int colorIndex) {
|
||||
this.colorIndex = colorIndex;
|
||||
}
|
||||
|
||||
public int getTechtreeUnlocked(final War3ID rawcode) {
|
||||
final Integer techtreeUnlocked = this.rawcodeToTechtreeUnlocked.get(rawcode);
|
||||
if (techtreeUnlocked == null) {
|
||||
return 0;
|
||||
}
|
||||
return techtreeUnlocked;
|
||||
}
|
||||
}
|
||||
|
@ -28,4 +28,10 @@ public interface SimulationRenderController {
|
||||
BufferedImage getBuildingPathingPixelMap(War3ID rawcode);
|
||||
|
||||
void spawnUnitConstructionFinishSound(CUnit constructedStructure);
|
||||
|
||||
void spawnBuildingDeathEffect(CUnit cUnit);
|
||||
|
||||
void spawnUnitReadySound(CUnit trainedUnit);
|
||||
|
||||
void unitRepositioned(CUnit cUnit);
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataU
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.IconUI;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButtonListener;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit.QueueItemType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitFilterFunction;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener;
|
||||
@ -111,11 +112,19 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
private final Rectangle tempRect = new Rectangle();
|
||||
private final Vector2 projectionTemp1 = new Vector2();
|
||||
private final Vector2 projectionTemp2 = new Vector2();
|
||||
|
||||
private UIFrame simpleInfoPanelUnitDetail;
|
||||
private StringFrame simpleNameValue;
|
||||
private StringFrame simpleClassValue;
|
||||
private StringFrame simpleBuildingActionLabel;
|
||||
private SimpleStatusBarFrame simpleBuildTimeIndicator;
|
||||
|
||||
private UIFrame simpleInfoPanelBuildingDetail;
|
||||
private StringFrame simpleBuildingNameValue;
|
||||
private StringFrame simpleBuildingDescriptionValue;
|
||||
private StringFrame simpleBuildingBuildingActionLabel;
|
||||
private SimpleStatusBarFrame simpleBuildingBuildTimeIndicator;
|
||||
|
||||
private UIFrame attack1Icon;
|
||||
private TextureFrame attack1IconBackdrop;
|
||||
private StringFrame attack1InfoPanelIconValue;
|
||||
@ -282,12 +291,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
this.unitLifeText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitHitPointText", 0);
|
||||
this.unitManaText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitManaPointText", 0);
|
||||
|
||||
// Create Simple Info Unit Detail
|
||||
this.simpleInfoPanelUnitDetail = this.rootFrame.createSimpleFrame("SimpleInfoPanelUnitDetail", this.consoleUI,
|
||||
0);
|
||||
this.simpleInfoPanelUnitDetail
|
||||
.addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f)));
|
||||
this.simpleInfoPanelUnitDetail.setWidth(GameUI.convertY(this.uiViewport, 0.180f));
|
||||
this.simpleInfoPanelUnitDetail.setHeight(GameUI.convertY(this.uiViewport, 0.105f));
|
||||
final float infoPanelUnitDetailWidth = GameUI.convertY(this.uiViewport, 0.180f);
|
||||
this.simpleInfoPanelUnitDetail.setWidth(infoPanelUnitDetailWidth);
|
||||
final float infoPanelUnitDetailHeight = GameUI.convertY(this.uiViewport, 0.105f);
|
||||
this.simpleInfoPanelUnitDetail.setHeight(infoPanelUnitDetailHeight);
|
||||
this.simpleNameValue = (StringFrame) this.rootFrame.getFrameByName("SimpleNameValue", 0);
|
||||
this.simpleClassValue = (StringFrame) this.rootFrame.getFrameByName("SimpleClassValue", 0);
|
||||
this.simpleBuildingActionLabel = (StringFrame) this.rootFrame.getFrameByName("SimpleBuildingActionLabel", 0);
|
||||
@ -297,8 +309,33 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
simpleBuildTimeIndicatorBar.setTexture("SimpleBuildTimeIndicator", this.rootFrame);
|
||||
final TextureFrame simpleBuildTimeIndicatorBorder = this.simpleBuildTimeIndicator.getBorderFrame();
|
||||
simpleBuildTimeIndicatorBorder.setTexture("SimpleBuildTimeIndicatorBorder", this.rootFrame);
|
||||
this.simpleBuildTimeIndicator.setWidth(GameUI.convertX(this.uiViewport, 0.10538f));
|
||||
this.simpleBuildTimeIndicator.setHeight(GameUI.convertY(this.uiViewport, 0.0103f));
|
||||
final float buildTimeIndicatorWidth = GameUI.convertX(this.uiViewport, 0.10538f);
|
||||
final float buildTimeIndicatorHeight = GameUI.convertY(this.uiViewport, 0.0103f);
|
||||
this.simpleBuildTimeIndicator.setWidth(buildTimeIndicatorWidth);
|
||||
this.simpleBuildTimeIndicator.setHeight(buildTimeIndicatorHeight);
|
||||
|
||||
// Create Simple Info Panel Building Detail
|
||||
this.simpleInfoPanelBuildingDetail = this.rootFrame.createSimpleFrame("SimpleInfoPanelBuildingDetail",
|
||||
this.consoleUI, 0);
|
||||
this.simpleInfoPanelBuildingDetail
|
||||
.addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f)));
|
||||
this.simpleInfoPanelBuildingDetail.setWidth(infoPanelUnitDetailWidth);
|
||||
this.simpleInfoPanelBuildingDetail.setHeight(infoPanelUnitDetailHeight);
|
||||
this.simpleBuildingNameValue = (StringFrame) this.rootFrame.getFrameByName("SimpleBuildingNameValue", 0);
|
||||
this.simpleBuildingDescriptionValue = (StringFrame) this.rootFrame
|
||||
.getFrameByName("SimpleBuildingDescriptionValue", 0);
|
||||
this.simpleBuildingBuildingActionLabel = (StringFrame) this.rootFrame
|
||||
.getFrameByName("SimpleBuildingActionLabel", 0);
|
||||
this.simpleBuildingBuildTimeIndicator = (SimpleStatusBarFrame) this.rootFrame
|
||||
.getFrameByName("SimpleBuildTimeIndicator", 0);
|
||||
final TextureFrame simpleBuildingBuildTimeIndicatorBar = this.simpleBuildingBuildTimeIndicator.getBarFrame();
|
||||
simpleBuildingBuildTimeIndicatorBar.setTexture("SimpleBuildTimeIndicator", this.rootFrame);
|
||||
final TextureFrame simpleBuildingBuildTimeIndicatorBorder = this.simpleBuildingBuildTimeIndicator
|
||||
.getBorderFrame();
|
||||
simpleBuildingBuildTimeIndicatorBorder.setTexture("SimpleBuildTimeIndicatorBorder", this.rootFrame);
|
||||
this.simpleBuildingBuildTimeIndicator.setWidth(buildTimeIndicatorWidth);
|
||||
this.simpleBuildingBuildTimeIndicator.setHeight(buildTimeIndicatorHeight);
|
||||
this.simpleInfoPanelBuildingDetail.setVisible(false);
|
||||
|
||||
this.attack1Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail,
|
||||
0);
|
||||
@ -494,7 +531,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
this.war3MapViewer.mapPathSolver, this.war3MapViewer.solverParams);
|
||||
this.cursorModelInstance = (MdxComplexInstance) model.addInstance();
|
||||
this.cursorModelInstance.setVertexColor(new float[] { 1, 1, 1, 0.5f });
|
||||
this.cursorModelInstance.setTeamColor(activeCommandUnit.getSimulationUnit().getPlayerIndex());
|
||||
this.cursorModelInstance.setTeamColor(this.activeCommandUnit.getSimulationUnit().getPlayerIndex());
|
||||
this.cursorModelInstance.rotate(RenderUnit.tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z,
|
||||
this.war3MapViewer.simulation.getGameplayConstants().getBuildingAngle()));
|
||||
this.cursorModelInstance.setAnimationSpeed(0f);
|
||||
@ -570,6 +607,14 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
.setValue(Math.min(this.selectedUnit.getSimulationUnit().getConstructionProgress()
|
||||
/ this.selectedUnit.getSimulationUnit().getUnitType().getBuildTime(), 0.99f));
|
||||
}
|
||||
if (this.simpleBuildingBuildTimeIndicator.isVisible() && (this.selectedUnit != null)) {
|
||||
this.simpleBuildingBuildTimeIndicator
|
||||
.setValue(Math.min(
|
||||
this.selectedUnit.getSimulationUnit().getConstructionProgress() / this.selectedUnit
|
||||
.getSimulationUnit().getBuildQueueTimeRemaining(this.war3MapViewer.simulation),
|
||||
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));
|
||||
@ -687,83 +732,110 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
|
||||
private void reloadSelectedUnitUI(final RenderUnit unit) {
|
||||
this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName());
|
||||
String classText = null;
|
||||
for (final CUnitClassification classification : unit.getSimulationUnit().getClassifications()) {
|
||||
if ((classification == CUnitClassification.MECHANICAL)
|
||||
&& unit.getSimulationUnit().getUnitType().isBuilding()) {
|
||||
// buildings dont display MECHANICAL
|
||||
continue;
|
||||
}
|
||||
if (classification.getDisplayName() != null) {
|
||||
classText = classification.getDisplayName();
|
||||
}
|
||||
}
|
||||
if (classText != null) {
|
||||
this.simpleClassValue.setText(classText);
|
||||
}
|
||||
else {
|
||||
this.simpleClassValue.setText("");
|
||||
}
|
||||
this.unitLifeText.setText(FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getLife()) + " / "
|
||||
+ unit.getSimulationUnit().getMaximumLife());
|
||||
final int maximumMana = unit.getSimulationUnit().getMaximumMana();
|
||||
final CUnit simulationUnit = unit.getSimulationUnit();
|
||||
this.unitLifeText.setText(
|
||||
FastNumberFormat.formatWholeNumber(simulationUnit.getLife()) + " / " + simulationUnit.getMaximumLife());
|
||||
final int maximumMana = simulationUnit.getMaximumMana();
|
||||
if (maximumMana > 0) {
|
||||
this.unitManaText.setText(
|
||||
FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getMana()) + " / " + maximumMana);
|
||||
this.unitManaText
|
||||
.setText(FastNumberFormat.formatWholeNumber(simulationUnit.getMana()) + " / " + maximumMana);
|
||||
}
|
||||
else {
|
||||
this.unitManaText.setText("");
|
||||
}
|
||||
this.simpleBuildingActionLabel.setText("");
|
||||
if (simulationUnit.getBuildQueue()[0] != null) {
|
||||
this.simpleInfoPanelBuildingDetail.setVisible(true);
|
||||
this.simpleInfoPanelUnitDetail.setVisible(false);
|
||||
this.simpleBuildingNameValue.setText(simulationUnit.getUnitType().getName());
|
||||
this.simpleBuildingDescriptionValue.setText("");
|
||||
|
||||
final boolean anyAttacks = unit.getSimulationUnit().getUnitType().getAttacks().size() > 0;
|
||||
final boolean constructing = unit.getSimulationUnit().isConstructing();
|
||||
final UIFrame localArmorIcon = this.armorIcon;
|
||||
final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop;
|
||||
final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue;
|
||||
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()));
|
||||
this.attack1InfoPanelIconValue.setText(attackOne.getMinDamage() + " - " + attackOne.getMaxDamage());
|
||||
if (unit.getSimulationUnit().getUnitType().getAttacks().size() > 1) {
|
||||
final CUnitAttack attackTwo = unit.getSimulationUnit().getUnitType().getAttacks().get(1);
|
||||
this.attack2Icon.setVisible(attackTwo.isShowUI());
|
||||
this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType()));
|
||||
this.attack2InfoPanelIconValue.setText(attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage());
|
||||
this.simpleBuildingBuildTimeIndicator.setVisible(true);
|
||||
this.simpleBuildTimeIndicator.setVisible(false);
|
||||
if (simulationUnit.getBuildQueueTypes()[0] == QueueItemType.UNIT) {
|
||||
this.simpleBuildingBuildingActionLabel
|
||||
.setText(this.rootFrame.getTemplates().getDecoratedString("TRAINING"));
|
||||
}
|
||||
else {
|
||||
this.attack2Icon.setVisible(false);
|
||||
this.simpleBuildingBuildingActionLabel
|
||||
.setText(this.rootFrame.getTemplates().getDecoratedString("RESEARCHING"));
|
||||
}
|
||||
|
||||
this.armorIcon
|
||||
.addSetPoint(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 {
|
||||
this.attack1Icon.setVisible(false);
|
||||
this.attack2Icon.setVisible(false);
|
||||
this.armorIcon.setVisible(false);
|
||||
}
|
||||
else {
|
||||
this.simpleInfoPanelBuildingDetail.setVisible(false);
|
||||
this.simpleInfoPanelUnitDetail.setVisible(true);
|
||||
this.simpleNameValue.setText(simulationUnit.getUnitType().getName());
|
||||
String classText = null;
|
||||
for (final CUnitClassification classification : simulationUnit.getClassifications()) {
|
||||
if ((classification == CUnitClassification.MECHANICAL) && simulationUnit.getUnitType().isBuilding()) {
|
||||
// buildings dont display MECHANICAL
|
||||
continue;
|
||||
}
|
||||
if (classification.getDisplayName() != null) {
|
||||
classText = classification.getDisplayName();
|
||||
}
|
||||
}
|
||||
if (classText != null) {
|
||||
this.simpleClassValue.setText(classText);
|
||||
}
|
||||
else {
|
||||
this.simpleClassValue.setText("");
|
||||
}
|
||||
|
||||
this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail,
|
||||
FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f)));
|
||||
this.armorIcon.positionBounds(this.uiViewport);
|
||||
}
|
||||
final boolean anyAttacks = simulationUnit.getUnitType().getAttacks().size() > 0;
|
||||
final boolean constructing = simulationUnit.isConstructing();
|
||||
final UIFrame localArmorIcon = this.armorIcon;
|
||||
final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop;
|
||||
final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue;
|
||||
if (anyAttacks && !constructing) {
|
||||
final CUnitAttack attackOne = simulationUnit.getUnitType().getAttacks().get(0);
|
||||
this.attack1Icon.setVisible(attackOne.isShowUI());
|
||||
this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType()));
|
||||
this.attack1InfoPanelIconValue.setText(attackOne.getMinDamage() + " - " + attackOne.getMaxDamage());
|
||||
if (simulationUnit.getUnitType().getAttacks().size() > 1) {
|
||||
final CUnitAttack attackTwo = simulationUnit.getUnitType().getAttacks().get(1);
|
||||
this.attack2Icon.setVisible(attackTwo.isShowUI());
|
||||
this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType()));
|
||||
this.attack2InfoPanelIconValue.setText(attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage());
|
||||
}
|
||||
else {
|
||||
this.attack2Icon.setVisible(false);
|
||||
}
|
||||
|
||||
localArmorIcon.setVisible(!constructing);
|
||||
this.simpleBuildTimeIndicator.setVisible(constructing);
|
||||
if (constructing) {
|
||||
this.simpleBuildingActionLabel.setText(this.rootFrame.getTemplates().getDecoratedString("CONSTRUCTING"));
|
||||
this.armorIcon.addSetPoint(
|
||||
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 {
|
||||
this.attack1Icon.setVisible(false);
|
||||
this.attack2Icon.setVisible(false);
|
||||
|
||||
this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail,
|
||||
FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f)));
|
||||
this.armorIcon.positionBounds(this.uiViewport);
|
||||
}
|
||||
|
||||
localArmorIcon.setVisible(!constructing);
|
||||
this.simpleBuildTimeIndicator.setVisible(constructing);
|
||||
this.simpleBuildingBuildTimeIndicator.setVisible(false);
|
||||
if (constructing) {
|
||||
this.simpleBuildingActionLabel
|
||||
.setText(this.rootFrame.getTemplates().getDecoratedString("CONSTRUCTING"));
|
||||
}
|
||||
else {
|
||||
this.simpleBuildingActionLabel.setText("");
|
||||
}
|
||||
final Texture defenseTexture = this.defenseBackdrops
|
||||
.getTexture(simulationUnit.getUnitType().getDefenseType());
|
||||
if (defenseTexture == null) {
|
||||
throw new RuntimeException(simulationUnit.getUnitType().getDefenseType() + " can't find texture!");
|
||||
}
|
||||
localArmorIconBackdrop.setTexture(defenseTexture);
|
||||
localArmorInfoPanelIconValue.setText(Integer.toString(simulationUnit.getDefense()));
|
||||
}
|
||||
final Texture defenseTexture = this.defenseBackdrops
|
||||
.getTexture(unit.getSimulationUnit().getUnitType().getDefenseType());
|
||||
if (defenseTexture == null) {
|
||||
throw new RuntimeException(
|
||||
unit.getSimulationUnit().getUnitType().getDefenseType() + " can't find texture!");
|
||||
}
|
||||
localArmorIconBackdrop.setTexture(defenseTexture);
|
||||
localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense()));
|
||||
clearAndRepopulateCommandCard();
|
||||
}
|
||||
|
||||
@ -779,8 +851,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon,
|
||||
final int abilityHandleId, final int orderId, final int autoCastId, final boolean active,
|
||||
final boolean autoCastActive, final boolean menuButton) {
|
||||
final int x = Math.max(0, Math.min(COMMAND_CARD_WIDTH - 1, buttonPositionX));
|
||||
final int y = Math.max(0, Math.min(COMMAND_CARD_HEIGHT - 1, buttonPositionY));
|
||||
int x = Math.max(0, Math.min(COMMAND_CARD_WIDTH - 1, buttonPositionX));
|
||||
int y = Math.max(0, Math.min(COMMAND_CARD_HEIGHT - 1, buttonPositionY));
|
||||
while (this.commandCard[y][x].isVisible() && (y < COMMAND_CARD_HEIGHT) && (x < COMMAND_CARD_WIDTH)) {
|
||||
x++;
|
||||
if (x >= COMMAND_CARD_WIDTH) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId, autoCastId, active, autoCastActive,
|
||||
menuButton);
|
||||
}
|
||||
@ -877,6 +956,11 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
reloadSelectedUnitUI(this.selectedUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueChanged() {
|
||||
reloadSelectedUnitUI(this.selectedUnit);
|
||||
}
|
||||
|
||||
private void clearAndRepopulateCommandCard() {
|
||||
clearCommandCard();
|
||||
final AbilityDataUI abilityDataUI = this.war3MapViewer.getAbilityDataUI();
|
||||
@ -885,9 +969,6 @@ 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 if (this.selectedUnit.getSimulationUnit().isConstructing()) {
|
||||
|
||||
}
|
||||
else {
|
||||
if (menuOrderId != 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user