mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Merge and some fixes, includes click drag ui test
This commit is contained in:
commit
5b7db285e2
@ -18,7 +18,7 @@ Path06="."
|
||||
[Map]
|
||||
//FilePath="CombatUnitTests.w3x"
|
||||
//FilePath="PitchRoll.w3x"
|
||||
//FilePath="PeonStartingBase.w3x"
|
||||
FilePath="PeonStartingBase.w3x"
|
||||
//FilePath="DungeonGoldMine.w3m"
|
||||
//FilePath="PlayerPeasants.w3m"
|
||||
//FilePath="FireLord.w3x"
|
||||
@ -29,4 +29,4 @@ Path06="."
|
||||
//FilePath="OrcAssault.w3x"
|
||||
//FilePath="FrostyVsFarm.w3m"
|
||||
//FilePath="ModelTest.w3x"
|
||||
FilePath="SpinningSample.w3x"
|
||||
//FilePath="SpinningSample.w3x"
|
@ -134,7 +134,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
}
|
||||
|
||||
final Element cameraData = this.viewer.miscData.get("Camera");
|
||||
final Element cameraListenerData = this.viewer.miscData.get("Listener");
|
||||
Element cameraListenerData = this.viewer.miscData.get("Listener");
|
||||
if (cameraListenerData == null) {
|
||||
cameraListenerData = new Element("Listener", new DataTable(null));
|
||||
}
|
||||
final CameraPreset[] cameraPresets = new CameraPreset[6];
|
||||
for (int i = 0; i < cameraPresets.length; i++) {
|
||||
cameraPresets[i] = new CameraPreset(cameraData.getFieldFloatValue("AOA", i),
|
||||
@ -353,6 +356,9 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(final char character) {
|
||||
if (character == '1') {
|
||||
Gdx.input.setCursorCatched(!Gdx.input.isCursorCatched());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -373,6 +379,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
||||
|
||||
@Override
|
||||
public boolean touchDragged(final int screenX, final int screenY, final int pointer) {
|
||||
final float worldScreenY = getHeight() - screenY;
|
||||
if (this.meleeUI.touchDragged(screenX, screenY, worldScreenY, pointer)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,14 @@ import com.etheller.warsmash.parsers.fdf.datamodel.SetPointDefinition;
|
||||
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
|
||||
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.AbstractUIFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.FilterModeTextureFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
||||
import com.etheller.warsmash.parsers.mdlx.Layer.FilterMode;
|
||||
import com.etheller.warsmash.units.DataTable;
|
||||
import com.etheller.warsmash.units.Element;
|
||||
import com.etheller.warsmash.util.ImageUtils;
|
||||
@ -211,6 +213,16 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|
||||
return textureFrame;
|
||||
}
|
||||
|
||||
public TextureFrame createTextureFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
|
||||
final Vector4Definition texCoord, final FilterMode filterMode) {
|
||||
final FilterModeTextureFrame textureFrame = new FilterModeTextureFrame(name, parent, decorateFileNames,
|
||||
texCoord);
|
||||
textureFrame.setFilterMode(filterMode);
|
||||
this.nameToFrame.put(name, textureFrame);
|
||||
add(textureFrame);
|
||||
return textureFrame;
|
||||
}
|
||||
|
||||
public StringFrame createStringFrame(final String name, final UIFrame parent, final Color color,
|
||||
final TextJustify justifyH, final TextJustify justifyV, final float fdfFontSize) {
|
||||
this.fontParam.size = (int) convertY(this.viewport, fdfFontSize);
|
||||
|
@ -25,6 +25,9 @@ public class StringFrame extends AbstractRenderableFrame {
|
||||
}
|
||||
|
||||
public void setText(final String text) {
|
||||
if (text == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
@ -63,4 +63,12 @@ public class TextureFrame extends AbstractRenderableFrame {
|
||||
public void setTexture(final TextureRegion texture) {
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
|
||||
if (this.renderBounds.contains(screenX, screenY)) {
|
||||
return this;
|
||||
}
|
||||
return super.touchDown(screenX, screenY, button);
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,43 @@ public class Quadtree<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean intersect(float x, float y, final QuadtreeIntersector<T> intersector) {
|
||||
if (this.leaf) {
|
||||
for (int i = 0; i < this.nodes.size; i++) {
|
||||
final Node<T> node = this.nodes.get(i);
|
||||
if (node.bounds.contains(x, y)) {
|
||||
if (intersector.onIntersect(node.object)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (this.northeast.bounds.contains(x, y)) {
|
||||
if (this.northeast.intersect(x, y, intersector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.northwest.bounds.contains(x, y)) {
|
||||
if (this.northwest.intersect(x, y, intersector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.southwest.bounds.contains(x, y)) {
|
||||
if (this.southwest.intersect(x, y, intersector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.southeast.bounds.contains(x, y)) {
|
||||
if (this.southeast.intersect(x, y, intersector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void add(final Node<T> node, final int depth) {
|
||||
if (this.leaf) {
|
||||
if ((this.nodes.size >= SPLIT_THRESHOLD) && (depth < MAX_DEPTH)) {
|
||||
|
@ -31,4 +31,8 @@ public class Bounds {
|
||||
public boolean intersectRayFast(final Ray ray) {
|
||||
return Intersector.intersectRayBoundsFast(ray, this.boundingBox);
|
||||
}
|
||||
|
||||
public BoundingBox getBoundingBox() {
|
||||
return boundingBox;
|
||||
}
|
||||
}
|
||||
|
@ -35,12 +35,13 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
@Override
|
||||
public InputStream read() {
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
;
|
||||
};
|
||||
if (data != null) {
|
||||
return Gdx.audio.newSound(temp);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
System.err.println("Warning: missing sound file: " + this.filename);
|
||||
return null;
|
||||
}
|
||||
@ -58,11 +59,9 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
stringBuilder.append(line);
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
}
|
||||
catch (final UnsupportedEncodingException e) {
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (final IOException e) {
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new MappedData(stringBuilder.toString());
|
||||
@ -96,10 +95,10 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
/**
|
||||
* If this is an SPL/UBR emitter object, ok will be set to true if the tables
|
||||
* are loaded.
|
||||
*
|
||||
* <p>
|
||||
* This is because, like the other geometry emitters, it is fine to use them
|
||||
* even if the textures don't load.
|
||||
*
|
||||
* <p>
|
||||
* The particles will simply be black.
|
||||
*/
|
||||
private boolean ok = false;
|
||||
@ -120,11 +119,9 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
|
||||
if ("SPL".equals(type)) {
|
||||
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPLAT;
|
||||
}
|
||||
else if ("UBR".equals(type)) {
|
||||
} else if ("UBR".equals(type)) {
|
||||
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_UBERSPLAT;
|
||||
}
|
||||
else if ("SPN".equals(type)) {
|
||||
} else if ("SPN".equals(type)) {
|
||||
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPN;
|
||||
}
|
||||
|
||||
@ -144,24 +141,20 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
if ("SPN".equals(type)) {
|
||||
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SpawnData.slk", solverParams).finalSrc,
|
||||
FetchDataTypeName.SLK, mappedDataCallback));
|
||||
}
|
||||
else if ("SPL".equals(type)) {
|
||||
} else if ("SPL".equals(type)) {
|
||||
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SplatData.slk", solverParams).finalSrc,
|
||||
FetchDataTypeName.SLK, mappedDataCallback));
|
||||
}
|
||||
else if ("UBR".equals(type)) {
|
||||
} else if ("UBR".equals(type)) {
|
||||
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\UberSplatData.slk", solverParams).finalSrc,
|
||||
FetchDataTypeName.SLK, mappedDataCallback));
|
||||
}
|
||||
else if ("SND".equals(type)) {
|
||||
} else if ("SND".equals(type)) {
|
||||
if (!model.reforged) {
|
||||
tables.add(viewer.loadGeneric(pathSolver.solve("UI\\SoundInfo\\AnimLookups.slk", solverParams).finalSrc,
|
||||
FetchDataTypeName.SLK, mappedDataCallback));
|
||||
}
|
||||
tables.add(viewer.loadGeneric(pathSolver.solve("UI\\SoundInfo\\AnimSounds.slk", solverParams).finalSrc,
|
||||
FetchDataTypeName.SLK, mappedDataCallback));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Units\Critters\BlackStagMale\BlackStagMale.mdx has an event object named
|
||||
// "Point01".
|
||||
return;
|
||||
@ -176,8 +169,7 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
final Float x = (Float) row.get(name);
|
||||
if (x == null) {
|
||||
return Float.NaN;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return x.floatValue();
|
||||
}
|
||||
}
|
||||
@ -190,14 +182,16 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
final Number x = (Number) row.get(name);
|
||||
if (x == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return x.intValue();
|
||||
}
|
||||
}
|
||||
|
||||
private void load(final List<GenericResource> tables) {
|
||||
final MappedData firstTable = (MappedData) tables.get(0).data;
|
||||
if (firstTable == null) {
|
||||
return;
|
||||
}
|
||||
final MappedDataRow row = firstTable.getRow(this.id.trim());
|
||||
|
||||
if (row != null) {
|
||||
@ -214,8 +208,7 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
// this.internalModel.whenLoaded((model) => this.ok = model.ok)
|
||||
this.ok = this.internalModel.ok;
|
||||
}
|
||||
}
|
||||
else if ("SPL".equals(this.type) || "UBR".equals(this.type)) {
|
||||
} else if ("SPL".equals(this.type) || "UBR".equals(this.type)) {
|
||||
final String texturesExt = model.reforged ? ".dds" : ".blp";
|
||||
|
||||
this.internalTexture = (Texture) viewer.load(
|
||||
@ -241,8 +234,7 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
getFloat(row, "LifespanRepeat")},
|
||||
{getFloat(row, "UVDecayStart"), getFloat(row, "UVDecayEnd"),
|
||||
getFloat(row, "DecayRepeat")},};
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.columns = 1;
|
||||
this.rows = 1;
|
||||
this.lifeSpan = getFloat(row, "BirthTime") + getFloat(row, "PauseTime") + getFloat(row, "Decay");
|
||||
@ -258,8 +250,7 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
this.blendDst = blendModes[1];
|
||||
|
||||
this.ok = true;
|
||||
}
|
||||
else if ("SND".equals(this.type)) {
|
||||
} else if ("SND".equals(this.type)) {
|
||||
// Only load sounds if audio is enabled.
|
||||
// This is mostly to save on bandwidth and loading time, especially when loading
|
||||
// full maps.
|
||||
@ -288,8 +279,7 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
System.err.println("Null sound: " + fileNames[i]);
|
||||
}
|
||||
resources[i] = genericResource;
|
||||
}
|
||||
catch (final Exception exc) {
|
||||
} catch (final Exception exc) {
|
||||
System.err.println("Failed to load sound: " + path);
|
||||
exc.printStackTrace();
|
||||
}
|
||||
@ -304,12 +294,10 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
this.ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
System.err.println("Unknown event object type: " + this.type + this.id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
System.err.println("Unknown event object ID: " + this.type + this.id);
|
||||
}
|
||||
}
|
||||
@ -318,13 +306,11 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
if (this.globalSequence != -1) {
|
||||
|
||||
return this.getValueAtTime(out, instance.counter % this.globalSequence, 0, this.globalSequence);
|
||||
}
|
||||
else if (instance.sequence != -1) {
|
||||
} else if (instance.sequence != -1) {
|
||||
final long[] interval = this.model.getSequences().get(instance.sequence).getInterval();
|
||||
|
||||
return this.getValueAtTime(out, instance.frame, interval[0], interval[1]);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out[0] = this.defval[0];
|
||||
|
||||
return -1;
|
||||
@ -338,8 +324,7 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
|
||||
out[0] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
else if (this.keyFrames[i] <= frame) {
|
||||
} else if (this.keyFrames[i] <= frame) {
|
||||
out[0] = 1;
|
||||
|
||||
return i;
|
||||
|
@ -160,14 +160,11 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
|
||||
if ("SPN".equals(type)) {
|
||||
emitter = new EventObjectSpnEmitter(this, emitterObject);
|
||||
}
|
||||
else if ("SPL".equals(type)) {
|
||||
} else if ("SPL".equals(type)) {
|
||||
emitter = new EventObjectSplEmitter(this, emitterObject);
|
||||
}
|
||||
else if ("UBR".equals(type)) {
|
||||
} else if ("UBR".equals(type)) {
|
||||
emitter = new EventObjectUbrEmitter(this, emitterObject);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
emitter = new EventObjectSndEmitter(this, emitterObject);
|
||||
}
|
||||
|
||||
@ -234,22 +231,18 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
|
||||
if (genericObject.parentId == -1) {
|
||||
node.parent = this;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
node.parent = nodes[genericObject.parentId];
|
||||
}
|
||||
|
||||
/// TODO: single-axis billboarding
|
||||
if (genericObject.billboarded != 0) {
|
||||
node.billboarded = true;
|
||||
}
|
||||
else if (genericObject.billboardedX != 0) {
|
||||
} else if (genericObject.billboardedX != 0) {
|
||||
node.billboardedX = true;
|
||||
}
|
||||
else if (genericObject.billboardedY != 0) {
|
||||
} else if (genericObject.billboardedY != 0) {
|
||||
node.billboardedY = true;
|
||||
}
|
||||
else if (genericObject.billboardedZ != 0) {
|
||||
} else if (genericObject.billboardedZ != 0) {
|
||||
node.billboardedZ = true;
|
||||
}
|
||||
|
||||
@ -412,8 +405,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
|
||||
geosetColor[3] = alphaHeap[0];
|
||||
}
|
||||
}
|
||||
else if (forced) {
|
||||
} else if (forced) {
|
||||
geosetColor[0] = 1;
|
||||
geosetColor[1] = 1;
|
||||
geosetColor[2] = 1;
|
||||
@ -464,8 +456,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
|
||||
uvAnim[4] = scaleHeap[0];
|
||||
}
|
||||
}
|
||||
else if (forced) {
|
||||
} else if (forced) {
|
||||
uvAnim[0] = 0;
|
||||
uvAnim[1] = 0;
|
||||
uvAnim[2] = 0;
|
||||
@ -545,8 +536,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
this.floatingFrame = this.frame = (int) interval[0]; // TODO not cast
|
||||
|
||||
this.resetEventEmitters();
|
||||
}
|
||||
else if (this.sequenceLoopMode == SequenceLoopMode.LOOP_TO_NEXT_ANIMATION) { // faux queued animation
|
||||
} else if (this.sequenceLoopMode == SequenceLoopMode.LOOP_TO_NEXT_ANIMATION) { // faux queued animation
|
||||
// mode
|
||||
final float framesPast = this.floatingFrame - interval[1];
|
||||
|
||||
@ -557,8 +547,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
this.sequenceEnded = false;
|
||||
this.resetEventEmitters();
|
||||
this.forced = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.floatingFrame = this.frame = (int) interval[1]; // TODO not cast
|
||||
this.counter -= integerFrameTime;
|
||||
this.allowParticleSpawn = false;
|
||||
@ -568,8 +557,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
}
|
||||
|
||||
this.sequenceEnded = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.sequenceEnded = false;
|
||||
}
|
||||
}
|
||||
@ -586,8 +574,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
// Update the batches
|
||||
this.updateBatches(forced);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// let variants = model.variants;
|
||||
|
||||
// if (forced || variants.nodes[sequenceId]) {
|
||||
@ -665,8 +652,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
this.frame = 0;
|
||||
this.floatingFrame = 0;
|
||||
this.allowParticleSpawn = false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.frame = (int) sequences.get(id).getInterval()[0]; // TODO not cast
|
||||
this.floatingFrame = this.frame;
|
||||
this.sequenceEnded = false;
|
||||
@ -734,15 +720,17 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
*
|
||||
* @param ray
|
||||
*/
|
||||
public boolean intersectRayWithCollision(final Ray ray, final Vector3 intersection, final boolean alwaysUseMesh) {
|
||||
public boolean intersectRayWithCollision(final Ray ray, final Vector3 intersection, final boolean alwaysUseMesh, final boolean onlyUseMesh) {
|
||||
final MdxModel mdxModel = (MdxModel) this.model;
|
||||
final List<CollisionShape> collisionShapes = mdxModel.collisionShapes;
|
||||
if (!onlyUseMesh) {
|
||||
for (final CollisionShape collisionShape : collisionShapes) {
|
||||
final MdxNode mdxNode = this.nodes[collisionShape.index];
|
||||
if (collisionShape.checkIntersect(ray, mdxNode, intersection)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collisionShapes.isEmpty() || alwaysUseMesh) {
|
||||
for (final Geoset geoset : mdxModel.geosets) {
|
||||
if (!geoset.unselectable) {
|
||||
|
@ -32,14 +32,14 @@ public class MdxHandler extends ModelHandler {
|
||||
Shaders.extendedShadowMap = viewer.webGL.createShaderProgram(
|
||||
"#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex, MdxShaders.fsComplexShadowMap);
|
||||
Shaders.particles = viewer.webGL.createShaderProgram(MdxShaders.vsParticles, MdxShaders.fsParticles);
|
||||
Shaders.simple = viewer.webGL.createShaderProgram(MdxShaders.vsSimple, MdxShaders.fsSimple);
|
||||
//Shaders.simple = viewer.webGL.createShaderProgram(MdxShaders.vsSimple, MdxShaders.fsSimple);
|
||||
// Shaders.hd = viewer.webGL.createShaderProgram(MdxShaders.vsHd, MdxShaders.fsHd);
|
||||
// TODO HD reforged
|
||||
|
||||
// If a shader failed to compile, don't allow the handler to be registered, and
|
||||
// send an error instead.
|
||||
return Shaders.complex.isCompiled() && Shaders.extended.isCompiled() && Shaders.particles.isCompiled()
|
||||
&& Shaders.simple.isCompiled() /* && Shaders.hd.isCompiled() */;
|
||||
/* && Shaders.simple.isCompiled() && Shaders.hd.isCompiled() */;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,6 +152,9 @@ public final class SdSequence<TYPE> {
|
||||
}
|
||||
|
||||
private TYPE[] fixTimelineArray(final Timeline<TYPE> timeline, final TYPE[] values) {
|
||||
if(values == null) {
|
||||
return null;
|
||||
}
|
||||
if (timeline.getName().equals(AnimationMap.KLAC.getWar3id())
|
||||
|| timeline.getName().equals(AnimationMap.KLBC.getWar3id())) {
|
||||
final float[][] flippedColorData = new float[values.length][3];
|
||||
|
@ -2,10 +2,13 @@ package com.etheller.warsmash.viewer5.handlers.w3x;
|
||||
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||
|
||||
public class RenderDestructable extends RenderDoodad {
|
||||
private static final War3ID TEX_FILE = War3ID.fromString("btxf");
|
||||
private static final War3ID TEX_ID = War3ID.fromString("btxi");
|
||||
|
||||
private final float life;
|
||||
|
||||
@ -14,6 +17,16 @@ public class RenderDestructable extends RenderDoodad {
|
||||
final float maxPitch, final float maxRoll, final float life) {
|
||||
super(map, model, row, doodad, type, maxPitch, maxRoll);
|
||||
this.life = life;
|
||||
String replaceableTextureFile = row.getFieldAsString(TEX_FILE, 0);
|
||||
final int replaceableTextureId = row.getFieldAsInteger(TEX_ID, 0);
|
||||
if ((replaceableTextureFile != null) && (replaceableTextureFile.length() > 1)) {
|
||||
int dotIndex = replaceableTextureFile.lastIndexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
replaceableTextureFile = replaceableTextureFile.substring(0, dotIndex);
|
||||
}
|
||||
replaceableTextureFile += ".blp";
|
||||
instance.setReplaceableTexture(replaceableTextureId, replaceableTextureFile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -13,8 +13,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||
|
||||
public class RenderDoodad {
|
||||
private static final int SAMPLE_RADIUS = 4;
|
||||
private static final War3ID TEX_FILE = War3ID.fromString("btxf");
|
||||
private static final War3ID TEX_ID = War3ID.fromString("btxi");
|
||||
public final ModelInstance instance;
|
||||
private final MutableGameObject row;
|
||||
private final float maxPitch;
|
||||
@ -30,8 +28,7 @@ public class RenderDoodad {
|
||||
|
||||
if (isSimple && false) {
|
||||
instance = model.addInstance(1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
instance = model.addInstance();
|
||||
((MdxComplexInstance) instance).setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
|
||||
}
|
||||
@ -74,17 +71,6 @@ public class RenderDoodad {
|
||||
final float defScale = row.readSLKTagFloat("defScale");
|
||||
instance.uniformScale(defScale);
|
||||
}
|
||||
if (type == WorldEditorDataType.DESTRUCTIBLES) {
|
||||
// TODO destructables need to be their own type, game simulation, etc
|
||||
String replaceableTextureFile = row.getFieldAsString(TEX_FILE, 0);
|
||||
final int replaceableTextureId = row.getFieldAsInteger(TEX_ID, 0);
|
||||
if ((replaceableTextureFile != null) && (replaceableTextureFile.length() > 1)) {
|
||||
if (!replaceableTextureFile.toLowerCase().endsWith(".blp")) {
|
||||
replaceableTextureFile += ".blp";
|
||||
}
|
||||
instance.setReplaceableTexture(replaceableTextureId, replaceableTextureFile);
|
||||
}
|
||||
}
|
||||
instance.setScene(map.worldScene);
|
||||
|
||||
this.instance = instance;
|
||||
|
@ -26,6 +26,7 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.math.collision.BoundingBox;
|
||||
import com.badlogic.gdx.math.collision.Ray;
|
||||
import com.etheller.warsmash.common.FetchDataTypeName;
|
||||
import com.etheller.warsmash.common.LoadGenericCallback;
|
||||
@ -48,6 +49,8 @@ import com.etheller.warsmash.units.manager.MutableObjectData;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
||||
import com.etheller.warsmash.util.MappedData;
|
||||
import com.etheller.warsmash.util.Quadtree;
|
||||
import com.etheller.warsmash.util.QuadtreeIntersector;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
@ -85,12 +88,14 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitFilterFunction
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.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.combat.attacks.CUnitAttackInstant;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissile;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CWidgetAbilityTargetCheckReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.PointAbilityTargetCheckReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
|
||||
|
||||
import mpq.MPQArchive;
|
||||
@ -117,10 +122,11 @@ public class War3MapViewer extends ModelViewer {
|
||||
private static final War3ID sloc = War3ID.fromString("sloc");
|
||||
private static final LoadGenericCallback stringDataCallback = new StringDataCallbackImplementation();
|
||||
private static final float[] rayHeap = new float[6];
|
||||
private static final Ray gdxRayHeap = new Ray();
|
||||
public static final Ray gdxRayHeap = new Ray();
|
||||
private static final Vector2 mousePosHeap = new Vector2();
|
||||
private static final Vector3 normalHeap = new Vector3();
|
||||
private static final Vector3 intersectionHeap = new Vector3();
|
||||
public static final Vector3 intersectionHeap = new Vector3();
|
||||
private static final Rectangle rectangleHeap = new Rectangle();
|
||||
public static final StreamDataCallbackImplementation streamDataCallback = new StreamDataCallbackImplementation();
|
||||
|
||||
public PathSolver wc3PathSolver = PathSolver.DEFAULT;
|
||||
@ -185,6 +191,11 @@ public class War3MapViewer extends ModelViewer {
|
||||
private GameUI gameUI;
|
||||
private Vector3 lightDirection;
|
||||
|
||||
private Quadtree<MdxComplexInstance> walkableObjectsTree;
|
||||
private final QuadtreeIntersectorFindsWalkableRenderHeight walkablesIntersector = new QuadtreeIntersectorFindsWalkableRenderHeight();
|
||||
private final QuadtreeIntersectorFindsHitPoint walkablesIntersectionFinder = new QuadtreeIntersectorFindsHitPoint();
|
||||
private final QuadtreeIntersectorFindsHighestWalkable intersectorFindsHighestWalkable = new QuadtreeIntersectorFindsHighestWalkable();
|
||||
|
||||
public War3MapViewer(final DataSource dataSource, final CanvasProvider canvas) {
|
||||
super(dataSource, canvas);
|
||||
this.gameDataSource = dataSource;
|
||||
@ -501,10 +512,9 @@ public class War3MapViewer extends ModelViewer {
|
||||
War3MapViewer.this.units.remove(renderUnit);
|
||||
War3MapViewer.this.worldScene.removeInstance(renderUnit.instance);
|
||||
}
|
||||
}, this.terrain.pathingGrid,
|
||||
new Rectangle(centerOffset[0], centerOffset[1], (mapSize[0] * 128f) - 128, (mapSize[1] * 128f) - 128),
|
||||
this.seededRandom, w3iFile.getPlayers());
|
||||
}, this.terrain.pathingGrid, this.terrain.getEntireMap(), this.seededRandom, w3iFile.getPlayers());
|
||||
|
||||
this.walkableObjectsTree = new Quadtree<>(this.terrain.getEntireMap());
|
||||
if (this.doodadsAndDestructiblesLoaded) {
|
||||
this.loadDoodadsAndDestructibles(this.allObjectData);
|
||||
}
|
||||
@ -632,8 +642,20 @@ public class War3MapViewer extends ModelViewer {
|
||||
}
|
||||
|
||||
if (type == WorldEditorDataType.DESTRUCTIBLES) {
|
||||
this.doodads.add(new RenderDestructable(this, model, row, doodad, type, maxPitch, maxRoll,
|
||||
doodad.getLife()));
|
||||
final RenderDestructable renderDestructable = new RenderDestructable(this, model, row, doodad, type,
|
||||
maxPitch, maxRoll, doodad.getLife());
|
||||
if (row.readSLKTagBoolean("walkable")) {
|
||||
final float x = doodad.getLocation()[0];
|
||||
final float y = doodad.getLocation()[1];
|
||||
final BoundingBox boundingBox = model.bounds.getBoundingBox();
|
||||
final float minX = boundingBox.min.x + x;
|
||||
final float minY = boundingBox.min.y + y;
|
||||
final Rectangle renderDestructableBounds = new Rectangle(minX, minY, boundingBox.getWidth(),
|
||||
boundingBox.getHeight());
|
||||
this.walkableObjectsTree.add((MdxComplexInstance) renderDestructable.instance,
|
||||
renderDestructableBounds);
|
||||
}
|
||||
this.doodads.add(renderDestructable);
|
||||
}
|
||||
else {
|
||||
this.doodads.add(new RenderDoodad(this, model, row, doodad, type, maxPitch, maxRoll));
|
||||
@ -1080,6 +1102,15 @@ public class War3MapViewer extends ModelViewer {
|
||||
gdxRayHeap.direction.nor();// needed for libgdx
|
||||
RenderMathUtils.intersectRayTriangles(gdxRayHeap, this.terrain.softwareGroundMesh.vertices,
|
||||
this.terrain.softwareGroundMesh.indices, 3, out);
|
||||
rectangleHeap.set(Math.min(out.x, gdxRayHeap.origin.x), Math.min(out.y, gdxRayHeap.origin.y),
|
||||
Math.abs(out.x - gdxRayHeap.origin.x), Math.abs(out.y - gdxRayHeap.origin.y));
|
||||
this.walkableObjectsTree.intersect(rectangleHeap, this.walkablesIntersectionFinder.reset(gdxRayHeap));
|
||||
if (this.walkablesIntersectionFinder.found) {
|
||||
out.set(this.walkablesIntersectionFinder.intersection);
|
||||
}
|
||||
else {
|
||||
out.z = Math.max(getWalkableRenderHeight(out.x, out.y), this.terrain.getGroundHeight(out.x, out.y));
|
||||
}
|
||||
}
|
||||
|
||||
public void showConfirmation(final Vector3 position, final float red, final float green, final float blue) {
|
||||
@ -1105,11 +1136,13 @@ public class War3MapViewer extends ModelViewer {
|
||||
final MdxComplexInstance instance = unit.instance;
|
||||
if (instance.isVisible(this.worldScene.camera)
|
||||
&& instance.intersectRayWithCollision(gdxRayHeap, intersectionHeap,
|
||||
unit.getSimulationUnit().getUnitType().isBuilding())
|
||||
unit.getSimulationUnit().getUnitType().isBuilding(), false)
|
||||
&& !unit.getSimulationUnit().isDead()) {
|
||||
if ((entity == null) || (entity.instance.depth > instance.depth)) {
|
||||
entity = unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<RenderUnit> sel;
|
||||
if (entity != null) {
|
||||
if (toggle) {
|
||||
@ -1148,7 +1181,7 @@ public class War3MapViewer extends ModelViewer {
|
||||
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())) {
|
||||
intersectionHeap, unit.getSimulationUnit().getUnitType().isBuilding(), false)) {
|
||||
if (filter.call(unit.getSimulationUnit())) {
|
||||
if ((entity == null) || (entity.instance.depth > instance.depth)) {
|
||||
entity = unit;
|
||||
@ -1242,6 +1275,41 @@ public class War3MapViewer extends ModelViewer {
|
||||
return (numElements < 0) ? 1 : (numElements >= MAXIMUM_ACCEPTED) ? MAXIMUM_ACCEPTED : numElements + 1;
|
||||
}
|
||||
|
||||
public boolean orderSmart(final float x, final float y) {
|
||||
mousePosHeap.x = x;
|
||||
mousePosHeap.y = y;
|
||||
boolean ordered = false;
|
||||
for (final RenderUnit unit : this.selected) {
|
||||
for (final CAbility ability : unit.getSimulationUnit().getAbilities()) {
|
||||
if (ability instanceof CAbilityMove) {
|
||||
ability.checkCanUse(this.simulation, unit.getSimulationUnit(), OrderIds.smart,
|
||||
BooleanAbilityActivationReceiver.INSTANCE);
|
||||
if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) {
|
||||
ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap,
|
||||
PointAbilityTargetCheckReceiver.INSTANCE);
|
||||
final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget();
|
||||
if (target != null) {
|
||||
ability.onOrder(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap,
|
||||
false);
|
||||
ordered = true;
|
||||
}
|
||||
else {
|
||||
System.err.println("Target not valid.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("Ability not ok to use.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("Ability not move.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return ordered;
|
||||
}
|
||||
|
||||
public boolean orderSmart(final RenderUnit target) {
|
||||
boolean ordered = false;
|
||||
for (final RenderUnit unit : this.selected) {
|
||||
@ -1348,4 +1416,82 @@ public class War3MapViewer extends ModelViewer {
|
||||
public AbilityDataUI getAbilityDataUI() {
|
||||
return this.abilityDataUI;
|
||||
}
|
||||
|
||||
public float getWalkableRenderHeight(final float x, final float y) {
|
||||
this.walkableObjectsTree.intersect(x, y, this.walkablesIntersector.reset(x, y));
|
||||
return this.walkablesIntersector.z;
|
||||
}
|
||||
|
||||
public MdxComplexInstance getHighestWalkableUnder(final float x, final float y) {
|
||||
this.walkableObjectsTree.intersect(x, y, this.intersectorFindsHighestWalkable.reset(x, y));
|
||||
return this.intersectorFindsHighestWalkable.highestInstance;
|
||||
}
|
||||
|
||||
private static final class QuadtreeIntersectorFindsWalkableRenderHeight
|
||||
implements QuadtreeIntersector<MdxComplexInstance> {
|
||||
private float z;
|
||||
private final Ray ray = new Ray();
|
||||
private final Vector3 intersection = new Vector3();
|
||||
|
||||
private QuadtreeIntersectorFindsWalkableRenderHeight reset(final float x, final float y) {
|
||||
this.z = -Float.MAX_VALUE;
|
||||
this.ray.set(x, y, 4096, 0, 0, -8192);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onIntersect(final MdxComplexInstance intersectingObject) {
|
||||
if (intersectingObject.intersectRayWithCollision(this.ray, this.intersection, true, true)) {
|
||||
this.z = Math.max(this.z, this.intersection.z);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class QuadtreeIntersectorFindsHighestWalkable
|
||||
implements QuadtreeIntersector<MdxComplexInstance> {
|
||||
private float z;
|
||||
private final Ray ray = new Ray();
|
||||
private final Vector3 intersection = new Vector3();
|
||||
private MdxComplexInstance highestInstance;
|
||||
|
||||
private QuadtreeIntersectorFindsHighestWalkable reset(final float x, final float y) {
|
||||
this.z = -Float.MAX_VALUE;
|
||||
this.ray.set(x, y, 4096, 0, 0, -8192);
|
||||
this.highestInstance = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onIntersect(final MdxComplexInstance intersectingObject) {
|
||||
if (intersectingObject.intersectRayWithCollision(this.ray, this.intersection, true, true)) {
|
||||
if (this.intersection.z > this.z) {
|
||||
this.z = this.intersection.z;
|
||||
this.highestInstance = intersectingObject;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class QuadtreeIntersectorFindsHitPoint implements QuadtreeIntersector<MdxComplexInstance> {
|
||||
private Ray ray;
|
||||
private final Vector3 intersection = new Vector3();
|
||||
private boolean found;
|
||||
|
||||
private QuadtreeIntersectorFindsHitPoint reset(final Ray ray) {
|
||||
this.ray = ray;
|
||||
this.found = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onIntersect(final MdxComplexInstance intersectingObject) {
|
||||
if (intersectingObject.intersectRayWithCollision(this.ray, this.intersection, true, true)) {
|
||||
this.found = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -411,6 +411,7 @@ public class Terrain {
|
||||
this.shaderMapBoundsRectangle = new Rectangle(this.shaderMapBounds[0], this.shaderMapBounds[1],
|
||||
this.shaderMapBounds[2] - this.shaderMapBounds[0], this.shaderMapBounds[3] - this.shaderMapBounds[1]);
|
||||
this.mapSize = w3eFile.getMapSize();
|
||||
this.entireMapRectangle = new Rectangle(centerOffset[0], centerOffset[1], (mapSize[0] * 128f) - 128, (mapSize[1] * 128f) - 128);
|
||||
this.softwareGroundMesh = new SoftwareGroundMesh(this.groundHeights, this.groundCornerHeights,
|
||||
this.centerOffset, width, height);
|
||||
|
||||
@ -1019,15 +1020,14 @@ public class Terrain {
|
||||
gl.glUniform1i(6, (int) this.waterIndex);
|
||||
gl.glUniform1f(this.waterShader.getUniformLocation("centerOffsetX"), this.centerOffset[0]);
|
||||
gl.glUniform1f(this.waterShader.getUniformLocation("centerOffsetY"), this.centerOffset[1]);
|
||||
gl.glUniform4fv(9, 1, this.shaderMapBounds, 0);
|
||||
gl.glUniform4fv(11, 1, this.shaderMapBounds, 0);
|
||||
|
||||
final W3xSceneLightManager lightManager = (W3xSceneLightManager) this.viewer.worldScene.getLightManager();
|
||||
final DataTexture unitLightsTexture = lightManager.getTerrainLightsTexture();
|
||||
final DataTexture terrainLightsTexture = lightManager.getTerrainLightsTexture();
|
||||
|
||||
unitLightsTexture.bind(21);
|
||||
gl.glUniform1i(this.waterShader.getUniformLocation("lightTexture"), 21);
|
||||
gl.glUniform1f(this.waterShader.getUniformLocation("lightCount"), lightManager.getTerrainLightCount());
|
||||
gl.glUniform1f(this.waterShader.getUniformLocation("lightCountHeight"), unitLightsTexture.getHeight());
|
||||
terrainLightsTexture.bind(3);
|
||||
gl.glUniform1f(9, lightManager.getTerrainLightCount());
|
||||
gl.glUniform1f(10, terrainLightsTexture.getHeight());
|
||||
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE0);
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.waterHeight);
|
||||
@ -1035,7 +1035,7 @@ public class Terrain {
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.groundCornerHeight);
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE2);
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.waterExists);
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE3);
|
||||
gl.glActiveTexture(GL30.GL_TEXTURE4);
|
||||
gl.glBindTexture(GL30.GL_TEXTURE_2D_ARRAY, this.waterTextureArray);
|
||||
|
||||
gl.glBindBuffer(GL30.GL_ARRAY_BUFFER, Shapes.INSTANCE.vertexBuffer);
|
||||
@ -1239,6 +1239,7 @@ public class Terrain {
|
||||
private final WaveBuilder waveBuilder;
|
||||
public PathingGrid pathingGrid;
|
||||
private final Rectangle shaderMapBoundsRectangle;
|
||||
private final Rectangle entireMapRectangle;
|
||||
|
||||
private static final class UnloadedTexture {
|
||||
private final int width;
|
||||
@ -1399,4 +1400,8 @@ public class Terrain {
|
||||
public Rectangle getPlayableMapArea() {
|
||||
return this.shaderMapBoundsRectangle;
|
||||
}
|
||||
|
||||
public Rectangle getEntireMap() {
|
||||
return entireMapRectangle;
|
||||
}
|
||||
}
|
||||
|
@ -428,9 +428,9 @@ public class TerrainShaders {
|
||||
"layout (location = 3) uniform vec4 deep_color_min;\r\n" + //
|
||||
"layout (location = 4) uniform vec4 deep_color_max;\r\n" + //
|
||||
"layout (location = 5) uniform float water_offset;\r\n" + //
|
||||
"layout (location = 10) uniform sampler2D lightTexture;\r\n" + //
|
||||
"layout (location = 11) uniform float lightCount;\r\n" + //
|
||||
"layout (location = 12) uniform float lightTextureHeight;\r\n" + //
|
||||
"layout (binding = 3) uniform sampler2D lightTexture;\r\n" + //
|
||||
"layout (location = 9) uniform float lightCount;\r\n" + //
|
||||
"layout (location = 10) uniform float lightTextureHeight;\r\n" + //
|
||||
"\r\n" + //
|
||||
"out vec2 UV;\r\n" + //
|
||||
"out vec4 Color;\r\n" + //
|
||||
@ -477,12 +477,12 @@ public class TerrainShaders {
|
||||
|
||||
public static final String frag = "#version 450 core\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (binding = 3) uniform sampler2DArray water_textures;\r\n" + //
|
||||
"layout (binding = 4) uniform sampler2DArray water_textures;\r\n" + //
|
||||
"layout (binding = 2) uniform sampler2D water_exists_texture;\r\n" + //
|
||||
"\r\n" + //
|
||||
"\r\n" + //
|
||||
"layout (location = 6) uniform int current_texture;\r\n" + //
|
||||
"layout (location = 9) uniform vec4 mapBounds;\r\n" + //
|
||||
"layout (location = 11) uniform vec4 mapBounds;\r\n" + //
|
||||
"\r\n" + //
|
||||
"in vec2 UV;\r\n" + //
|
||||
"in vec4 Color;\r\n" + //
|
||||
|
@ -24,6 +24,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.Moveme
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButtonListener;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandCardPopulatingAbilityVisitor;
|
||||
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.CUnitAnimationListener;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
|
||||
@ -131,10 +132,11 @@ public class RenderUnit {
|
||||
|
||||
}
|
||||
|
||||
public void populateCommandCard(final CommandButtonListener commandButtonListener,
|
||||
public void populateCommandCard(final CSimulation game, final CommandButtonListener commandButtonListener,
|
||||
final AbilityDataUI abilityDataUI) {
|
||||
for (final CAbility ability : this.simulationUnit.getAbilities()) {
|
||||
ability.visit(CommandCardPopulatingAbilityVisitor.INSTANCE.reset(commandButtonListener, abilityDataUI));
|
||||
ability.visit(CommandCardPopulatingAbilityVisitor.INSTANCE.reset(game, this.simulationUnit,
|
||||
commandButtonListener, abilityDataUI));
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,15 +168,43 @@ public class RenderUnit {
|
||||
final float groundHeight;
|
||||
final MovementType movementType = this.simulationUnit.getUnitType().getMovementType();
|
||||
final short terrainPathing = map.terrain.pathingGrid.getPathing(x, y);
|
||||
final boolean swimming = (movementType == MovementType.AMPHIBIOUS)
|
||||
boolean swimming = (movementType == MovementType.AMPHIBIOUS)
|
||||
&& PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.SWIMMABLE)
|
||||
&& !PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.WALKABLE);
|
||||
if ((swimming) || (movementType == MovementType.FLOAT) || (movementType == MovementType.FLY)
|
||||
|| (movementType == MovementType.HOVER)) {
|
||||
groundHeight = Math.max(map.terrain.getGroundHeight(x, y), map.terrain.getWaterHeight(x, y));
|
||||
final float groundHeightTerrain = map.terrain.getGroundHeight(x, y);
|
||||
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));
|
||||
}
|
||||
else {
|
||||
groundHeight = map.terrain.getGroundHeight(x, y);
|
||||
// land units will have their feet pass under the surface of the water
|
||||
groundHeightTerrainAndWater = groundHeightTerrain;
|
||||
}
|
||||
if (movementType == MovementType.FLOAT) {
|
||||
// boats cant go on bridges
|
||||
groundHeight = groundHeightTerrainAndWater;
|
||||
currentWalkableUnder = null;
|
||||
}
|
||||
else {
|
||||
currentWalkableUnder = map.getHighestWalkableUnder(x, y);
|
||||
if (currentWalkableUnder != null) {
|
||||
System.out.println("WALKABLE UNDER");
|
||||
}
|
||||
War3MapViewer.gdxRayHeap.set(x, y, 4096, 0, 0, -8192);
|
||||
if ((currentWalkableUnder != null)
|
||||
&& currentWalkableUnder.intersectRayWithCollision(War3MapViewer.gdxRayHeap,
|
||||
War3MapViewer.intersectionHeap, true, true)
|
||||
&& (War3MapViewer.intersectionHeap.z > groundHeightTerrainAndWater)) {
|
||||
groundHeight = War3MapViewer.intersectionHeap.z;
|
||||
swimming = false; // Naga Royal Guard should slither across a bridge, not swim in rock
|
||||
}
|
||||
else {
|
||||
groundHeight = groundHeightTerrainAndWater;
|
||||
currentWalkableUnder = null;
|
||||
}
|
||||
}
|
||||
if (swimming && !this.swimming) {
|
||||
this.unitAnimationListenerImpl.addSecondaryTag(AnimationTokens.SecondaryTag.SWIM);
|
||||
@ -263,17 +293,49 @@ public class RenderUnit {
|
||||
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 pitchSampleGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
|
||||
final float pitchSampleGorundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
|
||||
pitch = Math.max(-maxPitch, Math.min(maxPitch,
|
||||
(float) Math.atan2(pitchSampleGorundHeight2 - pitchSampleGroundHeight1, sampleRadius * 2)));
|
||||
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 rollSampleGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
|
||||
final float rollSampleGroundHeight2 = map.terrain.getGroundHeight(rollSampleForwardX, rollSampleForwardY);
|
||||
final float pitchSampleGroundHeight1;
|
||||
final float pitchSampleGroundHeight2;
|
||||
final float rollSampleGroundHeight1;
|
||||
final float rollSampleGroundHeight2;
|
||||
if (currentWalkableUnder != null) {
|
||||
pitchSampleGroundHeight1 = getGroundHeightSample(groundHeight, currentWalkableUnder, pitchSampleBackwardX,
|
||||
pitchSampleBackwardY);
|
||||
pitchSampleGroundHeight2 = getGroundHeightSample(groundHeight, currentWalkableUnder, pitchSampleForwardX,
|
||||
pitchSampleForwardY);
|
||||
rollSampleGroundHeight1 = getGroundHeightSample(groundHeight, currentWalkableUnder, rollSampleBackwardX,
|
||||
rollSampleBackwardY);
|
||||
rollSampleGroundHeight2 = getGroundHeightSample(groundHeight, currentWalkableUnder, rollSampleForwardX,
|
||||
rollSampleForwardY);
|
||||
}
|
||||
else {
|
||||
final float pitchGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
|
||||
final float pitchGroundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
|
||||
final float rollGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
|
||||
final float rollGroundHeight2 = map.terrain.getGroundHeight(rollSampleForwardX, rollSampleForwardY);
|
||||
if (standingOnWater) {
|
||||
pitchSampleGroundHeight1 = Math.max(pitchGroundHeight1,
|
||||
map.terrain.getWaterHeight(pitchSampleBackwardX, pitchSampleBackwardY));
|
||||
pitchSampleGroundHeight2 = Math.max(pitchGroundHeight2,
|
||||
map.terrain.getWaterHeight(pitchSampleForwardX, pitchSampleForwardY));
|
||||
rollSampleGroundHeight1 = Math.max(rollGroundHeight1,
|
||||
map.terrain.getWaterHeight(rollSampleBackwardX, rollSampleBackwardY));
|
||||
rollSampleGroundHeight2 = Math.max(rollGroundHeight2,
|
||||
map.terrain.getWaterHeight(rollSampleForwardX, rollSampleForwardY));
|
||||
}
|
||||
else {
|
||||
pitchSampleGroundHeight1 = pitchGroundHeight1;
|
||||
pitchSampleGroundHeight2 = pitchGroundHeight2;
|
||||
rollSampleGroundHeight1 = rollGroundHeight1;
|
||||
rollSampleGroundHeight2 = rollGroundHeight2;
|
||||
}
|
||||
}
|
||||
pitch = Math.max(-maxPitch, Math.min(maxPitch,
|
||||
(float) Math.atan2(pitchSampleGroundHeight2 - pitchSampleGroundHeight1, sampleRadius * 2)));
|
||||
roll = Math.max(-maxRoll, Math.min(maxRoll,
|
||||
(float) Math.atan2(rollSampleGroundHeight2 - rollSampleGroundHeight1, sampleRadius * 2)));
|
||||
this.instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Y, -pitch));
|
||||
@ -289,6 +351,21 @@ public class RenderUnit {
|
||||
this.unitAnimationListenerImpl.update();
|
||||
}
|
||||
|
||||
private float getGroundHeightSample(final float groundHeight, final MdxComplexInstance currentWalkableUnder,
|
||||
final float sampleX, final float sampleY) {
|
||||
final float sampleGroundHeight;
|
||||
War3MapViewer.gdxRayHeap.origin.x = sampleX;
|
||||
War3MapViewer.gdxRayHeap.origin.y = sampleY;
|
||||
if (currentWalkableUnder.intersectRayWithCollision(War3MapViewer.gdxRayHeap, War3MapViewer.intersectionHeap,
|
||||
true, true)) {
|
||||
sampleGroundHeight = War3MapViewer.intersectionHeap.z;
|
||||
}
|
||||
else {
|
||||
sampleGroundHeight = groundHeight;
|
||||
}
|
||||
return sampleGroundHeight;
|
||||
}
|
||||
|
||||
public CUnit getSimulationUnit() {
|
||||
return this.simulationUnit;
|
||||
}
|
||||
|
@ -34,5 +34,6 @@ public interface CommandButtonListener {
|
||||
// int getButtonPositionY();
|
||||
//
|
||||
// int getOrderId();
|
||||
void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int abilityHandleId, int orderId);
|
||||
void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int abilityHandleId, int orderId,
|
||||
boolean active);
|
||||
}
|
||||
|
@ -2,20 +2,29 @@ package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
|
||||
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.IconUI;
|
||||
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.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.CAbilityVisitor;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
|
||||
|
||||
public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void> {
|
||||
public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor();
|
||||
|
||||
private CSimulation game;
|
||||
private CUnit unit;
|
||||
|
||||
private CommandButtonListener commandButtonListener;
|
||||
private AbilityDataUI abilityDataUI;
|
||||
private boolean hasStop;
|
||||
|
||||
public CommandCardPopulatingAbilityVisitor reset(final CommandButtonListener commandButtonListener,
|
||||
final AbilityDataUI abilityDataUI) {
|
||||
public CommandCardPopulatingAbilityVisitor reset(final CSimulation game, final CUnit unit,
|
||||
final CommandButtonListener commandButtonListener, final AbilityDataUI abilityDataUI) {
|
||||
this.game = game;
|
||||
this.unit = unit;
|
||||
this.commandButtonListener = commandButtonListener;
|
||||
this.abilityDataUI = abilityDataUI;
|
||||
this.hasStop = false;
|
||||
@ -24,28 +33,41 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityAttack ability) {
|
||||
addCommandButton(this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack);
|
||||
addCommandButton(ability, this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack);
|
||||
if (!this.hasStop) {
|
||||
this.hasStop = true;
|
||||
addCommandButton(this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
|
||||
addCommandButton(null, this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void accept(final CAbilityMove ability) {
|
||||
addCommandButton(this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move);
|
||||
addCommandButton(this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition);
|
||||
addCommandButton(this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol);
|
||||
addCommandButton(ability, this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move);
|
||||
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition);
|
||||
addCommandButton(ability, this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol);
|
||||
if (!this.hasStop) {
|
||||
this.hasStop = true;
|
||||
addCommandButton(this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
|
||||
addCommandButton(null, this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addCommandButton(final IconUI iconUI, final int handleId, final int orderId) {
|
||||
private void addCommandButton(final CAbility ability, final IconUI iconUI, final int handleId, final int orderId) {
|
||||
final boolean active;
|
||||
if (this.unit.getCurrentOrder() == null) {
|
||||
active = (orderId == OrderIds.stop);
|
||||
}
|
||||
else {
|
||||
if (ability == null) {
|
||||
active = false;
|
||||
}
|
||||
else {
|
||||
ability.checkCanUse(this.game, this.unit, orderId, BooleanAbilityActivationReceiver.INSTANCE);
|
||||
active = BooleanAbilityActivationReceiver.INSTANCE.isOk();
|
||||
}
|
||||
}
|
||||
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
|
||||
iconUI.getIcon(), handleId, orderId);
|
||||
iconUI.getIcon(), handleId, orderId, active);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CAttackOrder;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorAttack;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehavior;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
|
||||
@ -37,8 +38,8 @@ public class CUnit extends CWidget {
|
||||
|
||||
private final List<CAbility> abilities = new ArrayList<>();
|
||||
|
||||
private COrder currentOrder;
|
||||
private final Queue<COrder> orderQueue = new LinkedList<>();
|
||||
private CBehavior currentOrder;
|
||||
private final Queue<CBehavior> orderQueue = new LinkedList<>();
|
||||
private final CUnitType unitType;
|
||||
|
||||
private Rectangle collisionRectangle;
|
||||
@ -189,6 +190,7 @@ public class CUnit extends CWidget {
|
||||
// remove current order, because it's completed, polling next
|
||||
// item from order queue
|
||||
this.currentOrder = this.orderQueue.poll();
|
||||
this.stateNotifier.ordersChanged();
|
||||
}
|
||||
if (this.currentOrder == null) {
|
||||
// maybe order "stop" here
|
||||
@ -222,7 +224,7 @@ public class CUnit extends CWidget {
|
||||
return game.getGameplayConstants().getBoneDecayTime();
|
||||
}
|
||||
|
||||
public void order(final COrder order, final boolean queue) {
|
||||
public void order(final CBehavior order, final boolean queue) {
|
||||
if (isDead()) {
|
||||
return;
|
||||
}
|
||||
@ -231,10 +233,12 @@ public class CUnit extends CWidget {
|
||||
}
|
||||
else {
|
||||
this.currentOrder = order;
|
||||
this.orderQueue.clear();
|
||||
}
|
||||
this.stateNotifier.ordersChanged();
|
||||
}
|
||||
|
||||
public COrder getCurrentOrder() {
|
||||
public CBehavior getCurrentOrder() {
|
||||
return this.currentOrder;
|
||||
}
|
||||
|
||||
@ -390,7 +394,7 @@ public class CUnit extends CWidget {
|
||||
CAllianceType.PASSIVE)) {
|
||||
for (final CUnitAttack attack : this.unitType.getAttacks()) {
|
||||
if (source.canBeTargetedBy(simulation, this, attack.getTargetsAllowed())) {
|
||||
this.order(new CAttackOrder(this, attack, OrderIds.attack, source), false);
|
||||
this.order(new CBehaviorAttack(this, attack, OrderIds.attack, source), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -521,6 +525,10 @@ public class CUnit extends CWidget {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("No targeting because " + targetsAllowed + " does not contain all of "
|
||||
+ this.unitType.getTargetedAs());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -550,7 +558,7 @@ public class CUnit extends CWidget {
|
||||
if (this.source.canReach(unit, this.source.acquisitionRange)
|
||||
&& unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed())
|
||||
&& (this.source.distance(unit) >= this.source.getUnitType().getMinimumAttackRange())) {
|
||||
this.source.order(new CAttackOrder(this.source, attack, OrderIds.attack, unit), false);
|
||||
this.source.order(new CBehaviorAttack(this.source, attack, OrderIds.attack, unit), false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import com.etheller.warsmash.util.SubscriberSetNotifier;
|
||||
public interface CUnitStateListener {
|
||||
void lifeChanged(); // hp (current) changes
|
||||
|
||||
void ordersChanged();
|
||||
|
||||
public static final class CUnitStateNotifier extends SubscriberSetNotifier<CUnitStateListener>
|
||||
implements CUnitStateListener {
|
||||
@Override
|
||||
@ -13,5 +15,12 @@ public interface CUnitStateListener {
|
||||
listener.lifeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ordersChanged() {
|
||||
for (final CUnitStateListener listener : set) {
|
||||
listener.ordersChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,4 +17,5 @@ public interface CAbility extends CAbilityView {
|
||||
void onOrder(CSimulation game, CUnit caster, int orderId, Vector2 point, boolean queue);
|
||||
|
||||
void onOrderNoTarget(CSimulation game, CUnit caster, int orderId, boolean queue);
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
|
||||
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.StringsToExternalizeLater;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CAttackOrder;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CMoveOrder;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehavior;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorAttack;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorMove;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType;
|
||||
@ -30,6 +32,15 @@ public class CAbilityAttack implements CAbility {
|
||||
@Override
|
||||
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
|
||||
final AbilityTargetCheckReceiver<CWidget> receiver) {
|
||||
if (orderId == OrderIds.smart) {
|
||||
if (target instanceof CUnit) {
|
||||
if (game.getPlayer(unit.getPlayerIndex()).hasAlliance(((CUnit) target).getPlayerIndex(),
|
||||
CAllianceType.PASSIVE)) {
|
||||
receiver.orderIdNotAccepted();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((orderId == OrderIds.smart) || (orderId == OrderIds.attack)) {
|
||||
boolean canTarget = false;
|
||||
for (final CUnitAttack attack : unit.getUnitType().getAttacks()) {
|
||||
@ -54,7 +65,30 @@ public class CAbilityAttack implements CAbility {
|
||||
@Override
|
||||
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target,
|
||||
final AbilityTargetCheckReceiver<Vector2> receiver) {
|
||||
receiver.mustTargetType(TargetType.UNIT);
|
||||
switch (orderId) {
|
||||
case OrderIds.attack:
|
||||
receiver.targetOk(target);
|
||||
break;
|
||||
case OrderIds.attackground:
|
||||
boolean allowAttackGround = false;
|
||||
for (final CUnitAttack attack : unit.getUnitType().getAttacks()) {
|
||||
if ((attack.getWeaponType() == CWeaponType.ARTILLERY)
|
||||
|| (attack.getWeaponType() == CWeaponType.ALINE)) {
|
||||
allowAttackGround = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allowAttackGround) {
|
||||
receiver.targetOk(target);
|
||||
}
|
||||
else {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
receiver.orderIdNotAccepted();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,15 +108,15 @@ public class CAbilityAttack implements CAbility {
|
||||
@Override
|
||||
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final CWidget target,
|
||||
final boolean queue) {
|
||||
COrder order = null;
|
||||
CBehavior order = null;
|
||||
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
|
||||
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
|
||||
order = new CAttackOrder(caster, attack, orderId, target);
|
||||
order = new CBehaviorAttack(caster, attack, orderId, target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (order == null) {
|
||||
order = new CMoveOrder(caster, orderId, target.getX(), target.getY());
|
||||
order = new CBehaviorMove(caster, orderId, target.getX(), target.getY());
|
||||
}
|
||||
caster.order(order, queue);
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ 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.StringsToExternalizeLater;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CMoveOrder;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CPatrolOrder;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorMove;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorPatrol;
|
||||
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;
|
||||
@ -85,13 +85,13 @@ public class CAbilityMove implements CAbility {
|
||||
@Override
|
||||
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final CWidget target,
|
||||
final boolean queue) {
|
||||
caster.order(new CPatrolOrder(caster, orderId, (CUnit) target), queue);
|
||||
caster.order(new CBehaviorPatrol(caster, orderId, (CUnit) target), queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final Vector2 target,
|
||||
final boolean queue) {
|
||||
caster.order(new CMoveOrder(caster, orderId, target.x, target.y), queue);
|
||||
caster.order(new CBehaviorMove(caster, orderId, target.x, target.y), queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -178,6 +178,7 @@ public class CUnitData {
|
||||
final List<CUnitAttack> attacks = new ArrayList<>();
|
||||
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
|
||||
if ((attacksEnabled & 0x1) != 0) {
|
||||
try {
|
||||
// attack one
|
||||
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
|
||||
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
|
||||
@ -218,8 +219,12 @@ public class CUnitData {
|
||||
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
|
||||
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
|
||||
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
|
||||
} catch (Exception exc) {
|
||||
System.err.println("Attack 1 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
|
||||
}
|
||||
}
|
||||
if ((attacksEnabled & 0x2) != 0) {
|
||||
try {
|
||||
// attack two
|
||||
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
|
||||
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
|
||||
@ -260,6 +265,9 @@ public class CUnitData {
|
||||
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
|
||||
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
|
||||
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
|
||||
} catch (Exception exc) {
|
||||
System.err.println("Attack 2 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
|
||||
}
|
||||
}
|
||||
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
|
||||
final boolean raise = (deathType & 0x1) != 0;
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
|
||||
|
||||
public interface COrder {
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||
|
||||
public interface CBehavior {
|
||||
/**
|
||||
* Executes one step of game simulation of the current order, returning true if
|
||||
* the order has completed. Many orders may wrap the move order and spend a
|
@ -3,13 +3,12 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
|
||||
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.simulation.COrder;
|
||||
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.combat.attacks.CUnitAttack;
|
||||
|
||||
public class CAttackOrder implements COrder {
|
||||
public class CBehaviorAttack implements CBehavior {
|
||||
private final CUnit unit;
|
||||
private final int orderId;
|
||||
private boolean wasWithinPropWindow = false;
|
||||
@ -17,11 +16,11 @@ public class CAttackOrder implements COrder {
|
||||
private final CWidget target;
|
||||
private int damagePointLaunchTime;
|
||||
private int backSwingTime;
|
||||
private COrder moveOrder;
|
||||
private CBehavior moveOrder;
|
||||
private int thisOrderCooldownEndTime;
|
||||
private boolean wasInRange = false;
|
||||
|
||||
public CAttackOrder(final CUnit unit, final CUnitAttack unitAttack, final int orderId, final CWidget target) {
|
||||
public CBehaviorAttack(final CUnit unit, final CUnitAttack unitAttack, final int orderId, final CWidget target) {
|
||||
this.unit = unit;
|
||||
this.unitAttack = unitAttack;
|
||||
this.orderId = orderId;
|
||||
@ -32,10 +31,10 @@ public class CAttackOrder implements COrder {
|
||||
private void createMoveOrder(final CUnit unit, final CWidget target) {
|
||||
if (!unit.isMovementDisabled()) { // TODO: Check mobility instead
|
||||
if ((target instanceof CUnit) && !(((CUnit) target).getUnitType().isBuilding())) {
|
||||
this.moveOrder = new CMoveOrder(unit, this.orderId, (CUnit) target);
|
||||
this.moveOrder = new CBehaviorMove(unit, this.orderId, (CUnit) target);
|
||||
}
|
||||
else {
|
||||
this.moveOrder = new CMoveOrder(unit, this.orderId, target.getX(), target.getY());
|
||||
this.moveOrder = new CBehaviorMove(unit, this.orderId, target.getX(), target.getY());
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -50,7 +49,7 @@ public class CAttackOrder implements COrder {
|
||||
return true;
|
||||
}
|
||||
float range = this.unitAttack.getRange();
|
||||
if ((this.target instanceof CUnit) && (((CUnit) this.target).getCurrentOrder() instanceof CMoveOrder)
|
||||
if ((this.target instanceof CUnit) && (((CUnit) this.target).getCurrentOrder() instanceof CBehaviorMove)
|
||||
&& (this.damagePointLaunchTime != 0 /*
|
||||
* only apply range motion buffer if they were already in range and
|
||||
* attacked
|
||||
@ -138,7 +137,6 @@ public class CAttackOrder implements COrder {
|
||||
else {
|
||||
damage = simulation.getSeededRandom().nextInt(maxDamage - minDamage) + minDamage;
|
||||
}
|
||||
System.out.println(damage + " from " + minDamage + " to " + maxDamage);
|
||||
this.unitAttack.launch(simulation, this.unit, this.target, damage);
|
||||
this.damagePointLaunchTime = 0;
|
||||
}
|
@ -10,13 +10,12 @@ 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.PathingGrid;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
|
||||
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.CWorldCollision;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CPathfindingProcessor;
|
||||
|
||||
public class CMoveOrder implements COrder {
|
||||
public class CBehaviorMove implements CBehavior {
|
||||
private static final Rectangle tempRect = new Rectangle();
|
||||
private final CUnit unit;
|
||||
private final int orderId;
|
||||
@ -27,7 +26,7 @@ public class CMoveOrder implements COrder {
|
||||
private int searchCycles = 0;
|
||||
private CUnit followUnit;
|
||||
|
||||
public CMoveOrder(final CUnit unit, final int orderId, final float targetX, final float targetY) {
|
||||
public CBehaviorMove(final CUnit unit, final int orderId, final float targetX, final float targetY) {
|
||||
this.unit = unit;
|
||||
this.orderId = orderId;
|
||||
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
|
||||
@ -36,7 +35,7 @@ public class CMoveOrder implements COrder {
|
||||
this.target = new Point2D.Float(targetX, targetY);
|
||||
}
|
||||
|
||||
public CMoveOrder(final CUnit unit, final int orderId, final CUnit followUnit) {
|
||||
public CBehaviorMove(final CUnit unit, final int orderId, final CUnit followUnit) {
|
||||
this.unit = unit;
|
||||
this.orderId = orderId;
|
||||
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
|
@ -0,0 +1,96 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
|
||||
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
|
||||
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;
|
||||
|
||||
public class CBehaviorPatrol implements CBehavior {
|
||||
private final CUnit unit;
|
||||
private final int orderId;
|
||||
private final CWidget target;
|
||||
private CBehavior moveOrder;
|
||||
|
||||
public CBehaviorPatrol(final CUnit unit, final int orderId, final CUnit target) {
|
||||
this.unit = unit;
|
||||
this.orderId = orderId;
|
||||
this.target = target;
|
||||
createMoveOrder(unit, target);
|
||||
}
|
||||
|
||||
private void createMoveOrder(final CUnit unit, final CUnit target) {
|
||||
if (!unit.isMovementDisabled()) { // TODO: Check mobility instead
|
||||
if ((target instanceof CUnit) && !(target.getUnitType().isBuilding())) {
|
||||
this.moveOrder = new CBehaviorMove(unit, this.orderId, target);
|
||||
}
|
||||
else {
|
||||
this.moveOrder = new CBehaviorMove(unit, this.orderId, target.getX(), target.getY());
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.moveOrder = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(final CSimulation simulation) {
|
||||
if (this.target.isDead()) {
|
||||
return true;
|
||||
}
|
||||
final float range = this.unit.getAcquisitionRange();
|
||||
if (!this.unit.canReach(this.target, range)) {
|
||||
if (this.moveOrder == null) {
|
||||
return true;
|
||||
}
|
||||
if (this.moveOrder.update(simulation)) {
|
||||
return true; // we just cant reach them
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!this.unit.isMovementDisabled()) {
|
||||
final float prevX = this.unit.getX();
|
||||
final float prevY = this.unit.getY();
|
||||
final float deltaY = this.target.getY() - prevY;
|
||||
final float deltaX = this.target.getX() - prevX;
|
||||
final double goalAngleRad = Math.atan2(deltaY, deltaX);
|
||||
float goalAngle = (float) Math.toDegrees(goalAngleRad);
|
||||
if (goalAngle < 0) {
|
||||
goalAngle += 360;
|
||||
}
|
||||
float facing = this.unit.getFacing();
|
||||
float delta = goalAngle - facing;
|
||||
final float turnRate = simulation.getUnitData().getTurnRate(this.unit.getTypeId());
|
||||
|
||||
if (delta < -180) {
|
||||
delta = 360 + delta;
|
||||
}
|
||||
if (delta > 180) {
|
||||
delta = -360 + delta;
|
||||
}
|
||||
final float absDelta = Math.abs(delta);
|
||||
|
||||
if ((absDelta <= 1.0) && (absDelta != 0)) {
|
||||
this.unit.setFacing(goalAngle);
|
||||
}
|
||||
else {
|
||||
float angleToAdd = Math.signum(delta) * (float) Math.toDegrees(turnRate);
|
||||
if (absDelta < Math.abs(angleToAdd)) {
|
||||
angleToAdd = delta;
|
||||
}
|
||||
facing += angleToAdd;
|
||||
this.unit.setFacing(facing);
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrderId() {
|
||||
return this.orderId;
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
|
||||
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||
|
||||
public class CDoNothingOrder implements COrder {
|
||||
public class CBehaviorStop implements CBehavior {
|
||||
private final int orderId;
|
||||
|
||||
public CDoNothingOrder(final int orderId) {
|
||||
public CBehaviorStop(final int orderId) {
|
||||
this.orderId = orderId;
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
|
||||
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
|
||||
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;
|
||||
|
||||
public class CPatrolOrder implements COrder {
|
||||
private final CUnit unit;
|
||||
private final int orderId;
|
||||
private final CWidget target;
|
||||
private COrder moveOrder;
|
||||
|
||||
public CPatrolOrder(final CUnit unit, final int orderId, final CUnit target) {
|
||||
this.unit = unit;
|
||||
this.orderId = orderId;
|
||||
this.target = target;
|
||||
createMoveOrder(unit, target);
|
||||
}
|
||||
|
||||
private void createMoveOrder(final CUnit unit, final CUnit target) {
|
||||
if (!unit.isMovementDisabled()) { // TODO: Check mobility instead
|
||||
if ((target instanceof CUnit) && !(target.getUnitType().isBuilding())) {
|
||||
this.moveOrder = new CMoveOrder(unit, this.orderId, target);
|
||||
}
|
||||
else {
|
||||
this.moveOrder = new CMoveOrder(unit, this.orderId, target.getX(), target.getY());
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.moveOrder = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(final CSimulation simulation) {
|
||||
if (this.target.isDead()) {
|
||||
return true;
|
||||
}
|
||||
final float range = this.unit.getAcquisitionRange();
|
||||
if (!this.unit.canReach(this.target, range)) {
|
||||
if (this.moveOrder == null) {
|
||||
return true;
|
||||
}
|
||||
if (this.moveOrder.update(simulation)) {
|
||||
return true; // we just cant reach them
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrderId() {
|
||||
return this.orderId;
|
||||
}
|
||||
|
||||
}
|
@ -177,7 +177,8 @@ public class CPathfindingProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
while (!openSet.isEmpty()) {
|
||||
int searchIterations = 0;
|
||||
while (!openSet.isEmpty() && searchIterations < 150000) {
|
||||
Node current = openSet.poll();
|
||||
if (isGoal(current)) {
|
||||
final LinkedList<Point2D.Float> totalPath = new LinkedList<>();
|
||||
@ -259,6 +260,7 @@ public class CPathfindingProcessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
searchIterations++;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class CPlayerUnitOrderExecutor implements CPlayerUnitOrderListener {
|
||||
if (this.abilityActivationReceiver.isUseOk()) {
|
||||
final StringMsgTargetCheckReceiver<Void> targetReceiver = this.<Void>targetCheckReceiver();
|
||||
ability.checkCanTargetNoTarget(this.game, unit, orderId, targetReceiver);
|
||||
if (targetReceiver.getTarget() != null) {
|
||||
if (targetReceiver.getMessage() == null) {
|
||||
ability.onOrderNoTarget(this.game, unit, orderId, queue);
|
||||
return true;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandCardCommandL
|
||||
public class CommandCardIcon extends AbstractRenderableFrame {
|
||||
|
||||
private TextureFrame iconFrame;
|
||||
private TextureFrame activeHighlightFrame;
|
||||
private SpriteFrame cooldownFrame;
|
||||
private SpriteFrame autocastFrame;
|
||||
private CommandButton commandButton;
|
||||
@ -30,8 +31,10 @@ public class CommandCardIcon extends AbstractRenderableFrame {
|
||||
this.commandCardCommandListener = commandCardCommandListener;
|
||||
}
|
||||
|
||||
public void set(final TextureFrame iconFrame, final SpriteFrame cooldownFrame, final SpriteFrame autocastFrame) {
|
||||
public void set(final TextureFrame iconFrame, final TextureFrame activeHighlightFrame,
|
||||
final SpriteFrame cooldownFrame, final SpriteFrame autocastFrame) {
|
||||
this.iconFrame = iconFrame;
|
||||
this.activeHighlightFrame = activeHighlightFrame;
|
||||
this.cooldownFrame = cooldownFrame;
|
||||
this.autocastFrame = autocastFrame;
|
||||
}
|
||||
@ -40,6 +43,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
|
||||
this.commandButton = commandButton;
|
||||
if (commandButton == null) {
|
||||
this.iconFrame.setVisible(false);
|
||||
this.activeHighlightFrame.setVisible(false);
|
||||
this.cooldownFrame.setVisible(false);
|
||||
this.autocastFrame.setVisible(false);
|
||||
}
|
||||
@ -64,8 +68,10 @@ public class CommandCardIcon extends AbstractRenderableFrame {
|
||||
}
|
||||
}
|
||||
|
||||
public void setCommandButtonData(final Texture texture, final int abilityHandleId, final int orderId) {
|
||||
public void setCommandButtonData(final Texture texture, final int abilityHandleId, final int orderId,
|
||||
final boolean active) {
|
||||
this.iconFrame.setVisible(true);
|
||||
this.activeHighlightFrame.setVisible(active);
|
||||
this.cooldownFrame.setVisible(false);
|
||||
this.autocastFrame.setVisible(false);
|
||||
this.iconFrame.setTexture(texture);
|
||||
@ -76,6 +82,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
|
||||
@Override
|
||||
protected void innerPositionBounds(final Viewport viewport) {
|
||||
this.iconFrame.positionBounds(viewport);
|
||||
this.activeHighlightFrame.positionBounds(viewport);
|
||||
this.cooldownFrame.positionBounds(viewport);
|
||||
this.autocastFrame.positionBounds(viewport);
|
||||
}
|
||||
@ -83,6 +90,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
|
||||
@Override
|
||||
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
|
||||
this.iconFrame.render(batch, baseFont, glyphLayout);
|
||||
this.activeHighlightFrame.render(batch, baseFont, glyphLayout);
|
||||
this.cooldownFrame.render(batch, baseFont, glyphLayout);
|
||||
this.autocastFrame.render(batch, baseFont, glyphLayout);
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
@ -28,6 +30,7 @@ import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
|
||||
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
||||
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
|
||||
import com.etheller.warsmash.parsers.mdlx.Layer.FilterMode;
|
||||
import com.etheller.warsmash.util.FastNumberFormat;
|
||||
import com.etheller.warsmash.util.ImageUtils;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
@ -135,6 +138,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
private int selectedSoundCount = 0;
|
||||
private final ActiveCommandUnitTargetFilter activeCommandUnitTargetFilter;
|
||||
|
||||
private UIFrame clickUI = null;
|
||||
|
||||
public MeleeUI(final DataSource dataSource, final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator,
|
||||
final Scene uiScene, final Scene portraitScene, final CameraPreset[] cameraPresets,
|
||||
final CameraRates cameraRates, final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener,
|
||||
@ -305,6 +310,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
this.rootFrame.add(commandCardIcon);
|
||||
final TextureFrame iconFrame = this.rootFrame.createTextureFrame(
|
||||
"SmashCommandButton_" + (commandButtonIndex) + "_Icon", this.rootFrame, false, null);
|
||||
final TextureFrame activeHighlightFrame = this.rootFrame.createTextureFrame(
|
||||
"SmashCommandButton_" + (commandButtonIndex) + "_ActiveHighlight", this.rootFrame, true, null,
|
||||
FilterMode.ADDALPHA);
|
||||
final SpriteFrame cooldownFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
|
||||
"SmashCommandButton_" + (commandButtonIndex) + "_Cooldown", this.rootFrame, "", 0);
|
||||
final SpriteFrame autocastFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
|
||||
@ -318,6 +326,11 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
iconFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
|
||||
iconFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
|
||||
iconFrame.setTexture(ImageUtils.DEFAULT_ICON_PATH, this.rootFrame);
|
||||
activeHighlightFrame
|
||||
.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0));
|
||||
activeHighlightFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
|
||||
activeHighlightFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
|
||||
activeHighlightFrame.setTexture("CommandButtonActiveHighlight", this.rootFrame);
|
||||
cooldownFrame.addSetPoint(new SetPoint(FramePoint.CENTER, commandCardIcon, FramePoint.CENTER, 0, 0));
|
||||
this.rootFrame.setSpriteFrameModel(cooldownFrame, this.rootFrame.getSkinField("CommandButtonCooldown"));
|
||||
cooldownFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
|
||||
@ -326,7 +339,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
this.rootFrame.setSpriteFrameModel(autocastFrame, this.rootFrame.getSkinField("CommandButtonAutocast"));
|
||||
autocastFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
|
||||
autocastFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
|
||||
commandCardIcon.set(iconFrame, cooldownFrame, autocastFrame);
|
||||
commandCardIcon.set(iconFrame, activeHighlightFrame, cooldownFrame, autocastFrame);
|
||||
this.commandCard[j][i] = commandCardIcon;
|
||||
commandCardIcon.setCommandButton(null);
|
||||
commandButtonIndex++;
|
||||
@ -408,7 +421,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
|
||||
mouseX = Math.max(minX, Math.min(maxX, mouseX));
|
||||
mouseY = Math.max(minY, Math.min(maxY, mouseY));
|
||||
Gdx.input.setCursorPosition(mouseX, mouseY);
|
||||
// Gdx.input.setCursorPosition(mouseX, mouseY);
|
||||
|
||||
screenCoordsVector.set(mouseX, mouseY);
|
||||
this.uiViewport.unproject(screenCoordsVector);
|
||||
@ -456,6 +469,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
this.cameraManager.updateCamera();
|
||||
}
|
||||
|
||||
private final ShapeRenderer shapeRenderer = new ShapeRenderer();
|
||||
|
||||
public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
|
||||
this.rootFrame.render(batch, font20, glyphLayout);
|
||||
if (this.selectedUnit != null) {
|
||||
@ -466,6 +481,18 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
this.meleeUIMinimap.render(batch, this.war3MapViewer.units);
|
||||
this.timeIndicator.setFrameByRatio(this.war3MapViewer.simulation.getGameTimeOfDay()
|
||||
/ this.war3MapViewer.simulation.getGameplayConstants().getGameDayHours());
|
||||
|
||||
if (this.clickUI != null) {
|
||||
batch.end();
|
||||
this.shapeRenderer.setProjectionMatrix(this.uiViewport.getCamera().combined);
|
||||
this.shapeRenderer.begin(ShapeType.Line);
|
||||
this.shapeRenderer.rect(this.clickUI.getFramePointX(FramePoint.LEFT),
|
||||
this.clickUI.getFramePointY(FramePoint.BOTTOM),
|
||||
this.clickUI.getFramePointX(FramePoint.RIGHT) - this.clickUI.getFramePointX(FramePoint.LEFT),
|
||||
this.clickUI.getFramePointY(FramePoint.TOP) - this.clickUI.getFramePointY(FramePoint.BOTTOM));
|
||||
this.shapeRenderer.end();
|
||||
batch.begin();
|
||||
}
|
||||
}
|
||||
|
||||
public void portraitTalk() {
|
||||
@ -477,8 +504,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
public boolean call(final CUnit unit) {
|
||||
final BooleanAbilityTargetCheckReceiver<CWidget> targetReceiver = BooleanAbilityTargetCheckReceiver
|
||||
.<CWidget>getInstance();
|
||||
MeleeUI.this.activeCommand.checkCanTarget(MeleeUI.this.war3MapViewer.simulation, unit,
|
||||
MeleeUI.this.activeCommandOrderId, unit, targetReceiver);
|
||||
MeleeUI.this.activeCommand.checkCanTarget(MeleeUI.this.war3MapViewer.simulation,
|
||||
MeleeUI.this.activeCommandUnit.getSimulationUnit(), MeleeUI.this.activeCommandOrderId, unit,
|
||||
targetReceiver);
|
||||
return targetReceiver.isTargetable();
|
||||
}
|
||||
}
|
||||
@ -541,11 +569,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
this.portrait.setSelectedUnit(unit);
|
||||
this.selectedUnit = unit;
|
||||
for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) {
|
||||
for (int i = 0; i < COMMAND_CARD_WIDTH; i++) {
|
||||
this.commandCard[j][i].setCommandButton(null);
|
||||
}
|
||||
}
|
||||
clearCommandCard();
|
||||
if (unit == null) {
|
||||
this.simpleNameValue.setText("");
|
||||
this.unitLifeText.setText("");
|
||||
@ -633,16 +657,24 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
localArmorIconBackdrop.setTexture(defenseTexture);
|
||||
localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense()));
|
||||
unit.populateCommandCard(this, this.war3MapViewer.getAbilityDataUI());
|
||||
unit.populateCommandCard(this.war3MapViewer.simulation, this, this.war3MapViewer.getAbilityDataUI());
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCommandCard() {
|
||||
for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) {
|
||||
for (int i = 0; i < COMMAND_CARD_WIDTH; i++) {
|
||||
this.commandCard[j][i].setCommandButton(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon,
|
||||
final int abilityHandleId, final int orderId) {
|
||||
final int abilityHandleId, final int orderId, final boolean active) {
|
||||
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));
|
||||
this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId);
|
||||
this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId, active);
|
||||
}
|
||||
|
||||
public void resize(final Rectangle viewport) {
|
||||
@ -732,6 +764,13 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ordersChanged() {
|
||||
clearCommandCard();
|
||||
this.selectedUnit.populateCommandCard(this.war3MapViewer.simulation, this,
|
||||
this.war3MapViewer.getAbilityDataUI());
|
||||
}
|
||||
|
||||
public RenderUnit getSelectedUnit() {
|
||||
return this.selectedUnit;
|
||||
}
|
||||
@ -748,6 +787,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
this.cameraManager.scrolled(amount);
|
||||
}
|
||||
|
||||
private float lastX, lastY;
|
||||
|
||||
public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) {
|
||||
screenCoordsVector.set(screenX, screenY);
|
||||
this.uiViewport.unproject(screenCoordsVector);
|
||||
@ -756,6 +797,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
screenCoordsVector.y);
|
||||
this.cameraManager.target.x = worldPoint.x;
|
||||
this.cameraManager.target.y = worldPoint.y;
|
||||
this.lastX = screenCoordsVector.x;
|
||||
this.lastY = screenCoordsVector.y;
|
||||
return true;
|
||||
}
|
||||
final UIFrame clickedUIFrame = this.rootFrame.touchDown(screenCoordsVector.x, screenCoordsVector.y, button);
|
||||
@ -790,6 +833,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
else {
|
||||
this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY);
|
||||
clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y);
|
||||
|
||||
this.activeCommand.checkCanTarget(this.war3MapViewer.simulation,
|
||||
this.activeCommandUnit.getSimulationUnit(), this.activeCommandOrderId,
|
||||
clickLocationTemp2, PointAbilityTargetCheckReceiver.INSTANCE);
|
||||
@ -822,10 +867,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
else {
|
||||
if (button == Input.Buttons.RIGHT) {
|
||||
final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY);
|
||||
if (getSelectedUnit() != null) {
|
||||
if ((rayPickUnit != null) && (rayPickUnit.playerIndex != getSelectedUnit().playerIndex)
|
||||
&& !rayPickUnit.getSimulationUnit().isDead()) {
|
||||
final RenderUnit rayPickUnit = this.war3MapViewer.rayPickUnit(screenX, worldScreenY);
|
||||
if ((rayPickUnit != null) && !rayPickUnit.getSimulationUnit().isDead()) {
|
||||
boolean ordered = false;
|
||||
for (final RenderUnit unit : this.war3MapViewer.selected) {
|
||||
for (final CAbility ability : unit.getSimulationUnit().getAbilities()) {
|
||||
@ -929,10 +973,34 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.clickUI = clickedUIFrame;
|
||||
this.lastX = screenCoordsVector.x;
|
||||
this.lastY = screenCoordsVector.y;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isShiftDown() {
|
||||
return Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT);
|
||||
}
|
||||
|
||||
public boolean touchDragged(final int screenX, final int screenY, final float worldScreenY, final int pointer) {
|
||||
screenCoordsVector.set(screenX, screenY);
|
||||
this.uiViewport.unproject(screenCoordsVector);
|
||||
final float dx = screenCoordsVector.x - this.lastX;
|
||||
final float dy = screenCoordsVector.y - this.lastY;
|
||||
|
||||
if (this.meleeUIMinimap.containsMouse(screenCoordsVector.x, screenCoordsVector.y)) {
|
||||
this.meleeUIMinimap.touchDragged(screenX, screenY, worldScreenY, pointer, dx, dy);
|
||||
}
|
||||
else if (this.clickUI != null) {
|
||||
this.clickUI.setFramePointX(FramePoint.LEFT, this.clickUI.getFramePointX(FramePoint.LEFT) + dx);
|
||||
this.clickUI.setFramePointY(FramePoint.BOTTOM, this.clickUI.getFramePointY(FramePoint.BOTTOM) + dy);
|
||||
}
|
||||
|
||||
this.lastX = screenCoordsVector.x;
|
||||
this.lastY = screenCoordsVector.y;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -59,4 +59,12 @@ public class MeleeUIMinimap {
|
||||
public boolean containsMouse(final float x, final float y) {
|
||||
return this.minimapFilledArea.contains(x, y);
|
||||
}
|
||||
|
||||
public void touchDragged(final int screenX, final int screenY, final float worldScreenY, final int pointer,
|
||||
final float dx, final float dy) {
|
||||
this.minimapFilledArea.x += dx;
|
||||
this.minimapFilledArea.y += dy;
|
||||
this.minimap.x += dx;
|
||||
this.minimap.y += dy;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import com.etheller.warsmash.viewer5.gl.SoundLengthExtension;
|
||||
import com.etheller.warsmash.viewer5.gl.WireframeExtension;
|
||||
|
||||
public class DesktopLauncher {
|
||||
public static void main(final String[] arg) {
|
||||
public static void main(String[] arg) {
|
||||
Extensions.angleInstancedArrays = new ANGLEInstancedArrays() {
|
||||
@Override
|
||||
public void glVertexAttribDivisorANGLE(final int index, final int divisor) {
|
||||
@ -83,10 +83,11 @@ public class DesktopLauncher {
|
||||
config.useGL30 = true;
|
||||
config.gles30ContextMajorVersion = 3;
|
||||
config.gles30ContextMinorVersion = 3;
|
||||
config.samples = 16;
|
||||
//config.samples = 16;
|
||||
// config.vSyncEnabled = false;
|
||||
// config.foregroundFPS = 0;
|
||||
// config.backgroundFPS = 0;
|
||||
arg = new String[]{"-windowed"};
|
||||
if ((arg.length > 0) && "-windowed".equals(arg[0])) {
|
||||
config.fullscreen = false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user