mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Support for walkable destructables
This commit is contained in:
parent
e919f35904
commit
7cea3e3fcd
@ -38,6 +38,7 @@ import com.etheller.warsmash.parsers.fdf.GameUI;
|
|||||||
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
|
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
|
||||||
import com.etheller.warsmash.units.DataTable;
|
import com.etheller.warsmash.units.DataTable;
|
||||||
import com.etheller.warsmash.units.Element;
|
import com.etheller.warsmash.units.Element;
|
||||||
|
import com.etheller.warsmash.units.HashedGameObject;
|
||||||
import com.etheller.warsmash.util.DataSourceFileHandle;
|
import com.etheller.warsmash.util.DataSourceFileHandle;
|
||||||
import com.etheller.warsmash.util.ImageUtils;
|
import com.etheller.warsmash.util.ImageUtils;
|
||||||
import com.etheller.warsmash.viewer5.CanvasProvider;
|
import com.etheller.warsmash.viewer5.CanvasProvider;
|
||||||
@ -141,7 +142,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Element cameraData = this.viewer.miscData.get("Camera");
|
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];
|
final CameraPreset[] cameraPresets = new CameraPreset[6];
|
||||||
for (int i = 0; i < cameraPresets.length; i++) {
|
for (int i = 0; i < cameraPresets.length; i++) {
|
||||||
cameraPresets[i] = new CameraPreset(cameraData.getFieldFloatValue("AOA", i),
|
cameraPresets[i] = new CameraPreset(cameraData.getFieldFloatValue("AOA", i),
|
||||||
|
@ -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) {
|
private void add(final Node<T> node, final int depth) {
|
||||||
if (this.leaf) {
|
if (this.leaf) {
|
||||||
if ((this.nodes.size >= SPLIT_THRESHOLD) && (depth < MAX_DEPTH)) {
|
if ((this.nodes.size >= SPLIT_THRESHOLD) && (depth < MAX_DEPTH)) {
|
||||||
|
@ -31,4 +31,8 @@ public class Bounds {
|
|||||||
public boolean intersectRayFast(final Ray ray) {
|
public boolean intersectRayFast(final Ray ray) {
|
||||||
return Intersector.intersectRayBoundsFast(ray, this.boundingBox);
|
return Intersector.intersectRayBoundsFast(ray, this.boundingBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BoundingBox getBoundingBox() {
|
||||||
|
return boundingBox;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,343 +22,328 @@ import com.etheller.warsmash.viewer5.Texture;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.EmitterObject;
|
import com.etheller.warsmash.viewer5.handlers.EmitterObject;
|
||||||
|
|
||||||
public class EventObjectEmitterObject extends GenericObject implements EmitterObject {
|
public class EventObjectEmitterObject extends GenericObject implements EmitterObject {
|
||||||
private static final class LoadGenericSoundCallback implements LoadGenericCallback {
|
private static final class LoadGenericSoundCallback implements LoadGenericCallback {
|
||||||
private final String filename;
|
private final String filename;
|
||||||
|
|
||||||
public LoadGenericSoundCallback(final String filename) {
|
public LoadGenericSoundCallback(final String filename) {
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(final InputStream data) {
|
public Object call(final InputStream data) {
|
||||||
final FileHandle temp = new FileHandle(this.filename) {
|
final FileHandle temp = new FileHandle(this.filename) {
|
||||||
@Override
|
@Override
|
||||||
public InputStream read() {
|
public InputStream read() {
|
||||||
return data;
|
return data;
|
||||||
};
|
}
|
||||||
};
|
|
||||||
if (data != null) {
|
|
||||||
return Gdx.audio.newSound(temp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
System.err.println("Warning: missing sound file: " + this.filename);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final LoadGenericCallback mappedDataCallback = new LoadGenericCallback() {
|
;
|
||||||
|
};
|
||||||
|
if (data != null) {
|
||||||
|
return Gdx.audio.newSound(temp);
|
||||||
|
} else {
|
||||||
|
System.err.println("Warning: missing sound file: " + this.filename);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private static final LoadGenericCallback mappedDataCallback = new LoadGenericCallback() {
|
||||||
public Object call(final InputStream data) {
|
|
||||||
final StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(data, "utf-8"))) {
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
stringBuilder.append(line);
|
|
||||||
stringBuilder.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (final UnsupportedEncodingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
catch (final IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return new MappedData(stringBuilder.toString());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private int geometryEmitterType = -1;
|
@Override
|
||||||
public final String type;
|
public Object call(final InputStream data) {
|
||||||
private final String id;
|
final StringBuilder stringBuilder = new StringBuilder();
|
||||||
public final long[] keyFrames;
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(data, "utf-8"))) {
|
||||||
private long globalSequence = -1;
|
String line;
|
||||||
private final long[] defval = { 1 };
|
while ((line = reader.readLine()) != null) {
|
||||||
public MdxModel internalModel;
|
stringBuilder.append(line);
|
||||||
public Texture internalTexture;
|
stringBuilder.append("\n");
|
||||||
public float[][] colors;
|
}
|
||||||
public float[] intervalTimes;
|
} catch (final UnsupportedEncodingException e) {
|
||||||
public float scale;
|
throw new RuntimeException(e);
|
||||||
public int columns;
|
} catch (final IOException e) {
|
||||||
public int rows;
|
throw new RuntimeException(e);
|
||||||
public float lifeSpan;
|
}
|
||||||
public int blendSrc;
|
return new MappedData(stringBuilder.toString());
|
||||||
public int blendDst;
|
}
|
||||||
public float[][] intervals;
|
};
|
||||||
public float distanceCutoff;
|
|
||||||
private float maxDistance;
|
|
||||||
public float minDistance;
|
|
||||||
private float pitch;
|
|
||||||
private float pitchVariance;
|
|
||||||
private float volume;
|
|
||||||
public List<Sound> decodedBuffers = new ArrayList<>();
|
|
||||||
/**
|
|
||||||
* If this is an SPL/UBR emitter object, ok will be set to true if the tables
|
|
||||||
* are loaded.
|
|
||||||
*
|
|
||||||
* This is because, like the other geometry emitters, it is fine to use them
|
|
||||||
* even if the textures don't load.
|
|
||||||
*
|
|
||||||
* The particles will simply be black.
|
|
||||||
*/
|
|
||||||
private boolean ok = false;
|
|
||||||
|
|
||||||
public EventObjectEmitterObject(final MdxModel model,
|
private int geometryEmitterType = -1;
|
||||||
final com.etheller.warsmash.parsers.mdlx.EventObject eventObject, final int index) {
|
public final String type;
|
||||||
super(model, eventObject, index);
|
private final String id;
|
||||||
|
public final long[] keyFrames;
|
||||||
|
private long globalSequence = -1;
|
||||||
|
private final long[] defval = {1};
|
||||||
|
public MdxModel internalModel;
|
||||||
|
public Texture internalTexture;
|
||||||
|
public float[][] colors;
|
||||||
|
public float[] intervalTimes;
|
||||||
|
public float scale;
|
||||||
|
public int columns;
|
||||||
|
public int rows;
|
||||||
|
public float lifeSpan;
|
||||||
|
public int blendSrc;
|
||||||
|
public int blendDst;
|
||||||
|
public float[][] intervals;
|
||||||
|
public float distanceCutoff;
|
||||||
|
private float maxDistance;
|
||||||
|
public float minDistance;
|
||||||
|
private float pitch;
|
||||||
|
private float pitchVariance;
|
||||||
|
private float volume;
|
||||||
|
public List<Sound> decodedBuffers = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
final ModelViewer viewer = model.viewer;
|
public EventObjectEmitterObject(final MdxModel model,
|
||||||
final String name = eventObject.getName();
|
final com.etheller.warsmash.parsers.mdlx.EventObject eventObject, final int index) {
|
||||||
String type = name.substring(0, 3);
|
super(model, eventObject, index);
|
||||||
final String id = name.substring(4);
|
|
||||||
|
|
||||||
// Same thing
|
final ModelViewer viewer = model.viewer;
|
||||||
if ("FPT".equals(type)) {
|
final String name = eventObject.getName();
|
||||||
type = "SPL";
|
String type = name.substring(0, 3);
|
||||||
}
|
final String id = name.substring(4);
|
||||||
|
|
||||||
if ("SPL".equals(type)) {
|
// Same thing
|
||||||
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPLAT;
|
if ("FPT".equals(type)) {
|
||||||
}
|
type = "SPL";
|
||||||
else if ("UBR".equals(type)) {
|
}
|
||||||
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_UBERSPLAT;
|
|
||||||
}
|
|
||||||
else if ("SPN".equals(type)) {
|
|
||||||
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPN;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.type = type;
|
if ("SPL".equals(type)) {
|
||||||
this.id = id;
|
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPLAT;
|
||||||
this.keyFrames = eventObject.getKeyFrames();
|
} else if ("UBR".equals(type)) {
|
||||||
|
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_UBERSPLAT;
|
||||||
|
} else if ("SPN".equals(type)) {
|
||||||
|
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPN;
|
||||||
|
}
|
||||||
|
|
||||||
final int globalSequenceId = eventObject.getGlobalSequenceId();
|
this.type = type;
|
||||||
if (globalSequenceId != -1) {
|
this.id = id;
|
||||||
this.globalSequence = model.getGlobalSequences().get(globalSequenceId);
|
this.keyFrames = eventObject.getKeyFrames();
|
||||||
}
|
|
||||||
|
|
||||||
final List<GenericResource> tables = new ArrayList<>();
|
final int globalSequenceId = eventObject.getGlobalSequenceId();
|
||||||
final PathSolver pathSolver = model.pathSolver;
|
if (globalSequenceId != -1) {
|
||||||
final Object solverParams = model.solverParams;
|
this.globalSequence = model.getGlobalSequences().get(globalSequenceId);
|
||||||
|
}
|
||||||
|
|
||||||
if ("SPN".equals(type)) {
|
final List<GenericResource> tables = new ArrayList<>();
|
||||||
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SpawnData.slk", solverParams).finalSrc,
|
final PathSolver pathSolver = model.pathSolver;
|
||||||
FetchDataTypeName.SLK, mappedDataCallback));
|
final Object solverParams = model.solverParams;
|
||||||
}
|
|
||||||
else if ("SPL".equals(type)) {
|
|
||||||
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SplatData.slk", solverParams).finalSrc,
|
|
||||||
FetchDataTypeName.SLK, mappedDataCallback));
|
|
||||||
}
|
|
||||||
else if ("UBR".equals(type)) {
|
|
||||||
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\UberSplatData.slk", solverParams).finalSrc,
|
|
||||||
FetchDataTypeName.SLK, mappedDataCallback));
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
// Units\Critters\BlackStagMale\BlackStagMale.mdx has an event object named
|
|
||||||
// "Point01".
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO I am scrapping some async stuff with promises here from the JS and
|
if ("SPN".equals(type)) {
|
||||||
// calling load
|
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SpawnData.slk", solverParams).finalSrc,
|
||||||
this.load(tables);
|
FetchDataTypeName.SLK, mappedDataCallback));
|
||||||
}
|
} else if ("SPL".equals(type)) {
|
||||||
|
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SplatData.slk", solverParams).finalSrc,
|
||||||
|
FetchDataTypeName.SLK, mappedDataCallback));
|
||||||
|
} else if ("UBR".equals(type)) {
|
||||||
|
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\UberSplatData.slk", solverParams).finalSrc,
|
||||||
|
FetchDataTypeName.SLK, mappedDataCallback));
|
||||||
|
} 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 {
|
||||||
|
// Units\Critters\BlackStagMale\BlackStagMale.mdx has an event object named
|
||||||
|
// "Point01".
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
private float getFloat(final MappedDataRow row, final String name) {
|
// TODO I am scrapping some async stuff with promises here from the JS and
|
||||||
final Float x = (Float) row.get(name);
|
// calling load
|
||||||
if (x == null) {
|
this.load(tables);
|
||||||
return Float.NaN;
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
return x.floatValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getInt(final MappedDataRow row, final String name) {
|
private float getFloat(final MappedDataRow row, final String name) {
|
||||||
return getInt(row, name, Integer.MIN_VALUE);
|
final Float x = (Float) row.get(name);
|
||||||
}
|
if (x == null) {
|
||||||
|
return Float.NaN;
|
||||||
|
} else {
|
||||||
|
return x.floatValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int getInt(final MappedDataRow row, final String name, final int defaultValue) {
|
private int getInt(final MappedDataRow row, final String name) {
|
||||||
final Number x = (Number) row.get(name);
|
return getInt(row, name, Integer.MIN_VALUE);
|
||||||
if (x == null) {
|
}
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return x.intValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void load(final List<GenericResource> tables) {
|
private int getInt(final MappedDataRow row, final String name, final int defaultValue) {
|
||||||
final MappedData firstTable = (MappedData) tables.get(0).data;
|
final Number x = (Number) row.get(name);
|
||||||
final MappedDataRow row = firstTable.getRow(this.id.trim());
|
if (x == null) {
|
||||||
|
return defaultValue;
|
||||||
|
} else {
|
||||||
|
return x.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (row != null) {
|
private void load(final List<GenericResource> tables) {
|
||||||
final MdxModel model = this.model;
|
final MappedData firstTable = (MappedData) tables.get(0).data;
|
||||||
final ModelViewer viewer = model.viewer;
|
if (firstTable == null) {
|
||||||
final PathSolver pathSolver = model.pathSolver;
|
return;
|
||||||
|
}
|
||||||
|
final MappedDataRow row = firstTable.getRow(this.id.trim());
|
||||||
|
|
||||||
if ("SPN".equals(this.type)) {
|
if (row != null) {
|
||||||
this.internalModel = (MdxModel) viewer.load(((String) row.get("Model")).replace(".mdl", ".mdx"),
|
final MdxModel model = this.model;
|
||||||
pathSolver, model.solverParams);
|
final ModelViewer viewer = model.viewer;
|
||||||
|
final PathSolver pathSolver = model.pathSolver;
|
||||||
|
|
||||||
if (this.internalModel != null) {
|
if ("SPN".equals(this.type)) {
|
||||||
// TODO javascript async code removed here
|
this.internalModel = (MdxModel) viewer.load(((String) row.get("Model")).replace(".mdl", ".mdx"),
|
||||||
|
pathSolver, model.solverParams);
|
||||||
|
|
||||||
|
if (this.internalModel != null) {
|
||||||
|
// TODO javascript async code removed here
|
||||||
// this.internalModel.whenLoaded((model) => this.ok = model.ok)
|
// this.internalModel.whenLoaded((model) => this.ok = model.ok)
|
||||||
this.ok = this.internalModel.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";
|
||||||
final String texturesExt = model.reforged ? ".dds" : ".blp";
|
|
||||||
|
|
||||||
this.internalTexture = (Texture) viewer.load(
|
this.internalTexture = (Texture) viewer.load(
|
||||||
"ReplaceableTextures\\Splats\\" + row.get("file") + texturesExt, pathSolver,
|
"ReplaceableTextures\\Splats\\" + row.get("file") + texturesExt, pathSolver,
|
||||||
model.solverParams);
|
model.solverParams);
|
||||||
|
|
||||||
this.scale = getFloat(row, "Scale");
|
this.scale = getFloat(row, "Scale");
|
||||||
this.colors = new float[][] {
|
this.colors = new float[][]{
|
||||||
{ getFloat(row, "StartR"), getFloat(row, "StartG"), getFloat(row, "StartB"),
|
{getFloat(row, "StartR"), getFloat(row, "StartG"), getFloat(row, "StartB"),
|
||||||
getFloat(row, "StartA") },
|
getFloat(row, "StartA")},
|
||||||
{ getFloat(row, "MiddleR"), getFloat(row, "MiddleG"), getFloat(row, "MiddleB"),
|
{getFloat(row, "MiddleR"), getFloat(row, "MiddleG"), getFloat(row, "MiddleB"),
|
||||||
getFloat(row, "MiddleA") },
|
getFloat(row, "MiddleA")},
|
||||||
{ getFloat(row, "EndR"), getFloat(row, "EndG"), getFloat(row, "EndB"),
|
{getFloat(row, "EndR"), getFloat(row, "EndG"), getFloat(row, "EndB"),
|
||||||
getFloat(row, "EndA") } };
|
getFloat(row, "EndA")}};
|
||||||
|
|
||||||
if ("SPL".equals(this.type)) {
|
if ("SPL".equals(this.type)) {
|
||||||
this.columns = getInt(row, "Columns");
|
this.columns = getInt(row, "Columns");
|
||||||
this.rows = getInt(row, "Rows");
|
this.rows = getInt(row, "Rows");
|
||||||
this.lifeSpan = getFloat(row, "Lifespan") + getFloat(row, "Decay");
|
this.lifeSpan = getFloat(row, "Lifespan") + getFloat(row, "Decay");
|
||||||
this.intervalTimes = new float[] { getFloat(row, "Lifespan"), getFloat(row, "Decay") };
|
this.intervalTimes = new float[]{getFloat(row, "Lifespan"), getFloat(row, "Decay")};
|
||||||
this.intervals = new float[][] {
|
this.intervals = new float[][]{
|
||||||
{ getFloat(row, "UVLifespanStart"), getFloat(row, "UVLifespanEnd"),
|
{getFloat(row, "UVLifespanStart"), getFloat(row, "UVLifespanEnd"),
|
||||||
getFloat(row, "LifespanRepeat") },
|
getFloat(row, "LifespanRepeat")},
|
||||||
{ getFloat(row, "UVDecayStart"), getFloat(row, "UVDecayEnd"),
|
{getFloat(row, "UVDecayStart"), getFloat(row, "UVDecayEnd"),
|
||||||
getFloat(row, "DecayRepeat") }, };
|
getFloat(row, "DecayRepeat")},};
|
||||||
}
|
} else {
|
||||||
else {
|
this.columns = 1;
|
||||||
this.columns = 1;
|
this.rows = 1;
|
||||||
this.rows = 1;
|
this.lifeSpan = getFloat(row, "BirthTime") + getFloat(row, "PauseTime") + getFloat(row, "Decay");
|
||||||
this.lifeSpan = getFloat(row, "BirthTime") + getFloat(row, "PauseTime") + getFloat(row, "Decay");
|
this.intervalTimes = new float[]{getFloat(row, "BirthTime"), getFloat(row, "PauseTime"),
|
||||||
this.intervalTimes = new float[] { getFloat(row, "BirthTime"), getFloat(row, "PauseTime"),
|
getFloat(row, "Decay")};
|
||||||
getFloat(row, "Decay") };
|
}
|
||||||
}
|
|
||||||
|
|
||||||
final int[] blendModes = FilterMode
|
final int[] blendModes = FilterMode
|
||||||
.emitterFilterMode(com.etheller.warsmash.parsers.mdlx.ParticleEmitter2.FilterMode
|
.emitterFilterMode(com.etheller.warsmash.parsers.mdlx.ParticleEmitter2.FilterMode
|
||||||
.fromId(getInt(row, "BlendMode")));
|
.fromId(getInt(row, "BlendMode")));
|
||||||
|
|
||||||
this.blendSrc = blendModes[0];
|
this.blendSrc = blendModes[0];
|
||||||
this.blendDst = blendModes[1];
|
this.blendDst = blendModes[1];
|
||||||
|
|
||||||
this.ok = true;
|
this.ok = true;
|
||||||
}
|
} else if ("SND".equals(this.type)) {
|
||||||
else if ("SND".equals(this.type)) {
|
// Only load sounds if audio is enabled.
|
||||||
// Only load sounds if audio is enabled.
|
// This is mostly to save on bandwidth and loading time, especially when loading
|
||||||
// This is mostly to save on bandwidth and loading time, especially when loading
|
// full maps.
|
||||||
// full maps.
|
if (viewer.audioEnabled) {
|
||||||
if (viewer.audioEnabled) {
|
final MappedData animSounds = (MappedData) tables.get(1).data;
|
||||||
final MappedData animSounds = (MappedData) tables.get(1).data;
|
|
||||||
|
|
||||||
final MappedDataRow animSoundsRow = animSounds.getRow((String) row.get("SoundLabel"));
|
final MappedDataRow animSoundsRow = animSounds.getRow((String) row.get("SoundLabel"));
|
||||||
|
|
||||||
if (animSoundsRow != null) {
|
if (animSoundsRow != null) {
|
||||||
this.distanceCutoff = getFloat(animSoundsRow, "DistanceCutoff");
|
this.distanceCutoff = getFloat(animSoundsRow, "DistanceCutoff");
|
||||||
this.maxDistance = getFloat(animSoundsRow, "MaxDistance");
|
this.maxDistance = getFloat(animSoundsRow, "MaxDistance");
|
||||||
this.minDistance = getFloat(animSoundsRow, "MinDistance");
|
this.minDistance = getFloat(animSoundsRow, "MinDistance");
|
||||||
this.pitch = getFloat(animSoundsRow, "Pitch");
|
this.pitch = getFloat(animSoundsRow, "Pitch");
|
||||||
this.pitchVariance = getFloat(animSoundsRow, "PitchVariance");
|
this.pitchVariance = getFloat(animSoundsRow, "PitchVariance");
|
||||||
this.volume = getFloat(animSoundsRow, "Volume");
|
this.volume = getFloat(animSoundsRow, "Volume");
|
||||||
|
|
||||||
final String[] fileNames = ((String) animSoundsRow.get("FileNames")).split(",");
|
final String[] fileNames = ((String) animSoundsRow.get("FileNames")).split(",");
|
||||||
final GenericResource[] resources = new GenericResource[fileNames.length];
|
final GenericResource[] resources = new GenericResource[fileNames.length];
|
||||||
for (int i = 0; i < fileNames.length; i++) {
|
for (int i = 0; i < fileNames.length; i++) {
|
||||||
final String path = ((String) animSoundsRow.get("DirectoryBase")) + fileNames[i];
|
final String path = ((String) animSoundsRow.get("DirectoryBase")) + fileNames[i];
|
||||||
try {
|
try {
|
||||||
final String pathString = pathSolver.solve(path, model.solverParams).finalSrc;
|
final String pathString = pathSolver.solve(path, model.solverParams).finalSrc;
|
||||||
final GenericResource genericResource = viewer.loadGeneric(pathString,
|
final GenericResource genericResource = viewer.loadGeneric(pathString,
|
||||||
FetchDataTypeName.ARRAY_BUFFER, new LoadGenericSoundCallback(pathString));
|
FetchDataTypeName.ARRAY_BUFFER, new LoadGenericSoundCallback(pathString));
|
||||||
if (genericResource == null) {
|
if (genericResource == null) {
|
||||||
System.err.println("Null sound: " + fileNames[i]);
|
System.err.println("Null sound: " + fileNames[i]);
|
||||||
}
|
}
|
||||||
resources[i] = genericResource;
|
resources[i] = genericResource;
|
||||||
}
|
} catch (final Exception exc) {
|
||||||
catch (final Exception exc) {
|
System.err.println("Failed to load sound: " + path);
|
||||||
System.err.println("Failed to load sound: " + path);
|
exc.printStackTrace();
|
||||||
exc.printStackTrace();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO JS async removed
|
// TODO JS async removed
|
||||||
for (final GenericResource resource : resources) {
|
for (final GenericResource resource : resources) {
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
this.decodedBuffers.add((Sound) resource.data);
|
this.decodedBuffers.add((Sound) resource.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.ok = true;
|
this.ok = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
System.err.println("Unknown event object type: " + this.type + this.id);
|
||||||
System.err.println("Unknown event object type: " + this.type + this.id);
|
}
|
||||||
}
|
} else {
|
||||||
}
|
System.err.println("Unknown event object ID: " + this.type + this.id);
|
||||||
else {
|
}
|
||||||
System.err.println("Unknown event object ID: " + this.type + this.id);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue(final long[] out, final MdxComplexInstance instance) {
|
public int getValue(final long[] out, final MdxComplexInstance instance) {
|
||||||
if (this.globalSequence != -1) {
|
if (this.globalSequence != -1) {
|
||||||
|
|
||||||
return this.getValueAtTime(out, instance.counter % this.globalSequence, 0, this.globalSequence);
|
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();
|
||||||
final long[] interval = this.model.getSequences().get(instance.sequence).getInterval();
|
|
||||||
|
|
||||||
return this.getValueAtTime(out, instance.frame, interval[0], interval[1]);
|
return this.getValueAtTime(out, instance.frame, interval[0], interval[1]);
|
||||||
}
|
} else {
|
||||||
else {
|
out[0] = this.defval[0];
|
||||||
out[0] = this.defval[0];
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getValueAtTime(final long[] out, final long frame, final long start, final long end) {
|
public int getValueAtTime(final long[] out, final long frame, final long start, final long end) {
|
||||||
if ((frame >= start) && (frame <= end)) {
|
if ((frame >= start) && (frame <= end)) {
|
||||||
for (int i = this.keyFrames.length - 1; i > -1; i--) {
|
for (int i = this.keyFrames.length - 1; i > -1; i--) {
|
||||||
if (this.keyFrames[i] < start) {
|
if (this.keyFrames[i] < start) {
|
||||||
out[0] = 0;
|
out[0] = 0;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
} else if (this.keyFrames[i] <= frame) {
|
||||||
else if (this.keyFrames[i] <= frame) {
|
out[0] = 1;
|
||||||
out[0] = 1;
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out[0] = 0;
|
out[0] = 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean ok() {
|
public boolean ok() {
|
||||||
return this.ok;
|
return this.ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getGeometryEmitterType() {
|
public int getGeometryEmitterType() {
|
||||||
return this.geometryEmitterType;
|
return this.geometryEmitterType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -32,14 +32,14 @@ public class MdxHandler extends ModelHandler {
|
|||||||
Shaders.extendedShadowMap = viewer.webGL.createShaderProgram(
|
Shaders.extendedShadowMap = viewer.webGL.createShaderProgram(
|
||||||
"#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex, MdxShaders.fsComplexShadowMap);
|
"#define EXTENDED_BONES\r\n" + MdxShaders.vsComplex, MdxShaders.fsComplexShadowMap);
|
||||||
Shaders.particles = viewer.webGL.createShaderProgram(MdxShaders.vsParticles, MdxShaders.fsParticles);
|
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);
|
// Shaders.hd = viewer.webGL.createShaderProgram(MdxShaders.vsHd, MdxShaders.fsHd);
|
||||||
// TODO HD reforged
|
// TODO HD reforged
|
||||||
|
|
||||||
// If a shader failed to compile, don't allow the handler to be registered, and
|
// If a shader failed to compile, don't allow the handler to be registered, and
|
||||||
// send an error instead.
|
// send an error instead.
|
||||||
return Shaders.complex.isCompiled() && Shaders.extended.isCompiled() && Shaders.particles.isCompiled()
|
return Shaders.complex.isCompiled() && Shaders.extended.isCompiled() && Shaders.particles.isCompiled()
|
||||||
&& Shaders.simple.isCompiled() /* && Shaders.hd.isCompiled() */;
|
/* && Shaders.simple.isCompiled() && Shaders.hd.isCompiled() */;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,6 +152,9 @@ public final class SdSequence<TYPE> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TYPE[] fixTimelineArray(final Timeline<TYPE> timeline, final TYPE[] values) {
|
private TYPE[] fixTimelineArray(final Timeline<TYPE> timeline, final TYPE[] values) {
|
||||||
|
if(values == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (timeline.getName().equals(AnimationMap.KLAC.getWar3id())
|
if (timeline.getName().equals(AnimationMap.KLAC.getWar3id())
|
||||||
|| timeline.getName().equals(AnimationMap.KLBC.getWar3id())) {
|
|| timeline.getName().equals(AnimationMap.KLBC.getWar3id())) {
|
||||||
final float[][] flippedColorData = new float[values.length][3];
|
final float[][] flippedColorData = new float[values.length][3];
|
||||||
|
@ -2,25 +2,38 @@ package com.etheller.warsmash.viewer5.handlers.w3x;
|
|||||||
|
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
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.mdx.MdxModel;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||||
|
|
||||||
public class RenderDestructable extends RenderDoodad {
|
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;
|
private final float life;
|
||||||
|
|
||||||
public RenderDestructable(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
public RenderDestructable(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||||
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
|
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
|
||||||
final float maxPitch, final float maxRoll, final float life) {
|
final float maxPitch, final float maxRoll, final float life) {
|
||||||
super(map, model, row, doodad, type, maxPitch, maxRoll);
|
super(map, model, row, doodad, type, maxPitch, maxRoll);
|
||||||
this.life = life;
|
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
|
@Override
|
||||||
public PrimaryTag getAnimation() {
|
public PrimaryTag getAnimation() {
|
||||||
if (this.life <= 0) {
|
if (this.life <= 0) {
|
||||||
return PrimaryTag.DEATH;
|
return PrimaryTag.DEATH;
|
||||||
}
|
}
|
||||||
return super.getAnimation();
|
return super.getAnimation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,86 +12,72 @@ import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||||
|
|
||||||
public class RenderDoodad {
|
public class RenderDoodad {
|
||||||
private static final int SAMPLE_RADIUS = 4;
|
private static final int SAMPLE_RADIUS = 4;
|
||||||
private static final War3ID TEX_FILE = War3ID.fromString("btxf");
|
public final ModelInstance instance;
|
||||||
private static final War3ID TEX_ID = War3ID.fromString("btxi");
|
private final MutableGameObject row;
|
||||||
public final ModelInstance instance;
|
private final float maxPitch;
|
||||||
private final MutableGameObject row;
|
private final float maxRoll;
|
||||||
private final float maxPitch;
|
|
||||||
private final float maxRoll;
|
|
||||||
|
|
||||||
public RenderDoodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
public RenderDoodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||||
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
|
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
|
||||||
final float maxPitch, final float maxRoll) {
|
final float maxPitch, final float maxRoll) {
|
||||||
this.maxPitch = maxPitch;
|
this.maxPitch = maxPitch;
|
||||||
this.maxRoll = maxRoll;
|
this.maxRoll = maxRoll;
|
||||||
final boolean isSimple = row.readSLKTagBoolean("lightweight");
|
final boolean isSimple = row.readSLKTagBoolean("lightweight");
|
||||||
ModelInstance instance;
|
ModelInstance instance;
|
||||||
|
|
||||||
if (isSimple && false) {
|
if (isSimple && false) {
|
||||||
instance = model.addInstance(1);
|
instance = model.addInstance(1);
|
||||||
}
|
} else {
|
||||||
else {
|
instance = model.addInstance();
|
||||||
instance = model.addInstance();
|
((MdxComplexInstance) instance).setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
|
||||||
((MdxComplexInstance) instance).setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
instance.move(doodad.getLocation());
|
instance.move(doodad.getLocation());
|
||||||
// TODO: the following pitch/roll system is a heuristic, and we probably want to
|
// TODO: the following pitch/roll system is a heuristic, and we probably want to
|
||||||
// revisit it later.
|
// revisit it later.
|
||||||
// Specifically, I was pretty convinced that whichever is applied first
|
// Specifically, I was pretty convinced that whichever is applied first
|
||||||
// (pitch/roll) should be used to do a projection onto the already-tilted plane
|
// (pitch/roll) should be used to do a projection onto the already-tilted plane
|
||||||
// to find the angle used for the other of the two
|
// to find the angle used for the other of the two
|
||||||
// (instead of measuring down from an imaginary flat ground plane, as we do
|
// (instead of measuring down from an imaginary flat ground plane, as we do
|
||||||
// currently).
|
// currently).
|
||||||
final float facingRadians = doodad.getAngle();
|
final float facingRadians = doodad.getAngle();
|
||||||
float pitch, roll;
|
float pitch, roll;
|
||||||
final float x = doodad.getLocation()[0];
|
final float x = doodad.getLocation()[0];
|
||||||
final float y = doodad.getLocation()[1];
|
final float y = doodad.getLocation()[1];
|
||||||
final float pitchSampleForwardX = x + (SAMPLE_RADIUS * (float) Math.cos(facingRadians));
|
final float pitchSampleForwardX = x + (SAMPLE_RADIUS * (float) Math.cos(facingRadians));
|
||||||
final float pitchSampleForwardY = y + (SAMPLE_RADIUS * (float) Math.sin(facingRadians));
|
final float pitchSampleForwardY = y + (SAMPLE_RADIUS * (float) Math.sin(facingRadians));
|
||||||
final float pitchSampleBackwardX = x - (SAMPLE_RADIUS * (float) Math.cos(facingRadians));
|
final float pitchSampleBackwardX = x - (SAMPLE_RADIUS * (float) Math.cos(facingRadians));
|
||||||
final float pitchSampleBackwardY = y - (SAMPLE_RADIUS * (float) Math.sin(facingRadians));
|
final float pitchSampleBackwardY = y - (SAMPLE_RADIUS * (float) Math.sin(facingRadians));
|
||||||
final float pitchSampleGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
|
final float pitchSampleGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
|
||||||
final float pitchSampleGorundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
|
final float pitchSampleGorundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
|
||||||
pitch = Math.max(-maxPitch, Math.min(maxPitch,
|
pitch = Math.max(-maxPitch, Math.min(maxPitch,
|
||||||
(float) Math.atan2(pitchSampleGorundHeight2 - pitchSampleGroundHeight1, SAMPLE_RADIUS * 2)));
|
(float) Math.atan2(pitchSampleGorundHeight2 - pitchSampleGroundHeight1, SAMPLE_RADIUS * 2)));
|
||||||
final double leftOfFacingAngle = facingRadians + (Math.PI / 2);
|
final double leftOfFacingAngle = facingRadians + (Math.PI / 2);
|
||||||
final float rollSampleForwardX = x + (SAMPLE_RADIUS * (float) Math.cos(leftOfFacingAngle));
|
final float rollSampleForwardX = x + (SAMPLE_RADIUS * (float) Math.cos(leftOfFacingAngle));
|
||||||
final float rollSampleForwardY = y + (SAMPLE_RADIUS * (float) Math.sin(leftOfFacingAngle));
|
final float rollSampleForwardY = y + (SAMPLE_RADIUS * (float) Math.sin(leftOfFacingAngle));
|
||||||
final float rollSampleBackwardX = x - (SAMPLE_RADIUS * (float) Math.cos(leftOfFacingAngle));
|
final float rollSampleBackwardX = x - (SAMPLE_RADIUS * (float) Math.cos(leftOfFacingAngle));
|
||||||
final float rollSampleBackwardY = y - (SAMPLE_RADIUS * (float) Math.sin(leftOfFacingAngle));
|
final float rollSampleBackwardY = y - (SAMPLE_RADIUS * (float) Math.sin(leftOfFacingAngle));
|
||||||
final float rollSampleGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
|
final float rollSampleGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
|
||||||
final float rollSampleGroundHeight2 = map.terrain.getGroundHeight(rollSampleForwardX, rollSampleForwardY);
|
final float rollSampleGroundHeight2 = map.terrain.getGroundHeight(rollSampleForwardX, rollSampleForwardY);
|
||||||
roll = Math.max(-maxRoll, Math.min(maxRoll,
|
roll = Math.max(-maxRoll, Math.min(maxRoll,
|
||||||
(float) Math.atan2(rollSampleGroundHeight2 - rollSampleGroundHeight1, SAMPLE_RADIUS * 2)));
|
(float) Math.atan2(rollSampleGroundHeight2 - rollSampleGroundHeight1, SAMPLE_RADIUS * 2)));
|
||||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, facingRadians));
|
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, facingRadians));
|
||||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Y, -pitch));
|
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Y, -pitch));
|
||||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_X, roll));
|
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_X, roll));
|
||||||
// instance.rotate(new Quaternion().setEulerAnglesRad(facingRadians, 0, 0));
|
// instance.rotate(new Quaternion().setEulerAnglesRad(facingRadians, 0, 0));
|
||||||
instance.scale(doodad.getScale());
|
instance.scale(doodad.getScale());
|
||||||
if (type == WorldEditorDataType.DOODADS) {
|
if (type == WorldEditorDataType.DOODADS) {
|
||||||
final float defScale = row.readSLKTagFloat("defScale");
|
final float defScale = row.readSLKTagFloat("defScale");
|
||||||
instance.uniformScale(defScale);
|
instance.uniformScale(defScale);
|
||||||
}
|
}
|
||||||
if (type == WorldEditorDataType.DESTRUCTIBLES) {
|
instance.setScene(map.worldScene);
|
||||||
// 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;
|
this.instance = instance;
|
||||||
this.row = row;
|
this.row = row;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrimaryTag getAnimation() {
|
public PrimaryTag getAnimation() {
|
||||||
return PrimaryTag.STAND;
|
return PrimaryTag.STAND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -411,6 +411,7 @@ public class Terrain {
|
|||||||
this.shaderMapBoundsRectangle = new Rectangle(this.shaderMapBounds[0], this.shaderMapBounds[1],
|
this.shaderMapBoundsRectangle = new Rectangle(this.shaderMapBounds[0], this.shaderMapBounds[1],
|
||||||
this.shaderMapBounds[2] - this.shaderMapBounds[0], this.shaderMapBounds[3] - this.shaderMapBounds[1]);
|
this.shaderMapBounds[2] - this.shaderMapBounds[0], this.shaderMapBounds[3] - this.shaderMapBounds[1]);
|
||||||
this.mapSize = w3eFile.getMapSize();
|
this.mapSize = w3eFile.getMapSize();
|
||||||
|
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.softwareGroundMesh = new SoftwareGroundMesh(this.groundHeights, this.groundCornerHeights,
|
||||||
this.centerOffset, width, height);
|
this.centerOffset, width, height);
|
||||||
|
|
||||||
@ -1019,15 +1020,14 @@ public class Terrain {
|
|||||||
gl.glUniform1i(6, (int) this.waterIndex);
|
gl.glUniform1i(6, (int) this.waterIndex);
|
||||||
gl.glUniform1f(this.waterShader.getUniformLocation("centerOffsetX"), this.centerOffset[0]);
|
gl.glUniform1f(this.waterShader.getUniformLocation("centerOffsetX"), this.centerOffset[0]);
|
||||||
gl.glUniform1f(this.waterShader.getUniformLocation("centerOffsetY"), this.centerOffset[1]);
|
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 W3xSceneLightManager lightManager = (W3xSceneLightManager) this.viewer.worldScene.getLightManager();
|
||||||
final DataTexture unitLightsTexture = lightManager.getTerrainLightsTexture();
|
final DataTexture terrainLightsTexture = lightManager.getTerrainLightsTexture();
|
||||||
|
|
||||||
unitLightsTexture.bind(21);
|
terrainLightsTexture.bind(3);
|
||||||
gl.glUniform1i(this.waterShader.getUniformLocation("lightTexture"), 21);
|
gl.glUniform1f(9, lightManager.getTerrainLightCount());
|
||||||
gl.glUniform1f(this.waterShader.getUniformLocation("lightCount"), lightManager.getTerrainLightCount());
|
gl.glUniform1f(10, terrainLightsTexture.getHeight());
|
||||||
gl.glUniform1f(this.waterShader.getUniformLocation("lightCountHeight"), unitLightsTexture.getHeight());
|
|
||||||
|
|
||||||
gl.glActiveTexture(GL30.GL_TEXTURE0);
|
gl.glActiveTexture(GL30.GL_TEXTURE0);
|
||||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.waterHeight);
|
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.waterHeight);
|
||||||
@ -1035,7 +1035,7 @@ public class Terrain {
|
|||||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.groundCornerHeight);
|
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.groundCornerHeight);
|
||||||
gl.glActiveTexture(GL30.GL_TEXTURE2);
|
gl.glActiveTexture(GL30.GL_TEXTURE2);
|
||||||
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.waterExists);
|
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.glBindTexture(GL30.GL_TEXTURE_2D_ARRAY, this.waterTextureArray);
|
||||||
|
|
||||||
gl.glBindBuffer(GL30.GL_ARRAY_BUFFER, Shapes.INSTANCE.vertexBuffer);
|
gl.glBindBuffer(GL30.GL_ARRAY_BUFFER, Shapes.INSTANCE.vertexBuffer);
|
||||||
@ -1239,6 +1239,7 @@ public class Terrain {
|
|||||||
private final WaveBuilder waveBuilder;
|
private final WaveBuilder waveBuilder;
|
||||||
public PathingGrid pathingGrid;
|
public PathingGrid pathingGrid;
|
||||||
private final Rectangle shaderMapBoundsRectangle;
|
private final Rectangle shaderMapBoundsRectangle;
|
||||||
|
private final Rectangle entireMapRectangle;
|
||||||
|
|
||||||
private static final class UnloadedTexture {
|
private static final class UnloadedTexture {
|
||||||
private final int width;
|
private final int width;
|
||||||
@ -1399,4 +1400,8 @@ public class Terrain {
|
|||||||
public Rectangle getPlayableMapArea() {
|
public Rectangle getPlayableMapArea() {
|
||||||
return this.shaderMapBoundsRectangle;
|
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 = 3) uniform vec4 deep_color_min;\r\n" + //
|
||||||
"layout (location = 4) uniform vec4 deep_color_max;\r\n" + //
|
"layout (location = 4) uniform vec4 deep_color_max;\r\n" + //
|
||||||
"layout (location = 5) uniform float water_offset;\r\n" + //
|
"layout (location = 5) uniform float water_offset;\r\n" + //
|
||||||
"layout (location = 10) uniform sampler2D lightTexture;\r\n" + //
|
"layout (binding = 3) uniform sampler2D lightTexture;\r\n" + //
|
||||||
"layout (location = 11) uniform float lightCount;\r\n" + //
|
"layout (location = 9) uniform float lightCount;\r\n" + //
|
||||||
"layout (location = 12) uniform float lightTextureHeight;\r\n" + //
|
"layout (location = 10) uniform float lightTextureHeight;\r\n" + //
|
||||||
"\r\n" + //
|
"\r\n" + //
|
||||||
"out vec2 UV;\r\n" + //
|
"out vec2 UV;\r\n" + //
|
||||||
"out vec4 Color;\r\n" + //
|
"out vec4 Color;\r\n" + //
|
||||||
@ -477,12 +477,12 @@ public class TerrainShaders {
|
|||||||
|
|
||||||
public static final String frag = "#version 450 core\r\n" + //
|
public static final String frag = "#version 450 core\r\n" + //
|
||||||
"\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" + //
|
"layout (binding = 2) uniform sampler2D water_exists_texture;\r\n" + //
|
||||||
"\r\n" + //
|
"\r\n" + //
|
||||||
"\r\n" + //
|
"\r\n" + //
|
||||||
"layout (location = 6) uniform int current_texture;\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" + //
|
"\r\n" + //
|
||||||
"in vec2 UV;\r\n" + //
|
"in vec2 UV;\r\n" + //
|
||||||
"in vec4 Color;\r\n" + //
|
"in vec4 Color;\r\n" + //
|
||||||
|
@ -29,374 +29,431 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitAnimationListe
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
|
||||||
|
|
||||||
public class RenderUnit {
|
public class RenderUnit {
|
||||||
private static final Quaternion tempQuat = new Quaternion();
|
private static final Quaternion tempQuat = new Quaternion();
|
||||||
private static final War3ID RED = War3ID.fromString("uclr");
|
private static final War3ID RED = War3ID.fromString("uclr");
|
||||||
private static final War3ID GREEN = War3ID.fromString("uclg");
|
private static final War3ID GREEN = War3ID.fromString("uclg");
|
||||||
private static final War3ID BLUE = War3ID.fromString("uclb");
|
private static final War3ID BLUE = War3ID.fromString("uclb");
|
||||||
private static final War3ID MODEL_SCALE = War3ID.fromString("usca");
|
private static final War3ID MODEL_SCALE = War3ID.fromString("usca");
|
||||||
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
|
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
|
||||||
private static final War3ID ORIENTATION_INTERPOLATION = War3ID.fromString("uori");
|
private static final War3ID ORIENTATION_INTERPOLATION = War3ID.fromString("uori");
|
||||||
private static final War3ID ANIM_PROPS = War3ID.fromString("uani");
|
private static final War3ID ANIM_PROPS = War3ID.fromString("uani");
|
||||||
private static final float[] heapZ = new float[3];
|
private static final float[] heapZ = new float[3];
|
||||||
public final MdxComplexInstance instance;
|
public final MdxComplexInstance instance;
|
||||||
public final MutableGameObject row;
|
public final MutableGameObject row;
|
||||||
public final float[] location = new float[3];
|
public final float[] location = new float[3];
|
||||||
public float selectionScale;
|
public float selectionScale;
|
||||||
public UnitSoundset soundset;
|
public UnitSoundset soundset;
|
||||||
public final MdxModel portraitModel;
|
public final MdxModel portraitModel;
|
||||||
public int playerIndex;
|
public int playerIndex;
|
||||||
private final CUnit simulationUnit;
|
private final CUnit simulationUnit;
|
||||||
public SplatMover shadow;
|
public SplatMover shadow;
|
||||||
public SplatMover selectionCircle;
|
public SplatMover selectionCircle;
|
||||||
|
|
||||||
private float x;
|
private float x;
|
||||||
private float y;
|
private float y;
|
||||||
private float facing;
|
private float facing;
|
||||||
|
|
||||||
private boolean swimming;
|
private boolean swimming;
|
||||||
|
|
||||||
private boolean dead = false;
|
private boolean dead = false;
|
||||||
|
|
||||||
private final UnitAnimationListenerImpl unitAnimationListenerImpl;
|
private final UnitAnimationListenerImpl unitAnimationListenerImpl;
|
||||||
private OrientationInterpolation orientationInterpolation;
|
private OrientationInterpolation orientationInterpolation;
|
||||||
private float currentTurnVelocity = 0;
|
private float currentTurnVelocity = 0;
|
||||||
public long lastUnitResponseEndTimeMillis;
|
public long lastUnitResponseEndTimeMillis;
|
||||||
private boolean corpse;
|
private boolean corpse;
|
||||||
private boolean boneCorpse;
|
private boolean boneCorpse;
|
||||||
private final RenderUnitTypeData typeData;
|
private final RenderUnitTypeData typeData;
|
||||||
|
|
||||||
public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||||
final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit, final UnitSoundset soundset,
|
final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit, final UnitSoundset soundset,
|
||||||
final MdxModel portraitModel, final CUnit simulationUnit, final RenderUnitTypeData typeData) {
|
final MdxModel portraitModel, final CUnit simulationUnit, final RenderUnitTypeData typeData) {
|
||||||
this.portraitModel = portraitModel;
|
this.portraitModel = portraitModel;
|
||||||
this.simulationUnit = simulationUnit;
|
this.simulationUnit = simulationUnit;
|
||||||
this.typeData = typeData;
|
this.typeData = typeData;
|
||||||
final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance();
|
final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance();
|
||||||
|
|
||||||
final float[] location = unit.getLocation();
|
final float[] location = unit.getLocation();
|
||||||
System.arraycopy(location, 0, this.location, 0, 3);
|
System.arraycopy(location, 0, this.location, 0, 3);
|
||||||
instance.move(location);
|
instance.move(location);
|
||||||
this.facing = simulationUnit.getFacing();
|
this.facing = simulationUnit.getFacing();
|
||||||
final float angle = (float) Math.toRadians(this.facing);
|
final float angle = (float) Math.toRadians(this.facing);
|
||||||
// instance.localRotation.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle);
|
// instance.localRotation.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle);
|
||||||
this.x = simulationUnit.getX();
|
this.x = simulationUnit.getX();
|
||||||
this.y = simulationUnit.getY();
|
this.y = simulationUnit.getY();
|
||||||
instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle));
|
instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle));
|
||||||
instance.scale(unit.getScale());
|
instance.scale(unit.getScale());
|
||||||
this.playerIndex = unit.getPlayer() & 0xFFFF;
|
this.playerIndex = unit.getPlayer() & 0xFFFF;
|
||||||
instance.setTeamColor(this.playerIndex);
|
instance.setTeamColor(this.playerIndex);
|
||||||
instance.setScene(map.worldScene);
|
instance.setScene(map.worldScene);
|
||||||
this.unitAnimationListenerImpl = new UnitAnimationListenerImpl(instance);
|
this.unitAnimationListenerImpl = new UnitAnimationListenerImpl(instance);
|
||||||
simulationUnit.setUnitAnimationListener(this.unitAnimationListenerImpl);
|
simulationUnit.setUnitAnimationListener(this.unitAnimationListenerImpl);
|
||||||
final String requiredAnimationNames = row.getFieldAsString(ANIM_PROPS, 0);
|
final String requiredAnimationNames = row.getFieldAsString(ANIM_PROPS, 0);
|
||||||
TokenLoop: for (final String animationName : requiredAnimationNames.split(",")) {
|
TokenLoop:
|
||||||
final String upperCaseToken = animationName.toUpperCase();
|
for (final String animationName : requiredAnimationNames.split(",")) {
|
||||||
for (final SecondaryTag secondaryTag : SecondaryTag.values()) {
|
final String upperCaseToken = animationName.toUpperCase();
|
||||||
if (upperCaseToken.equals(secondaryTag.name())) {
|
for (final SecondaryTag secondaryTag : SecondaryTag.values()) {
|
||||||
this.unitAnimationListenerImpl.addSecondaryTag(secondaryTag);
|
if (upperCaseToken.equals(secondaryTag.name())) {
|
||||||
continue TokenLoop;
|
this.unitAnimationListenerImpl.addSecondaryTag(secondaryTag);
|
||||||
}
|
continue TokenLoop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (row != null) {
|
if (row != null) {
|
||||||
heapZ[2] = simulationUnit.getFlyHeight();
|
heapZ[2] = simulationUnit.getFlyHeight();
|
||||||
this.location[2] += heapZ[2];
|
this.location[2] += heapZ[2];
|
||||||
|
|
||||||
instance.move(heapZ);
|
instance.move(heapZ);
|
||||||
War3ID red;
|
War3ID red;
|
||||||
War3ID green;
|
War3ID green;
|
||||||
War3ID blue;
|
War3ID blue;
|
||||||
War3ID scale;
|
War3ID scale;
|
||||||
scale = MODEL_SCALE;
|
scale = MODEL_SCALE;
|
||||||
red = RED;
|
red = RED;
|
||||||
green = GREEN;
|
green = GREEN;
|
||||||
blue = BLUE;
|
blue = BLUE;
|
||||||
instance.setVertexColor(new float[] { (row.getFieldAsInteger(red, 0)) / 255f,
|
instance.setVertexColor(new float[]{(row.getFieldAsInteger(red, 0)) / 255f,
|
||||||
(row.getFieldAsInteger(green, 0)) / 255f, (row.getFieldAsInteger(blue, 0)) / 255f });
|
(row.getFieldAsInteger(green, 0)) / 255f, (row.getFieldAsInteger(blue, 0)) / 255f});
|
||||||
instance.uniformScale(row.getFieldAsFloat(scale, 0));
|
instance.uniformScale(row.getFieldAsFloat(scale, 0));
|
||||||
|
|
||||||
this.selectionScale = row.getFieldAsFloat(War3MapViewer.UNIT_SELECT_SCALE, 0);
|
this.selectionScale = row.getFieldAsFloat(War3MapViewer.UNIT_SELECT_SCALE, 0);
|
||||||
int orientationInterpolationOrdinal = row.getFieldAsInteger(ORIENTATION_INTERPOLATION, 0);
|
int orientationInterpolationOrdinal = row.getFieldAsInteger(ORIENTATION_INTERPOLATION, 0);
|
||||||
if ((orientationInterpolationOrdinal < 0)
|
if ((orientationInterpolationOrdinal < 0)
|
||||||
|| (orientationInterpolationOrdinal >= OrientationInterpolation.VALUES.length)) {
|
|| (orientationInterpolationOrdinal >= OrientationInterpolation.VALUES.length)) {
|
||||||
orientationInterpolationOrdinal = 0;
|
orientationInterpolationOrdinal = 0;
|
||||||
}
|
}
|
||||||
this.orientationInterpolation = OrientationInterpolation.VALUES[orientationInterpolationOrdinal];
|
this.orientationInterpolation = OrientationInterpolation.VALUES[orientationInterpolationOrdinal];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.row = row;
|
this.row = row;
|
||||||
this.soundset = soundset;
|
this.soundset = soundset;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void populateCommandCard(final CommandButtonListener commandButtonListener,
|
public void populateCommandCard(final CommandButtonListener commandButtonListener,
|
||||||
final AbilityDataUI abilityDataUI) {
|
final AbilityDataUI abilityDataUI) {
|
||||||
for (final CAbility ability : this.simulationUnit.getAbilities()) {
|
for (final CAbility ability : this.simulationUnit.getAbilities()) {
|
||||||
ability.visit(CommandCardPopulatingAbilityVisitor.INSTANCE.reset(commandButtonListener, abilityDataUI));
|
ability.visit(CommandCardPopulatingAbilityVisitor.INSTANCE.reset(commandButtonListener, abilityDataUI));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAnimations(final War3MapViewer map) {
|
public void updateAnimations(final War3MapViewer map) {
|
||||||
final float deltaTime = Gdx.graphics.getDeltaTime();
|
final float deltaTime = Gdx.graphics.getDeltaTime();
|
||||||
final float simulationX = this.simulationUnit.getX();
|
final float simulationX = this.simulationUnit.getX();
|
||||||
final float simulationY = this.simulationUnit.getY();
|
final float simulationY = this.simulationUnit.getY();
|
||||||
final float simDx = simulationX - this.x;
|
final float simDx = simulationX - this.x;
|
||||||
final float simDy = simulationY - this.y;
|
final float simDy = simulationY - this.y;
|
||||||
final float distanceToSimulation = (float) Math.sqrt((simDx * simDx) + (simDy * simDy));
|
final float distanceToSimulation = (float) Math.sqrt((simDx * simDx) + (simDy * simDy));
|
||||||
final int speed = this.simulationUnit.getSpeed();
|
final int speed = this.simulationUnit.getSpeed();
|
||||||
final float speedDelta = speed * deltaTime;
|
final float speedDelta = speed * deltaTime;
|
||||||
if ((distanceToSimulation > speedDelta) && (deltaTime < 1.0)) {
|
if ((distanceToSimulation > speedDelta) && (deltaTime < 1.0)) {
|
||||||
// The 1.0 here says that after 1 second of lag, units just teleport to show
|
// The 1.0 here says that after 1 second of lag, units just teleport to show
|
||||||
// where they actually are
|
// where they actually are
|
||||||
this.x += (speedDelta * simDx) / distanceToSimulation;
|
this.x += (speedDelta * simDx) / distanceToSimulation;
|
||||||
this.y += (speedDelta * simDy) / distanceToSimulation;
|
this.y += (speedDelta * simDy) / distanceToSimulation;
|
||||||
}
|
} else {
|
||||||
else {
|
this.x = simulationX;
|
||||||
this.x = simulationX;
|
this.y = simulationY;
|
||||||
this.y = simulationY;
|
}
|
||||||
}
|
final float x = this.x;
|
||||||
final float x = this.x;
|
final float dx = x - this.location[0];
|
||||||
final float dx = x - this.location[0];
|
this.location[0] = x;
|
||||||
this.location[0] = x;
|
final float y = this.y;
|
||||||
final float y = this.y;
|
final float dy = y - this.location[1];
|
||||||
final float dy = y - this.location[1];
|
this.location[1] = y;
|
||||||
this.location[1] = y;
|
final float groundHeight;
|
||||||
final float groundHeight;
|
final MovementType movementType = this.simulationUnit.getUnitType().getMovementType();
|
||||||
final MovementType movementType = this.simulationUnit.getUnitType().getMovementType();
|
final short terrainPathing = map.terrain.pathingGrid.getPathing(x, y);
|
||||||
final short terrainPathing = map.terrain.pathingGrid.getPathing(x, y);
|
boolean swimming = (movementType == MovementType.AMPHIBIOUS)
|
||||||
final boolean swimming = (movementType == MovementType.AMPHIBIOUS)
|
&& PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.SWIMMABLE)
|
||||||
&& PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.SWIMMABLE)
|
&& !PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.WALKABLE);
|
||||||
&& !PathingGrid.isPathingFlag(terrainPathing, PathingGrid.PathingType.WALKABLE);
|
float groundHeightTerrain = map.terrain.getGroundHeight(x, y);
|
||||||
if ((swimming) || (movementType == MovementType.FLOAT) || (movementType == MovementType.FLY)
|
float groundHeightTerrainAndWater;
|
||||||
|| (movementType == MovementType.HOVER)) {
|
MdxComplexInstance currentWalkableUnder;
|
||||||
groundHeight = Math.max(map.terrain.getGroundHeight(x, y), map.terrain.getWaterHeight(x, y));
|
boolean standingOnWater = (swimming) || (movementType == MovementType.FLOAT) || (movementType == MovementType.FLY)
|
||||||
}
|
|| (movementType == MovementType.HOVER);
|
||||||
else {
|
if (standingOnWater) {
|
||||||
groundHeight = map.terrain.getGroundHeight(x, y);
|
groundHeightTerrainAndWater = Math.max(groundHeightTerrain, map.terrain.getWaterHeight(x, y));
|
||||||
}
|
} else {
|
||||||
if (swimming && !this.swimming) {
|
// land units will have their feet pass under the surface of the water
|
||||||
this.unitAnimationListenerImpl.addSecondaryTag(AnimationTokens.SecondaryTag.SWIM);
|
groundHeightTerrainAndWater = groundHeightTerrain;
|
||||||
}
|
}
|
||||||
else if (!swimming && this.swimming) {
|
if(movementType == MovementType.FLOAT) {
|
||||||
this.unitAnimationListenerImpl.removeSecondaryTag(AnimationTokens.SecondaryTag.SWIM);
|
// boats cant go on bridges
|
||||||
}
|
groundHeight = groundHeightTerrainAndWater;
|
||||||
this.swimming = swimming;
|
currentWalkableUnder = null;
|
||||||
final boolean dead = this.simulationUnit.isDead();
|
} else {
|
||||||
final boolean corpse = this.simulationUnit.isCorpse();
|
currentWalkableUnder = map.getHighestWalkableUnder(x, y);
|
||||||
final boolean boneCorpse = this.simulationUnit.isBoneCorpse();
|
if(currentWalkableUnder != null) {
|
||||||
if (dead && !this.dead) {
|
System.out.println("WALKABLE UNDER");
|
||||||
this.unitAnimationListenerImpl.playAnimation(true, PrimaryTag.DEATH, SequenceUtils.EMPTY, 1.0f, true);
|
}
|
||||||
if (this.shadow != null) {
|
War3MapViewer.gdxRayHeap.set(x, y, 4096, 0, 0, -8192);
|
||||||
this.shadow.destroy(Gdx.gl30, map.terrain.centerOffset);
|
if (currentWalkableUnder != null && currentWalkableUnder.intersectRayWithCollision(War3MapViewer.gdxRayHeap, War3MapViewer.intersectionHeap, true, true)
|
||||||
this.shadow = null;
|
&& War3MapViewer.intersectionHeap.z > groundHeightTerrainAndWater) {
|
||||||
}
|
groundHeight = War3MapViewer.intersectionHeap.z;
|
||||||
if (this.selectionCircle != null) {
|
swimming = false; // Naga Royal Guard should slither across a bridge, not swim in rock
|
||||||
this.selectionCircle.destroy(Gdx.gl30, map.terrain.centerOffset);
|
} else {
|
||||||
this.selectionCircle = null;
|
groundHeight = groundHeightTerrainAndWater;
|
||||||
}
|
currentWalkableUnder = null;
|
||||||
}
|
}
|
||||||
if (boneCorpse && !this.boneCorpse) {
|
}
|
||||||
this.unitAnimationListenerImpl.playAnimationWithDuration(true, PrimaryTag.DECAY, SequenceUtils.BONE,
|
if (swimming && !this.swimming) {
|
||||||
this.simulationUnit.getEndingDecayTime(map.simulation), true);
|
this.unitAnimationListenerImpl.addSecondaryTag(AnimationTokens.SecondaryTag.SWIM);
|
||||||
}
|
} else if (!swimming && this.swimming) {
|
||||||
else if (corpse && !this.corpse) {
|
this.unitAnimationListenerImpl.removeSecondaryTag(AnimationTokens.SecondaryTag.SWIM);
|
||||||
this.unitAnimationListenerImpl.playAnimationWithDuration(true, PrimaryTag.DECAY, SequenceUtils.FLESH,
|
}
|
||||||
map.simulation.getGameplayConstants().getDecayTime(), true);
|
this.swimming = swimming;
|
||||||
}
|
final boolean dead = this.simulationUnit.isDead();
|
||||||
this.dead = dead;
|
final boolean corpse = this.simulationUnit.isCorpse();
|
||||||
this.corpse = corpse;
|
final boolean boneCorpse = this.simulationUnit.isBoneCorpse();
|
||||||
this.boneCorpse = boneCorpse;
|
if (dead && !this.dead) {
|
||||||
this.location[2] = this.simulationUnit.getFlyHeight() + groundHeight;
|
this.unitAnimationListenerImpl.playAnimation(true, PrimaryTag.DEATH, SequenceUtils.EMPTY, 1.0f, true);
|
||||||
this.instance.moveTo(this.location);
|
if (this.shadow != null) {
|
||||||
float simulationFacing = this.simulationUnit.getFacing();
|
this.shadow.destroy(Gdx.gl30, map.terrain.centerOffset);
|
||||||
if (simulationFacing < 0) {
|
this.shadow = null;
|
||||||
simulationFacing += 360;
|
}
|
||||||
}
|
if (this.selectionCircle != null) {
|
||||||
float renderFacing = this.facing;
|
this.selectionCircle.destroy(Gdx.gl30, map.terrain.centerOffset);
|
||||||
if (renderFacing < 0) {
|
this.selectionCircle = null;
|
||||||
renderFacing += 360;
|
}
|
||||||
}
|
}
|
||||||
float facingDelta = simulationFacing - renderFacing;
|
if (boneCorpse && !this.boneCorpse) {
|
||||||
if (facingDelta < -180) {
|
this.unitAnimationListenerImpl.playAnimationWithDuration(true, PrimaryTag.DECAY, SequenceUtils.BONE,
|
||||||
facingDelta = 360 + facingDelta;
|
this.simulationUnit.getEndingDecayTime(map.simulation), true);
|
||||||
}
|
} else if (corpse && !this.corpse) {
|
||||||
if (facingDelta > 180) {
|
this.unitAnimationListenerImpl.playAnimationWithDuration(true, PrimaryTag.DECAY, SequenceUtils.FLESH,
|
||||||
facingDelta = -360 + facingDelta;
|
map.simulation.getGameplayConstants().getDecayTime(), true);
|
||||||
}
|
}
|
||||||
final float absoluteFacingDelta = Math.abs(facingDelta);
|
this.dead = dead;
|
||||||
final float turningSign = Math.signum(facingDelta);
|
this.corpse = corpse;
|
||||||
|
this.boneCorpse = boneCorpse;
|
||||||
|
this.location[2] = this.simulationUnit.getFlyHeight() + groundHeight;
|
||||||
|
this.instance.moveTo(this.location);
|
||||||
|
float simulationFacing = this.simulationUnit.getFacing();
|
||||||
|
if (simulationFacing < 0) {
|
||||||
|
simulationFacing += 360;
|
||||||
|
}
|
||||||
|
float renderFacing = this.facing;
|
||||||
|
if (renderFacing < 0) {
|
||||||
|
renderFacing += 360;
|
||||||
|
}
|
||||||
|
float facingDelta = simulationFacing - renderFacing;
|
||||||
|
if (facingDelta < -180) {
|
||||||
|
facingDelta = 360 + facingDelta;
|
||||||
|
}
|
||||||
|
if (facingDelta > 180) {
|
||||||
|
facingDelta = -360 + facingDelta;
|
||||||
|
}
|
||||||
|
final float absoluteFacingDelta = Math.abs(facingDelta);
|
||||||
|
final float turningSign = Math.signum(facingDelta);
|
||||||
|
|
||||||
final float absoluteFacingDeltaRadians = (float) Math.toRadians(absoluteFacingDelta);
|
final float absoluteFacingDeltaRadians = (float) Math.toRadians(absoluteFacingDelta);
|
||||||
float acceleration;
|
float acceleration;
|
||||||
final boolean endPhase = (absoluteFacingDeltaRadians <= this.orientationInterpolation.getEndingAccelCutoff())
|
final boolean endPhase = (absoluteFacingDeltaRadians <= this.orientationInterpolation.getEndingAccelCutoff())
|
||||||
&& ((this.currentTurnVelocity * turningSign) > 0);
|
&& ((this.currentTurnVelocity * turningSign) > 0);
|
||||||
if (endPhase) {
|
if (endPhase) {
|
||||||
this.currentTurnVelocity = (1
|
this.currentTurnVelocity = (1
|
||||||
- ((this.orientationInterpolation.getEndingAccelCutoff() - absoluteFacingDeltaRadians)
|
- ((this.orientationInterpolation.getEndingAccelCutoff() - absoluteFacingDeltaRadians)
|
||||||
/ this.orientationInterpolation.getEndingAccelCutoff()))
|
/ this.orientationInterpolation.getEndingAccelCutoff()))
|
||||||
* (this.orientationInterpolation.getMaxVelocity()) * turningSign;
|
* (this.orientationInterpolation.getMaxVelocity()) * turningSign;
|
||||||
}
|
} else {
|
||||||
else {
|
acceleration = this.orientationInterpolation.getStartingAcceleration() * turningSign;
|
||||||
acceleration = this.orientationInterpolation.getStartingAcceleration() * turningSign;
|
this.currentTurnVelocity = this.currentTurnVelocity + acceleration;
|
||||||
this.currentTurnVelocity = this.currentTurnVelocity + acceleration;
|
}
|
||||||
}
|
if ((this.currentTurnVelocity * turningSign) > this.orientationInterpolation.getMaxVelocity()) {
|
||||||
if ((this.currentTurnVelocity * turningSign) > this.orientationInterpolation.getMaxVelocity()) {
|
this.currentTurnVelocity = this.orientationInterpolation.getMaxVelocity() * turningSign;
|
||||||
this.currentTurnVelocity = this.orientationInterpolation.getMaxVelocity() * turningSign;
|
}
|
||||||
}
|
float angleToAdd = (float) ((Math.toDegrees(this.currentTurnVelocity) * deltaTime) / 0.03f);
|
||||||
float angleToAdd = (float) ((Math.toDegrees(this.currentTurnVelocity) * deltaTime) / 0.03f);
|
|
||||||
|
|
||||||
if (absoluteFacingDelta < Math.abs(angleToAdd)) {
|
if (absoluteFacingDelta < Math.abs(angleToAdd)) {
|
||||||
angleToAdd = facingDelta;
|
angleToAdd = facingDelta;
|
||||||
this.currentTurnVelocity = 0.0f;
|
this.currentTurnVelocity = 0.0f;
|
||||||
}
|
}
|
||||||
this.facing = (((this.facing + angleToAdd) % 360) + 360) % 360;
|
this.facing = (((this.facing + angleToAdd) % 360) + 360) % 360;
|
||||||
this.instance.setLocalRotation(tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.facing));
|
this.instance.setLocalRotation(tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.facing));
|
||||||
|
|
||||||
final float facingRadians = (float) Math.toRadians(this.facing);
|
final float facingRadians = (float) Math.toRadians(this.facing);
|
||||||
final float maxPitch = this.typeData.getMaxPitch();
|
final float maxPitch = this.typeData.getMaxPitch();
|
||||||
final float maxRoll = this.typeData.getMaxRoll();
|
final float maxRoll = this.typeData.getMaxRoll();
|
||||||
final float sampleRadius = this.typeData.getElevationSampleRadius();
|
final float sampleRadius = this.typeData.getElevationSampleRadius();
|
||||||
float pitch, roll;
|
float pitch, roll;
|
||||||
final float pitchSampleForwardX = x + (sampleRadius * (float) Math.cos(facingRadians));
|
final float pitchSampleForwardX = x + (sampleRadius * (float) Math.cos(facingRadians));
|
||||||
final float pitchSampleForwardY = y + (sampleRadius * (float) Math.sin(facingRadians));
|
final float pitchSampleForwardY = y + (sampleRadius * (float) Math.sin(facingRadians));
|
||||||
final float pitchSampleBackwardX = x - (sampleRadius * (float) Math.cos(facingRadians));
|
final float pitchSampleBackwardX = x - (sampleRadius * (float) Math.cos(facingRadians));
|
||||||
final float pitchSampleBackwardY = y - (sampleRadius * (float) Math.sin(facingRadians));
|
final float pitchSampleBackwardY = y - (sampleRadius * (float) Math.sin(facingRadians));
|
||||||
final float pitchSampleGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
|
final double leftOfFacingAngle = facingRadians + (Math.PI / 2);
|
||||||
final float pitchSampleGorundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
|
final float rollSampleForwardX = x + (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
||||||
pitch = Math.max(-maxPitch, Math.min(maxPitch,
|
final float rollSampleForwardY = y + (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
||||||
(float) Math.atan2(pitchSampleGorundHeight2 - pitchSampleGroundHeight1, sampleRadius * 2)));
|
final float rollSampleBackwardX = x - (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
||||||
final double leftOfFacingAngle = facingRadians + (Math.PI / 2);
|
final float rollSampleBackwardY = y - (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
||||||
final float rollSampleForwardX = x + (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
final float pitchSampleGroundHeight1;
|
||||||
final float rollSampleForwardY = y + (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
final float pitchSampleGroundHeight2;
|
||||||
final float rollSampleBackwardX = x - (sampleRadius * (float) Math.cos(leftOfFacingAngle));
|
final float rollSampleGroundHeight1;
|
||||||
final float rollSampleBackwardY = y - (sampleRadius * (float) Math.sin(leftOfFacingAngle));
|
final float rollSampleGroundHeight2;
|
||||||
final float rollSampleGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
|
if (currentWalkableUnder != null) {
|
||||||
final float rollSampleGroundHeight2 = map.terrain.getGroundHeight(rollSampleForwardX, rollSampleForwardY);
|
pitchSampleGroundHeight1 = getGroundHeightSample(groundHeight, currentWalkableUnder, pitchSampleBackwardX, pitchSampleBackwardY);
|
||||||
roll = Math.max(-maxRoll, Math.min(maxRoll,
|
pitchSampleGroundHeight2 = getGroundHeightSample(groundHeight, currentWalkableUnder, pitchSampleForwardX, pitchSampleForwardY);
|
||||||
(float) Math.atan2(rollSampleGroundHeight2 - rollSampleGroundHeight1, sampleRadius * 2)));
|
rollSampleGroundHeight1 = getGroundHeightSample(groundHeight, currentWalkableUnder, rollSampleBackwardX, rollSampleBackwardY);
|
||||||
this.instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Y, -pitch));
|
rollSampleGroundHeight2 = getGroundHeightSample(groundHeight, currentWalkableUnder, rollSampleForwardX, rollSampleForwardY);
|
||||||
this.instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_X, roll));
|
} else {
|
||||||
|
float pitchGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
|
||||||
|
float pitchGroundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
|
||||||
|
float rollGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
|
||||||
|
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));
|
||||||
|
this.instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_X, roll));
|
||||||
|
|
||||||
map.worldScene.instanceMoved(this.instance, this.location[0], this.location[1]);
|
map.worldScene.instanceMoved(this.instance, this.location[0], this.location[1]);
|
||||||
if (this.shadow != null) {
|
if (this.shadow != null) {
|
||||||
this.shadow.move(dx, dy, map.terrain.centerOffset);
|
this.shadow.move(dx, dy, map.terrain.centerOffset);
|
||||||
}
|
}
|
||||||
if (this.selectionCircle != null) {
|
if (this.selectionCircle != null) {
|
||||||
this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
|
this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
|
||||||
}
|
}
|
||||||
this.unitAnimationListenerImpl.update();
|
this.unitAnimationListenerImpl.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CUnit getSimulationUnit() {
|
private float getGroundHeightSample(float groundHeight, MdxComplexInstance currentWalkableUnder, float sampleX, float sampleY) {
|
||||||
return this.simulationUnit;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
private static final class UnitAnimationListenerImpl implements CUnitAnimationListener {
|
public CUnit getSimulationUnit() {
|
||||||
private final MdxComplexInstance instance;
|
return this.simulationUnit;
|
||||||
private final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet
|
}
|
||||||
.noneOf(AnimationTokens.SecondaryTag.class);
|
|
||||||
private final EnumSet<AnimationTokens.SecondaryTag> recycleSet = EnumSet
|
|
||||||
.noneOf(AnimationTokens.SecondaryTag.class);
|
|
||||||
private PrimaryTag currentAnimation;
|
|
||||||
private EnumSet<SecondaryTag> currentAnimationSecondaryTags;
|
|
||||||
private float currentSpeedRatio;
|
|
||||||
private boolean currentlyAllowingRarityVariations;
|
|
||||||
private final Queue<QueuedAnimation> animationQueue = new LinkedList<>();
|
|
||||||
|
|
||||||
public UnitAnimationListenerImpl(final MdxComplexInstance instance) {
|
private static final class UnitAnimationListenerImpl implements CUnitAnimationListener {
|
||||||
this.instance = instance;
|
private final MdxComplexInstance instance;
|
||||||
}
|
private final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet
|
||||||
|
.noneOf(AnimationTokens.SecondaryTag.class);
|
||||||
|
private final EnumSet<AnimationTokens.SecondaryTag> recycleSet = EnumSet
|
||||||
|
.noneOf(AnimationTokens.SecondaryTag.class);
|
||||||
|
private PrimaryTag currentAnimation;
|
||||||
|
private EnumSet<SecondaryTag> currentAnimationSecondaryTags;
|
||||||
|
private float currentSpeedRatio;
|
||||||
|
private boolean currentlyAllowingRarityVariations;
|
||||||
|
private final Queue<QueuedAnimation> animationQueue = new LinkedList<>();
|
||||||
|
|
||||||
public void addSecondaryTag(final AnimationTokens.SecondaryTag tag) {
|
public UnitAnimationListenerImpl(final MdxComplexInstance instance) {
|
||||||
this.secondaryAnimationTags.add(tag);
|
this.instance = instance;
|
||||||
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags, this.currentSpeedRatio,
|
}
|
||||||
this.currentlyAllowingRarityVariations);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeSecondaryTag(final AnimationTokens.SecondaryTag tag) {
|
public void addSecondaryTag(final AnimationTokens.SecondaryTag tag) {
|
||||||
this.secondaryAnimationTags.remove(tag);
|
this.secondaryAnimationTags.add(tag);
|
||||||
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags, this.currentSpeedRatio,
|
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags, this.currentSpeedRatio,
|
||||||
this.currentlyAllowingRarityVariations);
|
this.currentlyAllowingRarityVariations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void removeSecondaryTag(final AnimationTokens.SecondaryTag tag) {
|
||||||
public void playAnimation(final boolean force, final PrimaryTag animationName,
|
this.secondaryAnimationTags.remove(tag);
|
||||||
final EnumSet<SecondaryTag> secondaryAnimationTags, final float speedRatio,
|
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags, this.currentSpeedRatio,
|
||||||
final boolean allowRarityVariations) {
|
this.currentlyAllowingRarityVariations);
|
||||||
this.animationQueue.clear();
|
}
|
||||||
if (force || (animationName != this.currentAnimation)) {
|
|
||||||
this.currentAnimation = animationName;
|
|
||||||
this.currentAnimationSecondaryTags = secondaryAnimationTags;
|
|
||||||
this.currentSpeedRatio = speedRatio;
|
|
||||||
this.currentlyAllowingRarityVariations = allowRarityVariations;
|
|
||||||
this.recycleSet.clear();
|
|
||||||
this.recycleSet.addAll(this.secondaryAnimationTags);
|
|
||||||
this.recycleSet.addAll(secondaryAnimationTags);
|
|
||||||
this.instance.setAnimationSpeed(speedRatio);
|
|
||||||
SequenceUtils.randomSequence(this.instance, animationName, this.recycleSet, allowRarityVariations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playAnimationWithDuration(final boolean force, final PrimaryTag animationName,
|
@Override
|
||||||
final EnumSet<SecondaryTag> secondaryAnimationTags, final float duration,
|
public void playAnimation(final boolean force, final PrimaryTag animationName,
|
||||||
final boolean allowRarityVariations) {
|
final EnumSet<SecondaryTag> secondaryAnimationTags, final float speedRatio,
|
||||||
this.animationQueue.clear();
|
final boolean allowRarityVariations) {
|
||||||
if (force || (animationName != this.currentAnimation)) {
|
this.animationQueue.clear();
|
||||||
this.currentAnimation = animationName;
|
if (force || (animationName != this.currentAnimation)) {
|
||||||
this.currentAnimationSecondaryTags = secondaryAnimationTags;
|
this.currentAnimation = animationName;
|
||||||
this.currentlyAllowingRarityVariations = allowRarityVariations;
|
this.currentAnimationSecondaryTags = secondaryAnimationTags;
|
||||||
this.recycleSet.clear();
|
this.currentSpeedRatio = speedRatio;
|
||||||
this.recycleSet.addAll(this.secondaryAnimationTags);
|
this.currentlyAllowingRarityVariations = allowRarityVariations;
|
||||||
this.recycleSet.addAll(secondaryAnimationTags);
|
this.recycleSet.clear();
|
||||||
final Sequence sequence = SequenceUtils.randomSequence(this.instance, animationName, this.recycleSet,
|
this.recycleSet.addAll(this.secondaryAnimationTags);
|
||||||
allowRarityVariations);
|
this.recycleSet.addAll(secondaryAnimationTags);
|
||||||
if (sequence != null) {
|
this.instance.setAnimationSpeed(speedRatio);
|
||||||
this.currentSpeedRatio = ((sequence.getInterval()[1] - sequence.getInterval()[0]) / 1000.0f)
|
SequenceUtils.randomSequence(this.instance, animationName, this.recycleSet, allowRarityVariations);
|
||||||
/ duration;
|
}
|
||||||
this.instance.setAnimationSpeed(this.currentSpeedRatio);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public void playAnimationWithDuration(final boolean force, final PrimaryTag animationName,
|
||||||
public void queueAnimation(final PrimaryTag animationName, final EnumSet<SecondaryTag> secondaryAnimationTags,
|
final EnumSet<SecondaryTag> secondaryAnimationTags, final float duration,
|
||||||
final boolean allowRarityVariations) {
|
final boolean allowRarityVariations) {
|
||||||
this.animationQueue.add(new QueuedAnimation(animationName, secondaryAnimationTags, allowRarityVariations));
|
this.animationQueue.clear();
|
||||||
}
|
if (force || (animationName != this.currentAnimation)) {
|
||||||
|
this.currentAnimation = animationName;
|
||||||
|
this.currentAnimationSecondaryTags = secondaryAnimationTags;
|
||||||
|
this.currentlyAllowingRarityVariations = allowRarityVariations;
|
||||||
|
this.recycleSet.clear();
|
||||||
|
this.recycleSet.addAll(this.secondaryAnimationTags);
|
||||||
|
this.recycleSet.addAll(secondaryAnimationTags);
|
||||||
|
final Sequence sequence = SequenceUtils.randomSequence(this.instance, animationName, this.recycleSet,
|
||||||
|
allowRarityVariations);
|
||||||
|
if (sequence != null) {
|
||||||
|
this.currentSpeedRatio = ((sequence.getInterval()[1] - sequence.getInterval()[0]) / 1000.0f)
|
||||||
|
/ duration;
|
||||||
|
this.instance.setAnimationSpeed(this.currentSpeedRatio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void update() {
|
@Override
|
||||||
if (this.instance.sequenceEnded || (this.instance.sequence == -1)) {
|
public void queueAnimation(final PrimaryTag animationName, final EnumSet<SecondaryTag> secondaryAnimationTags,
|
||||||
// animation done
|
final boolean allowRarityVariations) {
|
||||||
if ((this.instance.sequence != -1) && (((MdxModel) this.instance.model).getSequences()
|
this.animationQueue.add(new QueuedAnimation(animationName, secondaryAnimationTags, allowRarityVariations));
|
||||||
.get(this.instance.sequence).getFlags() == 0)) {
|
}
|
||||||
// animation is a looping animation
|
|
||||||
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags,
|
|
||||||
this.currentSpeedRatio, this.currentlyAllowingRarityVariations);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final QueuedAnimation nextAnimation = this.animationQueue.poll();
|
|
||||||
if (nextAnimation != null) {
|
|
||||||
playAnimation(true, nextAnimation.animationName, nextAnimation.secondaryAnimationTags, 1.0f,
|
|
||||||
nextAnimation.allowRarityVariations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
public void update() {
|
||||||
|
if (this.instance.sequenceEnded || (this.instance.sequence == -1)) {
|
||||||
|
// animation done
|
||||||
|
if ((this.instance.sequence != -1) && (((MdxModel) this.instance.model).getSequences()
|
||||||
|
.get(this.instance.sequence).getFlags() == 0)) {
|
||||||
|
// animation is a looping animation
|
||||||
|
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags,
|
||||||
|
this.currentSpeedRatio, this.currentlyAllowingRarityVariations);
|
||||||
|
} else {
|
||||||
|
final QueuedAnimation nextAnimation = this.animationQueue.poll();
|
||||||
|
if (nextAnimation != null) {
|
||||||
|
playAnimation(true, nextAnimation.animationName, nextAnimation.secondaryAnimationTags, 1.0f,
|
||||||
|
nextAnimation.allowRarityVariations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final class QueuedAnimation {
|
}
|
||||||
private final PrimaryTag animationName;
|
|
||||||
private final EnumSet<SecondaryTag> secondaryAnimationTags;
|
|
||||||
private final boolean allowRarityVariations;
|
|
||||||
|
|
||||||
public QueuedAnimation(final PrimaryTag animationName, final EnumSet<SecondaryTag> secondaryAnimationTags,
|
private static final class QueuedAnimation {
|
||||||
final boolean allowRarityVariations) {
|
private final PrimaryTag animationName;
|
||||||
this.animationName = animationName;
|
private final EnumSet<SecondaryTag> secondaryAnimationTags;
|
||||||
this.secondaryAnimationTags = secondaryAnimationTags;
|
private final boolean allowRarityVariations;
|
||||||
this.allowRarityVariations = allowRarityVariations;
|
|
||||||
}
|
public QueuedAnimation(final PrimaryTag animationName, final EnumSet<SecondaryTag> secondaryAnimationTags,
|
||||||
}
|
final boolean allowRarityVariations) {
|
||||||
|
this.animationName = animationName;
|
||||||
|
this.secondaryAnimationTags = secondaryAnimationTags;
|
||||||
|
this.allowRarityVariations = allowRarityVariations;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,388 +32,396 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUni
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
|
||||||
|
|
||||||
public class CUnitData {
|
public class CUnitData {
|
||||||
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
|
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
|
||||||
private static final War3ID MANA_MAXIMUM = War3ID.fromString("umpm");
|
private static final War3ID MANA_MAXIMUM = War3ID.fromString("umpm");
|
||||||
private static final War3ID HIT_POINT_MAXIMUM = War3ID.fromString("uhpm");
|
private static final War3ID HIT_POINT_MAXIMUM = War3ID.fromString("uhpm");
|
||||||
private static final War3ID MOVEMENT_SPEED_BASE = War3ID.fromString("umvs");
|
private static final War3ID MOVEMENT_SPEED_BASE = War3ID.fromString("umvs");
|
||||||
private static final War3ID PROPULSION_WINDOW = War3ID.fromString("uprw");
|
private static final War3ID PROPULSION_WINDOW = War3ID.fromString("uprw");
|
||||||
private static final War3ID TURN_RATE = War3ID.fromString("umvr");
|
private static final War3ID TURN_RATE = War3ID.fromString("umvr");
|
||||||
private static final War3ID IS_BLDG = War3ID.fromString("ubdg");
|
private static final War3ID IS_BLDG = War3ID.fromString("ubdg");
|
||||||
private static final War3ID NAME = War3ID.fromString("unam");
|
private static final War3ID NAME = War3ID.fromString("unam");
|
||||||
private static final War3ID PROJECTILE_LAUNCH_X = War3ID.fromString("ulpx");
|
private static final War3ID PROJECTILE_LAUNCH_X = War3ID.fromString("ulpx");
|
||||||
private static final War3ID PROJECTILE_LAUNCH_Y = War3ID.fromString("ulpy");
|
private static final War3ID PROJECTILE_LAUNCH_Y = War3ID.fromString("ulpy");
|
||||||
private static final War3ID PROJECTILE_LAUNCH_Z = War3ID.fromString("ulpz");
|
private static final War3ID PROJECTILE_LAUNCH_Z = War3ID.fromString("ulpz");
|
||||||
private static final War3ID ATTACKS_ENABLED = War3ID.fromString("uaen");
|
private static final War3ID ATTACKS_ENABLED = War3ID.fromString("uaen");
|
||||||
private static final War3ID ATTACK1_BACKSWING_POINT = War3ID.fromString("ubs1");
|
private static final War3ID ATTACK1_BACKSWING_POINT = War3ID.fromString("ubs1");
|
||||||
private static final War3ID ATTACK1_DAMAGE_POINT = War3ID.fromString("udp1");
|
private static final War3ID ATTACK1_DAMAGE_POINT = War3ID.fromString("udp1");
|
||||||
private static final War3ID ATTACK1_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua1f");
|
private static final War3ID ATTACK1_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua1f");
|
||||||
private static final War3ID ATTACK1_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua1h");
|
private static final War3ID ATTACK1_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua1h");
|
||||||
private static final War3ID ATTACK1_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua1q");
|
private static final War3ID ATTACK1_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua1q");
|
||||||
private static final War3ID ATTACK1_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua1p");
|
private static final War3ID ATTACK1_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua1p");
|
||||||
private static final War3ID ATTACK1_ATTACK_TYPE = War3ID.fromString("ua1t");
|
private static final War3ID ATTACK1_ATTACK_TYPE = War3ID.fromString("ua1t");
|
||||||
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
|
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
|
||||||
private static final War3ID ATTACK1_DMG_BASE = War3ID.fromString("ua1b");
|
private static final War3ID ATTACK1_DMG_BASE = War3ID.fromString("ua1b");
|
||||||
private static final War3ID ATTACK1_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd1");
|
private static final War3ID ATTACK1_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd1");
|
||||||
private static final War3ID ATTACK1_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd1");
|
private static final War3ID ATTACK1_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd1");
|
||||||
private static final War3ID ATTACK1_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl1");
|
private static final War3ID ATTACK1_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl1");
|
||||||
private static final War3ID ATTACK1_DMG_DICE = War3ID.fromString("ua1d");
|
private static final War3ID ATTACK1_DMG_DICE = War3ID.fromString("ua1d");
|
||||||
private static final War3ID ATTACK1_DMG_SIDES_PER_DIE = War3ID.fromString("ua1s");
|
private static final War3ID ATTACK1_DMG_SIDES_PER_DIE = War3ID.fromString("ua1s");
|
||||||
private static final War3ID ATTACK1_DMG_SPILL_DIST = War3ID.fromString("usd1");
|
private static final War3ID ATTACK1_DMG_SPILL_DIST = War3ID.fromString("usd1");
|
||||||
private static final War3ID ATTACK1_DMG_SPILL_RADIUS = War3ID.fromString("usr1");
|
private static final War3ID ATTACK1_DMG_SPILL_RADIUS = War3ID.fromString("usr1");
|
||||||
private static final War3ID ATTACK1_DMG_UPGRADE_AMT = War3ID.fromString("udu1");
|
private static final War3ID ATTACK1_DMG_UPGRADE_AMT = War3ID.fromString("udu1");
|
||||||
private static final War3ID ATTACK1_TARGET_COUNT = War3ID.fromString("utc1");
|
private static final War3ID ATTACK1_TARGET_COUNT = War3ID.fromString("utc1");
|
||||||
private static final War3ID ATTACK1_PROJECTILE_ARC = War3ID.fromString("uma1");
|
private static final War3ID ATTACK1_PROJECTILE_ARC = War3ID.fromString("uma1");
|
||||||
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
|
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
|
||||||
private static final War3ID ATTACK1_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh1");
|
private static final War3ID ATTACK1_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh1");
|
||||||
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
|
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
|
||||||
private static final War3ID ATTACK1_RANGE = War3ID.fromString("ua1r");
|
private static final War3ID ATTACK1_RANGE = War3ID.fromString("ua1r");
|
||||||
private static final War3ID ATTACK1_RANGE_MOTION_BUFFER = War3ID.fromString("urb1");
|
private static final War3ID ATTACK1_RANGE_MOTION_BUFFER = War3ID.fromString("urb1");
|
||||||
private static final War3ID ATTACK1_SHOW_UI = War3ID.fromString("uwu1");
|
private static final War3ID ATTACK1_SHOW_UI = War3ID.fromString("uwu1");
|
||||||
private static final War3ID ATTACK1_TARGETS_ALLOWED = War3ID.fromString("ua1g");
|
private static final War3ID ATTACK1_TARGETS_ALLOWED = War3ID.fromString("ua1g");
|
||||||
private static final War3ID ATTACK1_WEAPON_SOUND = War3ID.fromString("ucs1");
|
private static final War3ID ATTACK1_WEAPON_SOUND = War3ID.fromString("ucs1");
|
||||||
private static final War3ID ATTACK1_WEAPON_TYPE = War3ID.fromString("ua1w");
|
private static final War3ID ATTACK1_WEAPON_TYPE = War3ID.fromString("ua1w");
|
||||||
|
|
||||||
private static final War3ID ATTACK2_BACKSWING_POINT = War3ID.fromString("ubs2");
|
private static final War3ID ATTACK2_BACKSWING_POINT = War3ID.fromString("ubs2");
|
||||||
private static final War3ID ATTACK2_DAMAGE_POINT = War3ID.fromString("udp2");
|
private static final War3ID ATTACK2_DAMAGE_POINT = War3ID.fromString("udp2");
|
||||||
private static final War3ID ATTACK2_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua2f");
|
private static final War3ID ATTACK2_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua2f");
|
||||||
private static final War3ID ATTACK2_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua2h");
|
private static final War3ID ATTACK2_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua2h");
|
||||||
private static final War3ID ATTACK2_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua2q");
|
private static final War3ID ATTACK2_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua2q");
|
||||||
private static final War3ID ATTACK2_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua2p");
|
private static final War3ID ATTACK2_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua2p");
|
||||||
private static final War3ID ATTACK2_ATTACK_TYPE = War3ID.fromString("ua2t");
|
private static final War3ID ATTACK2_ATTACK_TYPE = War3ID.fromString("ua2t");
|
||||||
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
|
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
|
||||||
private static final War3ID ATTACK2_DMG_BASE = War3ID.fromString("ua2b");
|
private static final War3ID ATTACK2_DMG_BASE = War3ID.fromString("ua2b");
|
||||||
private static final War3ID ATTACK2_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd2");
|
private static final War3ID ATTACK2_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd2");
|
||||||
private static final War3ID ATTACK2_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd2");
|
private static final War3ID ATTACK2_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd2");
|
||||||
private static final War3ID ATTACK2_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl2");
|
private static final War3ID ATTACK2_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl2");
|
||||||
private static final War3ID ATTACK2_DMG_DICE = War3ID.fromString("ua2d");
|
private static final War3ID ATTACK2_DMG_DICE = War3ID.fromString("ua2d");
|
||||||
private static final War3ID ATTACK2_DMG_SIDES_PER_DIE = War3ID.fromString("ua2s");
|
private static final War3ID ATTACK2_DMG_SIDES_PER_DIE = War3ID.fromString("ua2s");
|
||||||
private static final War3ID ATTACK2_DMG_SPILL_DIST = War3ID.fromString("usd2");
|
private static final War3ID ATTACK2_DMG_SPILL_DIST = War3ID.fromString("usd2");
|
||||||
private static final War3ID ATTACK2_DMG_SPILL_RADIUS = War3ID.fromString("usr2");
|
private static final War3ID ATTACK2_DMG_SPILL_RADIUS = War3ID.fromString("usr2");
|
||||||
private static final War3ID ATTACK2_DMG_UPGRADE_AMT = War3ID.fromString("udu2");
|
private static final War3ID ATTACK2_DMG_UPGRADE_AMT = War3ID.fromString("udu2");
|
||||||
private static final War3ID ATTACK2_TARGET_COUNT = War3ID.fromString("utc2");
|
private static final War3ID ATTACK2_TARGET_COUNT = War3ID.fromString("utc2");
|
||||||
private static final War3ID ATTACK2_PROJECTILE_ARC = War3ID.fromString("uma2");
|
private static final War3ID ATTACK2_PROJECTILE_ARC = War3ID.fromString("uma2");
|
||||||
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
|
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
|
||||||
private static final War3ID ATTACK2_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh2");
|
private static final War3ID ATTACK2_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh2");
|
||||||
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
|
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
|
||||||
private static final War3ID ATTACK2_RANGE = War3ID.fromString("ua2r");
|
private static final War3ID ATTACK2_RANGE = War3ID.fromString("ua2r");
|
||||||
private static final War3ID ATTACK2_RANGE_MOTION_BUFFER = War3ID.fromString("urb2");
|
private static final War3ID ATTACK2_RANGE_MOTION_BUFFER = War3ID.fromString("urb2");
|
||||||
private static final War3ID ATTACK2_SHOW_UI = War3ID.fromString("uwu2");
|
private static final War3ID ATTACK2_SHOW_UI = War3ID.fromString("uwu2");
|
||||||
private static final War3ID ATTACK2_TARGETS_ALLOWED = War3ID.fromString("ua2g");
|
private static final War3ID ATTACK2_TARGETS_ALLOWED = War3ID.fromString("ua2g");
|
||||||
private static final War3ID ATTACK2_WEAPON_SOUND = War3ID.fromString("ucs2");
|
private static final War3ID ATTACK2_WEAPON_SOUND = War3ID.fromString("ucs2");
|
||||||
private static final War3ID ATTACK2_WEAPON_TYPE = War3ID.fromString("ua2w");
|
private static final War3ID ATTACK2_WEAPON_TYPE = War3ID.fromString("ua2w");
|
||||||
|
|
||||||
private static final War3ID ACQUISITION_RANGE = War3ID.fromString("uacq");
|
private static final War3ID ACQUISITION_RANGE = War3ID.fromString("uacq");
|
||||||
private static final War3ID MINIMUM_ATTACK_RANGE = War3ID.fromString("uamn");
|
private static final War3ID MINIMUM_ATTACK_RANGE = War3ID.fromString("uamn");
|
||||||
|
|
||||||
private static final War3ID PROJECTILE_IMPACT_Z = War3ID.fromString("uimz");
|
private static final War3ID PROJECTILE_IMPACT_Z = War3ID.fromString("uimz");
|
||||||
|
|
||||||
private static final War3ID DEATH_TYPE = War3ID.fromString("udea");
|
private static final War3ID DEATH_TYPE = War3ID.fromString("udea");
|
||||||
private static final War3ID ARMOR_TYPE = War3ID.fromString("uarm");
|
private static final War3ID ARMOR_TYPE = War3ID.fromString("uarm");
|
||||||
|
|
||||||
private static final War3ID DEFENSE = War3ID.fromString("udef");
|
private static final War3ID DEFENSE = War3ID.fromString("udef");
|
||||||
private static final War3ID DEFENSE_TYPE = War3ID.fromString("udty");
|
private static final War3ID DEFENSE_TYPE = War3ID.fromString("udty");
|
||||||
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
|
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
|
||||||
private static final War3ID MOVE_TYPE = War3ID.fromString("umvt");
|
private static final War3ID MOVE_TYPE = War3ID.fromString("umvt");
|
||||||
private static final War3ID COLLISION_SIZE = War3ID.fromString("ucol");
|
private static final War3ID COLLISION_SIZE = War3ID.fromString("ucol");
|
||||||
private static final War3ID CLASSIFICATION = War3ID.fromString("utyp");
|
private static final War3ID CLASSIFICATION = War3ID.fromString("utyp");
|
||||||
private static final War3ID DEATH_TIME = War3ID.fromString("udtm");
|
private static final War3ID DEATH_TIME = War3ID.fromString("udtm");
|
||||||
private static final War3ID TARGETED_AS = War3ID.fromString("utar");
|
private static final War3ID TARGETED_AS = War3ID.fromString("utar");
|
||||||
private final MutableObjectData unitData;
|
private final MutableObjectData unitData;
|
||||||
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
|
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
|
||||||
|
|
||||||
public CUnitData(final MutableObjectData unitData) {
|
public CUnitData(final MutableObjectData unitData) {
|
||||||
this.unitData = unitData;
|
this.unitData = unitData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
|
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
|
||||||
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
|
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
|
||||||
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
|
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
|
||||||
final MutableGameObject unitType = this.unitData.get(typeId);
|
final MutableGameObject unitType = this.unitData.get(typeId);
|
||||||
final int handleId = handleIdAllocator.createId();
|
final int handleId = handleIdAllocator.createId();
|
||||||
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
|
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
|
||||||
final int manaInitial = unitType.getFieldAsInteger(MANA_INITIAL_AMOUNT, 0);
|
final int manaInitial = unitType.getFieldAsInteger(MANA_INITIAL_AMOUNT, 0);
|
||||||
final int manaMaximum = unitType.getFieldAsInteger(MANA_MAXIMUM, 0);
|
final int manaMaximum = unitType.getFieldAsInteger(MANA_MAXIMUM, 0);
|
||||||
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
|
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
|
||||||
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
|
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
|
||||||
|
|
||||||
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
|
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
|
||||||
|
|
||||||
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
|
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
|
||||||
speed, defense, unitTypeInstance);
|
speed, defense, unitTypeInstance);
|
||||||
if (speed > 0) {
|
if (speed > 0) {
|
||||||
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
|
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
|
||||||
}
|
}
|
||||||
if (!unitTypeInstance.getAttacks().isEmpty()) {
|
if (!unitTypeInstance.getAttacks().isEmpty()) {
|
||||||
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
|
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
|
||||||
}
|
}
|
||||||
return unit;
|
return unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap,
|
private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap,
|
||||||
final MutableGameObject unitType) {
|
final MutableGameObject unitType) {
|
||||||
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
|
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
|
||||||
if (unitTypeInstance == null) {
|
if (unitTypeInstance == null) {
|
||||||
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
|
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
|
||||||
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
|
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
|
||||||
final float collisionSize = unitType.getFieldAsFloat(COLLISION_SIZE, 0);
|
final float collisionSize = unitType.getFieldAsFloat(COLLISION_SIZE, 0);
|
||||||
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
|
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
|
||||||
final PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
|
final PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
|
||||||
final String unitName = unitType.getFieldAsString(NAME, 0);
|
final String unitName = unitType.getFieldAsString(NAME, 0);
|
||||||
final float acquisitionRange = unitType.getFieldAsFloat(ACQUISITION_RANGE, 0);
|
final float acquisitionRange = unitType.getFieldAsFloat(ACQUISITION_RANGE, 0);
|
||||||
final float minimumAttackRange = unitType.getFieldAsFloat(MINIMUM_ATTACK_RANGE, 0);
|
final float minimumAttackRange = unitType.getFieldAsFloat(MINIMUM_ATTACK_RANGE, 0);
|
||||||
final EnumSet<CTargetType> targetedAs = CTargetType
|
final EnumSet<CTargetType> targetedAs = CTargetType
|
||||||
.parseTargetTypeSet(unitType.getFieldAsString(TARGETED_AS, 0));
|
.parseTargetTypeSet(unitType.getFieldAsString(TARGETED_AS, 0));
|
||||||
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
|
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
|
||||||
final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
|
final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
|
||||||
if (classificationString != null) {
|
if (classificationString != null) {
|
||||||
final String[] classificationValues = classificationString.split(",");
|
final String[] classificationValues = classificationString.split(",");
|
||||||
for (final String unitEditorKey : classificationValues) {
|
for (final String unitEditorKey : classificationValues) {
|
||||||
final CUnitClassification unitClassification = CUnitClassification
|
final CUnitClassification unitClassification = CUnitClassification
|
||||||
.parseUnitClassification(unitEditorKey);
|
.parseUnitClassification(unitEditorKey);
|
||||||
if (unitClassification != null) {
|
if (unitClassification != null) {
|
||||||
classifications.add(unitClassification);
|
classifications.add(unitClassification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final List<CUnitAttack> attacks = new ArrayList<>();
|
final List<CUnitAttack> attacks = new ArrayList<>();
|
||||||
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
|
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
|
||||||
if ((attacksEnabled & 0x1) != 0) {
|
if ((attacksEnabled & 0x1) != 0) {
|
||||||
// attack one
|
try {
|
||||||
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
|
// attack one
|
||||||
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
|
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
|
||||||
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_FULL_DMG, 0);
|
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
|
||||||
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_HALF_DMG, 0);
|
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_FULL_DMG, 0);
|
||||||
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_QUARTER_DMG, 0);
|
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_HALF_DMG, 0);
|
||||||
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
|
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_QUARTER_DMG, 0);
|
||||||
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_AREA_OF_EFFECT_TARGETS, 0));
|
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
|
||||||
final CAttackType attackType = CAttackType
|
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_AREA_OF_EFFECT_TARGETS, 0));
|
||||||
.parseAttackType(unitType.getFieldAsString(ATTACK1_ATTACK_TYPE, 0));
|
final CAttackType attackType = CAttackType
|
||||||
final float cooldownTime = unitType.getFieldAsFloat(ATTACK1_COOLDOWN, 0);
|
.parseAttackType(unitType.getFieldAsString(ATTACK1_ATTACK_TYPE, 0));
|
||||||
final int damageBase = unitType.getFieldAsInteger(ATTACK1_DMG_BASE, 0);
|
final float cooldownTime = unitType.getFieldAsFloat(ATTACK1_COOLDOWN, 0);
|
||||||
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_HALF, 0);
|
final int damageBase = unitType.getFieldAsInteger(ATTACK1_DMG_BASE, 0);
|
||||||
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_QUARTER, 0);
|
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_HALF, 0);
|
||||||
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK1_DAMAGE_LOSS_FACTOR, 0);
|
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_QUARTER, 0);
|
||||||
final int damageDice = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
|
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK1_DAMAGE_LOSS_FACTOR, 0);
|
||||||
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0);
|
final int damageDice = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
|
||||||
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_DIST, 0);
|
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0);
|
||||||
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_RADIUS, 0);
|
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_DIST, 0);
|
||||||
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK1_DMG_UPGRADE_AMT, 0);
|
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_RADIUS, 0);
|
||||||
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK1_TARGET_COUNT, 0);
|
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK1_DMG_UPGRADE_AMT, 0);
|
||||||
final float projectileArc = unitType.getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
|
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK1_TARGET_COUNT, 0);
|
||||||
final String projectileArt = unitType.getFieldAsString(ATTACK1_MISSILE_ART, 0);
|
final float projectileArc = unitType.getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
|
||||||
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK1_PROJECTILE_HOMING_ENABLED,
|
final String projectileArt = unitType.getFieldAsString(ATTACK1_MISSILE_ART, 0);
|
||||||
0);
|
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK1_PROJECTILE_HOMING_ENABLED,
|
||||||
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
|
0);
|
||||||
final int range = unitType.getFieldAsInteger(ATTACK1_RANGE, 0);
|
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
|
||||||
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK1_RANGE_MOTION_BUFFER, 0);
|
final int range = unitType.getFieldAsInteger(ATTACK1_RANGE, 0);
|
||||||
final boolean showUI = unitType.getFieldAsBoolean(ATTACK1_SHOW_UI, 0);
|
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK1_RANGE_MOTION_BUFFER, 0);
|
||||||
final EnumSet<CTargetType> targetsAllowed = CTargetType
|
final boolean showUI = unitType.getFieldAsBoolean(ATTACK1_SHOW_UI, 0);
|
||||||
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_TARGETS_ALLOWED, 0));
|
final EnumSet<CTargetType> targetsAllowed = CTargetType
|
||||||
final String weaponSound = unitType.getFieldAsString(ATTACK1_WEAPON_SOUND, 0);
|
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_TARGETS_ALLOWED, 0));
|
||||||
final CWeaponType weaponType = CWeaponType
|
final String weaponSound = unitType.getFieldAsString(ATTACK1_WEAPON_SOUND, 0);
|
||||||
.parseWeaponType(unitType.getFieldAsString(ATTACK1_WEAPON_TYPE, 0));
|
final CWeaponType weaponType = CWeaponType
|
||||||
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
|
.parseWeaponType(unitType.getFieldAsString(ATTACK1_WEAPON_TYPE, 0));
|
||||||
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
|
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
|
||||||
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice,
|
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
|
||||||
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
|
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice,
|
||||||
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
|
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
|
||||||
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
|
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
|
||||||
}
|
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
|
||||||
if ((attacksEnabled & 0x2) != 0) {
|
} catch (Exception exc) {
|
||||||
// attack two
|
System.err.println("Attack 1 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
|
||||||
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
|
}
|
||||||
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
|
}
|
||||||
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_FULL_DMG, 0);
|
if ((attacksEnabled & 0x2) != 0) {
|
||||||
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_HALF_DMG, 0);
|
try {
|
||||||
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_QUARTER_DMG, 0);
|
// attack two
|
||||||
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
|
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
|
||||||
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_AREA_OF_EFFECT_TARGETS, 0));
|
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
|
||||||
final CAttackType attackType = CAttackType
|
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_FULL_DMG, 0);
|
||||||
.parseAttackType(unitType.getFieldAsString(ATTACK2_ATTACK_TYPE, 0));
|
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_HALF_DMG, 0);
|
||||||
final float cooldownTime = unitType.getFieldAsFloat(ATTACK2_COOLDOWN, 0);
|
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_QUARTER_DMG, 0);
|
||||||
final int damageBase = unitType.getFieldAsInteger(ATTACK2_DMG_BASE, 0);
|
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
|
||||||
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_HALF, 0);
|
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_AREA_OF_EFFECT_TARGETS, 0));
|
||||||
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_QUARTER, 0);
|
final CAttackType attackType = CAttackType
|
||||||
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK2_DAMAGE_LOSS_FACTOR, 0);
|
.parseAttackType(unitType.getFieldAsString(ATTACK2_ATTACK_TYPE, 0));
|
||||||
final int damageDice = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
|
final float cooldownTime = unitType.getFieldAsFloat(ATTACK2_COOLDOWN, 0);
|
||||||
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0);
|
final int damageBase = unitType.getFieldAsInteger(ATTACK2_DMG_BASE, 0);
|
||||||
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_DIST, 0);
|
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_HALF, 0);
|
||||||
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_RADIUS, 0);
|
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_QUARTER, 0);
|
||||||
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK2_DMG_UPGRADE_AMT, 0);
|
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK2_DAMAGE_LOSS_FACTOR, 0);
|
||||||
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK2_TARGET_COUNT, 0);
|
final int damageDice = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
|
||||||
final float projectileArc = unitType.getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
|
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0);
|
||||||
final String projectileArt = unitType.getFieldAsString(ATTACK2_MISSILE_ART, 0);
|
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_DIST, 0);
|
||||||
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK2_PROJECTILE_HOMING_ENABLED,
|
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_RADIUS, 0);
|
||||||
0);
|
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK2_DMG_UPGRADE_AMT, 0);
|
||||||
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
|
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK2_TARGET_COUNT, 0);
|
||||||
final int range = unitType.getFieldAsInteger(ATTACK2_RANGE, 0);
|
final float projectileArc = unitType.getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
|
||||||
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK2_RANGE_MOTION_BUFFER, 0);
|
final String projectileArt = unitType.getFieldAsString(ATTACK2_MISSILE_ART, 0);
|
||||||
final boolean showUI = unitType.getFieldAsBoolean(ATTACK2_SHOW_UI, 0);
|
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK2_PROJECTILE_HOMING_ENABLED,
|
||||||
final EnumSet<CTargetType> targetsAllowed = CTargetType
|
0);
|
||||||
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_TARGETS_ALLOWED, 0));
|
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
|
||||||
final String weaponSound = unitType.getFieldAsString(ATTACK2_WEAPON_SOUND, 0);
|
final int range = unitType.getFieldAsInteger(ATTACK2_RANGE, 0);
|
||||||
final CWeaponType weaponType = CWeaponType
|
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK2_RANGE_MOTION_BUFFER, 0);
|
||||||
.parseWeaponType(unitType.getFieldAsString(ATTACK2_WEAPON_TYPE, 0));
|
final boolean showUI = unitType.getFieldAsBoolean(ATTACK2_SHOW_UI, 0);
|
||||||
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
|
final EnumSet<CTargetType> targetsAllowed = CTargetType
|
||||||
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
|
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_TARGETS_ALLOWED, 0));
|
||||||
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice,
|
final String weaponSound = unitType.getFieldAsString(ATTACK2_WEAPON_SOUND, 0);
|
||||||
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
|
final CWeaponType weaponType = CWeaponType
|
||||||
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
|
.parseWeaponType(unitType.getFieldAsString(ATTACK2_WEAPON_TYPE, 0));
|
||||||
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
|
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
|
||||||
}
|
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
|
||||||
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
|
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice,
|
||||||
final boolean raise = (deathType & 0x1) != 0;
|
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
|
||||||
final boolean decay = (deathType & 0x2) != 0;
|
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
|
||||||
final String armorType = unitType.getFieldAsString(ARMOR_TYPE, 0);
|
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
|
||||||
final float impactZ = unitType.getFieldAsFloat(PROJECTILE_IMPACT_Z, 0);
|
} catch (Exception exc) {
|
||||||
final CDefenseType defenseType = CDefenseType.parseDefenseType(unitType.getFieldAsString(DEFENSE_TYPE, 0));
|
System.err.println("Attack 2 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
|
||||||
final float deathTime = unitType.getFieldAsFloat(DEATH_TIME, 0);
|
}
|
||||||
unitTypeInstance = new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize, classifications,
|
}
|
||||||
attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime,
|
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
|
||||||
targetedAs, acquisitionRange, minimumAttackRange);
|
final boolean raise = (deathType & 0x1) != 0;
|
||||||
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
final boolean decay = (deathType & 0x2) != 0;
|
||||||
}
|
final String armorType = unitType.getFieldAsString(ARMOR_TYPE, 0);
|
||||||
return unitTypeInstance;
|
final float impactZ = unitType.getFieldAsFloat(PROJECTILE_IMPACT_Z, 0);
|
||||||
}
|
final CDefenseType defenseType = CDefenseType.parseDefenseType(unitType.getFieldAsString(DEFENSE_TYPE, 0));
|
||||||
|
final float deathTime = unitType.getFieldAsFloat(DEATH_TIME, 0);
|
||||||
|
unitTypeInstance = new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize, classifications,
|
||||||
|
attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime,
|
||||||
|
targetedAs, acquisitionRange, minimumAttackRange);
|
||||||
|
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
||||||
|
}
|
||||||
|
return unitTypeInstance;
|
||||||
|
}
|
||||||
|
|
||||||
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
|
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
|
||||||
final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
|
final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
|
||||||
final EnumSet<CTargetType> areaOfEffectTargets, final CAttackType attackType, final float cooldownTime,
|
final EnumSet<CTargetType> areaOfEffectTargets, final CAttackType attackType, final float cooldownTime,
|
||||||
final int damageBase, final float damageFactorMedium, final float damageFactorSmall,
|
final int damageBase, final float damageFactorMedium, final float damageFactorSmall,
|
||||||
final float damageLossFactor, final int damageDice, final int damageSidesPerDie,
|
final float damageLossFactor, final int damageDice, final int damageSidesPerDie,
|
||||||
final float damageSpillDistance, final float damageSpillRadius, final int damageUpgradeAmount,
|
final float damageSpillDistance, final float damageSpillRadius, final int damageUpgradeAmount,
|
||||||
final int maximumNumberOfTargets, final float projectileArc, final String projectileArt,
|
final int maximumNumberOfTargets, final float projectileArc, final String projectileArt,
|
||||||
final boolean projectileHomingEnabled, final int projectileSpeed, final int range,
|
final boolean projectileHomingEnabled, final int projectileSpeed, final int range,
|
||||||
final float rangeMotionBuffer, final boolean showUI, final EnumSet<CTargetType> targetsAllowed,
|
final float rangeMotionBuffer, final boolean showUI, final EnumSet<CTargetType> targetsAllowed,
|
||||||
final String weaponSound, final CWeaponType weaponType) {
|
final String weaponSound, final CWeaponType weaponType) {
|
||||||
final CUnitAttack attack;
|
final CUnitAttack attack;
|
||||||
switch (weaponType) {
|
switch (weaponType) {
|
||||||
case MISSILE:
|
case MISSILE:
|
||||||
attack = new CUnitAttackMissile(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
attack = new CUnitAttackMissile(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
||||||
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
||||||
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
|
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
|
||||||
projectileSpeed);
|
projectileSpeed);
|
||||||
break;
|
break;
|
||||||
case MBOUNCE:
|
case MBOUNCE:
|
||||||
attack = new CUnitAttackMissileBounce(animationBackswingPoint, animationDamagePoint, attackType,
|
attack = new CUnitAttackMissileBounce(animationBackswingPoint, animationDamagePoint, attackType,
|
||||||
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
|
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
|
||||||
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
|
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
|
||||||
projectileHomingEnabled, projectileSpeed, damageLossFactor, maximumNumberOfTargets,
|
projectileHomingEnabled, projectileSpeed, damageLossFactor, maximumNumberOfTargets,
|
||||||
areaOfEffectFullDamage, areaOfEffectTargets);
|
areaOfEffectFullDamage, areaOfEffectTargets);
|
||||||
break;
|
break;
|
||||||
case MSPLASH:
|
case MSPLASH:
|
||||||
case ARTILLERY:
|
case ARTILLERY:
|
||||||
attack = new CUnitAttackMissileSplash(animationBackswingPoint, animationDamagePoint, attackType,
|
attack = new CUnitAttackMissileSplash(animationBackswingPoint, animationDamagePoint, attackType,
|
||||||
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
|
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
|
||||||
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
|
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
|
||||||
projectileHomingEnabled, projectileSpeed, areaOfEffectFullDamage, areaOfEffectMediumDamage,
|
projectileHomingEnabled, projectileSpeed, areaOfEffectFullDamage, areaOfEffectMediumDamage,
|
||||||
areaOfEffectSmallDamage, areaOfEffectTargets, damageFactorMedium, damageFactorSmall);
|
areaOfEffectSmallDamage, areaOfEffectTargets, damageFactorMedium, damageFactorSmall);
|
||||||
break;
|
break;
|
||||||
case MLINE:
|
case MLINE:
|
||||||
case ALINE:
|
case ALINE:
|
||||||
attack = new CUnitAttackMissileLine(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
attack = new CUnitAttackMissileLine(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
||||||
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
||||||
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
|
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
|
||||||
projectileSpeed, damageSpillDistance, damageSpillRadius);
|
projectileSpeed, damageSpillDistance, damageSpillRadius);
|
||||||
break;
|
break;
|
||||||
case INSTANT:
|
case INSTANT:
|
||||||
attack = new CUnitAttackInstant(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
attack = new CUnitAttackInstant(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
||||||
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
||||||
targetsAllowed, weaponSound, weaponType, projectileArt);
|
targetsAllowed, weaponSound, weaponType, projectileArt);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
attack = new CUnitAttackNormal(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
attack = new CUnitAttackNormal(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
|
||||||
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
|
||||||
targetsAllowed, weaponSound, weaponType);
|
targetsAllowed, weaponSound, weaponType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return attack;
|
return attack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getPropulsionWindow(final War3ID unitTypeId) {
|
public float getPropulsionWindow(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(PROPULSION_WINDOW, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(PROPULSION_WINDOW, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getTurnRate(final War3ID unitTypeId) {
|
public float getTurnRate(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(TURN_RATE, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(TURN_RATE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBuilding(final War3ID unitTypeId) {
|
public boolean isBuilding(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsBoolean(IS_BLDG, 0);
|
return this.unitData.get(unitTypeId).getFieldAsBoolean(IS_BLDG, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName(final War3ID unitTypeId) {
|
public String getName(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getName();
|
return this.unitData.get(unitTypeId).getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getA1MinDamage(final War3ID unitTypeId) {
|
public int getA1MinDamage(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
|
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
|
||||||
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0);
|
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getA1MaxDamage(final War3ID unitTypeId) {
|
public int getA1MaxDamage(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
|
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
|
||||||
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0)
|
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0)
|
||||||
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0));
|
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getA2MinDamage(final War3ID unitTypeId) {
|
public int getA2MinDamage(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
|
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
|
||||||
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0);
|
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getA2MaxDamage(final War3ID unitTypeId) {
|
public int getA2MaxDamage(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
|
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
|
||||||
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0)
|
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0)
|
||||||
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0));
|
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDefense(final War3ID unitTypeId) {
|
public int getDefense(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsInteger(DEFENSE, 0);
|
return this.unitData.get(unitTypeId).getFieldAsInteger(DEFENSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getA1ProjectileSpeed(final War3ID unitTypeId) {
|
public int getA1ProjectileSpeed(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
|
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getA1ProjectileArc(final War3ID unitTypeId) {
|
public float getA1ProjectileArc(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getA2ProjectileSpeed(final War3ID unitTypeId) {
|
public int getA2ProjectileSpeed(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
|
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getA2ProjectileArc(final War3ID unitTypeId) {
|
public float getA2ProjectileArc(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getA1MissileArt(final War3ID unitTypeId) {
|
public String getA1MissileArt(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK1_MISSILE_ART, 0);
|
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK1_MISSILE_ART, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getA2MissileArt(final War3ID unitTypeId) {
|
public String getA2MissileArt(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK2_MISSILE_ART, 0);
|
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK2_MISSILE_ART, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getA1Cooldown(final War3ID unitTypeId) {
|
public float getA1Cooldown(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_COOLDOWN, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_COOLDOWN, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getA2Cooldown(final War3ID unitTypeId) {
|
public float getA2Cooldown(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_COOLDOWN, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_COOLDOWN, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getProjectileLaunchX(final War3ID unitTypeId) {
|
public float getProjectileLaunchX(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_X, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_X, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getProjectileLaunchY(final War3ID unitTypeId) {
|
public float getProjectileLaunchY(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Y, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getProjectileLaunchZ(final War3ID unitTypeId) {
|
public float getProjectileLaunchZ(final War3ID unitTypeId) {
|
||||||
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Z, 0);
|
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Z, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,6 @@ public class CAttackOrder implements COrder {
|
|||||||
else {
|
else {
|
||||||
damage = simulation.getSeededRandom().nextInt(maxDamage - minDamage) + minDamage;
|
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.unitAttack.launch(simulation, this.unit, this.target, damage);
|
||||||
this.damagePointLaunchTime = 0;
|
this.damagePointLaunchTime = 0;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,8 @@ public class CPathfindingProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!openSet.isEmpty()) {
|
int searchIterations = 0;
|
||||||
|
while (!openSet.isEmpty() && searchIterations < 150000) {
|
||||||
Node current = openSet.poll();
|
Node current = openSet.poll();
|
||||||
if (isGoal(current)) {
|
if (isGoal(current)) {
|
||||||
final LinkedList<Point2D.Float> totalPath = new LinkedList<>();
|
final LinkedList<Point2D.Float> totalPath = new LinkedList<>();
|
||||||
@ -259,6 +260,7 @@ public class CPathfindingProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
searchIterations++;
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import com.etheller.warsmash.viewer5.gl.SoundLengthExtension;
|
|||||||
import com.etheller.warsmash.viewer5.gl.WireframeExtension;
|
import com.etheller.warsmash.viewer5.gl.WireframeExtension;
|
||||||
|
|
||||||
public class DesktopLauncher {
|
public class DesktopLauncher {
|
||||||
public static void main(final String[] arg) {
|
public static void main(String[] arg) {
|
||||||
Extensions.angleInstancedArrays = new ANGLEInstancedArrays() {
|
Extensions.angleInstancedArrays = new ANGLEInstancedArrays() {
|
||||||
@Override
|
@Override
|
||||||
public void glVertexAttribDivisorANGLE(final int index, final int divisor) {
|
public void glVertexAttribDivisorANGLE(final int index, final int divisor) {
|
||||||
@ -83,10 +83,11 @@ public class DesktopLauncher {
|
|||||||
config.useGL30 = true;
|
config.useGL30 = true;
|
||||||
config.gles30ContextMajorVersion = 3;
|
config.gles30ContextMajorVersion = 3;
|
||||||
config.gles30ContextMinorVersion = 3;
|
config.gles30ContextMinorVersion = 3;
|
||||||
config.samples = 16;
|
//config.samples = 16;
|
||||||
// config.vSyncEnabled = false;
|
// config.vSyncEnabled = false;
|
||||||
// config.foregroundFPS = 0;
|
// config.foregroundFPS = 0;
|
||||||
// config.backgroundFPS = 0;
|
// config.backgroundFPS = 0;
|
||||||
|
arg = new String[]{"-windowed"};
|
||||||
if ((arg.length > 0) && "-windowed".equals(arg[0])) {
|
if ((arg.length > 0) && "-windowed".equals(arg[0])) {
|
||||||
config.fullscreen = false;
|
config.fullscreen = false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user