Update with fixes for ui

This commit is contained in:
Retera 2020-10-20 08:39:35 -04:00
parent faf1cb4b72
commit e919f35904
67 changed files with 2516 additions and 879 deletions

View File

@ -24,5 +24,9 @@ Path06="."
//FilePath="FireLord.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PhoenixAttack.w3x"
FilePath="LightEnvironmentTest.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="LightEnvironmentTest.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x"
//FilePath="FrostyVsFarm.w3m"
//FilePath="ModelTest.w3x"
FilePath="SpinningSample.w3x"

View File

@ -1,15 +1,13 @@
package com.etheller.warsmash;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.imageio.ImageIO;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
@ -26,8 +24,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
@ -43,27 +40,29 @@ import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.util.DataSourceFileHandle;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Camera;
import com.etheller.warsmash.viewer5.CanvasProvider;
import com.etheller.warsmash.viewer5.Model;
import com.etheller.warsmash.viewer5.ModelInstance;
import com.etheller.warsmash.viewer5.ModelViewer;
import com.etheller.warsmash.viewer5.PathSolver;
import com.etheller.warsmash.viewer5.RenderBatch;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.TextureMapper;
import com.etheller.warsmash.viewer5.handlers.ModelHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.ReplaceableIds;
import com.etheller.warsmash.viewer5.handlers.tga.TgaFile;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSound;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraPreset;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraRates;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
private static final double HORIZONTAL_ANGLE_INCREMENT = Math.PI / 60;
private static final boolean ENABLE_MUSIC = false;
private static final Vector3 clickLocationTemp = new Vector3();
private static final Vector2 clickLocationTemp2 = new Vector2();
private DataSource codebase;
private War3MapViewer viewer;
private GameCameraManager cameraManager;
private final Rectangle tempRect = new Rectangle();
// libGDX stuff
@ -74,22 +73,18 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private ExtendViewport uiViewport;
private GlyphLayout glyphLayout;
private Texture consoleUITexture;
private int selectedSoundCount = 0;
private Rectangle minimap;
private Rectangle minimapFilledArea;
private final Texture[] teamColors = new Texture[WarsmashConstants.MAX_PLAYERS];
private Texture solidGreenTexture;
private ShapeRenderer shapeRenderer;
private boolean showTalentTree;
private final List<Message> messages = new LinkedList<>();
private MdxModel timeIndicator;
private final DataTable warsmashIni;
private Scene uiScene;
private MeleeUI meleeUI;
public WarsmashGdxMapGame(final DataTable warsmashIni) {
this.warsmashIni = warsmashIni;
}
@ -158,14 +153,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
cameraListenerData.getFieldFloatValue("ListenerDistance", i),
cameraListenerData.getFieldFloatValue("ListenerAOA", i));
}
this.cameraManager = new GameCameraManager(cameraPresets);
this.cameraManager.setupCamera(this.viewer.worldScene);
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1); // TODO remove white background
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final Scene portraitScene = this.viewer.addSimpleScene();
this.uiScene = this.viewer.addSimpleScene();
this.uiScene.alpha = true;
@ -197,56 +190,13 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.batch = new SpriteBatch();
// this.consoleUITexture = new Texture(new DataSourceFileHandle(this.viewer.dataSource, "AlphaUi.png"));
if (this.viewer.dataSource.has("war3mapMap.tga")) {
try {
this.minimapTexture = ImageUtils.getTextureNoColorCorrection(TgaFile.readTGA("war3mapMap.tga",
this.viewer.dataSource.getResourceAsStream("war3mapMap.tga")));
}
catch (final IOException e) {
System.err.println("Could not load minimap TGA file");
e.printStackTrace();
}
}
else if (this.viewer.dataSource.has("war3mapMap.blp")) {
try {
this.minimapTexture = ImageUtils
.getTexture(ImageIO.read(this.viewer.dataSource.getResourceAsStream("war3mapMap.blp")));
}
catch (final IOException e) {
System.err.println("Could not load minimap BLP file");
e.printStackTrace();
}
}
for (int i = 0; i < this.teamColors.length; i++) {
this.teamColors[i] = ImageUtils.getBLPTexture(this.viewer.dataSource,
"ReplaceableTextures\\" + ReplaceableIds.getPathString(1) + ReplaceableIds.getIdString(i) + ".blp");
}
this.solidGreenTexture = ImageUtils.getBLPTexture(this.viewer.dataSource,
"ReplaceableTextures\\TeamColor\\TeamColor06.blp");
Gdx.input.setInputProcessor(this);
this.minimap = new Rectangle(18.75f, 13.75f, 278.75f, 276.25f);
final Rectangle playableMapArea = this.viewer.terrain.getPlayableMapArea();
final float worldWidth = playableMapArea.getWidth();
final float worldHeight = playableMapArea.getHeight();
final float worldSize = Math.max(worldWidth, worldHeight);
final float minimapFilledWidth = (worldWidth / worldSize) * this.minimap.width;
final float minimapFilledHeight = (worldHeight / worldSize) * this.minimap.height;
this.minimapFilledArea = new Rectangle(this.minimap.x + ((this.minimap.width - minimapFilledWidth) / 2),
this.minimap.y + ((this.minimap.height - minimapFilledHeight) / 2), minimapFilledWidth,
minimapFilledHeight);
if (this.viewer.startLocations[0] != null) {
this.cameraManager.target.x = this.viewer.startLocations[0].x;
this.cameraManager.target.y = this.viewer.startLocations[0].y;
}
this.shapeRenderer = new ShapeRenderer();
this.talentTreeWindow = new Rectangle(100, 300, 1400, 800);
// Jass2.loadJUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, this.viewer,
// new RootFrameListener() {
@ -255,30 +205,45 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
// WarsmashGdxMapGame.this.gameUI = rootFrame;
// }
// }, "Scripts\\common.jui", "Scripts\\melee.jui");
this.meleeUI = new MeleeUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, this.viewer,
new RootFrameListener() {
final Element cameraRatesElement = this.viewer.miscData.get("CameraRates");
final CameraRates cameraRates = new CameraRates(cameraRatesElement.getFieldFloatValue("AOA"),
cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"),
cameraRatesElement.getFieldFloatValue("Distance"), cameraRatesElement.getFieldFloatValue("Forward"),
cameraRatesElement.getFieldFloatValue("Strafe"));
this.meleeUI = new MeleeUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, portraitScene,
cameraPresets, cameraRates, this.viewer, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
final String musicField = rootFrame.getSkinField("Music_V1");
final String[] musics = musicField.split(";");
final String musicPath = musics[(int) (Math.random() * musics.length)];
final Music music = Gdx.audio.newMusic(
new DataSourceFileHandle(WarsmashGdxMapGame.this.viewer.dataSource, musicPath));
music.setVolume(0.2f);
music.setLooping(true);
music.play();
if (ENABLE_MUSIC) {
final String musicField = rootFrame.getSkinField("Music_V1");
final String[] musics = musicField.split(";");
final String musicPath = musics[(int) (Math.random() * musics.length)];
final Music music = Gdx.audio.newMusic(
new DataSourceFileHandle(WarsmashGdxMapGame.this.viewer.dataSource, musicPath));
music.setVolume(0.2f);
music.setLooping(true);
music.play();
}
}
});
final ModelInstance libgdxContentInstance = new LibGDXContentLayerModel(null, this.viewer, "",
this.viewer.mapPathSolver, "").addInstance();
libgdxContentInstance.setScene(this.uiScene);
this.meleeUI.main();
fontGenerator.dispose();
updateUIScene();
this.meleeUI.resize();
resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
try {
this.viewer.loadAfterUI();
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
private void updateUIScene() {
@ -304,21 +269,9 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final float deltaTime = Gdx.graphics.getDeltaTime();
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
this.cameraManager.target.add(this.cameraVelocity.x * deltaTime, this.cameraVelocity.y * deltaTime, 0);
this.cameraManager.target.z = (Math.max(
this.viewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y),
this.viewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y)) - 256)
+ this.cameraManager.presets[this.cameraManager.currentPreset].height + 256;
this.cameraManager.updateCamera();
this.meleeUI.updatePortrait();
this.meleeUI.update(deltaTime);
this.viewer.updateAndRender();
// gl.glDrawElements(GL20.GL_TRIANGLES, this.elements, GL20.GL_UNSIGNED_SHORT, this.faceOffset);
// this.batch.begin();
// this.font.draw(this.batch, Integer.toString(Gdx.graphics.getFramesPerSecond()), 0, 0);
// this.batch.end();
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glDisable(GL30.GL_CULL_FACE);
@ -326,6 +279,18 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.viewer.webGL.useShaderProgram(null);
Gdx.gl30.glActiveTexture(GL30.GL_TEXTURE0);
}
private void renderLibGDXContent() {
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glDisable(GL30.GL_CULL_FACE);
this.viewer.webGL.useShaderProgram(null);
Gdx.gl30.glActiveTexture(GL30.GL_TEXTURE0);
this.uiViewport.apply();
this.batch.setProjectionMatrix(this.uiCamera.combined);
this.batch.begin();
@ -334,54 +299,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
this.glyphLayout.setText(this.font, fpsString);
this.font.draw(this.batch, fpsString, (this.uiViewport.getMinWorldWidth() - this.glyphLayout.width) / 2, 1100);
this.batch.draw(this.minimapTexture, this.minimap.x, this.minimap.y, this.minimap.width, this.minimap.height);
final Rectangle playableMapArea = this.viewer.terrain.getPlayableMapArea();
for (final RenderUnit unit : this.viewer.units) {
if (unit.playerIndex >= WarsmashConstants.MAX_PLAYERS) {
System.err.println(unit.row.getName() + " at ( " + unit.location[0] + ", " + unit.location[1] + " )"
+ " with " + unit.playerIndex);
unit.playerIndex -= 12;
}
final Texture minimapIcon = this.teamColors[unit.playerIndex];
this.batch.draw(minimapIcon,
this.minimapFilledArea.x
+ (((unit.location[0] - playableMapArea.getX()) / (playableMapArea.getWidth()))
* this.minimapFilledArea.width),
this.minimapFilledArea.y
+ (((unit.location[1] - playableMapArea.getY()) / (playableMapArea.getHeight()))
* this.minimapFilledArea.height),
4, 4);
}
this.batch.end();
if (this.showTalentTree) {
this.shapeRenderer.setProjectionMatrix(this.uiCamera.combined);
this.shapeRenderer.setColor(Color.BLACK);
this.shapeRenderer.begin(ShapeType.Filled);
this.shapeRenderer.rect(this.talentTreeWindow.x, this.talentTreeWindow.y, this.talentTreeWindow.width,
this.talentTreeWindow.height);
this.shapeRenderer.end();
this.shapeRenderer.setColor(Color.YELLOW);
this.shapeRenderer.begin(ShapeType.Line);
this.shapeRenderer.rect(100, 300, 1400, 800);
this.shapeRenderer.end();
this.batch.begin();
this.font.setColor(Color.YELLOW);
final String title = "Mage Talent Tree";
this.glyphLayout.setText(this.font, title);
this.font.draw(this.batch, title,
this.talentTreeWindow.x + ((this.talentTreeWindow.width - this.glyphLayout.width) / 2),
(this.talentTreeWindow.y + this.talentTreeWindow.height) - 45);
this.batch.end();
}
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
}
@Override
@ -401,212 +322,34 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
@Override
public void resize(final int width, final int height) {
super.resize(width, height);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
this.meleeUI.resize(setupWorldFrameViewport(width, height));
updateUIScene();
}
private Rectangle setupWorldFrameViewport(final int width, final int height) {
this.tempRect.x = 0;
this.tempRect.width = width;
final float topHeight = 0.02666f * height;
final float bottomHeight = 0.21333f * height;
this.tempRect.y = (int) bottomHeight;
this.tempRect.height = height - (int) (topHeight + bottomHeight);
this.cameraManager.camera.viewport(this.tempRect);
final float portraitTestWidth = (100 / 640f) * width;
final float portraitTestHeight = (100 / 480f) * height;
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
updateUIScene();
this.meleeUI.resize();
return this.tempRect;
}
public static abstract class CameraManager {
protected final float[] cameraPositionTemp = new float[3];
protected final float[] cameraTargetTemp = new float[3];
protected CanvasProvider canvas;
protected Camera camera;
protected float moveSpeed;
protected float rotationSpeed;
protected float zoomFactor;
protected float horizontalAngle;
protected float verticalAngle;
protected float distance;
protected Vector3 position;
protected Vector3 target;
protected Vector3 worldUp;
protected Vector3 vecHeap;
protected Quaternion quatHeap;
protected Quaternion quatHeap2;
public CameraManager() {
}
// An orbit camera setup example.
// Left mouse button controls the orbit itself.
// The right mouse button allows to move the camera and the point it's looking
// at on the XY plane.
// Scrolling zooms in and out.
public void setupCamera(final Scene scene) {
this.canvas = scene.viewer.canvas;
this.camera = scene.camera;
this.moveSpeed = 2;
this.rotationSpeed = (float) HORIZONTAL_ANGLE_INCREMENT;
this.zoomFactor = 0.1f;
this.horizontalAngle = 0;// (float) (Math.PI / 2);
this.verticalAngle = (float) Math.toRadians(34);
this.distance = 1650;
this.position = new Vector3();
this.target = new Vector3(0, 0, 0);
this.worldUp = new Vector3(0, 0, 1);
this.vecHeap = new Vector3();
this.quatHeap = new Quaternion();
this.quatHeap2 = new Quaternion();
updateCamera();
// cameraUpdate();
}
public abstract void updateCamera();
// private void cameraUpdate() {
//
// }
}
public static final class GameCameraManager extends CameraManager {
private final CameraPreset[] presets;
private int currentPreset = 0;
protected boolean insertDown;
protected boolean deleteDown;
public GameCameraManager(final CameraPreset[] presets) {
this.presets = presets;
}
@Override
public void updateCamera() {
this.quatHeap2.idt();
final CameraPreset cameraPreset = this.presets[this.currentPreset];
this.quatHeap.idt();
this.horizontalAngle = (float) Math
.toRadians(cameraPreset.getRotation(this.insertDown, this.deleteDown) - 90);
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
this.distance = Math.max(1200, cameraPreset.distance);
this.verticalAngle = (float) Math.toRadians(Math.min(335, cameraPreset.aoa) - 270);
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
this.quatHeap.mul(this.quatHeap2);
this.position.set(0, 0, 1);
this.quatHeap.transform(this.position);
this.position.nor();
this.position.scl(this.distance);
this.position = this.position.add(this.target);
this.camera.perspective((float) Math.toRadians(cameraPreset.fov / 2), this.camera.getAspect(),
cameraPreset.nearZ, cameraPreset.farZ);
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
}
public static final class PortraitCameraManager extends CameraManager {
public com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
protected MdxComplexInstance modelInstance;
@Override
public void updateCamera() {
this.quatHeap.idt();
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
this.quatHeap2.idt();
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
this.quatHeap.mul(this.quatHeap2);
this.position.set(0, 0, 1);
this.quatHeap.transform(this.position);
this.position.scl(this.distance);
this.position = this.position.add(this.target);
if (this.modelCamera != null) {
this.modelCamera.getPositionTranslation(this.cameraPositionTemp, this.modelInstance.sequence,
this.modelInstance.frame, this.modelInstance.counter);
this.modelCamera.getTargetTranslation(this.cameraTargetTemp, this.modelInstance.sequence,
this.modelInstance.frame, this.modelInstance.counter);
this.position.set(this.modelCamera.position);
this.target.set(this.modelCamera.targetPosition);
this.position.add(this.cameraPositionTemp[0], this.cameraPositionTemp[1], this.cameraPositionTemp[2]);
this.target.add(this.cameraTargetTemp[0], this.cameraTargetTemp[1], this.cameraTargetTemp[2]);
this.camera.perspective(this.modelCamera.fieldOfView * 0.75f, this.camera.getAspect(),
this.modelCamera.nearClippingPlane, this.modelCamera.farClippingPlane);
}
else {
this.camera.perspective(70, this.camera.getAspect(), 100, 5000);
}
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
public void setModelInstance(final MdxComplexInstance modelInstance, final MdxModel portraitModel) {
this.modelInstance = modelInstance;
if (modelInstance == null) {
this.modelCamera = null;
}
else if ((portraitModel != null) && (portraitModel.getCameras().size() > 0)) {
this.modelCamera = portraitModel.getCameras().get(0);
}
}
}
private final float cameraSpeed = 4096.0f; // per second
private final Vector2 cameraVelocity = new Vector2();
private Texture minimapTexture;
private Rectangle talentTreeWindow;
private Scene uiScene;
private MeleeUI meleeUI;
@Override
public boolean keyDown(final int keycode) {
if (keycode == Input.Keys.LEFT) {
this.cameraVelocity.x = -this.cameraSpeed;
}
else if (keycode == Input.Keys.RIGHT) {
this.cameraVelocity.x = this.cameraSpeed;
}
else if (keycode == Input.Keys.DOWN) {
this.cameraVelocity.y = -this.cameraSpeed;
}
else if (keycode == Input.Keys.UP) {
this.cameraVelocity.y = this.cameraSpeed;
}
else if (keycode == Input.Keys.INSERT) {
this.cameraManager.insertDown = true;
}
else if (keycode == Input.Keys.FORWARD_DEL) {
this.cameraManager.deleteDown = true;
}
this.meleeUI.keyDown(keycode);
return true;
}
@Override
public boolean keyUp(final int keycode) {
if (keycode == Input.Keys.LEFT) {
this.cameraVelocity.x = 0;
}
else if (keycode == Input.Keys.RIGHT) {
this.cameraVelocity.x = 0;
}
else if (keycode == Input.Keys.DOWN) {
this.cameraVelocity.y = 0;
}
else if (keycode == Input.Keys.UP) {
this.cameraVelocity.y = 0;
}
else if (keycode == Input.Keys.INSERT) {
this.cameraManager.insertDown = false;
}
else if (keycode == Input.Keys.FORWARD_DEL) {
this.cameraManager.deleteDown = false;
}
this.meleeUI.keyUp(keycode);
return true;
}
@ -624,13 +367,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
clickLocationTemp2.y = screenY;
this.uiViewport.unproject(clickLocationTemp2);
if (this.minimapFilledArea.contains(clickLocationTemp2.x, clickLocationTemp2.y)) {
final float clickX = (clickLocationTemp2.x - this.minimapFilledArea.x) / this.minimapFilledArea.width;
final float clickY = (clickLocationTemp2.y - this.minimapFilledArea.y) / this.minimapFilledArea.height;
this.cameraManager.target.x = (clickX * this.viewer.terrain.columns * 128)
+ this.viewer.terrain.centerOffset[0];
this.cameraManager.target.y = (clickY * this.viewer.terrain.rows * 128)
+ this.viewer.terrain.centerOffset[1];
if (this.meleeUI.touchDown(clickLocationTemp2.x, clickLocationTemp2.y, button)) {
return false;
}
if (button == Input.Buttons.RIGHT) {
@ -723,13 +460,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
@Override
public boolean scrolled(final int amount) {
this.cameraManager.currentPreset -= amount;
if (this.cameraManager.currentPreset < 0) {
this.cameraManager.currentPreset = 0;
}
if (this.cameraManager.currentPreset >= this.cameraManager.presets.length) {
this.cameraManager.currentPreset = this.cameraManager.presets.length - 1;
}
this.meleeUI.scrolled(amount);
return true;
}
@ -743,43 +474,88 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
}
}
private static class CameraPreset {
private final float aoa;
private final float fov;
private final float rotation;
private final float rotationInsert;
private final float rotationDelete;
private final float distance;
private final float farZ;
private final float nearZ;
private final float height;
private final float listenerDistance;
private final float listenerAOA;
private class LibGDXContentLayerModelInstance extends ModelInstance {
public CameraPreset(final float aoa, final float fov, final float rotation, final float rotationInsert,
final float rotationDelete, final float distance, final float farZ, final float nearZ,
final float height, final float listenerDistance, final float listenerAOA) {
this.aoa = aoa;
this.fov = fov;
this.rotation = rotation;
this.rotationInsert = rotationInsert;
this.rotationDelete = rotationDelete;
this.distance = distance;
this.farZ = farZ;
this.nearZ = nearZ;
this.height = height;
this.listenerDistance = listenerDistance;
this.listenerAOA = listenerAOA;
public LibGDXContentLayerModelInstance(final Model model) {
super(model);
}
public float getRotation(final boolean insertDown, final boolean deleteDown) {
if (insertDown && !deleteDown) {
return this.rotationInsert;
}
if (!insertDown && deleteDown) {
return this.rotationDelete;
}
return this.rotation;
@Override
public void updateAnimations(final float dt) {
}
@Override
public void clearEmittedObjects() {
}
@Override
protected void updateLights(final Scene scene2) {
}
@Override
public void renderOpaque(final Matrix4 mvp) {
}
@Override
public void renderTranslucent() {
renderLibGDXContent();
}
@Override
public void load() {
}
@Override
protected RenderBatch getBatch(final TextureMapper textureMapper2) {
throw new UnsupportedOperationException("NOT API");
}
@Override
public void setReplaceableTexture(final int replaceableTextureId, final String replaceableTextureFile) {
}
@Override
public boolean isBatched() {
return super.isBatched();
}
@Override
protected void removeLights(final Scene scene2) {
// TODO Auto-generated method stub
}
}
private class LibGDXContentLayerModel extends Model {
public LibGDXContentLayerModel(final ModelHandler handler, final ModelViewer viewer, final String extension,
final PathSolver pathSolver, final String fetchUrl) {
super(handler, viewer, extension, pathSolver, fetchUrl);
this.ok = true;
}
@Override
protected ModelInstance createInstance(final int type) {
return new LibGDXContentLayerModelInstance(this);
}
@Override
protected void lateLoad() {
}
@Override
protected void load(final InputStream src, final Object options) {
}
@Override
protected void error(final Exception e) {
}
}
}

View File

@ -164,6 +164,13 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return file;
}
public String trySkinField(String file) {
if ((file != null) && this.skin.hasField(file)) {
file = this.skin.getField(file);
}
return file;
}
public DataTable getSkinData() {
return this.skinData;
}
@ -196,6 +203,14 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return null;
}
public TextureFrame createTextureFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final Vector4Definition texCoord) {
final TextureFrame textureFrame = new TextureFrame(name, parent, decorateFileNames, texCoord);
this.nameToFrame.put(name, textureFrame);
add(textureFrame);
return textureFrame;
}
public UIFrame inflate(final FrameDefinition frameDefinition, final UIFrame parent,
final FrameDefinition parentDefinitionIfAvailable) {
UIFrame inflatedFrame = null;
@ -213,7 +228,8 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
inflatedFrame = simpleFrame;
}
else if ("SPRITE".equals(frameDefinition.getFrameType())) {
final SpriteFrame spriteFrame = new SpriteFrame(frameDefinition.getName(), parent, this.uiScene);
final SpriteFrame spriteFrame = new SpriteFrame(frameDefinition.getName(), parent, this.uiScene,
viewport2);
String backgroundArt = frameDefinition.getString("BackgroundArt");
if (frameDefinition.has("DecorateFileNames") || ((parentDefinitionIfAvailable != null)
&& parentDefinitionIfAvailable.has("DecorateFileNames"))) {
@ -224,13 +240,9 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
throw new IllegalStateException("Decorated file name lookup not available: " + backgroundArt);
}
}
if (backgroundArt.toLowerCase().endsWith(".mdl") || backgroundArt.toLowerCase().endsWith(".mdx")) {
backgroundArt = backgroundArt.substring(0, backgroundArt.length() - 4);
if (backgroundArt != null) {
setSpriteFrameModel(spriteFrame, backgroundArt);
}
backgroundArt += ".mdx";
final MdxModel model = (MdxModel) this.modelViewer.load(backgroundArt, this.modelViewer.mapPathSolver,
this.modelViewer.solverParams);
spriteFrame.setModel(model);
viewport2 = this.fdfCoordinateResolutionDummyViewport;
inflatedFrame = spriteFrame;
}
@ -330,9 +342,24 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return inflatedFrame;
}
public void setSpriteFrameModel(final SpriteFrame spriteFrame, String backgroundArt) {
if (backgroundArt.toLowerCase().endsWith(".mdl") || backgroundArt.toLowerCase().endsWith(".mdx")) {
backgroundArt = backgroundArt.substring(0, backgroundArt.length() - 4);
}
backgroundArt += ".mdx";
final MdxModel model = (MdxModel) this.modelViewer.load(backgroundArt, this.modelViewer.mapPathSolver,
this.modelViewer.solverParams);
spriteFrame.setModel(model);
}
public UIFrame createFrameByType(final String typeName, final String name, final UIFrame owner,
final String inherits, final int createContext) {
throw new UnsupportedOperationException("Not yet implemented");
// TODO idk what inherits is doing yet, and I didn't implement createContext yet
// even though it looked like just mapping/indexing on int
final FrameDefinition frameDefinition = new FrameDefinition(FrameClass.Frame, typeName, name);
final UIFrame inflatedFrame = inflate(frameDefinition, owner, null);
add(inflatedFrame);
return inflatedFrame;
}
public UIFrame getFrameByName(final String name, final int createContext) {
@ -353,6 +380,20 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return (fdfY / 0.6f) * viewport.getWorldHeight();
}
public static float unconvertX(final Viewport viewport, final float nonFdfX) {
if (viewport instanceof ExtendViewport) {
return (nonFdfX / ((ExtendViewport) viewport).getMinWorldWidth()) * 0.8f;
}
return (nonFdfX / viewport.getWorldWidth()) * 0.8f;
}
public static float unconvertY(final Viewport viewport, final float nonFdfY) {
if (viewport instanceof ExtendViewport) {
return (nonFdfY / ((ExtendViewport) viewport).getMinWorldHeight()) * 0.6f;
}
return (nonFdfY / viewport.getWorldHeight()) * 0.6f;
}
public Texture loadTexture(String path) {
if (!path.contains(".")) {
path = path + ".blp";
@ -374,4 +415,10 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
public final void positionBounds(final Viewport viewport) {
innerPositionBounds(viewport);
}
@Override
public void add(final UIFrame childFrame) {
super.add(childFrame);
this.nameToFrame.put(childFrame.getName(), childFrame);
}
}

View File

@ -1,6 +1,7 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
@ -252,6 +253,15 @@ public abstract class AbstractRenderableFrame implements UIFrame {
@Override
public void addSetPoint(final SetPoint setPointDefinition) {
// TODO this is O(N) in the number of SetPoints, and that
// is not good performance.
final Iterator<SetPoint> iterator = this.setPoints.iterator();
while (iterator.hasNext()) {
final SetPoint setPoint = iterator.next();
if (setPoint.getMyPoint() == setPointDefinition.getMyPoint()) {
iterator.remove();
}
}
this.setPoints.add(setPointDefinition);
}
@ -261,9 +271,6 @@ public abstract class AbstractRenderableFrame implements UIFrame {
// TODO this is a bit of a hack, remove later
return;
}
if ("ResourceBarFrame".equals(this.name)) {
System.out.println("doing resource bar");
}
if (this.anchors.isEmpty() && this.setPoints.isEmpty()) {
this.renderBounds.x = this.parent.getFramePointX(FramePoint.LEFT);
this.renderBounds.y = this.parent.getFramePointY(FramePoint.BOTTOM);
@ -334,4 +341,14 @@ public abstract class AbstractRenderableFrame implements UIFrame {
protected abstract void internalRender(SpriteBatch batch, BitmapFont baseFont, GlyphLayout glyphLayout);
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
return null;
}
@Override
public String getName() {
return this.name;
}
}

View File

@ -35,4 +35,15 @@ public abstract class AbstractUIFrame extends AbstractRenderableFrame implements
childFrame.positionBounds(viewport);
}
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.touchDown(screenX, screenY, button);
if (clickedChild != null) {
return clickedChild;
}
}
return super.touchDown(screenX, screenY, button);
}
}

View File

@ -4,19 +4,26 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
public class SpriteFrame extends AbstractRenderableFrame {
private final Scene scene;
private MdxComplexInstance instance;
private float zDepth;
private final Viewport uiViewport;
public SpriteFrame(final String name, final UIFrame parent, final Scene scene) {
public SpriteFrame(final String name, final UIFrame parent, final Scene scene, final Viewport uiViewport) {
super(name, parent);
this.scene = scene;
this.uiViewport = uiViewport;
}
public void setModel(final MdxModel model) {
@ -27,21 +34,44 @@ public class SpriteFrame extends AbstractRenderableFrame {
this.instance = (MdxComplexInstance) model.addInstance();
this.instance.setSequenceLoopMode(SequenceLoopMode.MODEL_LOOP);
this.instance.setScene(this.scene);
this.instance.setLocation(this.renderBounds.x, this.renderBounds.y, 0);
this.instance.setLocation(this.renderBounds.x, this.renderBounds.y, this.zDepth);
}
else {
this.instance = null;
}
}
@Override
public void setVisible(final boolean visible) {
super.setVisible(visible);
updateInstanceLocation(this.uiViewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
}
@Override
protected void innerPositionBounds(final Viewport viewport) {
public void setFramePointX(final FramePoint framePoint, final float x) {
super.setFramePointX(framePoint, x);
updateInstanceLocation(this.uiViewport);
}
@Override
public void setFramePointY(final FramePoint framePoint, final float y) {
super.setFramePointY(framePoint, y);
updateInstanceLocation(this.uiViewport);
}
public void setZDepth(final float depth) {
this.zDepth = depth;
updateInstanceLocation(this.uiViewport);
}
@Override
protected void innerPositionBounds(final Viewport viewport) {
updateInstanceLocation(viewport);
}
public void setSequence(final int index) {
@ -50,6 +80,18 @@ public class SpriteFrame extends AbstractRenderableFrame {
}
}
public void setSequence(final String animationName) {
if (this.instance != null) {
SequenceUtils.randomSequence(this.instance, animationName.toLowerCase());
}
}
public void setSequence(final PrimaryTag animationName) {
if (this.instance != null) {
SequenceUtils.randomSequence(this.instance, animationName);
}
}
public void setAnimationSpeed(final float speedRatio) {
if (this.instance != null) {
this.instance.setAnimationSpeed(speedRatio);
@ -68,4 +110,17 @@ public class SpriteFrame extends AbstractRenderableFrame {
}
}
private void updateInstanceLocation(final Viewport viewport) {
if (this.instance != null) {
this.instance.setLocation(GameUI.unconvertX(viewport, this.renderBounds.x),
GameUI.unconvertY(viewport, this.renderBounds.y), this.zDepth);
if (isVisible()) {
this.instance.show();
}
else {
this.instance.hide();
}
}
}
}

View File

@ -31,4 +31,8 @@ public interface UIFrame {
void setSetAllPoints(boolean setAllPoints);
void setVisible(boolean visible);
UIFrame touchDown(float screenX, float screenY, int button);
String getName();
}

View File

@ -145,4 +145,6 @@ public abstract class ModelInstance extends Node {
protected abstract RenderBatch getBatch(TextureMapper textureMapper2);
public abstract void setReplaceableTexture(int replaceableTextureId, String replaceableTextureFile);
protected abstract void removeLights(Scene scene2);
}

View File

@ -147,6 +147,7 @@ public abstract class Scene {
public boolean removeInstance(final ModelInstance instance) {
if (instance.scene == this) {
instance.removeLights(this);
innerRemove(instance);
instance.scene = null;
@ -219,7 +220,6 @@ public abstract class Scene {
this.emitterObjectUpdater.update(dt);
this.updatedParticles = this.emitterObjectUpdater.objects.size();
this.lightManager.update();
}
protected abstract void innerUpdate(float dt, int frame);
@ -239,6 +239,7 @@ public abstract class Scene {
gl.glDepthMask(true);
gl.glClear(GL20.GL_DEPTH_BUFFER_BIT | GL20.GL_COLOR_BUFFER_BIT);
}
this.lightManager.update();
}
public void renderOpaque() {

View File

@ -57,11 +57,10 @@ public class Shaders {
" ";
public static String lightSystem(final String normalName, final String positionName, final String lightTexture,
final String lightCount, final boolean terrain) {
final String lightTextureHeight, final String lightCount, final boolean terrain) {
return " vec3 lightFactor = vec3(0.0,0.0,0.0);\r\n" + //
" float lightIndex = 0.0;\r\n" + //
" for(float lightIndex = 0.0; lightIndex < " + lightCount + "; lightIndex += 1.0) {\r\n" + //
" float rowPos = (lightIndex + 0.5) / " + lightCount + ";\r\n" + //
" for(float lightIndex = 0.5; lightIndex < " + lightCount + "; lightIndex += 1.0) {\r\n" + //
" float rowPos = (lightIndex) / " + lightTextureHeight + ";\r\n" + //
" vec4 lightPosition = texture2D(" + lightTexture + ", vec2(0.125, rowPos));\r\n" + //
" vec3 lightExtra = texture2D(" + lightTexture + ", vec2(0.375, rowPos)).xyz;\r\n" + //
" vec4 lightColor = texture2D(" + lightTexture + ", vec2(0.625, rowPos));\r\n" + //

View File

@ -69,7 +69,7 @@ public class AnimatedObject {
return -1;
}
public int getQuadValue(final float[] out, final War3ID name, final int sequence, final int frame,
public int getQuatValue(final float[] out, final War3ID name, final int sequence, final int frame,
final int counter, final float[] defaultValue) {
if (sequence != -1) {
final Sd<?> animation = this.timelines.get(name);

View File

@ -65,7 +65,8 @@ public class BatchGroup extends GenericGroup {
unitLightsTexture.bind(14);
shader.setUniformi("u_lightTexture", 14);
shader.setUniformf("u_lightCount", unitLightsTexture.getHeight() - 0.5f);
shader.setUniformf("u_lightCount", lightManager.getUnitLightCount());
shader.setUniformf("u_lightTextureHeight", unitLightsTexture.getHeight());
// Instances of models with no bones don't have a bone texture.
if (boneTexture != null) {

View File

@ -128,7 +128,7 @@ public class GenericObject extends AnimatedObject implements GenericIndexed {
}
public int getRotation(final float[] out, final int sequence, final int frame, final int counter) {
return this.getQuadValue(out, AnimationMap.KGRT.getWar3id(), sequence, frame, counter,
return this.getQuatValue(out, AnimationMap.KGRT.getWar3id(), sequence, frame, counter,
RenderMathUtils.FLOAT_QUAT_DEFAULT);
}

View File

@ -88,15 +88,23 @@ public class LightInstance implements UpdatableObject, SceneLightInstance {
public void update(final Scene scene) {
this.light.getVisibility(scalarHeap, this.instance.sequence, this.instance.frame, this.instance.counter);
this.visible = scalarHeap[0] > 0;
updateVisibility(scene, this.visible);
}
public void remove(final Scene scene) {
updateVisibility(scene, false);
}
private void updateVisibility(final Scene scene, final boolean visible) {
if (scene != null) {
if (this.loadedInScene != this.visible) {
if (this.visible) {
if (this.loadedInScene != visible) {
if (visible) {
scene.addLight(this);
}
else {
scene.removeLight(this);
}
this.loadedInScene = this.visible;
this.loadedInScene = visible;
}
}
}

View File

@ -614,6 +614,13 @@ public class MdxComplexInstance extends ModelInstance {
}
}
@Override
protected void removeLights(final Scene scene2) {
for (final LightInstance light : this.lights) {
light.remove(this.scene);
}
}
/**
* Set the team color of this instance.
*/

View File

@ -83,7 +83,9 @@ public class MdxShaders {
" gl_FragColor = color;\r\n" + //
" }\r\n";
public static final String vsComplex = " uniform mat4 u_mvp;\r\n" + //
public static final String vsComplex = "\r\n" + //
"\r\n" + //
" uniform mat4 u_mvp;\r\n" + //
" uniform vec4 u_vertexColor;\r\n" + //
" uniform vec4 u_geosetColor;\r\n" + //
" uniform float u_layerAlpha;\r\n" + //
@ -106,6 +108,7 @@ public class MdxShaders {
" varying float v_uvScale;\r\n" + //
" uniform sampler2D u_lightTexture;\r\n" + //
" uniform float u_lightCount;\r\n" + //
" uniform float u_lightTextureHeight;\r\n" + //
Shaders.boneTexture + "\r\n" + //
" void transform(inout vec3 position, inout vec3 normal) {\r\n" + //
" // For the broken models out there, since the game supports this.\r\n" + //
@ -150,7 +153,8 @@ public class MdxShaders {
" v_uvScale = u_uvScale;\r\n" + //
" gl_Position = u_mvp * vec4(position, 1.0);\r\n" + //
" if(!u_unshaded) {\r\n" + //
Shaders.lightSystem("normal", "position", "u_lightTexture", "u_lightCount", false) + "\r\n" + //
Shaders.lightSystem("normal", "position", "u_lightTexture", "u_lightTextureHeight", "u_lightCount", false)
+ "\r\n" + //
" v_color.xyz *= clamp(lightFactor, 0.0, 1.0);\r\n" + //
" }\r\n" + //
" }";

View File

@ -37,6 +37,10 @@ public class MdxSimpleInstance extends BatchedInstance {
protected void updateLights(final Scene scene2) {
}
@Override
protected void removeLights(final Scene scene2) {
}
@Override
public void load() {
}

View File

@ -67,13 +67,12 @@ public class Particle2 extends EmittedObject<MdxComplexInstance, ParticleEmitter
// Local rotation
rotationHeap.idt();
rotationHeap.mulLeft(HALF_PI_Z);
rotationHeap.mulLeft(rotationHeap2.setFromAxisRad(0, 1, 0, RenderMathUtils.randomInRange(-latitude, latitude)));
rotationHeap.mul(HALF_PI_Z);
rotationHeap.mul(rotationHeap2.setFromAxisRad(0, 1, 0, RenderMathUtils.randomInRange(-latitude, latitude)));
// If this is not a line emitter, emit in a sphere rather than a circle
if (emitterObject.lineEmitter == 0) {
rotationHeap
.mulLeft(rotationHeap2.setFromAxisRad(1, 0, 0, RenderMathUtils.randomInRange(-latitude, latitude)));
rotationHeap.mul(rotationHeap2.setFromAxisRad(1, 0, 0, RenderMathUtils.randomInRange(-latitude, latitude)));
}
// World rotation

View File

@ -20,7 +20,7 @@ public class TextureAnimation extends AnimatedObject {
}
public int getRotation(final float[] out, final int sequence, final int frame, final int counter) {
return this.getVectorValue(out, AnimationMap.KTAR.getWar3id(), sequence, frame, counter,
return this.getQuatValue(out, AnimationMap.KTAR.getWar3id(), sequence, frame, counter,
RenderMathUtils.FLOAT_QUAT_DEFAULT);
}

View File

@ -11,7 +11,7 @@ public class AnimationTokens {
MORPH,
PORTRAIT,
SLEEP,
SPELL,
// SPELL,
STAND,
WALK;
}

View File

@ -5,11 +5,11 @@ import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
public class Destructable extends Doodad {
public class RenderDestructable extends RenderDoodad {
private final float life;
public Destructable(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 float maxPitch, final float maxRoll, final float life) {
super(map, model, row, doodad, type, maxPitch, maxRoll);

View File

@ -11,7 +11,7 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
public class Doodad {
public class RenderDoodad {
private static final int SAMPLE_RADIUS = 4;
private static final War3ID TEX_FILE = War3ID.fromString("btxf");
private static final War3ID TEX_ID = War3ID.fromString("btxi");
@ -20,7 +20,7 @@ public class Doodad {
private final float maxPitch;
private final float maxRoll;
public Doodad(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 float maxPitch, final float maxRoll) {
this.maxPitch = maxPitch;

View File

@ -232,4 +232,8 @@ public class SequenceUtils {
return null;
}
}
public static Sequence randomSequence(final MdxComplexInstance target, final PrimaryTag animationName) {
return randomSequence(target, animationName, EMPTY, false);
}
}

View File

@ -6,20 +6,24 @@ import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.math.Vector3;
import com.etheller.warsmash.viewer5.SceneLightInstance;
import com.etheller.warsmash.viewer5.SceneLightManager;
import com.etheller.warsmash.viewer5.gl.DataTexture;
import com.etheller.warsmash.viewer5.handlers.mdx.Light;
import com.etheller.warsmash.viewer5.handlers.mdx.LightInstance;
public class W3xScenePortraitLightManager implements SceneLightManager, W3xSceneLightManager {
private final War3MapViewer viewer;
private final Vector3 hardcodedLightDirection;
public final List<LightInstance> lights;
private FloatBuffer lightDataCopyHeap;
private final DataTexture unitLightsTexture;
private final War3MapViewer viewer;
private int unitLightCount;
public W3xScenePortraitLightManager(final War3MapViewer viewer) {
public W3xScenePortraitLightManager(final War3MapViewer viewer, final Vector3 lightDirection) {
this.viewer = viewer;
this.hardcodedLightDirection = lightDirection;
this.lights = new ArrayList<>();
this.unitLightsTexture = new DataTexture(viewer.gl, 4, 4, 1);
this.lightDataCopyHeap = ByteBuffer.allocateDirect(16 * 1 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
@ -52,13 +56,35 @@ public class W3xScenePortraitLightManager implements SceneLightManager, W3xScene
this.unitLightCount = 0;
this.lightDataCopyHeap.clear();
int offset = 0;
if (this.viewer.dncUnitDay != null) {
if (!this.viewer.dncUnitDay.lights.isEmpty()) {
this.viewer.dncUnitDay.lights.get(0).bind(0, this.lightDataCopyHeap);
offset += 16;
this.unitLightCount++;
if (this.hardcodedLightDirection == null) {
if (this.viewer.dncTarget != null) {
if (!this.viewer.dncTarget.lights.isEmpty()) {
this.viewer.dncTarget.lights.get(0).bind(0, this.lightDataCopyHeap);
offset += 16;
this.unitLightCount++;
}
}
}
else {
this.lightDataCopyHeap.put(offset, this.hardcodedLightDirection.y);
this.lightDataCopyHeap.put(offset + 1, -this.hardcodedLightDirection.x);
this.lightDataCopyHeap.put(offset + 2, -this.hardcodedLightDirection.z);
this.lightDataCopyHeap.put(offset + 3, -this.hardcodedLightDirection.z);
this.lightDataCopyHeap.put(offset + 4, Light.Type.DIRECTIONAL.ordinal());
this.lightDataCopyHeap.put(offset + 5, 1);
this.lightDataCopyHeap.put(offset + 6, 2);
this.lightDataCopyHeap.put(offset + 7, 0);
this.lightDataCopyHeap.put(offset + 8, 1);
this.lightDataCopyHeap.put(offset + 9, 1);
this.lightDataCopyHeap.put(offset + 10, 1);
this.lightDataCopyHeap.put(offset + 11, 1);
this.lightDataCopyHeap.put(offset + 12, 1);
this.lightDataCopyHeap.put(offset + 13, 1);
this.lightDataCopyHeap.put(offset + 14, 1);
this.lightDataCopyHeap.put(offset + 15, 0.3f);
offset += 16;
this.unitLightCount++;
}
for (final LightInstance light : this.lights) {
light.bind(offset, this.lightDataCopyHeap);
offset += 16;

View File

@ -8,14 +8,16 @@ public class W3xShaders {
}
public static final String vert = "\r\n" + //
"\r\n" + //
" uniform mat4 u_mvp;\r\n" + //
" uniform sampler2D u_heightMap;\r\n" + //
" uniform vec2 u_pixel;\r\n" + //
" uniform vec2 u_size;\r\n" + //
" uniform vec2 u_shadowPixel;\r\n" + //
" uniform vec2 u_centerOffset;\r\n" + //
" uniform sampler2D lightTexture;\r\n" + //
" uniform float lightCount;\r\n" + //
" uniform sampler2D u_lightTexture;\r\n" + //
" uniform float u_lightCount;\r\n" + //
" uniform float u_lightTextureHeight;\r\n" + //
" attribute vec3 a_position;\r\n" + //
" attribute vec2 a_uv;\r\n" + //
" varying vec2 v_uv;\r\n" + //
@ -42,7 +44,9 @@ public class W3xShaders {
" vec3 myposition = vec3(a_position.xy, height * 128.0 + a_position.z);\r\n" + //
" gl_Position = u_mvp * vec4(myposition.xyz, 1.0);\r\n" + //
" a_positionHeight = a_position.z;\r\n" + //
Shaders.lightSystem("v_normal", "myposition", "lightTexture", "lightCount", true) + "\r\n" + //
Shaders.lightSystem("v_normal", "myposition", "u_lightTexture", "u_lightTextureHeight", "u_lightCount",
true)
+ "\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
" }\r\n" + //
" ";

View File

@ -76,6 +76,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderAttackProjecti
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderEffect;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderItem;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnitTypeData;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
@ -86,6 +88,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityM
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackInstant;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CWidgetAbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.PointAbilityTargetCheckReceiver;
@ -109,6 +112,9 @@ public class War3MapViewer extends ModelViewer {
private static final War3ID ITEM_FILE = War3ID.fromString("ifil");
private static final War3ID UNIT_PATHING = War3ID.fromString("upat");
private static final War3ID DESTRUCTABLE_PATHING = War3ID.fromString("bptx");
private static final War3ID ELEVATION_SAMPLE_RADIUS = War3ID.fromString("uerd");
private static final War3ID MAX_PITCH = War3ID.fromString("umxp");
private static final War3ID MAX_ROLL = War3ID.fromString("umxr");
private static final War3ID sloc = War3ID.fromString("sloc");
private static final LoadGenericCallback stringDataCallback = new StringDataCallbackImplementation();
private static final float[] rayHeap = new float[6];
@ -131,7 +137,7 @@ public class War3MapViewer extends ModelViewer {
public MappedData doodadsData = new MappedData();
public MappedData doodadMetaData = new MappedData();
public MappedData destructableMetaData = new MappedData();
public List<Doodad> doodads = new ArrayList<>();
public List<RenderDoodad> doodads = new ArrayList<>();
public List<TerrainDoodad> terrainDoodads = new ArrayList<>();
public boolean doodadsReady;
public boolean unitsAndItemsLoaded;
@ -164,6 +170,7 @@ public class War3MapViewer extends ModelViewer {
public CSimulation simulation;
private float updateTime;
// for World Editor, I think
public Vector2[] startLocations = new Vector2[WarsmashConstants.MAX_PLAYERS];
private final DynamicShadowManager dynamicShadowManager = new DynamicShadowManager();
@ -175,7 +182,9 @@ public class War3MapViewer extends ModelViewer {
private final List<SelectionCircleSize> selectionCircleSizes = new ArrayList<>();
private final Map<CUnit, RenderUnit> unitToRenderPeer = new HashMap<>();
private final Map<War3ID, RenderUnitTypeData> unitIdToTypeData = new HashMap<>();
private GameUI gameUI;
private Vector3 lightDirection;
public War3MapViewer(final DataSource dataSource, final CanvasProvider canvas) {
super(dataSource, canvas);
@ -269,6 +278,11 @@ public class War3MapViewer extends ModelViewer {
this.miscData.readTXT(miscDataTxtStream, true);
}
}
final Element light = this.miscData.get("Light");
final float lightX = light.getFieldFloatValue("Direction", 0);
final float lightY = light.getFieldFloatValue("Direction", 1);
final float lightZ = light.getFieldFloatValue("Direction", 2);
this.lightDirection = new Vector3(lightX, lightY, lightZ).nor();
this.unitGlobalStrings = new DataTable(worldEditStrings);
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\UnitGlobalStrings.txt")) {
this.unitGlobalStrings.readTXT(miscDataTxtStream, true);
@ -381,9 +395,9 @@ public class War3MapViewer extends ModelViewer {
this.confirmationInstance.setSequence(0);
this.confirmationInstance.setScene(this.worldScene);
final Warcraft3MapObjectData modifications = this.mapMpq.readModifications();
this.simulation = new CSimulation(this.miscData, modifications.getUnits(), modifications.getAbilities(),
new SimulationRenderController() {
this.allObjectData = this.mapMpq.readModifications();
this.simulation = new CSimulation(this.miscData, this.allObjectData.getUnits(),
this.allObjectData.getAbilities(), new SimulationRenderController() {
private final Map<String, UnitSound> keyToCombatSound = new HashMap<>();
@Override
@ -493,25 +507,39 @@ public class War3MapViewer extends ModelViewer {
this.seededRandom, w3iFile.getPlayers());
if (this.doodadsAndDestructiblesLoaded) {
this.loadDoodadsAndDestructibles(modifications);
this.loadDoodadsAndDestructibles(this.allObjectData);
}
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
}
if (this.unitsAndItemsLoaded) {
this.loadUnitsAndItems(modifications);
}
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
}
this.terrain.initShadows();
this.terrain.createWaves();
loadLightsAndShading(tileset);
}
/**
* Loads the map information that should be loaded after UI, such as units, who
* need to be able to setup their UI counterparts (icons, etc) for their
* abilities while loading. This allows the dynamic creation of units while the
* game is playing to better share code with the startup sequence's creation of
* units.
*
* @throws IOException
*/
public void loadAfterUI() throws IOException {
if (this.unitsAndItemsLoaded) {
this.loadUnitsAndItems(this.allObjectData);
}
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
}
// After we finish loading units, we need to update & create the stored shadow
// information for all unit shadows
this.terrain.initShadows();
}
private void loadLightsAndShading(final char tileset) {
// TODO this should be set by the war3map.j actually, not by the tileset, so the
// call to set day night models is just for testing to make the test look pretty
@ -605,11 +633,11 @@ public class War3MapViewer extends ModelViewer {
}
if (type == WorldEditorDataType.DESTRUCTIBLES) {
this.doodads
.add(new Destructable(this, model, row, doodad, type, maxPitch, maxRoll, doodad.getLife()));
this.doodads.add(new RenderDestructable(this, model, row, doodad, type, maxPitch, maxRoll,
doodad.getLife()));
}
else {
this.doodads.add(new Doodad(this, model, row, doodad, type, maxPitch, maxRoll));
this.doodads.add(new RenderDoodad(this, model, row, doodad, type, maxPitch, maxRoll));
}
}
}
@ -841,8 +869,9 @@ public class War3MapViewer extends ModelViewer {
final float angle = (float) Math.toDegrees(unit.getAngle());
final CUnit simulationUnit = this.simulation.createUnit(row.getAlias(), unit.getPlayer(),
unit.getLocation()[0], unit.getLocation()[1], angle, buildingPathingPixelMap);
final RenderUnitTypeData typeData = getUnitTypeData(unit.getId(), row);
final RenderUnit renderUnit = new RenderUnit(this, model, row, unit, soundset, portraitModel,
simulationUnit);
simulationUnit, typeData);
this.unitToRenderPeer.put(simulationUnit, renderUnit);
this.units.add(renderUnit);
if (unitShadowSplat != null) {
@ -879,6 +908,16 @@ public class War3MapViewer extends ModelViewer {
this.anyReady = true;
}
private RenderUnitTypeData getUnitTypeData(final War3ID key, final MutableGameObject row) {
RenderUnitTypeData unitTypeData = this.unitIdToTypeData.get(key);
if (unitTypeData == null) {
unitTypeData = new RenderUnitTypeData(row.getFieldAsFloat(MAX_PITCH, 0), row.getFieldAsFloat(MAX_ROLL, 0),
row.getFieldAsFloat(ELEVATION_SAMPLE_RADIUS, 0));
this.unitIdToTypeData.put(key, unitTypeData);
}
return unitTypeData;
}
@Override
public void update() {
if (this.anyReady) {
@ -903,13 +942,15 @@ public class War3MapViewer extends ModelViewer {
SequenceUtils.randomStandSequence(mdxComplexInstance);
}
}
for (final Doodad item : this.doodads) {
for (final RenderDoodad item : this.doodads) {
final ModelInstance instance = item.instance;
if ((instance instanceof MdxComplexInstance) && (instance != this.confirmationInstance)) {
if (instance instanceof MdxComplexInstance) {
final MdxComplexInstance mdxComplexInstance = (MdxComplexInstance) instance;
if ((mdxComplexInstance.sequence == -1)
|| (mdxComplexInstance.sequenceEnded && (((MdxModel) mdxComplexInstance.model).sequences
.get(mdxComplexInstance.sequence).getFlags() == 0))) {
|| (mdxComplexInstance.sequenceEnded/*
* && (((MdxModel) mdxComplexInstance.model).sequences
* .get(mdxComplexInstance.sequence).getFlags() == 0)
*/)) {
SequenceUtils.randomSequence(mdxComplexInstance, item.getAnimation(), SequenceUtils.EMPTY,
true);
}
@ -1178,6 +1219,8 @@ public class War3MapViewer extends ModelViewer {
private float selectionCircleScaleFactor;
private DataTable worldEditData;
private WorldEditStrings worldEditStrings;
private Warcraft3MapObjectData allObjectData;
private AbilityDataUI abilityDataUI;
/**
* Returns a power of two size for the given target capacity.
@ -1199,14 +1242,15 @@ public class War3MapViewer extends ModelViewer {
for (final RenderUnit unit : this.selected) {
for (final CAbility ability : unit.getSimulationUnit().getAbilities()) {
if (ability instanceof CAbilityMove) {
ability.checkCanUse(this.simulation, unit.getSimulationUnit(),
ability.checkCanUse(this.simulation, unit.getSimulationUnit(), OrderIds.smart,
BooleanAbilityActivationReceiver.INSTANCE);
if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) {
ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), mousePosHeap,
ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap,
PointAbilityTargetCheckReceiver.INSTANCE);
final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget();
if (target != null) {
ability.onOrder(this.simulation, unit.getSimulationUnit(), mousePosHeap, false);
ability.onOrder(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap,
false);
ordered = true;
}
else {
@ -1231,14 +1275,15 @@ public class War3MapViewer extends ModelViewer {
for (final RenderUnit unit : this.selected) {
for (final CAbility ability : unit.getSimulationUnit().getAbilities()) {
if (ability instanceof CAbilityAttack) {
ability.checkCanUse(this.simulation, unit.getSimulationUnit(),
ability.checkCanUse(this.simulation, unit.getSimulationUnit(), OrderIds.smart,
BooleanAbilityActivationReceiver.INSTANCE);
if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) {
ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), target.getSimulationUnit(),
CWidgetAbilityTargetCheckReceiver.INSTANCE);
ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), OrderIds.smart,
target.getSimulationUnit(), CWidgetAbilityTargetCheckReceiver.INSTANCE);
final CWidget targetWidget = CWidgetAbilityTargetCheckReceiver.INSTANCE.getTarget();
if (targetWidget != null) {
ability.onOrder(this.simulation, unit.getSimulationUnit(), targetWidget, false);
ability.onOrder(this.simulation, unit.getSimulationUnit(), OrderIds.smart, targetWidget,
false);
ordered = true;
}
else {
@ -1308,7 +1353,7 @@ public class War3MapViewer extends ModelViewer {
@Override
public SceneLightManager createLightManager(final boolean simple) {
if (simple) {
return new W3xScenePortraitLightManager(this);
return new W3xScenePortraitLightManager(this, this.lightDirection);
}
else {
return new W3xSceneWorldLightManager(this);
@ -1321,12 +1366,14 @@ public class War3MapViewer extends ModelViewer {
public void setGameUI(final GameUI gameUI) {
this.gameUI = gameUI;
for (final RenderUnit unit : this.units) {
unit.initAbilityUI(this);
}
this.abilityDataUI = new AbilityDataUI(this.allObjectData.getAbilities(), gameUI);
}
public GameUI getGameUI() {
return this.gameUI;
}
public AbilityDataUI getAbilityDataUI() {
return this.abilityDataUI;
}
}

View File

@ -0,0 +1,62 @@
package com.etheller.warsmash.viewer5.handlers.w3x.camera;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Vector3;
import com.etheller.warsmash.viewer5.Camera;
import com.etheller.warsmash.viewer5.CanvasProvider;
import com.etheller.warsmash.viewer5.Scene;
public abstract class CameraManager {
private static final double HORIZONTAL_ANGLE_INCREMENT = Math.PI / 60;
protected final float[] cameraPositionTemp = new float[3];
protected final float[] cameraTargetTemp = new float[3];
protected CanvasProvider canvas;
protected Camera camera;
protected float moveSpeed;
protected float rotationSpeed;
protected float zoomFactor;
protected float horizontalAngle;
protected float verticalAngle;
protected float distance;
protected Vector3 position;
public Vector3 target;
protected Vector3 worldUp;
protected Vector3 vecHeap;
protected Quaternion quatHeap;
protected Quaternion quatHeap2;
public CameraManager() {
}
// An orbit camera setup example.
// Left mouse button controls the orbit itself.
// The right mouse button allows to move the camera and the point it's looking
// at on the XY plane.
// Scrolling zooms in and out.
public void setupCamera(final Scene scene) {
this.canvas = scene.viewer.canvas;
this.camera = scene.camera;
this.moveSpeed = 2;
this.rotationSpeed = (float) HORIZONTAL_ANGLE_INCREMENT;
this.zoomFactor = 0.1f;
this.horizontalAngle = 0;// (float) (Math.PI / 2);
this.verticalAngle = (float) Math.toRadians(34);
this.distance = 1650;
this.position = new Vector3();
this.target = new Vector3(0, 0, 0);
this.worldUp = new Vector3(0, 0, 1);
this.vecHeap = new Vector3();
this.quatHeap = new Quaternion();
this.quatHeap2 = new Quaternion();
updateCamera();
// cameraUpdate();
}
public abstract void updateCamera();
// private void cameraUpdate() {
//
// }
}

View File

@ -0,0 +1,10 @@
package com.etheller.warsmash.viewer5.handlers.w3x.camera;
public final class CameraPanControls {
protected boolean down;
protected boolean up;
protected boolean left;
protected boolean right;
protected boolean insertDown;
protected boolean deleteDown;
}

View File

@ -0,0 +1,85 @@
package com.etheller.warsmash.viewer5.handlers.w3x.camera;
public class CameraPreset {
private final float aoa;
private final float fov;
private final float rotation;
private final float rotationInsert;
private final float rotationDelete;
private final float distance;
private final float farZ;
private final float nearZ;
private final float height;
private final float listenerDistance;
private final float listenerAOA;
public CameraPreset(final float aoa, final float fov, final float rotation, final float rotationInsert,
final float rotationDelete, final float distance, final float farZ, final float nearZ, final float height,
final float listenerDistance, final float listenerAOA) {
this.aoa = aoa;
this.fov = fov;
this.rotation = rotation;
this.rotationInsert = rotationInsert;
this.rotationDelete = rotationDelete;
this.distance = distance;
this.farZ = farZ;
this.nearZ = nearZ;
this.height = height;
this.listenerDistance = listenerDistance;
this.listenerAOA = listenerAOA;
}
public float getRotation(final boolean insertDown, final boolean deleteDown) {
if (insertDown && !deleteDown) {
return this.rotationInsert;
}
if (!insertDown && deleteDown) {
return this.rotationDelete;
}
return this.rotation;
}
public float getHeight() {
return this.height;
}
public float getAoa() {
return this.aoa;
}
public float getFov() {
return this.fov;
}
public float getRotation() {
return this.rotation;
}
public float getRotationInsert() {
return this.rotationInsert;
}
public float getRotationDelete() {
return this.rotationDelete;
}
public float getDistance() {
return this.distance;
}
public float getFarZ() {
return this.farZ;
}
public float getNearZ() {
return this.nearZ;
}
public float getListenerDistance() {
return this.listenerDistance;
}
public float getListenerAOA() {
return this.listenerAOA;
}
}

View File

@ -0,0 +1,20 @@
package com.etheller.warsmash.viewer5.handlers.w3x.camera;
public class CameraRates {
public final float aoa;
public final float fov;
public final float rotation;
public final float distance;
public final float forward;
public final float strafe;
public CameraRates(final float aoa, final float fov, final float rotation, final float distance,
final float forward, final float strafe) {
this.aoa = aoa;
this.fov = fov;
this.rotation = rotation;
this.distance = distance;
this.forward = forward;
this.strafe = strafe;
}
}

View File

@ -0,0 +1,154 @@
package com.etheller.warsmash.viewer5.handlers.w3x.camera;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.math.Rectangle;
public final class GameCameraManager extends CameraManager {
private final CameraPreset[] presets;
private final CameraRates cameraRates;
public final CameraPanControls cameraPanControls;
private int currentPreset = 0;
public GameCameraManager(final CameraPreset[] presets, final CameraRates cameraRates) {
this.presets = presets;
this.cameraRates = cameraRates;
this.cameraPanControls = new CameraPanControls();
}
@Override
public void updateCamera() {
this.quatHeap2.idt();
final CameraPreset cameraPreset = this.presets[this.currentPreset];
this.quatHeap.idt();
this.horizontalAngle = (float) Math.toRadians(
cameraPreset.getRotation(this.cameraPanControls.insertDown, this.cameraPanControls.deleteDown) - 90);
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
this.distance = Math.max(1200, cameraPreset.getDistance());
this.verticalAngle = (float) Math.toRadians(Math.min(335, cameraPreset.getAoa()) - 270);
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
this.quatHeap.mul(this.quatHeap2);
this.position.set(0, 0, 1);
this.quatHeap.transform(this.position);
this.position.nor();
this.position.scl(this.distance);
this.position = this.position.add(this.target);
this.camera.perspective((float) Math.toRadians(cameraPreset.getFov() / 2), this.camera.getAspect(),
cameraPreset.getNearZ(), cameraPreset.getFarZ());
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
public void resize(final Rectangle viewport) {
this.camera.viewport(viewport);
}
public void applyVelocity(final float deltaTime, boolean up, boolean down, boolean left, boolean right) {
final float velocityX;
final float velocityY;
up |= this.cameraPanControls.up;
down |= this.cameraPanControls.down;
left |= this.cameraPanControls.left;
right |= this.cameraPanControls.right;
if (up) {
if (down) {
velocityY = 0;
}
else {
velocityY = this.cameraRates.forward;
}
}
else if (down) {
velocityY = -this.cameraRates.forward;
}
else {
velocityY = 0;
}
if (right) {
if (left) {
velocityX = 0;
}
else {
velocityX = this.cameraRates.strafe;
}
}
else if (left) {
velocityX = -this.cameraRates.strafe;
}
else {
velocityX = 0;
}
this.target.add(velocityX * deltaTime, velocityY * deltaTime, 0);
}
public void updateTargetZ(final float groundHeight) {
this.target.z = groundHeight + this.presets[this.currentPreset].getHeight();
}
public void scrolled(final int amount) {
this.currentPreset -= amount;
if (this.currentPreset < 0) {
this.currentPreset = 0;
}
if (this.currentPreset >= this.presets.length) {
this.currentPreset = this.presets.length - 1;
}
}
public boolean keyDown(final int keycode) {
if (keycode == Input.Keys.LEFT) {
this.cameraPanControls.left = true;
return true;
}
else if (keycode == Input.Keys.RIGHT) {
this.cameraPanControls.right = true;
return true;
}
else if (keycode == Input.Keys.DOWN) {
this.cameraPanControls.down = true;
return true;
}
else if (keycode == Input.Keys.UP) {
this.cameraPanControls.up = true;
return true;
}
else if (keycode == Input.Keys.INSERT) {
this.cameraPanControls.insertDown = true;
return true;
}
else if (keycode == Input.Keys.FORWARD_DEL) {
this.cameraPanControls.deleteDown = true;
return true;
}
return false;
}
public boolean keyUp(final int keycode) {
if (keycode == Input.Keys.LEFT) {
this.cameraPanControls.left = false;
return true;
}
else if (keycode == Input.Keys.RIGHT) {
this.cameraPanControls.right = false;
return true;
}
else if (keycode == Input.Keys.DOWN) {
this.cameraPanControls.down = false;
return true;
}
else if (keycode == Input.Keys.UP) {
this.cameraPanControls.up = false;
return true;
}
else if (keycode == Input.Keys.INSERT) {
this.cameraPanControls.insertDown = false;
return true;
}
else if (keycode == Input.Keys.FORWARD_DEL) {
this.cameraPanControls.deleteDown = false;
return true;
}
return false;
}
}

View File

@ -0,0 +1,52 @@
package com.etheller.warsmash.viewer5.handlers.w3x.camera;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
public final class PortraitCameraManager extends CameraManager {
public com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
protected MdxComplexInstance modelInstance;
@Override
public void updateCamera() {
this.quatHeap.idt();
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
this.quatHeap2.idt();
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
this.quatHeap.mul(this.quatHeap2);
this.position.set(0, 0, 1);
this.quatHeap.transform(this.position);
this.position.scl(this.distance);
this.position = this.position.add(this.target);
if (this.modelCamera != null) {
this.modelCamera.getPositionTranslation(this.cameraPositionTemp, this.modelInstance.sequence,
this.modelInstance.frame, this.modelInstance.counter);
this.modelCamera.getTargetTranslation(this.cameraTargetTemp, this.modelInstance.sequence,
this.modelInstance.frame, this.modelInstance.counter);
this.position.set(this.modelCamera.position);
this.target.set(this.modelCamera.targetPosition);
this.position.add(this.cameraPositionTemp[0], this.cameraPositionTemp[1], this.cameraPositionTemp[2]);
this.target.add(this.cameraTargetTemp[0], this.cameraTargetTemp[1], this.cameraTargetTemp[2]);
this.camera.perspective(this.modelCamera.fieldOfView * 0.75f, this.camera.getAspect(),
this.modelCamera.nearClippingPlane, this.modelCamera.farClippingPlane);
}
else {
this.camera.perspective(70, this.camera.getAspect(), 100, 5000);
}
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
public void setModelInstance(final MdxComplexInstance modelInstance, final MdxModel portraitModel) {
this.modelInstance = modelInstance;
if (modelInstance == null) {
this.modelCamera = null;
}
else if ((portraitModel != null) && (portraitModel.getCameras().size() > 0)) {
this.modelCamera = portraitModel.getCameras().get(0);
}
}
}

View File

@ -890,7 +890,8 @@ public class Terrain {
unitLightsTexture.bind(21);
gl.glUniform1i(this.groundShader.getUniformLocation("lightTexture"), 21);
gl.glUniform1f(this.groundShader.getUniformLocation("lightCount"), unitLightsTexture.getHeight() - 0.5f);
gl.glUniform1f(this.groundShader.getUniformLocation("lightCount"), lightManager.getTerrainLightCount());
gl.glUniform1f(this.groundShader.getUniformLocation("lightTextureHeight"), unitLightsTexture.getHeight());
gl.glUniformMatrix4fv(this.groundShader.getUniformLocation("DepthBiasMVP"), 1, false,
dynamicShadowManager.getDepthBiasMVP().val, 0);
@ -989,8 +990,9 @@ public class Terrain {
final DataTexture terrainLightsTexture = lightManager.getTerrainLightsTexture();
terrainLightsTexture.bind(21);
gl.glUniform1i(shader.getUniformLocation("lightTexture"), 21);
gl.glUniform1f(shader.getUniformLocation("lightCount"), terrainLightsTexture.getHeight() - 0.5f);
gl.glUniform1i(shader.getUniformLocation("u_lightTexture"), 21);
gl.glUniform1f(shader.getUniformLocation("u_lightCount"), lightManager.getTerrainLightCount());
gl.glUniform1f(shader.getUniformLocation("u_lightTextureHeight"), terrainLightsTexture.getHeight());
// Render the cliffs
for (final SplatModel splat : this.uberSplatModels) {
@ -1024,7 +1026,8 @@ public class Terrain {
unitLightsTexture.bind(21);
gl.glUniform1i(this.waterShader.getUniformLocation("lightTexture"), 21);
gl.glUniform1f(this.waterShader.getUniformLocation("lightCount"), unitLightsTexture.getHeight() - 0.5f);
gl.glUniform1f(this.waterShader.getUniformLocation("lightCount"), lightManager.getTerrainLightCount());
gl.glUniform1f(this.waterShader.getUniformLocation("lightCountHeight"), unitLightsTexture.getHeight());
gl.glActiveTexture(GL30.GL_TEXTURE0);
gl.glBindTexture(GL30.GL_TEXTURE_2D, this.waterHeight);
@ -1080,7 +1083,8 @@ public class Terrain {
unitLightsTexture.bind(21);
gl.glUniform1i(this.cliffShader.getUniformLocation("lightTexture"), 21);
gl.glUniform1f(this.cliffShader.getUniformLocation("lightCount"), unitLightsTexture.getHeight() - 0.5f);
gl.glUniform1f(this.cliffShader.getUniformLocation("lightCount"), lightManager.getTerrainLightCount());
gl.glUniform1f(this.cliffShader.getUniformLocation("lightTextureHeight"), unitLightsTexture.getHeight());
this.cliffShader.setUniformi("shadowMap", 2);
gl.glActiveTexture(GL30.GL_TEXTURE2);

View File

@ -25,6 +25,7 @@ public class TerrainShaders {
"layout (location = 4) uniform float centerOffsetY;\r\n" + //
"layout (location = 5) uniform sampler2D lightTexture;\r\n" + //
"layout (location = 6) uniform float lightCount;\r\n" + //
"layout (location = 7) uniform float lightTextureHeight;\r\n" + //
"\r\n" + //
"layout (location = 0) out vec3 UV;\r\n" + //
"layout (location = 1) out vec3 Normal;\r\n" + //
@ -60,7 +61,9 @@ public class TerrainShaders {
" vec3 terrain_normal = normalize(vNormal);//vec3(hL - hR, hD - hU, 2.0)+vNormal);\r\n" + //
"\r\n" + //
" Normal = terrain_normal;\r\n" + //
Shaders.lightSystem("Normal", "myposition.xyz", "lightTexture", "lightCount", true) + "\r\n" + //
Shaders.lightSystem("Normal", "myposition.xyz", "lightTexture", "lightTextureHeight", "lightCount",
true)
+ "\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
"}";
@ -135,6 +138,7 @@ public class TerrainShaders {
"layout (location = 5) uniform float centerOffsetY;\r\n" + //
"layout (location = 7) uniform sampler2D lightTexture;\r\n" + //
"layout (location = 8) uniform float lightCount;\r\n" + //
"layout (location = 9) uniform float lightTextureHeight;\r\n" + //
"\r\n" + //
"layout (location = 0) out vec2 UV;\r\n" + //
"layout (location = 1) out flat uvec4 texture_indices;\r\n" + //
@ -173,7 +177,8 @@ public class TerrainShaders {
" v_suv = (vPosition + pos) / size;\r\n" + //
" position.x = (position.x - centerOffsetX) / (size.x * 128.0);\r\n" + //
" position.y = (position.y - centerOffsetY) / (size.y * 128.0);\r\n" + //
Shaders.lightSystem("normal", "positionWorld", "lightTexture", "lightCount", true) + "\r\n" + //
Shaders.lightSystem("normal", "positionWorld", "lightTexture", "lightTextureHeight", "lightCount", true)
+ "\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
"}";
@ -425,6 +430,7 @@ public class TerrainShaders {
"layout (location = 5) uniform float water_offset;\r\n" + //
"layout (location = 10) uniform sampler2D lightTexture;\r\n" + //
"layout (location = 11) uniform float lightCount;\r\n" + //
"layout (location = 12) uniform float lightTextureHeight;\r\n" + //
"\r\n" + //
"out vec2 UV;\r\n" + //
"out vec4 Color;\r\n" + //
@ -463,7 +469,9 @@ public class TerrainShaders {
" value = clamp(value - deeplevel, 0.f, maxdepth - deeplevel) / (maxdepth - deeplevel);\r\n" + //
" Color = deep_color_min * (1.f - value) + deep_color_max * value;\r\n" + //
" }\r\n" + //
Shaders.lightSystem("Normal", "myposition.xyz", "lightTexture", "lightCount", true) + "\r\n" + //
Shaders.lightSystem("Normal", "myposition.xyz", "lightTexture", "lightTextureHeight", "lightCount",
true)
+ "\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //
" }";

View File

@ -1,33 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
import com.badlogic.gdx.graphics.Texture;
public class CommandCardIcon {
private final int x;
private final int y;
private final Texture texture;
private final int orderId;
public CommandCardIcon(final int x, final int y, final Texture texture, final int orderId) {
this.x = x;
this.y = y;
this.texture = texture;
this.orderId = orderId;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public Texture getTexture() {
return this.texture;
}
public int getOrderId() {
return this.orderId;
}
}

View File

@ -1,18 +1,13 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Quaternion;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.mdlx.Sequence;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.RenderMathUtils;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
@ -26,22 +21,14 @@ import com.etheller.warsmash.viewer5.handlers.w3x.UnitSoundset;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButtonListener;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandCardPopulatingAbilityVisitor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitAnimationListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityHoldPosition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityPatrol;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityStop;
public class RenderUnit {
private static final War3ID ABILITY_MOVE = War3ID.fromString("Amov");
private static final War3ID ABILITY_STOP = War3ID.fromString("Astp");
private static final War3ID ABILITY_HOLD_POSITION = War3ID.fromString("Ahol");
private static final War3ID ABILITY_PATROL = War3ID.fromString("Apat");
private static final War3ID ABILITY_ATTACK = War3ID.fromString("Aatk");
private static final Quaternion tempQuat = new Quaternion();
private static final War3ID RED = War3ID.fromString("uclr");
private static final War3ID GREEN = War3ID.fromString("uclg");
@ -61,7 +48,6 @@ public class RenderUnit {
private final CUnit simulationUnit;
public SplatMover shadow;
public SplatMover selectionCircle;
private final List<CommandCardIcon> commandCardIcons = new ArrayList<>();
private float x;
private float y;
@ -77,12 +63,14 @@ public class RenderUnit {
public long lastUnitResponseEndTimeMillis;
private boolean corpse;
private boolean boneCorpse;
private final RenderUnitTypeData typeData;
public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit, final UnitSoundset soundset,
final MdxModel portraitModel, final CUnit simulationUnit) {
final MdxModel portraitModel, final CUnit simulationUnit, final RenderUnitTypeData typeData) {
this.portraitModel = portraitModel;
this.simulationUnit = simulationUnit;
this.typeData = typeData;
final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance();
final float[] location = unit.getLocation();
@ -143,43 +131,10 @@ public class RenderUnit {
}
public void initAbilityUI(final War3MapViewer map) {
public void populateCommandCard(final CommandButtonListener commandButtonListener,
final AbilityDataUI abilityDataUI) {
for (final CAbility ability : this.simulationUnit.getAbilities()) {
if (ability instanceof CAbilityMove) {
final GameUI gameUI = map.getGameUI();
final Element moveCommand = gameUI.getSkinData().get("CmdMove");
final String moveCommandArt = gameUI.getSkinField(moveCommand.getField("Art"));
this.commandCardIcons.add(new CommandCardIcon(0, 0,
ImageUtils.getBLPTexture(map.dataSource, moveCommandArt), ability.getOrderId()));
}
else if (ability instanceof CAbilityAttack) {
final GameUI gameUI = map.getGameUI();
final Element command = gameUI.getSkinData().get("CmdAttack");
final String commandArt = gameUI.getSkinField(command.getField("Art"));
this.commandCardIcons.add(new CommandCardIcon(3, 0,
ImageUtils.getBLPTexture(map.dataSource, commandArt), ability.getOrderId()));
}
else if (ability instanceof CAbilityHoldPosition) {
final GameUI gameUI = map.getGameUI();
final Element command = gameUI.getSkinData().get("CmdHoldPos");
final String commandArt = gameUI.getSkinField(command.getField("Art"));
this.commandCardIcons.add(new CommandCardIcon(2, 0,
ImageUtils.getBLPTexture(map.dataSource, commandArt), ability.getOrderId()));
}
else if (ability instanceof CAbilityPatrol) {
final GameUI gameUI = map.getGameUI();
final Element command = gameUI.getSkinData().get("CmdPatrol");
final String commandArt = gameUI.getSkinField(command.getField("Art"));
this.commandCardIcons.add(new CommandCardIcon(0, 1,
ImageUtils.getBLPTexture(map.dataSource, commandArt), ability.getOrderId()));
}
else if (ability instanceof CAbilityStop) {
final GameUI gameUI = map.getGameUI();
final Element command = gameUI.getSkinData().get("CmdStop");
final String commandArt = gameUI.getSkinField(command.getField("Art"));
this.commandCardIcons.add(new CommandCardIcon(1, 0,
ImageUtils.getBLPTexture(map.dataSource, commandArt), ability.getOrderId()));
}
ability.visit(CommandCardPopulatingAbilityVisitor.INSTANCE.reset(commandButtonListener, abilityDataUI));
}
}
@ -298,6 +253,32 @@ public class RenderUnit {
}
this.facing = (((this.facing + angleToAdd) % 360) + 360) % 360;
this.instance.setLocalRotation(tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.facing));
final float facingRadians = (float) Math.toRadians(this.facing);
final float maxPitch = this.typeData.getMaxPitch();
final float maxRoll = this.typeData.getMaxRoll();
final float sampleRadius = this.typeData.getElevationSampleRadius();
float pitch, roll;
final float pitchSampleForwardX = x + (sampleRadius * (float) Math.cos(facingRadians));
final float pitchSampleForwardY = y + (sampleRadius * (float) Math.sin(facingRadians));
final float pitchSampleBackwardX = x - (sampleRadius * (float) Math.cos(facingRadians));
final float pitchSampleBackwardY = y - (sampleRadius * (float) Math.sin(facingRadians));
final float pitchSampleGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
final float pitchSampleGorundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
pitch = Math.max(-maxPitch, Math.min(maxPitch,
(float) Math.atan2(pitchSampleGorundHeight2 - pitchSampleGroundHeight1, sampleRadius * 2)));
final double leftOfFacingAngle = facingRadians + (Math.PI / 2);
final float rollSampleForwardX = x + (sampleRadius * (float) Math.cos(leftOfFacingAngle));
final float rollSampleForwardY = y + (sampleRadius * (float) Math.sin(leftOfFacingAngle));
final float rollSampleBackwardX = x - (sampleRadius * (float) Math.cos(leftOfFacingAngle));
final float rollSampleBackwardY = y - (sampleRadius * (float) Math.sin(leftOfFacingAngle));
final float rollSampleGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
final float rollSampleGroundHeight2 = map.terrain.getGroundHeight(rollSampleForwardX, rollSampleForwardY);
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]);
if (this.shadow != null) {
this.shadow.move(dx, dy, map.terrain.centerOffset);
@ -312,10 +293,6 @@ public class RenderUnit {
return this.simulationUnit;
}
public List<CommandCardIcon> getCommandCardIcons() {
return this.commandCardIcons;
}
private static final class UnitAnimationListenerImpl implements CUnitAnimationListener {
private final MdxComplexInstance instance;
private final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet

View File

@ -0,0 +1,25 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
public class RenderUnitTypeData {
private final float maxPitch;
private final float maxRoll;
private final float sampleRadius;
public RenderUnitTypeData(final float maxPitch, final float maxRoll, final float sampleRadius) {
this.maxPitch = maxPitch;
this.maxRoll = maxRoll;
this.sampleRadius = sampleRadius;
}
public float getMaxPitch() {
return this.maxPitch;
}
public float getMaxRoll() {
return this.maxRoll;
}
public float getElevationSampleRadius() {
return this.sampleRadius;
}
}

View File

@ -0,0 +1,112 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability;
import java.util.HashMap;
import java.util.Map;
import com.badlogic.gdx.graphics.Texture;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.units.manager.MutableObjectData;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.War3ID;
public class AbilityDataUI {
// Standard ability icon fields
private static final War3ID ICON_NORMAL_X = War3ID.fromString("abpx");
private static final War3ID ICON_NORMAL_Y = War3ID.fromString("abpy");
private static final War3ID ICON_NORMAL = War3ID.fromString("aart");
private static final War3ID ICON_TURN_OFF = War3ID.fromString("auar");
private static final War3ID ICON_TURN_OFF_X = War3ID.fromString("aubx");
private static final War3ID ICON_TURN_OFF_Y = War3ID.fromString("auby");
private static final War3ID ICON_RESEARCH = War3ID.fromString("arar");
private static final War3ID ICON_RESEARCH_X = War3ID.fromString("arpx");
private static final War3ID ICON_RESEARCH_Y = War3ID.fromString("arpy");
private final Map<War3ID, AbilityIconUI> rawcodeToUI = new HashMap<>();
private final IconUI moveUI;
private final IconUI stopUI;
private final IconUI holdPosUI;
private final IconUI patrolUI;
private final IconUI attackUI;
private final IconUI attackGroundUI;
public AbilityDataUI(final MutableObjectData abilityData, final GameUI gameUI) {
final String disabledPrefix = gameUI.getSkinField("CommandButtonDisabledArtPath");
for (final War3ID alias : abilityData.keySet()) {
final MutableGameObject abilityTypeData = abilityData.get(alias);
final String iconResearchPath = gameUI.trySkinField(abilityTypeData.getFieldAsString(ICON_RESEARCH, 0));
final String iconNormalPath = gameUI.trySkinField(abilityTypeData.getFieldAsString(ICON_NORMAL, 0));
final String iconTurnOffPath = gameUI.trySkinField(abilityTypeData.getFieldAsString(ICON_TURN_OFF, 0));
final int iconResearchX = abilityTypeData.getFieldAsInteger(ICON_RESEARCH_X, 0);
final int iconResearchY = abilityTypeData.getFieldAsInteger(ICON_RESEARCH_Y, 0);
final int iconNormalX = abilityTypeData.getFieldAsInteger(ICON_NORMAL_X, 0);
final int iconNormalY = abilityTypeData.getFieldAsInteger(ICON_NORMAL_Y, 0);
final int iconTurnOffX = abilityTypeData.getFieldAsInteger(ICON_TURN_OFF_X, 0);
final int iconTurnOffY = abilityTypeData.getFieldAsInteger(ICON_TURN_OFF_Y, 0);
final Texture iconResearch = gameUI.loadTexture(iconResearchPath);
final Texture iconResearchDisabled = gameUI.loadTexture(disable(iconResearchPath, disabledPrefix));
final Texture iconNormal = gameUI.loadTexture(iconNormalPath);
final Texture iconNormalDisabled = gameUI.loadTexture(disable(iconNormalPath, disabledPrefix));
final Texture iconTurnOff = gameUI.loadTexture(iconTurnOffPath);
final Texture iconTurnOffDisabled = gameUI.loadTexture(disable(iconTurnOffPath, disabledPrefix));
this.rawcodeToUI.put(alias,
new AbilityIconUI(new IconUI(iconResearch, iconResearchDisabled, iconResearchX, iconResearchY),
new IconUI(iconNormal, iconNormalDisabled, iconNormalX, iconNormalY),
new IconUI(iconTurnOff, iconTurnOffDisabled, iconTurnOffX, iconTurnOffY)));
}
this.moveUI = createBuiltInIconUI(gameUI, "CmdMove", disabledPrefix);
this.stopUI = createBuiltInIconUI(gameUI, "CmdStop", disabledPrefix);
this.holdPosUI = createBuiltInIconUI(gameUI, "CmdHoldPos", disabledPrefix);
this.patrolUI = createBuiltInIconUI(gameUI, "CmdPatrol", disabledPrefix);
this.attackUI = createBuiltInIconUI(gameUI, "CmdAttack", disabledPrefix);
this.attackGroundUI = createBuiltInIconUI(gameUI, "CmdAttackGround", disabledPrefix);
}
private IconUI createBuiltInIconUI(final GameUI gameUI, final String key, final String disabledPrefix) {
final Element builtInAbility = gameUI.getSkinData().get(key);
final String iconPath = gameUI.trySkinField(builtInAbility.getField("Art"));
final Texture icon = gameUI.loadTexture(iconPath);
final Texture iconDisabled = gameUI.loadTexture(disable(iconPath, disabledPrefix));
final int buttonPositionX = builtInAbility.getFieldValue("Buttonpos", 0);
final int buttonPositionY = builtInAbility.getFieldValue("Buttonpos", 1);
return new IconUI(icon, iconDisabled, buttonPositionX, buttonPositionY);
}
public AbilityIconUI getUI(final War3ID rawcode) {
return this.rawcodeToUI.get(rawcode);
}
private static String disable(final String path, final String disabledPrefix) {
final int slashIndex = path.lastIndexOf('\\');
String name = path;
if (slashIndex != -1) {
name = path.substring(slashIndex + 1);
}
return disabledPrefix + name;
}
public IconUI getMoveUI() {
return this.moveUI;
}
public IconUI getStopUI() {
return this.stopUI;
}
public IconUI getHoldPosUI() {
return this.holdPosUI;
}
public IconUI getPatrolUI() {
return this.patrolUI;
}
public IconUI getAttackUI() {
return this.attackUI;
}
public IconUI getAttackGroundUI() {
return this.attackGroundUI;
}
}

View File

@ -0,0 +1,25 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability;
public class AbilityIconUI {
private final IconUI learnIconUI;
private final IconUI onIconUI;
private final IconUI offIconUI;
public AbilityIconUI(final IconUI learnIconUI, final IconUI onIconUI, final IconUI offIconUI) {
this.learnIconUI = learnIconUI;
this.onIconUI = onIconUI;
this.offIconUI = offIconUI;
}
public IconUI getLearnIconUI() {
return this.learnIconUI;
}
public IconUI getOnIconUI() {
return this.onIconUI;
}
public IconUI getOffIconUI() {
return this.offIconUI;
}
}

View File

@ -0,0 +1,34 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability;
import com.badlogic.gdx.graphics.Texture;
public class IconUI {
private final Texture icon;
private final Texture iconDisabled;
private final int buttonPositionX;
private final int buttonPositionY;
public IconUI(final Texture icon, final Texture iconDisabled, final int buttonPositionX,
final int buttonPositionY) {
this.icon = icon;
this.iconDisabled = iconDisabled;
this.buttonPositionX = buttonPositionX;
this.buttonPositionY = buttonPositionY;
}
public Texture getIcon() {
return this.icon;
}
public Texture getIconDisabled() {
return this.iconDisabled;
}
public int getButtonPositionX() {
return this.buttonPositionX;
}
public int getButtonPositionY() {
return this.buttonPositionY;
}
}

View File

@ -0,0 +1,94 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.badlogic.gdx.graphics.Texture;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityIconUI;
public class AbilityCommandButton implements CommandButton {
private final AbilityIconUI abilityIconUI;
private final int orderId;
public AbilityCommandButton(final AbilityIconUI abilityIconUI, final int orderId) {
this.abilityIconUI = abilityIconUI;
this.orderId = orderId;
}
@Override
public String getToolTip() {
return null;
}
@Override
public String getUberTip() {
return null;
}
@Override
public int getLumberCost() {
return 0;
}
@Override
public int getGoldCost() {
return 0;
}
@Override
public int getManaCost() {
return 0;
}
@Override
public int getFoodCost() {
return 0;
}
@Override
public Texture getIcon() {
return this.abilityIconUI.getOnIconUI().getIcon();
}
@Override
public Texture getDisabledIcon() {
return this.abilityIconUI.getOnIconUI().getIconDisabled();
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public float getCooldown() {
return 0;
}
@Override
public float getCooldownRemaining() {
return 0;
}
@Override
public boolean isAutoCastCapable() {
return false;
}
@Override
public boolean isAutoCastActive() {
return false;
}
@Override
public int getButtonPositionX() {
return this.abilityIconUI.getOnIconUI().getButtonPositionX();
}
@Override
public int getButtonPositionY() {
return this.abilityIconUI.getOnIconUI().getButtonPositionY();
}
@Override
public int getOrderId() {
return this.orderId;
}
}

View File

@ -0,0 +1,95 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.badlogic.gdx.graphics.Texture;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.IconUI;
public class BasicCommandButton implements CommandButton {
private final IconUI iconUI;
private final int orderId;
public BasicCommandButton(final IconUI iconUI, final int orderId) {
this.iconUI = iconUI;
this.orderId = orderId;
}
@Override
public String getToolTip() {
return null;
}
@Override
public String getUberTip() {
return null;
}
@Override
public int getLumberCost() {
return 0;
}
@Override
public int getGoldCost() {
return 0;
}
@Override
public int getManaCost() {
return 0;
}
@Override
public int getFoodCost() {
return 0;
}
@Override
public Texture getIcon() {
return this.iconUI.getIcon();
}
@Override
public Texture getDisabledIcon() {
return this.iconUI.getIconDisabled();
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public float getCooldown() {
return 0;
}
@Override
public float getCooldownRemaining() {
return 0;
}
@Override
public boolean isAutoCastCapable() {
return false;
}
@Override
public boolean isAutoCastActive() {
return false;
}
@Override
public int getButtonPositionX() {
return this.iconUI.getButtonPositionX();
}
@Override
public int getButtonPositionY() {
return this.iconUI.getButtonPositionY();
}
@Override
public int getOrderId() {
return this.orderId;
}
}

View File

@ -0,0 +1,38 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.badlogic.gdx.graphics.Texture;
public interface CommandButton {
String getToolTip();
String getUberTip();
int getLumberCost();
int getGoldCost();
int getManaCost();
int getFoodCost();
Texture getIcon();
Texture getDisabledIcon();
boolean isEnabled();
float getCooldown();
float getCooldownRemaining();
boolean isAutoCastCapable();
boolean isAutoCastActive();
int getButtonPositionX();
int getButtonPositionY();
int getOrderId();
}

View File

@ -0,0 +1,38 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.badlogic.gdx.graphics.Texture;
public interface CommandButtonListener {
// String getToolTip();
//
// String getUberTip();
//
// int getLumberCost();
//
// int getGoldCost();
//
// int getManaCost();
//
// int getFoodCost();
//
// Texture getIcon();
//
// Texture getDisabledIcon();
//
// boolean isEnabled();
//
// float getCooldown();
//
// float getCooldownRemaining();
//
// boolean isAutoCastCapable();
//
// boolean isAutoCastActive();
//
// int getButtonPositionX();
//
// int getButtonPositionY();
//
// int getOrderId();
void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int orderId);
}

View File

@ -0,0 +1,51 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.IconUI;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void> {
public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor();
private CommandButtonListener commandButtonListener;
private AbilityDataUI abilityDataUI;
private boolean hasStop;
public CommandCardPopulatingAbilityVisitor reset(final CommandButtonListener commandButtonListener,
final AbilityDataUI abilityDataUI) {
this.commandButtonListener = commandButtonListener;
this.abilityDataUI = abilityDataUI;
this.hasStop = false;
return this;
}
@Override
public Void accept(final CAbilityAttack ability) {
addCommandButton(this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
}
return null;
}
@Override
public Void accept(final CAbilityMove ability) {
addCommandButton(this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move);
addCommandButton(this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition);
addCommandButton(this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
}
return null;
}
private void addCommandButton(final IconUI iconUI, final int handleId, final int orderId) {
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
iconUI.getIcon(), orderId);
}
}

View File

@ -20,6 +20,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.C
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.data.CAbilityData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.data.CUnitData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CPathfindingProcessor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CMapControl;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CRace;
@ -59,15 +60,17 @@ public class CSimulation {
this.pathfindingProcessor = new CPathfindingProcessor(pathingGrid, this.worldCollision);
this.seededRandom = seededRandom;
this.players = new ArrayList<>();
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
for (int i = 0; i < (WarsmashConstants.MAX_PLAYERS - 4); i++) {
CPlayer newPlayer;
if (i < playerInfos.size()) {
final Player playerInfo = playerInfos.get(i);
this.players.add(new CPlayer(playerInfo.getId(), CMapControl.values()[playerInfo.getType()],
playerInfo.getName(), CRace.parseRace(playerInfo.getRace()), playerInfo.getStartLocation()));
newPlayer = new CPlayer(playerInfo.getId(), CMapControl.values()[playerInfo.getType()],
playerInfo.getName(), CRace.parseRace(playerInfo.getRace()), playerInfo.getStartLocation());
}
else {
this.players.add(new CPlayer(i, CMapControl.NONE, "Default string", CRace.OTHER, new float[] { 0, 0 }));
newPlayer = new CPlayer(i, CMapControl.NONE, "Default string", CRace.OTHER, new float[] { 0, 0 });
}
this.players.add(newPlayer);
}
this.players.add(new CPlayer(this.players.size(), CMapControl.NEUTRAL,
miscData.getLocalizedString("WESTRING_PLAYER_NA"), CRace.OTHER, new float[] { 0, 0 }));
@ -75,8 +78,14 @@ public class CSimulation {
miscData.getLocalizedString("WESTRING_PLAYER_NV"), CRace.OTHER, new float[] { 0, 0 }));
this.players.add(new CPlayer(this.players.size(), CMapControl.NEUTRAL,
miscData.getLocalizedString("WESTRING_PLAYER_NE"), CRace.OTHER, new float[] { 0, 0 }));
this.players.add(new CPlayer(this.players.size(), CMapControl.NEUTRAL,
miscData.getLocalizedString("WESTRING_PLAYER_NP"), CRace.OTHER, new float[] { 0, 0 }));
final CPlayer neutralPassive = new CPlayer(this.players.size(), CMapControl.NEUTRAL,
miscData.getLocalizedString("WESTRING_PLAYER_NP"), CRace.OTHER, new float[] { 0, 0 });
this.players.add(neutralPassive);
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
final CPlayer cPlayer = this.players.get(i);
cPlayer.setAlliance(neutralPassive, CAllianceType.PASSIVE, true);
neutralPassive.setAlliance(cPlayer, CAllianceType.PASSIVE, true);
}
}
@ -94,8 +103,8 @@ public class CSimulation {
public CUnit createUnit(final War3ID typeId, final int playerIndex, final float x, final float y,
final float facing, final BufferedImage buildingPathingPixelMap) {
final CUnit unit = this.unitData.create(this, playerIndex, this.handleIdAllocator.createId(), typeId, x, y,
facing, buildingPathingPixelMap);
final CUnit unit = this.unitData.create(this, playerIndex, typeId, x, y, facing, buildingPathingPixelMap,
this.simulationRenderController, this.handleIdAllocator);
this.units.add(unit);
this.worldCollision.addUnit(unit);
return unit;

View File

@ -18,6 +18,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CAttackOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
@ -389,7 +390,7 @@ public class CUnit extends CWidget {
CAllianceType.PASSIVE)) {
for (final CUnitAttack attack : this.unitType.getAttacks()) {
if (source.canBeTargetedBy(simulation, this, attack.getTargetsAllowed())) {
this.order(new CAttackOrder(this, attack, source), false);
this.order(new CAttackOrder(this, attack, OrderIds.attack, source), false);
break;
}
}
@ -527,6 +528,10 @@ public class CUnit extends CWidget {
return this.unitType.isBuilding();
}
public float getAcquisitionRange() {
return this.acquisitionRange;
}
private static final class AutoAttackTargetFinderEnum implements CUnitEnumFunction {
private CSimulation game;
private CUnit source;
@ -545,7 +550,7 @@ public class CUnit extends CWidget {
if (this.source.canReach(unit, this.source.acquisitionRange)
&& unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed())
&& (this.source.distance(unit) >= this.source.getUnitType().getMinimumAttackRange())) {
this.source.order(new CAttackOrder(this.source, attack, unit), false);
this.source.order(new CAttackOrder(this.source, attack, OrderIds.attack, unit), false);
return true;
}
}

View File

@ -12,11 +12,9 @@ public interface CAbility extends CAbilityView {
/* should fire when ability removed from unit */
void onRemove(CSimulation game, CUnit unit);
void onOrder(CSimulation game, CUnit caster, CWidget target, boolean queue);
void onOrder(CSimulation game, CUnit caster, int orderId, CWidget target, boolean queue);
void onOrder(CSimulation game, CUnit caster, Vector2 point, boolean queue);
void onOrder(CSimulation game, CUnit caster, int orderId, Vector2 point, boolean queue);
void onOrderNoTarget(CSimulation game, CUnit caster, boolean queue);
int getOrderId();
void onOrderNoTarget(CSimulation game, CUnit caster, int orderId, boolean queue);
}

View File

@ -9,33 +9,56 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.StringsToExternaliz
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CAttackOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CMoveOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType;
public class CAbilityAttack implements CAbility {
public static final int ORDER_ID = 860000; // fake, later will use WC3 one probably
public static final CAbilityAttack INSTANCE = new CAbilityAttack();
private final int handleId;
public CAbilityAttack(final int handleId) {
this.handleId = handleId;
}
@Override
public void checkCanUse(final CSimulation game, final CUnit unit, final AbilityActivationReceiver receiver) {
public void checkCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.useOk();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final CWidget target,
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.targetOk(target);
if ((orderId == OrderIds.smart) || (orderId == OrderIds.attack)) {
boolean canTarget = false;
for (final CUnitAttack attack : unit.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, unit, attack.getTargetsAllowed())) {
canTarget = true;
break;
}
}
if (canTarget) {
receiver.targetOk(target);
}
else {
// TODO obviously we should later support better warnings here
receiver.mustTargetType(TargetType.UNIT);
}
}
else {
receiver.orderIdNotAccepted();
}
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final Vector2 target,
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target,
final AbilityTargetCheckReceiver<Vector2> receiver) {
receiver.mustTargetType(TargetType.UNIT);
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit,
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.mustTargetType(TargetType.UNIT);
}
@ -49,33 +72,40 @@ public class CAbilityAttack implements CAbility {
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final CWidget target, final boolean queue) {
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final CWidget target,
final boolean queue) {
COrder order = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
order = new CAttackOrder(caster, attack, target);
order = new CAttackOrder(caster, attack, orderId, target);
break;
}
}
if (order == null) {
order = new CMoveOrder(caster, target.getX(), target.getY());
order = new CMoveOrder(caster, orderId, target.getX(), target.getY());
}
caster.order(order, queue);
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final Vector2 target, final boolean queue) {
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final Vector2 target,
final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_WIDGET);
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final boolean queue) {
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final int orderId, final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_WIDGET);
}
@Override
public int getOrderId() {
return ORDER_ID;
public <T> T visit(final CAbilityVisitor<T> visitor) {
return visitor.accept(this);
}
@Override
public int getHandleId() {
return this.handleId;
}
}

View File

@ -1,69 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
import com.badlogic.gdx.math.Vector2;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CDoNothingOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType;
public class CAbilityHoldPosition implements CAbility {
public static final int ORDER_ID = 860002; // fake, later will use WC3 one probably
public static CAbilityHoldPosition INSTANCE = new CAbilityHoldPosition();
@Override
public void checkCanUse(final CSimulation game, final CUnit unit, final AbilityActivationReceiver receiver) {
receiver.useOk();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.mustTargetType(TargetType.NO_TARGET);
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final Vector2 target,
final AbilityTargetCheckReceiver<Vector2> receiver) {
receiver.mustTargetType(TargetType.NO_TARGET);
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.targetOk(null);
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final CWidget target, final boolean queue) {
caster.order(new CDoNothingOrder(getOrderId()), queue);
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final Vector2 target, final boolean queue) {
caster.order(new CDoNothingOrder(getOrderId()), queue);
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final boolean queue) {
caster.order(new CDoNothingOrder(getOrderId()), queue);
}
@Override
public int getOrderId() {
return ORDER_ID;
}
}

View File

@ -6,35 +6,70 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.StringsToExternalizeLater;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CMoveOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CPatrolOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType;
public class CAbilityMove implements CAbility {
public static final int ORDER_ID = 859999; // fake, later will use WC3 one probably
public static CAbilityMove INSTANCE = new CAbilityMove();
private final int handleId;
public CAbilityMove(final int handleId) {
this.handleId = handleId;
}
@Override
public void checkCanUse(final CSimulation game, final CUnit unit, final AbilityActivationReceiver receiver) {
public void checkCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.useOk();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final CWidget target,
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.mustTargetType(TargetType.POINT);
switch (orderId) {
case OrderIds.smart:
case OrderIds.patrol:
if (target instanceof CUnit) {
receiver.targetOk(target);
}
else {
receiver.mustTargetType(TargetType.UNIT_OR_POINT);
}
break;
default:
receiver.orderIdNotAccepted();
break;
}
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final Vector2 target,
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target,
final AbilityTargetCheckReceiver<Vector2> receiver) {
receiver.targetOk(target);
switch (orderId) {
case OrderIds.smart:
case OrderIds.move:
case OrderIds.patrol:
receiver.targetOk(target);
break;
default:
receiver.orderIdNotAccepted();
break;
}
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit,
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.mustTargetType(TargetType.POINT);
switch (orderId) {
case OrderIds.holdposition:
receiver.targetOk(null);
break;
default:
receiver.orderIdNotAccepted();
break;
}
}
@Override
@ -48,23 +83,30 @@ public class CAbilityMove implements CAbility {
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final CWidget target, final boolean queue) {
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final CWidget target,
final boolean queue) {
caster.order(new CPatrolOrder(caster, orderId, (CUnit) target), queue);
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final Vector2 target,
final boolean queue) {
caster.order(new CMoveOrder(caster, orderId, target.x, target.y), queue);
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final int orderId, final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_POINT);
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final Vector2 target, final boolean queue) {
caster.order(new CMoveOrder(caster, target.x, target.y), queue);
public <T> T visit(final CAbilityVisitor<T> visitor) {
return visitor.accept(this);
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_POINT);
}
@Override
public int getOrderId() {
return ORDER_ID;
public int getHandleId() {
return this.handleId;
}
}

View File

@ -1,70 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
import com.badlogic.gdx.math.Vector2;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.StringsToExternalizeLater;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CMoveOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType;
public class CAbilityPatrol implements CAbility {
public static final int ORDER_ID = 860001; // fake, later will use WC3 one probably
public static CAbilityPatrol INSTANCE = new CAbilityPatrol();
@Override
public void checkCanUse(final CSimulation game, final CUnit unit, final AbilityActivationReceiver receiver) {
receiver.useOk();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.mustTargetType(TargetType.POINT);
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final Vector2 target,
final AbilityTargetCheckReceiver<Vector2> receiver) {
receiver.targetOk(target);
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.mustTargetType(TargetType.POINT);
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final CWidget target, final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_POINT);
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final Vector2 target, final boolean queue) {
caster.order(new CMoveOrder(caster, target.x, target.y), queue);
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_POINT);
}
@Override
public int getOrderId() {
return ORDER_ID;
}
}

View File

@ -1,69 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
import com.badlogic.gdx.math.Vector2;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CDoNothingOrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver.TargetType;
public class CAbilityStop implements CAbility {
public static final int ORDER_ID = 860003; // fake, later will use WC3 one probably
public static CAbilityStop INSTANCE = new CAbilityStop();
@Override
public void checkCanUse(final CSimulation game, final CUnit unit, final AbilityActivationReceiver receiver) {
receiver.useOk();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.mustTargetType(TargetType.NO_TARGET);
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final Vector2 target,
final AbilityTargetCheckReceiver<Vector2> receiver) {
receiver.mustTargetType(TargetType.NO_TARGET);
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.targetOk(null);
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final CWidget target, final boolean queue) {
caster.order(new CDoNothingOrder(getOrderId()), queue);
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final Vector2 target, final boolean queue) {
caster.order(new CDoNothingOrder(getOrderId()), queue);
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final boolean queue) {
caster.order(new CDoNothingOrder(getOrderId()), queue);
}
@Override
public int getOrderId() {
return ORDER_ID;
}
}

View File

@ -0,0 +1,5 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
public interface CAbilityToggleableView extends CAbilityView {
boolean isActive();
}

View File

@ -8,12 +8,17 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivat
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
public interface CAbilityView {
void checkCanUse(CSimulation game, CUnit unit, AbilityActivationReceiver receiver);
void checkCanUse(CSimulation game, CUnit unit, int orderId, AbilityActivationReceiver receiver);
void checkCanTarget(CSimulation game, CUnit unit, CWidget target, AbilityTargetCheckReceiver<CWidget> receiver);
void checkCanTarget(CSimulation game, CUnit unit, int orderId, CWidget target,
AbilityTargetCheckReceiver<CWidget> receiver);
void checkCanTarget(CSimulation game, CUnit unit, Vector2 target, AbilityTargetCheckReceiver<Vector2> receiver);
void checkCanTarget(CSimulation game, CUnit unit, int orderId, Vector2 target,
AbilityTargetCheckReceiver<Vector2> receiver);
void checkCanTargetNoTarget(CSimulation game, CUnit unit, AbilityTargetCheckReceiver<Void> receiver);
void checkCanTargetNoTarget(CSimulation game, CUnit unit, int orderId, AbilityTargetCheckReceiver<Void> receiver);
int getHandleId();
<T> T visit(CAbilityVisitor<T> visitor);
}

View File

@ -0,0 +1,15 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
/**
* A visitor for the lowest level inherent types of an ability. It's a bit of a
* design clash to have the notion of an ability visitor pattern while also
* having any arbitrary number of "ability types" defined in config files. But
* the way that we will handle this for now will be with the notion of a generic
* ability (one whose UI information and behaviors come from a rawcode) versus
* abilities with engine-level type information (move, stop, attack).
*/
public interface CAbilityVisitor<T> {
T accept(CAbilityAttack ability);
T accept(CAbilityMove ability);
}

View File

@ -15,11 +15,9 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.HandleIdAllocator;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityHoldPosition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityPatrol;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityStop;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
@ -31,6 +29,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUni
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissileLine;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissileSplash;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackNormal;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
public class CUnitData {
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
@ -126,9 +125,11 @@ public class CUnitData {
this.unitData = unitData;
}
public CUnit create(final CSimulation simulation, final int playerIndex, final int handleId, final War3ID typeId,
final float x, final float y, final float facing, final BufferedImage buildingPathingPixelMap) {
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
final MutableGameObject unitType = this.unitData.get(typeId);
final int handleId = handleIdAllocator.createId();
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
final int manaInitial = unitType.getFieldAsInteger(MANA_INITIAL_AMOUNT, 0);
final int manaMaximum = unitType.getFieldAsInteger(MANA_MAXIMUM, 0);
@ -140,15 +141,10 @@ public class CUnitData {
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
speed, defense, unitTypeInstance);
if (speed > 0) {
unit.add(simulation, CAbilityMove.INSTANCE);
unit.add(simulation, CAbilityPatrol.INSTANCE);
unit.add(simulation, CAbilityHoldPosition.INSTANCE);
unit.add(simulation, CAbilityStop.INSTANCE);
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
}
final int dmgDice1 = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
final int dmgDice2 = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
if ((dmgDice1 != 0) || (dmgDice2 != 0)) {
unit.add(simulation, CAbilityAttack.INSTANCE);
if (!unitTypeInstance.getAttacks().isEmpty()) {
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
}
return unit;
}

View File

@ -7,11 +7,11 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
public class CAttackOrder implements COrder {
private final CUnit unit;
private final int orderId;
private boolean wasWithinPropWindow = false;
private final CUnitAttack unitAttack;
private final CWidget target;
@ -21,9 +21,10 @@ public class CAttackOrder implements COrder {
private int thisOrderCooldownEndTime;
private boolean wasInRange = false;
public CAttackOrder(final CUnit unit, final CUnitAttack unitAttack, final CWidget target) {
public CAttackOrder(final CUnit unit, final CUnitAttack unitAttack, final int orderId, final CWidget target) {
this.unit = unit;
this.unitAttack = unitAttack;
this.orderId = orderId;
this.target = target;
createMoveOrder(unit, target);
}
@ -31,10 +32,10 @@ public class CAttackOrder implements COrder {
private void createMoveOrder(final CUnit unit, final CWidget target) {
if (!unit.isMovementDisabled()) { // TODO: Check mobility instead
if ((target instanceof CUnit) && !(((CUnit) target).getUnitType().isBuilding())) {
this.moveOrder = new CMoveOrder(unit, (CUnit) target);
this.moveOrder = new CMoveOrder(unit, this.orderId, (CUnit) target);
}
else {
this.moveOrder = new CMoveOrder(unit, target.getX(), target.getY());
this.moveOrder = new CMoveOrder(unit, this.orderId, target.getX(), target.getY());
}
}
else {
@ -172,7 +173,7 @@ public class CAttackOrder implements COrder {
@Override
public int getOrderId() {
return CAbilityAttack.ORDER_ID;
return this.orderId;
}
}

View File

@ -14,12 +14,12 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWorldCollision;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CPathfindingProcessor;
public class CMoveOrder implements COrder {
private static final Rectangle tempRect = new Rectangle();
private final CUnit unit;
private final int orderId;
private boolean wasWithinPropWindow = false;
private List<Point2D.Float> path = null;
private final CPathfindingProcessor.GridMapping gridMapping;
@ -27,16 +27,18 @@ public class CMoveOrder implements COrder {
private int searchCycles = 0;
private CUnit followUnit;
public CMoveOrder(final CUnit unit, final float targetX, final float targetY) {
public CMoveOrder(final CUnit unit, final int orderId, final float targetX, final float targetY) {
this.unit = unit;
this.orderId = orderId;
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
: CPathfindingProcessor.GridMapping.CELLS;
this.target = new Point2D.Float(targetX, targetY);
}
public CMoveOrder(final CUnit unit, final CUnit followUnit) {
public CMoveOrder(final CUnit unit, final int orderId, final CUnit followUnit) {
this.unit = unit;
this.orderId = orderId;
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
: CPathfindingProcessor.GridMapping.CELLS;
@ -313,7 +315,7 @@ public class CMoveOrder implements COrder {
@Override
public int getOrderId() {
return CAbilityMove.ORDER_ID;
return this.orderId;
}
}

View File

@ -0,0 +1,58 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
public class CPatrolOrder implements COrder {
private final CUnit unit;
private final int orderId;
private final CWidget target;
private COrder moveOrder;
public CPatrolOrder(final CUnit unit, final int orderId, final CUnit target) {
this.unit = unit;
this.orderId = orderId;
this.target = target;
createMoveOrder(unit, target);
}
private void createMoveOrder(final CUnit unit, final CUnit target) {
if (!unit.isMovementDisabled()) { // TODO: Check mobility instead
if ((target instanceof CUnit) && !(target.getUnitType().isBuilding())) {
this.moveOrder = new CMoveOrder(unit, this.orderId, target);
}
else {
this.moveOrder = new CMoveOrder(unit, this.orderId, target.getX(), target.getY());
}
}
else {
this.moveOrder = null;
}
}
@Override
public boolean update(final CSimulation simulation) {
if (this.target.isDead()) {
return true;
}
final float range = this.unit.getAcquisitionRange();
if (!this.unit.canReach(this.target, range)) {
if (this.moveOrder == null) {
return true;
}
if (this.moveOrder.update(simulation)) {
return true; // we just cant reach them
}
return false;
}
return false;
}
@Override
public int getOrderId() {
return this.orderId;
}
}

View File

@ -0,0 +1,457 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
/**
* Thanks to the Wurst guys for this list of ids, taken from this link:
* https://github.com/wurstscript/WurstStdlib2/blob/master/wurst/_wurst/assets/Orders.wurst
*
* The original code ported to create this Java file is licensed under the
* Apache License; you can read more at the link above.
*
*/
public class OrderIds {
;/**
* This is an order with no target that opens up the build menu of a unit that
* can build structures.
*/
;
public static final int buildmenu = 851994;
/**
* 851976 (cancel): This is an order with no target that is like a click on a
* cancel button. We used to be able to catch cancel clicks with this id back
* then but this id doesn't seem to work any more.
*/
public static final int cancel = 851976;
/**
* An item targeted order that move the target item to a certain inventory slot
* of the ordered hero.
*/
public static final int itemdrag00 = 852002;
/**
* An item targeted order that move the target item to a certain inventory slot
* of the ordered hero.
*/
public static final int itemdrag01 = 852003;
/**
* An item targeted order that move the target item to a certain inventory slot
* of the ordered hero.
*/
public static final int itemdrag02 = 852004;
/**
* An item targeted order that move the target item to a certain inventory slot
* of the ordered hero.
*/
public static final int itemdrag03 = 852005;
/**
* An item targeted order that move the target item to a certain inventory slot
* of the ordered hero.
*/
public static final int itemdrag04 = 852006;
/**
* An item targeted order that move the target item to a certain inventory slot
* of the ordered hero.
*/
public static final int itemdrag05 = 852007;
/**
* An order that will make the ordered hero use the item in a certain inventory
* slot. If it's an order with no target or object or point targeted depends on
* the type of item.
*/
public static final int itemuse00 = 852008;
/**
* An order that will make the ordered hero use the item in a certain inventory
* slot. If it's an order with no target or object or point targeted depends on
* the type of item.
*/
public static final int itemuse01 = 852009;
/**
* An order that will make the ordered hero use the item in a certain inventory
* slot. If it's an order with no target or object or point targeted depends on
* the type of item.
*/
public static final int itemuse02 = 852010;
/**
* An order that will make the ordered hero use the item in a certain inventory
* slot. If it's an order with no target or object or point targeted depends on
* the type of item.
*/
public static final int itemuse03 = 852011;
/**
* An order that will make the ordered hero use the item in a certain inventory
* slot. If it's an order with no target or object or point targeted depends on
* the type of item.
*/
public static final int itemuse04 = 852012;
/**
* An order that will make the ordered hero use the item in a certain inventory
* slot. If it's an order with no target or object or point targeted depends on
* the type of item.
*/
public static final int itemuse05 = 852013;
/**
* Order for AIaa ability, which blizzard made for tome of attack, but never
* used it. But it can actually change caster's base attack!
*/
public static final int tomeOfAttack = 852259;
/** This is a point or object targeted order that is like a right click. */
public static final int smart = 851971;
/**
* This is an order with no target that opens the skill menu of heroes. If it is
* issued for a normal unit with triggers it will black out the command card for
* this unit, the command card will revert to normal after reselecting the unit.
*/
public static final int skillmenu = 852000;
/**
* This order is issued to units that get stunned by a spell, for example War
* Stomp (AOws). This is probably a hold position + hold fire order. The ordered
* unit will be unable to move and attack.
*/
public static final int stunned = 851973;
public static final int wandOfIllusion = 852274;
public static final int absorb = 852529;
public static final int acidbomb = 852662;
public static final int acolyteharvest = 852185;
public static final int ambush = 852131;
public static final int ancestralspirit = 852490;
public static final int ancestralspirittarget = 852491;
public static final int animatedead = 852217;
public static final int antimagicshell = 852186;
public static final int attack = 851983;
public static final int attackground = 851984;
public static final int attackonce = 851985;
public static final int attributemodskill = 852576;
public static final int auraunholy = 852215;
public static final int auravampiric = 852216;
public static final int autodispel = 852132;
public static final int autodispeloff = 852134;
public static final int autodispelon = 852133;
public static final int autoentangle = 852505;
public static final int autoentangleinstant = 852506;
public static final int autoharvestgold = 852021;
public static final int autoharvestlumber = 852022;
public static final int avatar = 852086;
public static final int avengerform = 852531;
public static final int awaken = 852466;
public static final int banish = 852486;
public static final int barkskin = 852135;
public static final int barkskinoff = 852137;
public static final int barkskinon = 852136;
public static final int battleroar = 852599;
public static final int battlestations = 852099;
public static final int bearform = 852138;
public static final int berserk = 852100;
public static final int blackarrow = 852577;
public static final int blackarrowoff = 852579;
public static final int blackarrowon = 852578;
public static final int blight = 852187;
public static final int blink = 852525;
public static final int blizzard = 852089;
public static final int bloodlust = 852101;
public static final int bloodlustoff = 852103;
public static final int bloodluston = 852102;
public static final int board = 852043;
public static final int breathoffire = 852580;
public static final int breathoffrost = 852560;
public static final int build = 851994;
public static final int burrow = 852533;
public static final int cannibalize = 852188;
public static final int carrionscarabs = 852551;
public static final int carrionscarabsinstant = 852554;
public static final int carrionscarabsoff = 852553;
public static final int carrionscarabson = 852552;
public static final int carrionswarm = 852218;
public static final int chainlightning = 852119;
public static final int channel = 852600;
public static final int charm = 852581;
public static final int chemicalrage = 852663;
public static final int cloudoffog = 852473;
public static final int clusterrockets = 852652;
public static final int coldarrows = 852244;
public static final int coldarrowstarg = 852243;
public static final int controlmagic = 852474;
public static final int corporealform = 852493;
public static final int corrosivebreath = 852140;
public static final int coupleinstant = 852508;
public static final int coupletarget = 852507;
public static final int creepanimatedead = 852246;
public static final int creepdevour = 852247;
public static final int creepheal = 852248;
public static final int creephealoff = 852250;
public static final int creephealon = 852249;
public static final int creepthunderbolt = 852252;
public static final int creepthunderclap = 852253;
public static final int cripple = 852189;
public static final int curse = 852190;
public static final int curseoff = 852192;
public static final int curseon = 852191;
public static final int cyclone = 852144;
public static final int darkconversion = 852228;
public static final int darkportal = 852229;
public static final int darkritual = 852219;
public static final int darksummoning = 852220;
public static final int deathanddecay = 852221;
public static final int deathcoil = 852222;
public static final int deathpact = 852223;
public static final int decouple = 852509;
public static final int defend = 852055;
public static final int detectaoe = 852015;
public static final int detonate = 852145;
public static final int devour = 852104;
public static final int devourmagic = 852536;
public static final int disassociate = 852240;
public static final int disenchant = 852495;
public static final int dismount = 852470;
public static final int dispel = 852057;
public static final int divineshield = 852090;
public static final int doom = 852583;
public static final int drain = 852487;
public static final int dreadlordinferno = 852224;
public static final int dropitem = 852001;
public static final int drunkenhaze = 852585;
public static final int earthquake = 852121;
public static final int eattree = 852146;
public static final int elementalfury = 852586;
public static final int ensnare = 852106;
public static final int ensnareoff = 852108;
public static final int ensnareon = 852107;
public static final int entangle = 852147;
public static final int entangleinstant = 852148;
public static final int entanglingroots = 852171;
public static final int etherealform = 852496;
public static final int evileye = 852105;
public static final int faeriefire = 852149;
public static final int faeriefireoff = 852151;
public static final int faeriefireon = 852150;
public static final int fanofknives = 852526;
public static final int farsight = 852122;
public static final int fingerofdeath = 852230;
public static final int firebolt = 852231;
public static final int flamestrike = 852488;
public static final int flamingarrows = 852174;
public static final int flamingarrowstarg = 852173;
public static final int flamingattack = 852540;
public static final int flamingattacktarg = 852539;
public static final int flare = 852060;
public static final int forceboard = 852044;
public static final int forceofnature = 852176;
public static final int forkedlightning = 852587;
public static final int freezingbreath = 852195;
public static final int frenzy = 852561;
public static final int frenzyoff = 852563;
public static final int frenzyon = 852562;
public static final int frostarmor = 852225;
public static final int frostarmoroff = 852459;
public static final int frostarmoron = 852458;
public static final int frostnova = 852226;
public static final int getitem = 851981;
public static final int gold2lumber = 852233;
public static final int grabtree = 852511;
public static final int harvest = 852018;
public static final int heal = 852063;
public static final int healingspray = 852664;
public static final int healingward = 852109;
public static final int healingwave = 852501;
public static final int healoff = 852065;
public static final int healon = 852064;
public static final int hex = 852502;
public static final int holdposition = 851993;
public static final int holybolt = 852092;
public static final int howlofterror = 852588;
public static final int humanbuild = 851995;
public static final int immolation = 852177;
public static final int impale = 852555;
public static final int incineratearrow = 852670;
public static final int incineratearrowoff = 852672;
public static final int incineratearrowon = 852671;
public static final int inferno = 852232;
public static final int innerfire = 852066;
public static final int innerfireoff = 852068;
public static final int innerfireon = 852067;
public static final int instant = 852200;
public static final int invisibility = 852069;
public static final int lavamonster = 852667;
public static final int lightningshield = 852110;
public static final int load = 852046;
public static final int loadarcher = 852142;
public static final int loadcorpse = 852050;
public static final int loadcorpseinstant = 852053;
public static final int locustswarm = 852556;
public static final int lumber2gold = 852234;
public static final int magicdefense = 852478;
public static final int magicleash = 852480;
public static final int magicundefense = 852479;
public static final int manaburn = 852179;
public static final int manaflareoff = 852513;
public static final int manaflareon = 852512;
public static final int manashieldoff = 852590;
public static final int manashieldon = 852589;
public static final int massteleport = 852093;
public static final int mechanicalcritter = 852564;
public static final int metamorphosis = 852180;
public static final int militia = 852072;
public static final int militiaconvert = 852071;
public static final int militiaoff = 852073;
public static final int militiaunconvert = 852651;
public static final int mindrot = 852565;
public static final int mirrorimage = 852123;
public static final int monsoon = 852591;
public static final int mount = 852469;
public static final int mounthippogryph = 852143;
public static final int move = 851986;
public static final int moveAI = 851988;
public static final int nagabuild = 852467;
public static final int neutraldetectaoe = 852023;
public static final int neutralinteract = 852566;
public static final int neutralspell = 852630;
public static final int nightelfbuild = 851997;
public static final int orcbuild = 851996;
public static final int parasite = 852601;
public static final int parasiteoff = 852603;
public static final int parasiteon = 852602;
public static final int patrol = 851990;
public static final int phaseshift = 852514;
public static final int phaseshiftinstant = 852517;
public static final int phaseshiftoff = 852516;
public static final int phaseshifton = 852515;
public static final int phoenixfire = 852481;
public static final int phoenixmorph = 852482;
public static final int poisonarrows = 852255;
public static final int poisonarrowstarg = 852254;
public static final int polymorph = 852074;
public static final int possession = 852196;
public static final int preservation = 852568;
public static final int purge = 852111;
public static final int rainofchaos = 852237;
public static final int rainoffire = 852238;
public static final int raisedead = 852197;
public static final int raisedeadoff = 852199;
public static final int raisedeadon = 852198;
public static final int ravenform = 852155;
public static final int recharge = 852157;
public static final int rechargeoff = 852159;
public static final int rechargeon = 852158;
public static final int rejuvination = 852160;
public static final int renew = 852161;
public static final int renewoff = 852163;
public static final int renewon = 852162;
public static final int repair = 852024;
public static final int repairoff = 852026;
public static final int repairon = 852025;
public static final int replenish = 852542;
public static final int replenishlife = 852545;
public static final int replenishlifeoff = 852547;
public static final int replenishlifeon = 852546;
public static final int replenishmana = 852548;
public static final int replenishmanaoff = 852550;
public static final int replenishmanaon = 852549;
public static final int replenishoff = 852544;
public static final int replenishon = 852543;
public static final int request_hero = 852239;
public static final int requestsacrifice = 852201;
public static final int restoration = 852202;
public static final int restorationoff = 852204;
public static final int restorationon = 852203;
public static final int resumebuild = 851999;
public static final int resumeharvesting = 852017;
public static final int resurrection = 852094;
public static final int returnresources = 852020;
public static final int revenge = 852241;
public static final int revive = 852039;
public static final int roar = 852164;
public static final int robogoblin = 852656;
public static final int root = 852165;
public static final int sacrifice = 852205;
public static final int sanctuary = 852569;
public static final int scout = 852181;
public static final int selfdestruct = 852040;
public static final int selfdestructoff = 852042;
public static final int selfdestructon = 852041;
public static final int sentinel = 852182;
public static final int setrally = 851980;
public static final int shadowsight = 852570;
public static final int shadowstrike = 852527;
public static final int shockwave = 852125;
public static final int silence = 852592;
public static final int sleep = 852227;
public static final int slow = 852075;
public static final int slowoff = 852077;
public static final int slowon = 852076;
public static final int soulburn = 852668;
public static final int soulpreservation = 852242;
public static final int spellshield = 852571;
public static final int spellshieldaoe = 852572;
public static final int spellsteal = 852483;
public static final int spellstealoff = 852485;
public static final int spellstealon = 852484;
public static final int spies = 852235;
public static final int spiritlink = 852499;
public static final int spiritofvengeance = 852528;
public static final int spirittroll = 852573;
public static final int spiritwolf = 852126;
public static final int stampede = 852593;
public static final int standdown = 852113;
public static final int starfall = 852183;
public static final int stasistrap = 852114;
public static final int steal = 852574;
public static final int stomp = 852127;
public static final int stoneform = 852206;
public static final int stop = 851972;
public static final int submerge = 852604;
public static final int summonfactory = 852658;
public static final int summongrizzly = 852594;
public static final int summonphoenix = 852489;
public static final int summonquillbeast = 852595;
public static final int summonwareagle = 852596;
public static final int tankdroppilot = 852079;
public static final int tankloadpilot = 852080;
public static final int tankpilot = 852081;
public static final int taunt = 852520;
public static final int thunderbolt = 852095;
public static final int thunderclap = 852096;
public static final int tornado = 852597;
public static final int townbelloff = 852083;
public static final int townbellon = 852082;
public static final int tranquility = 852184;
public static final int transmute = 852665;
public static final int unavatar = 852087;
public static final int unavengerform = 852532;
public static final int unbearform = 852139;
public static final int unburrow = 852534;
public static final int uncoldarrows = 852245;
public static final int uncorporealform = 852494;
public static final int undeadbuild = 851998;
public static final int undefend = 852056;
public static final int undivineshield = 852091;
public static final int unetherealform = 852497;
public static final int unflamingarrows = 852175;
public static final int unflamingattack = 852541;
public static final int unholyfrenzy = 852209;
public static final int unimmolation = 852178;
public static final int unload = 852047;
public static final int unloadall = 852048;
public static final int unloadallcorpses = 852054;
public static final int unloadallinstant = 852049;
public static final int unpoisonarrows = 852256;
public static final int unravenform = 852156;
public static final int unrobogoblin = 852657;
public static final int unroot = 852166;
public static final int unstableconcoction = 852500;
public static final int unstoneform = 852207;
public static final int unsubmerge = 852605;
public static final int unsummon = 852210;
public static final int unwindwalk = 852130;
public static final int vengeance = 852521;
public static final int vengeanceinstant = 852524;
public static final int vengeanceoff = 852523;
public static final int vengeanceon = 852522;
public static final int volcano = 852669;
public static final int voodoo = 852503;
public static final int ward = 852504;
public static final int waterelemental = 852097;
public static final int wateryminion = 852598;
public static final int web = 852211;
public static final int weboff = 852213;
public static final int webon = 852212;
public static final int whirlwind = 852128;
public static final int windwalk = 852129;
public static final int wispharvest = 852214;
}

View File

@ -17,6 +17,8 @@ public interface AbilityTargetCheckReceiver<TARGET_TYPE> {
void targetNotInPlayableMap();
void orderIdNotAccepted();
public static enum TeamType {
ALLIED,
ENEMY,

View File

@ -48,6 +48,11 @@ public class CWidgetAbilityTargetCheckReceiver implements AbilityTargetCheckRece
this.target = null;
}
@Override
public void orderIdNotAccepted() {
this.target = null;
}
public CWidget getTarget() {
return this.target;
}

View File

@ -20,7 +20,6 @@ public class PointAbilityTargetCheckReceiver implements AbilityTargetCheckReceiv
@Override
public void mustTargetType(final TargetType correctType) {
this.target = null;
}
@Override
@ -48,6 +47,11 @@ public class PointAbilityTargetCheckReceiver implements AbilityTargetCheckReceiv
this.target = null;
}
@Override
public void orderIdNotAccepted() {
this.target = null;
}
public Vector2 getTarget() {
return this.target;
}

View File

@ -0,0 +1,88 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.frames.AbstractRenderableFrame;
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButton;
public class CommandCardIcon extends AbstractRenderableFrame {
private TextureFrame iconFrame;
private SpriteFrame cooldownFrame;
private SpriteFrame autocastFrame;
private CommandButton commandButton;
public CommandCardIcon(final String name, final UIFrame parent) {
super(name, parent);
}
public void set(final TextureFrame iconFrame, final SpriteFrame cooldownFrame, final SpriteFrame autocastFrame) {
this.iconFrame = iconFrame;
this.cooldownFrame = cooldownFrame;
this.autocastFrame = autocastFrame;
}
public void setCommandButton(final CommandButton commandButton) {
this.commandButton = commandButton;
if (commandButton == null) {
this.iconFrame.setVisible(false);
this.cooldownFrame.setVisible(false);
this.autocastFrame.setVisible(false);
}
else {
if (commandButton.isEnabled()) {
this.iconFrame.setTexture(commandButton.getIcon());
}
else {
this.iconFrame.setTexture(commandButton.getDisabledIcon());
}
if (commandButton.getCooldownRemaining() <= 0) {
this.cooldownFrame.setVisible(false);
}
else {
this.cooldownFrame.setVisible(true);
this.cooldownFrame.setSequence(PrimaryTag.STAND);
this.cooldownFrame.setAnimationSpeed(commandButton.getCooldown());
this.cooldownFrame
.setFrameByRatio(1 - (commandButton.getCooldownRemaining() / commandButton.getCooldown()));
}
this.autocastFrame.setVisible(commandButton.isAutoCastActive());
}
}
public void setCommandButtonData(final Texture texture, final int orderId) {
this.iconFrame.setVisible(true);
this.cooldownFrame.setVisible(false);
this.autocastFrame.setVisible(false);
this.iconFrame.setTexture(texture);
}
@Override
protected void innerPositionBounds(final Viewport viewport) {
this.iconFrame.positionBounds(viewport);
this.cooldownFrame.positionBounds(viewport);
this.autocastFrame.positionBounds(viewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.iconFrame.render(batch, baseFont, glyphLayout);
this.cooldownFrame.render(batch, baseFont, glyphLayout);
this.autocastFrame.render(batch, baseFont, glyphLayout);
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (this.renderBounds.contains(screenX, screenY)) {
return this;
}
return null;
}
}

View File

@ -2,8 +2,10 @@ package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
@ -12,7 +14,6 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.WarsmashGdxMapGame;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
@ -25,28 +26,39 @@ import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.util.FastNumberFormat;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.ReplaceableIds;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.tga.TgaFile;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.CommandCardIcon;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraPreset;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.CameraRates;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.GameCameraManager;
import com.etheller.warsmash.viewer5.handlers.w3x.camera.PortraitCameraManager;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButtonListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityStop;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CodeKeyType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
public class MeleeUI implements CUnitStateListener {
public class MeleeUI implements CUnitStateListener, CommandButtonListener {
private static final int COMMAND_CARD_WIDTH = 4;
private static final int COMMAND_CARD_HEIGHT = 3;
private static final Vector2 screenCoordsVector = new Vector2();
private final DataSource dataSource;
private final Viewport uiViewport;
private final FreeTypeFontGenerator fontGenerator;
private final Scene uiScene;
private final Scene portraitScene;
private final GameCameraManager cameraManager;
private final War3MapViewer war3MapViewer;
private final RootFrameListener rootFrameListener;
private GameUI rootFrame;
@ -82,23 +94,72 @@ public class MeleeUI implements CUnitStateListener {
private StringFrame armorInfoPanelIconLevel;
private InfoPanelIconBackdrops damageBackdrops;
private InfoPanelIconBackdrops defenseBackdrops;
private final CommandCardIcon[][] commandCard = new CommandCardIcon[COMMAND_CARD_HEIGHT][COMMAND_CARD_WIDTH];
private RenderUnit selectedUnit;
// TODO remove this & replace with FDF
private final Texture activeButtonTexture;
private UIFrame inventoryCover;
private SpriteFrame cursorFrame;
private MeleeUIMinimap meleeUIMinimap;
public MeleeUI(final DataSource dataSource, final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator,
final Scene uiScene, final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener) {
final Scene uiScene, final Scene portraitScene, final CameraPreset[] cameraPresets,
final CameraRates cameraRates, final War3MapViewer war3MapViewer,
final RootFrameListener rootFrameListener) {
this.dataSource = dataSource;
this.uiViewport = uiViewport;
this.fontGenerator = fontGenerator;
this.uiScene = uiScene;
this.portraitScene = portraitScene;
this.war3MapViewer = war3MapViewer;
this.rootFrameListener = rootFrameListener;
this.cameraManager = new GameCameraManager(cameraPresets, cameraRates);
this.cameraManager.setupCamera(war3MapViewer.worldScene);
if (this.war3MapViewer.startLocations[0] != null) {
this.cameraManager.target.x = this.war3MapViewer.startLocations[0].x;
this.cameraManager.target.y = this.war3MapViewer.startLocations[0].y;
}
this.activeButtonTexture = ImageUtils.getBLPTexture(war3MapViewer.mapMpq,
"UI\\Widgets\\Console\\Human\\CommandButton\\human-activebutton.blp");
}
private MeleeUIMinimap createMinimap(final War3MapViewer war3MapViewer) {
final Rectangle minimapDisplayArea = new Rectangle(18.75f, 13.75f, 278.75f, 276.25f);
Texture minimapTexture = null;
if (war3MapViewer.dataSource.has("war3mapMap.tga")) {
try {
minimapTexture = ImageUtils.getTextureNoColorCorrection(TgaFile.readTGA("war3mapMap.tga",
war3MapViewer.dataSource.getResourceAsStream("war3mapMap.tga")));
}
catch (final IOException e) {
System.err.println("Could not load minimap TGA file");
e.printStackTrace();
}
}
else if (war3MapViewer.dataSource.has("war3mapMap.blp")) {
try {
minimapTexture = ImageUtils
.getTexture(ImageIO.read(war3MapViewer.dataSource.getResourceAsStream("war3mapMap.blp")));
}
catch (final IOException e) {
System.err.println("Could not load minimap BLP file");
e.printStackTrace();
}
}
final Texture[] teamColors = new Texture[WarsmashConstants.MAX_PLAYERS];
for (int i = 0; i < teamColors.length; i++) {
teamColors[i] = ImageUtils.getBLPTexture(war3MapViewer.dataSource,
"ReplaceableTextures\\" + ReplaceableIds.getPathString(1) + ReplaceableIds.getIdString(i) + ".blp");
}
final Rectangle playableMapArea = war3MapViewer.terrain.getPlayableMapArea();
return new MeleeUIMinimap(minimapDisplayArea, playableMapArea, minimapTexture, teamColors);
}
/**
@ -109,7 +170,7 @@ public class MeleeUI implements CUnitStateListener {
// =================================
// Load skins and templates
// =================================
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 0), this.uiViewport,
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 3), this.uiViewport,
this.fontGenerator, this.uiScene, this.war3MapViewer);
this.rootFrameListener.onCreate(this.rootFrame);
try {
@ -155,7 +216,7 @@ public class MeleeUI implements CUnitStateListener {
this.timeIndicator.setAnimationSpeed(0.0f); // do not advance automatically
// Create the unit portrait stuff
this.portrait = new Portrait(this.war3MapViewer);
this.portrait = new Portrait(this.war3MapViewer, this.portraitScene);
positionPortrait();
this.unitPortrait = this.rootFrame.createSimpleFrame("UnitPortrait", this.consoleUI, 0);
this.unitLifeText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitHitPointText", 0);
@ -198,36 +259,122 @@ public class MeleeUI implements CUnitStateListener {
this.inventoryCover = this.rootFrame.createSimpleFrame("SmashConsoleInventoryCover", this.rootFrame, 0);
int commandButtonIndex = 0;
for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) {
for (int i = 0; i < COMMAND_CARD_WIDTH; i++) {
final CommandCardIcon commandCardIcon = new CommandCardIcon("SmashCommandButton_" + commandButtonIndex,
this.rootFrame);
this.rootFrame.add(commandCardIcon);
final TextureFrame iconFrame = this.rootFrame.createTextureFrame(
"SmashCommandButton_" + (commandButtonIndex) + "_Icon", this.rootFrame, false, null);
final SpriteFrame cooldownFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
"SmashCommandButton_" + (commandButtonIndex) + "_Cooldown", this.rootFrame, "", 0);
final SpriteFrame autocastFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
"SmashCommandButton_" + (commandButtonIndex) + "_Autocast", this.rootFrame, "", 0);
iconFrame.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT,
GameUI.convertX(this.uiViewport, 0.6175f + (0.0434f * i)),
GameUI.convertY(this.uiViewport, 0.095f - (0.044f * j))));
iconFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
iconFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
iconFrame.setTexture(ImageUtils.DEFAULT_ICON_PATH, this.rootFrame);
cooldownFrame.addSetPoint(new SetPoint(FramePoint.CENTER, iconFrame, FramePoint.CENTER, 0, 0));
this.rootFrame.setSpriteFrameModel(cooldownFrame, this.rootFrame.getSkinField("CommandButtonCooldown"));
cooldownFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
cooldownFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
autocastFrame.addSetPoint(new SetPoint(FramePoint.CENTER, iconFrame, FramePoint.CENTER, 0, 0));
this.rootFrame.setSpriteFrameModel(autocastFrame, this.rootFrame.getSkinField("CommandButtonAutocast"));
autocastFrame.setWidth(GameUI.convertX(this.uiViewport, 0.039f));
autocastFrame.setHeight(GameUI.convertY(this.uiViewport, 0.039f));
commandCardIcon.set(iconFrame, cooldownFrame, autocastFrame);
this.commandCard[j][i] = commandCardIcon;
commandCardIcon.setCommandButton(null);
commandButtonIndex++;
}
}
this.cursorFrame = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE", "SmashCursorFrame", this.rootFrame,
"", 0);
this.rootFrame.setSpriteFrameModel(this.cursorFrame, this.rootFrame.getSkinField("Cursor"));
this.cursorFrame.setSequence("Normal");
this.cursorFrame.setZDepth(1.0f);
Gdx.input.setCursorCatched(true);
this.meleeUIMinimap = createMinimap(this.war3MapViewer);
this.rootFrame.positionBounds(this.uiViewport);
selectUnit(null);
}
public void updatePortrait() {
public void update(final float deltaTime) {
this.portrait.update();
int mouseX = Gdx.input.getX();
int mouseY = Gdx.input.getY();
final int minX = this.uiViewport.getScreenX();
final int maxX = minX + this.uiViewport.getScreenWidth();
final int minY = this.uiViewport.getScreenY();
final int maxY = minY + this.uiViewport.getScreenHeight();
final boolean left = mouseX <= (minX + 3);
final boolean right = mouseX >= (maxX - 3);
final boolean up = mouseY <= (minY + 3);
final boolean down = mouseY >= (maxY - 3);
this.cameraManager.applyVelocity(deltaTime, up, down, left, right);
mouseX = Math.max(minX, Math.min(maxX, mouseX));
mouseY = Math.max(minY, Math.min(maxY, mouseY));
Gdx.input.setCursorPosition(mouseX, mouseY);
screenCoordsVector.set(mouseX, mouseY);
this.uiViewport.unproject(screenCoordsVector);
this.cursorFrame.setFramePointX(FramePoint.LEFT, screenCoordsVector.x);
this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y);
if (down) {
if (left) {
this.cursorFrame.setSequence("Scroll Down Left");
}
else if (right) {
this.cursorFrame.setSequence("Scroll Down Right");
}
else {
this.cursorFrame.setSequence("Scroll Down");
}
}
else if (up) {
if (left) {
this.cursorFrame.setSequence("Scroll Up Left");
}
else if (right) {
this.cursorFrame.setSequence("Scroll Up Right");
}
else {
this.cursorFrame.setSequence("Scroll Up");
}
}
else if (left) {
this.cursorFrame.setSequence("Scroll Left");
}
else if (right) {
this.cursorFrame.setSequence("Scroll Right");
}
else {
this.cursorFrame.setSequence("Normal");
}
final float groundHeight = Math.max(
this.war3MapViewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y),
this.war3MapViewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y));
this.cameraManager.updateTargetZ(groundHeight);
this.cameraManager.updateCamera();
}
public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
this.rootFrame.render(batch, font20, glyphLayout);
if (this.selectedUnit != null) {
font20.setColor(Color.WHITE);
final COrder currentOrder = this.selectedUnit.getSimulationUnit().getCurrentOrder();
for (final CommandCardIcon commandCardIcon : this.selectedUnit.getCommandCardIcons()) {
batch.draw(commandCardIcon.getTexture(), 1235 + (86.8f * commandCardIcon.getX()),
190 - (88 * commandCardIcon.getY()), 78f, 78f);
if (((currentOrder != null) && (currentOrder.getOrderId() == commandCardIcon.getOrderId()))
|| ((currentOrder == null) && (commandCardIcon.getOrderId() == CAbilityStop.ORDER_ID))) {
final int blendDstFunc = batch.getBlendDstFunc();
final int blendSrcFunc = batch.getBlendSrcFunc();
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
batch.draw(this.activeButtonTexture, 1235 + (86.8f * commandCardIcon.getX()),
190 - (88 * commandCardIcon.getY()), 78f, 78f);
batch.setBlendFunction(blendSrcFunc, blendDstFunc);
}
}
}
this.meleeUIMinimap.render(batch, this.war3MapViewer.units);
this.timeIndicator.setFrameByRatio(this.war3MapViewer.simulation.getGameTimeOfDay()
/ this.war3MapViewer.simulation.getGameplayConstants().getGameDayHours());
}
@ -238,12 +385,12 @@ public class MeleeUI implements CUnitStateListener {
private static final class Portrait {
private MdxComplexInstance modelInstance;
private final WarsmashGdxMapGame.PortraitCameraManager portraitCameraManager;
private final PortraitCameraManager portraitCameraManager;
private final Scene portraitScene;
public Portrait(final War3MapViewer war3MapViewer) {
this.portraitScene = war3MapViewer.addSimpleScene();
this.portraitCameraManager = new WarsmashGdxMapGame.PortraitCameraManager();
public Portrait(final War3MapViewer war3MapViewer, final Scene portraitScene) {
this.portraitScene = portraitScene;
this.portraitCameraManager = new PortraitCameraManager();
this.portraitCameraManager.setupCamera(this.portraitScene);
this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48));
}
@ -294,6 +441,11 @@ public class MeleeUI implements CUnitStateListener {
}
this.portrait.setSelectedUnit(unit);
this.selectedUnit = unit;
for (int j = 0; j < COMMAND_CARD_HEIGHT; j++) {
for (int i = 0; i < COMMAND_CARD_WIDTH; i++) {
this.commandCard[j][i].setCommandButton(null);
}
}
if (unit == null) {
this.simpleNameValue.setText("");
this.unitLifeText.setText("");
@ -340,9 +492,9 @@ public class MeleeUI implements CUnitStateListener {
this.simpleBuildingActionLabel.setText("");
final boolean anyAttacks = unit.getSimulationUnit().getUnitType().getAttacks().size() > 0;
final UIFrame localArmorIcon;
final TextureFrame localArmorIconBackdrop;
final StringFrame localArmorInfoPanelIconValue;
final UIFrame localArmorIcon = this.armorIcon;
final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop;
final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue;
if (anyAttacks) {
final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0);
this.attack1Icon.setVisible(attackOne.isShowUI());
@ -358,17 +510,18 @@ public class MeleeUI implements CUnitStateListener {
this.attack2Icon.setVisible(false);
}
localArmorIcon = this.armorIcon;
localArmorIconBackdrop = this.armorIconBackdrop;
localArmorInfoPanelIconValue = this.armorInfoPanelIconValue;
this.armorIcon.addSetPoint(
new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f)));
this.armorIcon.positionBounds(this.uiViewport);
}
else {
this.armorIcon.setVisible(false);
this.attack1Icon.setVisible(false);
this.attack2Icon.setVisible(false);
localArmorIcon = this.attack1Icon;
localArmorIconBackdrop = this.attack1IconBackdrop;
localArmorInfoPanelIconValue = this.attack1InfoPanelIconValue;
this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail,
FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f)));
this.armorIcon.positionBounds(this.uiViewport);
}
localArmorIcon.setVisible(true);
@ -380,10 +533,21 @@ public class MeleeUI implements CUnitStateListener {
}
localArmorIconBackdrop.setTexture(defenseTexture);
localArmorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense()));
unit.populateCommandCard(this, this.war3MapViewer.getAbilityDataUI());
}
}
public void resize() {
@Override
public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon,
final int orderId) {
final int x = Math.max(0, Math.min(COMMAND_CARD_WIDTH - 1, buttonPositionX));
final int y = Math.max(0, Math.min(COMMAND_CARD_HEIGHT - 1, buttonPositionY));
this.commandCard[y][x].setCommandButtonData(icon, orderId);
}
public void resize(final Rectangle viewport) {
this.cameraManager.resize(viewport);
positionPortrait();
}
@ -472,4 +636,30 @@ public class MeleeUI implements CUnitStateListener {
public RenderUnit getSelectedUnit() {
return this.selectedUnit;
}
public boolean keyDown(final int keycode) {
return this.cameraManager.keyDown(keycode);
}
public boolean keyUp(final int keycode) {
return this.cameraManager.keyUp(keycode);
}
public void scrolled(final int amount) {
this.cameraManager.scrolled(amount);
}
public boolean touchDown(final float screenX, final float screenY, final int button) {
if (this.meleeUIMinimap.containsMouse(screenX, screenY)) {
final Vector2 worldPoint = this.meleeUIMinimap.getWorldPointFromScreen(screenX, screenY);
this.cameraManager.target.x = worldPoint.x;
this.cameraManager.target.y = worldPoint.y;
return true;
}
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
this.rootFrame.touchDown(GameUI.unconvertX(this.uiViewport, screenCoordsVector.x),
GameUI.unconvertY(this.uiViewport, screenCoordsVector.y), button);
return false;
}
}

View File

@ -0,0 +1,62 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
public class MeleeUIMinimap {
private final Rectangle minimap;
private final Rectangle minimapFilledArea;
private final Texture minimapTexture;
private final Rectangle playableMapArea;
private final Texture[] teamColors;
public MeleeUIMinimap(final Rectangle displayArea, final Rectangle playableMapArea, final Texture minimapTexture,
final Texture[] teamColors) {
this.playableMapArea = playableMapArea;
this.minimapTexture = minimapTexture;
this.teamColors = teamColors;
this.minimap = displayArea;
final float worldWidth = playableMapArea.getWidth();
final float worldHeight = playableMapArea.getHeight();
final float worldSize = Math.max(worldWidth, worldHeight);
final float minimapFilledWidth = (worldWidth / worldSize) * this.minimap.width;
final float minimapFilledHeight = (worldHeight / worldSize) * this.minimap.height;
this.minimapFilledArea = new Rectangle(this.minimap.x + ((this.minimap.width - minimapFilledWidth) / 2),
this.minimap.y + ((this.minimap.height - minimapFilledHeight) / 2), minimapFilledWidth,
minimapFilledHeight);
}
public void render(final SpriteBatch batch, final Iterable<RenderUnit> units) {
batch.draw(this.minimapTexture, this.minimap.x, this.minimap.y, this.minimap.width, this.minimap.height);
for (final RenderUnit unit : units) {
final Texture minimapIcon = this.teamColors[unit.playerIndex];
batch.draw(minimapIcon,
this.minimapFilledArea.x
+ (((unit.location[0] - this.playableMapArea.getX()) / (this.playableMapArea.getWidth()))
* this.minimapFilledArea.width),
this.minimapFilledArea.y
+ (((unit.location[1] - this.playableMapArea.getY()) / (this.playableMapArea.getHeight()))
* this.minimapFilledArea.height),
4, 4);
}
}
public Vector2 getWorldPointFromScreen(final float screenX, final float screenY) {
final Rectangle filledArea = this.minimapFilledArea;
final float clickX = (screenX - filledArea.x) / filledArea.width;
final float clickY = (screenY - filledArea.y) / filledArea.height;
final float worldX = (clickX * this.playableMapArea.width) + this.playableMapArea.x;
final float worldY = (clickY * this.playableMapArea.height) + this.playableMapArea.y;
return new Vector2(worldX, worldY);
}
public boolean containsMouse(final float x, final float y) {
return this.minimapFilledArea.contains(x, y);
}
}