This commit is contained in:
Retera 2021-12-09 17:43:18 -05:00
commit 01f22540a2
41 changed files with 3916 additions and 1795 deletions

View File

@ -0,0 +1,868 @@
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 com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.util.DataSourceFileHandle;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.StringBundle;
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.SolvedPath;
import com.etheller.warsmash.viewer5.TextureMapper;
import com.etheller.warsmash.viewer5.handlers.ModelHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.Sequence;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.TestUI;
public class WarsmashGdxFDFTestRenderScreen implements InputProcessor, Screen, SingleModelScreen {
private static final boolean ENABLE_AUDIO = true;
private DataSource codebase;
private MdxViewer viewer;
private MdxModel model;
private CameraManager cameraManager;
private final Rectangle tempRect = new Rectangle();
// libGDX stuff
private OrthographicCamera uiCamera;
private SpriteBatch batch;
private Viewport uiViewport;
private GlyphLayout glyphLayout;
private final DataTable warsmashIni;
private Scene uiScene;
private Texture solidGreenTexture;
private TestUI menuUI;
private final WarsmashGdxMultiScreenGame game;
private Music currentMusic;
private boolean hasPlayedStandHack = false;
private boolean loaded = false;
private final String finalFileToLoad;
public WarsmashGdxFDFTestRenderScreen(final DataTable warsmashIni, final WarsmashGdxMultiScreenGame game,
final String finalFileToLoad) {
this.warsmashIni = warsmashIni;
this.game = game;
this.finalFileToLoad = finalFileToLoad;
}
@Override
public void show() {
if (!this.loaded) {
this.loaded = true;
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
//
Gdx.gl30.glGenVertexArrays(1, temp);
WarsmashGdxGame.VAO = temp.get(0);
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
final String renderer = Gdx.gl.glGetString(GL20.GL_RENDERER);
System.err.println("Renderer: " + renderer);
this.codebase = WarsmashGdxMapScreen.parseDataSources(this.warsmashIni);
this.viewer = new MdxViewer(this.codebase, this.game, Vector3.Zero);
this.viewer.addHandler(new MdxHandler());
this.viewer.enableAudio();
this.scene = this.viewer.addSimpleScene();
this.scene.enableAudio();
this.uiScene = this.viewer.addSimpleScene();
this.uiScene.alpha = true;
if (ENABLE_AUDIO) {
this.uiScene.enableAudio();
}
final int width = Gdx.graphics.getWidth();
final int height = Gdx.graphics.getHeight();
this.glyphLayout = new GlyphLayout();
// Constructs a new OrthographicCamera, using the given viewport width and
// height
// Height is multiplied by aspect ratio.
this.uiCamera = new OrthographicCamera();
int aspect3By4Width;
int aspect3By4Height;
if (width < ((height * 4) / 3)) {
aspect3By4Width = width;
aspect3By4Height = (width * 3) / 4;
}
else {
aspect3By4Width = (height * 4) / 3;
aspect3By4Height = height;
}
this.uiViewport = new FitViewport(aspect3By4Width, aspect3By4Height, this.uiCamera);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.getMinWorldWidth() / 2, this.getMinWorldHeight() / 2, 0);
this.uiCamera.update();
this.batch = new SpriteBatch();
this.solidGreenTexture = ImageUtils.getAnyExtensionTexture(this.viewer.dataSource,
"ReplaceableTextures\\TeamColor\\TeamColor06.blp");
this.cameraManager = new CameraManager();
this.cameraManager.setupCamera(this.scene);
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1);
final DataTable musicSLK = new DataTable(StringBundle.EMPTY);
final String musicSLKPath = "UI\\SoundInfo\\Music.SLK";
if (this.viewer.dataSource.has(musicSLKPath)) {
try (InputStream miscDataTxtStream = this.viewer.dataSource.getResourceAsStream(musicSLKPath)) {
musicSLK.readSLK(miscDataTxtStream);
}
catch (final IOException e) {
e.printStackTrace();
}
}
this.menuUI = new TestUI(this.viewer.dataSource, this.uiViewport, this.uiScene, this.viewer, this.game,
this, this.warsmashIni, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
// WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
if (WarsmashConstants.ENABLE_MUSIC) {
final String musicField = rootFrame
.getSkinField("GlueMusic_V" + WarsmashConstants.GAME_VERSION);
final String[] musics = musicField.split(";");
String musicPath = musics[(int) (Math.random() * musics.length)];
if (musicSLK.get(musicPath) != null) {
musicPath = musicSLK.get(musicPath).getField("FileNames");
}
final String[] moreSplitMusics = musicPath.split(",");
final String finalMusicPath = moreSplitMusics[(int) (Math.random()
* moreSplitMusics.length)];
final Music music = Gdx.audio.newMusic(new DataSourceFileHandle(
WarsmashGdxFDFTestRenderScreen.this.viewer.dataSource, finalMusicPath));
// music.setVolume(0.2f);
music.setLooping(true);
music.play();
WarsmashGdxFDFTestRenderScreen.this.currentMusic = music;
}
WarsmashGdxFDFTestRenderScreen.this
.singleModelScene(WarsmashGdxFDFTestRenderScreen.this.scene,
War3MapViewer.mdx(rootFrame.getSkinField(
"GlueSpriteLayerBackground_V" + WarsmashConstants.GAME_VERSION)),
"Stand");
WarsmashGdxFDFTestRenderScreen.this.modelCamera = WarsmashGdxFDFTestRenderScreen.this.mainModel.cameras
.get(0);
}
}, this.finalFileToLoad);
final ModelInstance libgdxContentInstance = new LibGDXContentLayerModel(null, this.viewer, "",
PathSolver.DEFAULT, "").addInstance();
libgdxContentInstance.setLocation(0f, 0f, -0.5f);
libgdxContentInstance.setScene(this.uiScene);
this.menuUI.main();
this.updateUIScene();
this.resize(width, height);
}
Gdx.input.setInputProcessor(this);
if (this.currentMusic != null) {
this.currentMusic.play();
}
}
private float getMinWorldWidth() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldWidth();
}
return this.uiViewport.getWorldWidth();
}
private float getMinWorldHeight() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldHeight();
}
return this.uiViewport.getWorldHeight();
}
private void updateUIScene() {
this.tempRect.x = this.uiViewport.getScreenX();
this.tempRect.y = this.uiViewport.getScreenY();
this.tempRect.width = this.uiViewport.getScreenWidth();
this.tempRect.height = this.uiViewport.getScreenHeight();
this.uiScene.camera.viewport(this.tempRect);
final float worldWidth = this.uiViewport.getWorldWidth();
final float worldHeight = this.uiViewport.getWorldHeight();
final float xScale = worldWidth / this.getMinWorldWidth();
final float yScale = worldHeight / this.getMinWorldHeight();
final float uiSceneWidth = 0.8f * xScale;
final float uiSceneHeight = 0.6f * yScale;
final float uiSceneX = (0.8f - uiSceneWidth) / 2;
final float uiSceneY = (0.6f - uiSceneHeight) / 2;
this.uiScene.camera.ortho(uiSceneX, uiSceneWidth + uiSceneX, uiSceneY, uiSceneHeight + uiSceneY, -1024f, 1024);
}
private void makeDruidSquare(final Scene scene) {
final MdxModel model2 = (MdxModel) this.viewer.load("units\\nightelf\\druidoftheclaw\\druidoftheclaw.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
this.makePerfectSquare(scene, model2, 15);
}
private void singleAcolyteScene(final Scene scene) {
final MdxModel model2 = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.setScene(scene);
int animIndex = 0;
for (final Sequence s : model2.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = model2.getSequences().indexOf(s);
}
}
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void singleModelScene(final Scene scene, final String path, final String animName) {
final MdxModel model2 = (MdxModel) this.viewer.load(path, new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.setScene(scene);
int animIndex = 0;
for (final Sequence s : model2.getSequences()) {
if (s.getName().toLowerCase().startsWith(animName)) {
animIndex = model2.getSequences().indexOf(s);
break;
}
}
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
this.mainInstance = instance3;
this.mainModel = model2;
}
@Override
public void setModel(final String path) {
if (this.mainInstance != null) {
this.mainInstance.detach();
}
if (path == null) {
this.modelCamera = null;
this.mainInstance = null;
this.mainModel = null;
}
else {
this.singleModelScene(this.scene, War3MapViewer.mdx(path), "birth");
WarsmashGdxFDFTestRenderScreen.this.modelCamera = WarsmashGdxFDFTestRenderScreen.this.mainModel.cameras
.get(0);
// this hack is because we only have the queued animation system in RenderWidget
// which is stupid and back and needs to get moved to the model instance
// itself... our model instance class is a
// hacky replica of a model viewer tool with a bunch of irrelevant loop type
// settings instead of what it should be
this.hasPlayedStandHack = false;
}
}
private void acolytesHarvestingScene(final Scene scene) {
final MdxModel acolyteModel = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxModel mineEffectModel = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\undeadmine\\undeadminecircle.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
for (int i = 0; i < 5; i++) {
final MdxComplexInstance acolyteInstance = (MdxComplexInstance) acolyteModel.addInstance(0);
acolyteInstance.setScene(scene);
int animIndex = i % acolyteModel.getSequences().size();
for (final Sequence s : acolyteModel.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = acolyteModel.getSequences().indexOf(s);
}
}
acolyteInstance.setSequence(animIndex);
acolyteInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final double angle = ((Math.PI * 2) / 5) * i;
acolyteInstance.localLocation.x = (float) Math.cos(angle) * 256;
acolyteInstance.localLocation.y = (float) Math.sin(angle) * 256;
acolyteInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle + Math.PI));
final MdxComplexInstance effectInstance = (MdxComplexInstance) mineEffectModel.addInstance(0);
effectInstance.setScene(scene);
effectInstance.setSequence(1);
effectInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
effectInstance.localLocation.x = (float) Math.cos(angle) * 256;
effectInstance.localLocation.y = (float) Math.sin(angle) * 256;
effectInstance.localRotation.setFromAxisRad(0, 0, 1, (float) angle);
}
final MdxModel mineModel = (MdxModel) this.viewer.load("buildings\\undead\\hauntedmine\\hauntedmine.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance = (MdxComplexInstance) mineModel.addInstance(0);
mineInstance.setScene(scene);
mineInstance.setSequence(2);
mineInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void acolytesHarvestingSceneJoke2(final Scene scene) {
final MdxModel acolyteModel = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxModel mineEffectModel = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\undeadmine\\undeadminecircle.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
for (int i = 0; i < 5; i++) {
final MdxComplexInstance acolyteInstance = (MdxComplexInstance) acolyteModel.addInstance(0);
acolyteInstance.setScene(scene);
int animIndex = i % acolyteModel.getSequences().size();
for (final Sequence s : acolyteModel.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand work")) {
animIndex = acolyteModel.getSequences().indexOf(s);
}
}
acolyteInstance.setSequence(animIndex);
acolyteInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final double angle = ((Math.PI * 2) / 5) * i;
acolyteInstance.localLocation.x = (float) Math.cos(angle) * 256;
acolyteInstance.localLocation.y = (float) Math.sin(angle) * 256;
acolyteInstance.localRotation.setFromAxisRad(0, 0, 1, (float) (angle + Math.PI));
final MdxComplexInstance effectInstance = (MdxComplexInstance) mineEffectModel.addInstance(0);
effectInstance.setScene(scene);
effectInstance.setSequence(1);
effectInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
effectInstance.localLocation.x = (float) Math.cos(angle) * 256;
effectInstance.localLocation.y = (float) Math.sin(angle) * 256;
effectInstance.localRotation.setFromAxisRad(0, 0, 1, (float) angle);
}
final MdxModel mineModel = (MdxModel) this.viewer.load("units\\orc\\spiritwolf\\spiritwolf.mdx",
new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance = (MdxComplexInstance) mineModel.addInstance(0);
mineInstance.setScene(scene);
mineInstance.setSequence(0);
mineInstance.localScale.x = 2;
mineInstance.localScale.y = 2;
mineInstance.localScale.z = 2;
mineInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
final MdxModel mineModel2 = (MdxModel) this.viewer
.load("abilities\\spells\\undead\\unsummon\\unsummontarget.mdx", new PathSolver() {
@Override
public SolvedPath solve(final String src, final Object solverParams) {
return new SolvedPath(src, src.substring(src.lastIndexOf('.')), true);
}
}, null);
final MdxComplexInstance mineInstance2 = (MdxComplexInstance) mineModel2.addInstance(0);
mineInstance2.setScene(scene);
mineInstance2.setSequence(0);
mineInstance2.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
private void makeFourHundred(final Scene scene, final MdxModel model2) {
for (int i = 0; i < 400; i++) {
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.localLocation.x = ((i % 20) - 10) * 128;
instance3.localLocation.y = ((i / 20) - 10) * 128;
instance3.setScene(scene);
final int animIndex = i % model2.getSequences().size();
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
}
private void makePerfectSquare(final Scene scene, final MdxModel model2, final int n) {
final int n2 = n * n;
for (int i = 0; i < n2; i++) {
final MdxComplexInstance instance3 = (MdxComplexInstance) model2.addInstance(0);
instance3.localLocation.x = ((i % n) - (n / 2)) * 128;
instance3.localLocation.y = ((i / n) - (n / 2)) * 128;
instance3.setScene(scene);
final int animIndex = i % model2.getSequences().size();
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
}
}
public static void bindDefaultVertexArray() {
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
}
private final int frame = 0;
private MdxComplexInstance mainInstance;
private MdxModel mainModel;
private com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
private final boolean firstFrame = true;
private Scene scene;
@Override
public void render(final float delta) {
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final float deltaTime = Gdx.graphics.getDeltaTime();
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
this.cameraManager.updateCamera();
this.menuUI.update(deltaTime);
if ((this.mainInstance != null) && this.mainInstance.sequenceEnded
&& (((this.mainModel.getSequences().get(this.mainInstance.sequence).getFlags() & 0x1) == 0)
|| !this.hasPlayedStandHack)) {
SequenceUtils.randomStandSequence(this.mainInstance);
this.hasPlayedStandHack = true;
}
this.viewer.updateAndRender();
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);
}
@Override
public void dispose() {
this.menuUI.dispose();
}
@Override
public void resize(final int width, final int height) {
this.tempRect.width = width;
this.tempRect.height = height;
final float fourThirdsHeight = (this.tempRect.height * 4) / 3;
if (fourThirdsHeight < this.tempRect.width) {
final float dx = this.tempRect.width - fourThirdsHeight;
this.tempRect.width = fourThirdsHeight;
this.tempRect.x = dx / 2;
}
else {
final float threeFourthsWidth = (this.tempRect.width * 3) / 4;
if (threeFourthsWidth < this.tempRect.height) {
final float dy = this.tempRect.height - threeFourthsWidth;
this.tempRect.height = threeFourthsWidth;
this.tempRect.y = dy;
}
}
this.cameraManager.camera.viewport(this.tempRect);
// super.resize(width, height);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.getMinWorldWidth() / 2, this.getMinWorldHeight() / 2, 0);
this.menuUI.resize();
this.updateUIScene();
}
class CameraManager {
private CanvasProvider canvas;
private Camera camera;
private float moveSpeed;
private float rotationSpeed;
private float zoomFactor;
private float horizontalAngle;
private float verticalAngle;
private float distance;
private Vector3 position;
private Vector3 target;
private Vector3 worldUp;
private Vector3 vecHeap;
private Vector3 vecHeap2;
private Quaternion quatHeap;
private Quaternion quatHeap2;
// 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.
private void setupCamera(final Scene scene) {
this.canvas = scene.viewer.canvas;
this.camera = scene.camera;
this.moveSpeed = 2;
this.rotationSpeed = (float) (Math.PI / 180);
this.zoomFactor = 0.1f;
this.horizontalAngle = (float) (Math.PI / 2);
this.verticalAngle = (float) (Math.PI / 4);
this.distance = 500;
this.position = new Vector3();
this.target = new Vector3(0, 0, 50);
this.worldUp = new Vector3(0, 0, 1);
this.vecHeap = new Vector3();
this.vecHeap2 = new Vector3();
this.quatHeap = new Quaternion();
this.quatHeap2 = new Quaternion();
this.updateCamera();
// cameraUpdate();
}
private void updateCamera() {
// Limit the vertical angle so it doesn't flip.
// Since the camera uses a quaternion, flips don't matter to it, but this feels
// better.
this.verticalAngle = (float) Math.min(Math.max(0.01, this.verticalAngle), Math.PI - 0.01);
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 (WarsmashGdxFDFTestRenderScreen.this.modelCamera != null) {
WarsmashGdxFDFTestRenderScreen.this.modelCamera.getPositionTranslation(
WarsmashGdxFDFTestRenderScreen.this.cameraPositionTemp,
WarsmashGdxFDFTestRenderScreen.this.mainInstance.sequence,
WarsmashGdxFDFTestRenderScreen.this.mainInstance.frame,
WarsmashGdxFDFTestRenderScreen.this.mainInstance.counter);
WarsmashGdxFDFTestRenderScreen.this.modelCamera.getTargetTranslation(
WarsmashGdxFDFTestRenderScreen.this.cameraTargetTemp,
WarsmashGdxFDFTestRenderScreen.this.mainInstance.sequence,
WarsmashGdxFDFTestRenderScreen.this.mainInstance.frame,
WarsmashGdxFDFTestRenderScreen.this.mainInstance.counter);
this.position.set(WarsmashGdxFDFTestRenderScreen.this.modelCamera.position);
this.target.set(WarsmashGdxFDFTestRenderScreen.this.modelCamera.targetPosition);
// this.vecHeap2.set(this.target);
// this.vecHeap2.sub(this.position);
// this.vecHeap.set(this.vecHeap2);
// this.vecHeap.crs(this.worldUp);
// this.vecHeap.crs(this.vecHeap2);
// this.vecHeap.nor();
// this.vecHeap.scl(this.camera.rect.height / 2f);
// this.position.add(this.vecHeap);
this.position.add(WarsmashGdxFDFTestRenderScreen.this.cameraPositionTemp[0],
WarsmashGdxFDFTestRenderScreen.this.cameraPositionTemp[1],
WarsmashGdxFDFTestRenderScreen.this.cameraPositionTemp[2]);
this.target.add(WarsmashGdxFDFTestRenderScreen.this.cameraTargetTemp[0],
WarsmashGdxFDFTestRenderScreen.this.cameraTargetTemp[1],
WarsmashGdxFDFTestRenderScreen.this.cameraTargetTemp[2]);
this.camera.perspective(WarsmashGdxFDFTestRenderScreen.this.modelCamera.fieldOfView * 0.6f,
this.camera.rect.width / this.camera.rect.height,
WarsmashGdxFDFTestRenderScreen.this.modelCamera.nearClippingPlane,
WarsmashGdxFDFTestRenderScreen.this.modelCamera.farClippingPlane);
}
else {
this.camera.perspective(70, this.camera.getAspect(), 100, 5000);
}
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
// private void cameraUpdate() {
//
// }
}
public DataSource getCodebase() {
return this.codebase;
}
@Override
public boolean keyDown(final int keycode) {
return this.menuUI.keyDown(keycode);
}
@Override
public boolean keyUp(final int keycode) {
return this.menuUI.keyUp(keycode);
}
@Override
public boolean keyTyped(final char character) {
return this.menuUI.keyTyped(character);
}
@Override
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.touchDown(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchUp(final int screenX, final int screenY, final int pointer, final int button) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.touchUp(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchDragged(final int screenX, final int screenY, final int pointer) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.touchDragged(screenX, screenY, worldScreenY, pointer)) {
return false;
}
return false;
}
@Override
public boolean mouseMoved(final int screenX, final int screenY) {
final float worldScreenY = this.game.getHeight() - screenY;
if (this.menuUI.mouseMoved(screenX, screenY, worldScreenY)) {
return false;
}
return false;
}
@Override
public boolean scrolled(final int amount) {
// TODO Auto-generated method stub
return false;
}
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();
this.menuUI.render(this.batch, this.glyphLayout);
this.batch.end();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
}
private class LibGDXContentLayerModelInstance extends ModelInstance {
public LibGDXContentLayerModelInstance(final Model model) {
super(model);
}
@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() {
WarsmashGdxFDFTestRenderScreen.this.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) {
}
}
@Override
public void hide() {
if (this.currentMusic != null) {
this.currentMusic.stop();
}
this.menuUI.hide();
}
@Override
public void pause() {
}
@Override
public void resume() {
}
}

View File

@ -160,6 +160,11 @@ public class CascDataSource implements DataSource {
return internalGetFile(filepath);
}
@Override
public File getDirectory(String filepath) throws IOException {
return null;
}
private File internalGetFile(final String tempFilepath) {
try {
if (this.rootFileSystem.isFile(tempFilepath) && this.rootFileSystem.isFileAvailable(tempFilepath)) {

View File

@ -47,6 +47,24 @@ public class CompoundDataSource implements DataSource {
return null;
}
@Override
public File getDirectory(String filepath) throws IOException {
try {
for (int i = this.mpqList.size() - 1; i >= 0; i--) {
final DataSource mpq = this.mpqList.get(i);
final File tempProduct = mpq.getDirectory(filepath);
if (tempProduct != null) {
return tempProduct;
}
}
}
catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
public ByteBuffer read(final String path) throws IOException {
try {

View File

@ -28,6 +28,15 @@ public interface DataSource {
*/
File getFile(String filepath) throws IOException;
/**
* Returns a directory from a FolderDataSource, otherwise returns null
*
* @param filepath
* @return
* @throws IOException
*/
File getDirectory(String filepath) throws IOException;
ByteBuffer read(String path) throws IOException;
/**

View File

@ -52,6 +52,16 @@ public class FolderDataSource implements DataSource {
return new File(this.folderPath.toString() + File.separatorChar + filepath);
}
@Override
public File getDirectory(String filepath) throws IOException {
filepath = fixFilepath(filepath);
File file = new File(this.folderPath.toString() + File.separatorChar + filepath);
if(!file.exists() || !file.isDirectory()) {
return null;
}
return file;
}
@Override
public ByteBuffer read(String path) throws IOException {
path = fixFilepath(path);

View File

@ -112,6 +112,11 @@ public class MpqDataSource implements DataSource {
return tempProduct;
}
@Override
public File getDirectory(String filepath) throws IOException {
return null;
}
@Override
public boolean has(final String filepath) {
try {

View File

@ -22,6 +22,11 @@ public class SubdirDataSource implements DataSource {
return this.dataSource.getFile(this.subdir + filepath);
}
@Override
public File getDirectory(String filepath) throws IOException {
return this.dataSource.getDirectory(this.subdir + filepath);
}
@Override
public ByteBuffer read(final String path) throws IOException {
return this.dataSource.read(this.subdir + path);

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@ public class GlueButtonFrame extends AbstractRenderableFrame implements Clickabl
private UIFrame activeChild;
private Runnable onClick;
private ButtonListener buttonListener = ButtonListener.DO_NOTHING;
public GlueButtonFrame(final String name, final UIFrame parent) {
super(name, parent);
@ -66,6 +67,10 @@ public class GlueButtonFrame extends AbstractRenderableFrame implements Clickabl
this.onClick = onClick;
}
public void setButtonListener(ButtonListener buttonListener) {
this.buttonListener = buttonListener;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
if (this.controlBackdrop != null) {
@ -101,14 +106,20 @@ public class GlueButtonFrame extends AbstractRenderableFrame implements Clickabl
@Override
public void mouseDown(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlPushedBackdrop;
if(this.controlPushedBackdrop != null) {
this.activeChild = this.controlPushedBackdrop;
}
buttonListener.mouseDown(gameUI, uiViewport);
}
}
@Override
public void mouseUp(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlBackdrop;
if(this.controlBackdrop != null) {
this.activeChild = this.controlBackdrop;
}
buttonListener.mouseUp(gameUI, uiViewport);
}
}
@ -139,6 +150,11 @@ public class GlueButtonFrame extends AbstractRenderableFrame implements Clickabl
}
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
buttonListener.mouseDragged(rootFrame, uiViewport, x,y);
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
@ -163,4 +179,21 @@ public class GlueButtonFrame extends AbstractRenderableFrame implements Clickabl
return super.getFrameChildUnderMouse(screenX, screenY);
}
public interface ButtonListener {
void mouseDown(GameUI gameUI, Viewport uiViewport);
void mouseUp(GameUI gameUI, Viewport uiViewport);
void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y);
ButtonListener DO_NOTHING = new ButtonListener() {
@Override
public void mouseDown(GameUI gameUI, Viewport uiViewport) {}
@Override
public void mouseUp(GameUI gameUI, Viewport uiViewport) {}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {}
};
}
}

View File

@ -15,188 +15,281 @@ import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
public class ListBoxFrame extends ControlFrame {
// TODO where are these colors in the UI definition files?
private static final Color SELECT_COLOR = Color.BLUE;
private static final Color MOUSE_OVER_HIGHLIGHT_COLOR = new Color(0.3f, 0.3f, 1.0f, 0.25f);
public class ListBoxFrame extends ControlFrame implements ScrollBarFrame.ScrollBarChangeListener {
// TODO where are these colors in the UI definition files?
private static final Color SELECT_COLOR = Color.BLUE;
private static final Color MOUSE_OVER_HIGHLIGHT_COLOR = new Color(0.3f, 0.3f, 1.0f, 0.25f);
private final List<String> listItems = new ArrayList<>();
private final List<SingleStringFrame> stringFrames = new ArrayList<>();
private BitmapFont frameFont;
private float listBoxBorder;
private int selectedIndex = -1;
private int mouseOverIndex = -1;
private final List<String> listItems = new ArrayList<>();
private final List<SingleStringFrame> stringFrames = new ArrayList<>();
private BitmapFont frameFont;
private float listBoxBorder;
private int selectedIndex = -1;
private int mouseOverIndex = -1;
private final TextureFrame selectionFrame;
private final TextureFrame mouseHighlightFrame;
private GameUI gameUI;
private Viewport viewport;
private Runnable onSelect;
private final TextureFrame selectionFrame;
private final TextureFrame mouseHighlightFrame;
private GameUI gameUI;
private Viewport viewport;
private Runnable onSelect;
private ScrollBarFrame scrollBarFrame;
public ListBoxFrame(final String name, final UIFrame parent, final Viewport viewport) {
super(name, parent);
this.listBoxBorder = GameUI.convertX(viewport, 0.01f);
this.selectionFrame = new TextureFrame(null, this, false, null);
this.mouseHighlightFrame = new TextureFrame(null, this, false, null);
final Pixmap pixmap = new Pixmap(1, 1, Format.RGBA8888);
pixmap.setColor(SELECT_COLOR);
pixmap.fill();
this.selectionFrame.setTexture(new Texture(pixmap));
final Pixmap mousePixmap = new Pixmap(1, 1, Format.RGBA8888);
mousePixmap.setColor(MOUSE_OVER_HIGHLIGHT_COLOR);
mousePixmap.fill();
this.mouseHighlightFrame.setTexture(new Texture(mousePixmap));
}
public ListBoxFrame(final String name, final UIFrame parent, final Viewport viewport) {
super(name, parent);
this.listBoxBorder = GameUI.convertX(viewport, 0.01f);
this.selectionFrame = new TextureFrame(null, this, false, null);
this.mouseHighlightFrame = new TextureFrame(null, this, false, null);
final Pixmap pixmap = new Pixmap(1, 1, Format.RGBA8888);
pixmap.setColor(SELECT_COLOR);
pixmap.fill();
this.selectionFrame.setTexture(new Texture(pixmap));
final Pixmap mousePixmap = new Pixmap(1, 1, Format.RGBA8888);
mousePixmap.setColor(MOUSE_OVER_HIGHLIGHT_COLOR);
mousePixmap.fill();
this.mouseHighlightFrame.setTexture(new Texture(mousePixmap));
}
public void setListBoxBorder(final float listBoxBorder) {
this.listBoxBorder = listBoxBorder;
}
public void setScrollBarFrame(ScrollBarFrame scrollBarFrame) {
this.scrollBarFrame = scrollBarFrame;
// TODO might be a better place to add these set points, but we definitely need them
scrollBarFrame.addSetPoint(new SetPoint(FramePoint.TOPRIGHT, this, FramePoint.TOPRIGHT, -listBoxBorder, -listBoxBorder));
scrollBarFrame.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, this, FramePoint.BOTTOMRIGHT, -listBoxBorder, listBoxBorder));
scrollBarFrame.setChangeListener(this);
}
public float getListBoxBorder() {
return this.listBoxBorder;
}
public ScrollBarFrame getScrollBarFrame() {
return scrollBarFrame;
}
public void setFrameFont(final BitmapFont frameFont) {
this.frameFont = frameFont;
}
public void setListBoxBorder(final float listBoxBorder) {
this.listBoxBorder = listBoxBorder;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.gameUI = gameUI;
this.viewport = viewport;
super.innerPositionBounds(gameUI, viewport);
updateUI(gameUI, viewport);
}
public float getListBoxBorder() {
return this.listBoxBorder;
}
private void positionChildren(final GameUI gameUI, final Viewport viewport) {
for (final SingleStringFrame frame : this.stringFrames) {
frame.positionBounds(gameUI, viewport);
}
this.selectionFrame.positionBounds(gameUI, viewport);
this.mouseHighlightFrame.positionBounds(gameUI, viewport);
}
public void setFrameFont(final BitmapFont frameFont) {
this.frameFont = frameFont;
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
super.internalRender(batch, baseFont, glyphLayout);
this.selectionFrame.render(batch, baseFont, glyphLayout);
this.mouseHighlightFrame.render(batch, baseFont, glyphLayout);
for (final SingleStringFrame frame : this.stringFrames) {
frame.render(batch, baseFont, glyphLayout);
}
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.gameUI = gameUI;
this.viewport = viewport;
super.innerPositionBounds(gameUI, viewport);
updateUI(gameUI, viewport);
}
public void addItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.add(item);
updateUI(gameUI, viewport);
}
private void positionChildren(final GameUI gameUI, final Viewport viewport) {
for (final SingleStringFrame frame : this.stringFrames) {
frame.positionBounds(gameUI, viewport);
}
this.selectionFrame.positionBounds(gameUI, viewport);
this.mouseHighlightFrame.positionBounds(gameUI, viewport);
if (scrollBarFrame != null) {
this.scrollBarFrame.positionBounds(gameUI, viewport);
}
}
public void setItems(final List<String> items, final GameUI gameUI, final Viewport viewport) {
this.listItems.clear();
this.listItems.addAll(items);
updateUI(gameUI, viewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
super.internalRender(batch, baseFont, glyphLayout);
this.selectionFrame.render(batch, baseFont, glyphLayout);
this.mouseHighlightFrame.render(batch, baseFont, glyphLayout);
for (final SingleStringFrame frame : this.stringFrames) {
frame.render(batch, baseFont, glyphLayout);
}
if (scrollBarFrame != null) {
scrollBarFrame.render(batch, baseFont, glyphLayout);
}
}
public void removeItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(item);
updateUI(gameUI, viewport);
}
public void addItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.add(item);
updateUI(gameUI, viewport);
}
public void removeItem(final int index, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(index);
updateUI(gameUI, viewport);
}
public void setItems(final List<String> items, final GameUI gameUI, final Viewport viewport) {
this.listItems.clear();
this.listItems.addAll(items);
updateUI(gameUI, viewport);
}
public void setSelectedIndex(final int selectedIndex) {
this.selectedIndex = selectedIndex;
}
public void removeItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(item);
updateUI(gameUI, viewport);
}
public int getSelectedIndex() {
return this.selectedIndex;
}
public void removeItem(final int index, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(index);
updateUI(gameUI, viewport);
}
private void updateUI(final GameUI gameUI, final Viewport viewport) {
this.stringFrames.clear();
SingleStringFrame prev = null;
int i = 0;
boolean foundSelected = false;
boolean foundMouseOver = false;
for (final String string : this.listItems) {
final boolean selected = (i == this.selectedIndex);
final boolean mousedOver = (i == this.mouseOverIndex);
final SingleStringFrame stringFrame = new SingleStringFrame("LISTY" + i++, this, Color.WHITE,
TextJustify.LEFT, TextJustify.MIDDLE, this.frameFont);
stringFrame.setText(string);
stringFrame.setWidth(this.renderBounds.width - (this.listBoxBorder * 2));
stringFrame.setHeight(this.frameFont.getLineHeight());
if (prev != null) {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, prev, FramePoint.BOTTOMLEFT, 0, 0));
}
else {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, this.listBoxBorder,
-this.listBoxBorder));
}
this.stringFrames.add(stringFrame);
prev = stringFrame;
if (selected) {
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundSelected = true;
}
else if (mousedOver) {
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundMouseOver = true;
}
}
this.selectionFrame.setVisible(foundSelected);
this.mouseHighlightFrame.setVisible(foundMouseOver);
positionChildren(gameUI, viewport);
}
public void setSelectedIndex(final int selectedIndex) {
this.selectedIndex = selectedIndex;
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
int index = 0;
for (final SingleStringFrame stringFrame : this.stringFrames) {
if (stringFrame.getRenderBounds().contains(screenX, screenY)) {
this.selectedIndex = index;
}
index++;
}
updateUI(this.gameUI, this.viewport);
if (this.onSelect != null) {
this.onSelect.run();
}
return this;
}
return super.touchDown(screenX, screenY, button);
}
public int getSelectedIndex() {
return this.selectedIndex;
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
int index = 0;
int mouseOverIndex = -1;
for (final SingleStringFrame stringFrame : this.stringFrames) {
if (stringFrame.getRenderBounds().contains(screenX, screenY)) {
mouseOverIndex = index;
}
index++;
}
if (this.mouseOverIndex != mouseOverIndex) {
this.mouseOverIndex = mouseOverIndex;
updateUI(this.gameUI, this.viewport);
}
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
public String getSelectedItem() {
if(selectedIndex < 0 || selectedIndex >= listItems.size()) {
return null;
}
return listItems.get(selectedIndex);
}
public void setOnSelect(final Runnable onSelect) {
this.onSelect = onSelect;
}
private void updateUI(final GameUI gameUI, final Viewport viewport) {
SingleStringFrame prev = null;
boolean foundSelected = false;
boolean foundMouseOver = false;
int numStringFrames = (int)(Math.floor( (renderBounds.height - listBoxBorder*2) / (frameFont.getLineHeight()) ));
int scrollOffset = computeScrollOffset(numStringFrames);
if(numStringFrames != stringFrames.size()) {
this.stringFrames.clear();
for(int stringFrameIndex = 0; stringFrameIndex < numStringFrames; stringFrameIndex++) {
final int index = stringFrameIndex + scrollOffset;
final boolean selected = (index == this.selectedIndex);
final boolean mousedOver = (index == this.mouseOverIndex);
final SingleStringFrame stringFrame = new SingleStringFrame("LISTY" + index, this, Color.WHITE,
TextJustify.LEFT, TextJustify.MIDDLE, this.frameFont);
if(index < listItems.size()) {
stringFrame.setText(listItems.get(index));
}
stringFrame.setWidth(this.renderBounds.width - (this.listBoxBorder * 2));
stringFrame.setHeight(this.frameFont.getLineHeight());
if (prev != null) {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, prev, FramePoint.BOTTOMLEFT, 0, 0));
} else {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, this.listBoxBorder,
-this.listBoxBorder));
}
this.stringFrames.add(stringFrame);
prev = stringFrame;
if (selected) {
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundSelected = true;
} else if (mousedOver) {
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundMouseOver = true;
}
}
} else {
for(int stringFrameIndex = 0; stringFrameIndex < numStringFrames; stringFrameIndex++) {
final int index = stringFrameIndex + scrollOffset;
final boolean selected = (index == this.selectedIndex);
final boolean mousedOver = (index == this.mouseOverIndex);
SingleStringFrame stringFrame = stringFrames.get(stringFrameIndex);
if(index < listItems.size()) {
stringFrame.setText(listItems.get(index));
}
if (selected) {
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.selectionFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundSelected = true;
} else if (mousedOver) {
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, stringFrame, FramePoint.TOPLEFT, 0, 0));
this.mouseHighlightFrame
.addSetPoint(new SetPoint(FramePoint.BOTTOMRIGHT, stringFrame, FramePoint.BOTTOMRIGHT, 0, 0));
foundMouseOver = true;
}
}
}
this.selectionFrame.setVisible(foundSelected);
this.mouseHighlightFrame.setVisible(foundMouseOver);
positionChildren(gameUI, viewport);
}
private int computeScrollOffset(int numStringFrames) {
int scrollOffset;
if(scrollBarFrame != null && listItems.size() > numStringFrames){
scrollOffset = (int)Math.ceil(((100 - scrollBarFrame.getValue()) / 100f) * (listItems.size() - numStringFrames));
} else {
scrollOffset = 0;
}
return scrollOffset;
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
if(scrollBarFrame!=null) {
UIFrame sliderFrameChildUnderMouse = scrollBarFrame.touchDown(screenX, screenY, button);
if (sliderFrameChildUnderMouse != null) {
return sliderFrameChildUnderMouse;
}
}
int index = 0;
for (final SingleStringFrame stringFrame : this.stringFrames) {
if (stringFrame.getRenderBounds().contains(screenX, screenY)) {
this.selectedIndex = index + computeScrollOffset(stringFrames.size());
}
index++;
}
updateUI(this.gameUI, this.viewport);
if (this.onSelect != null) {
this.onSelect.run();
}
return this;
}
return super.touchDown(screenX, screenY, button);
}
@Override
public UIFrame touchUp(float screenX, float screenY, int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
if (scrollBarFrame != null) {
UIFrame sliderFrameChildUnderMouse = scrollBarFrame.touchDown(screenX, screenY, button);
if (sliderFrameChildUnderMouse != null) {
return sliderFrameChildUnderMouse;
}
}
}
return super.touchUp(screenX, screenY, button);
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
if(scrollBarFrame!=null) {
UIFrame sliderFrameChildUnderMouse = scrollBarFrame.getFrameChildUnderMouse(screenX, screenY);
if (sliderFrameChildUnderMouse != null) {
return sliderFrameChildUnderMouse;
}
}
int index = 0;
int mouseOverIndex = -1;
for (final SingleStringFrame stringFrame : this.stringFrames) {
if (stringFrame.getRenderBounds().contains(screenX, screenY)) {
mouseOverIndex = index;
}
index++;
}
if (this.mouseOverIndex != mouseOverIndex) {
this.mouseOverIndex = mouseOverIndex + computeScrollOffset(stringFrames.size());
updateUI(this.gameUI, this.viewport);
}
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
public void setOnSelect(final Runnable onSelect) {
this.onSelect = onSelect;
}
@Override
public void onChange(GameUI gameUI, Viewport uiViewport, int newValue) {
updateUI(gameUI, uiViewport);
}
}

View File

@ -0,0 +1,261 @@
package com.etheller.warsmash.parsers.fdf.frames;
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.handlers.w3x.ui.command.ClickableFrame;
public class ScrollBarFrame extends AbstractRenderableFrame implements ClickableFrame {
private UIFrame controlBackdrop;
private UIFrame incButtonFrame;
private UIFrame decButtonFrame;
private UIFrame thumbButtonFrame;
private int scrollValuePercent = 50;
private ScrollBarChangeListener changeListener = ScrollBarChangeListener.DO_NOTHING;
public ScrollBarFrame(final String name, final UIFrame parent, boolean vertical) {
super(name, parent);
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
}
public void setIncButtonFrame(UIFrame incButtonFrame) {
this.incButtonFrame = incButtonFrame;
((GlueButtonFrame)incButtonFrame).setButtonListener(new GlueButtonFrame.ButtonListener() {
@Override
public void mouseDown(GameUI gameUI, Viewport uiViewport) {
}
@Override
public void mouseUp(GameUI gameUI, Viewport uiViewport) {
setValue(gameUI, uiViewport, scrollValuePercent+10);
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
}
});
}
public void setDecButtonFrame(UIFrame decButtonFrame) {
this.decButtonFrame = decButtonFrame;
((GlueButtonFrame)decButtonFrame).setButtonListener(new GlueButtonFrame.ButtonListener() {
@Override
public void mouseDown(GameUI gameUI, Viewport uiViewport) {
}
@Override
public void mouseUp(GameUI gameUI, Viewport uiViewport) {
setValue(gameUI, uiViewport, scrollValuePercent-10);
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
}
});
}
public void setThumbButtonFrame(UIFrame thumbButtonFrame) {
if (this.thumbButtonFrame instanceof GlueButtonFrame) {
((GlueButtonFrame) this.thumbButtonFrame).setButtonListener(GlueButtonFrame.ButtonListener.DO_NOTHING);
}
this.thumbButtonFrame = thumbButtonFrame;
if (thumbButtonFrame instanceof GlueButtonFrame) {
GlueButtonFrame frame = (GlueButtonFrame) thumbButtonFrame;
frame.setButtonListener(new GlueButtonFrame.ButtonListener() {
@Override
public void mouseDown(GameUI gameUI, Viewport uiViewport) {
}
@Override
public void mouseUp(GameUI gameUI, Viewport uiViewport) {
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
ScrollBarFrame.this.mouseDragged(rootFrame, uiViewport, x, y);
}
});
}
}
private float getMaxThumbButtonTravelDistance() {
return renderBounds.height - thumbButtonFrame.getAssignedHeight() - incButtonFrame.getAssignedHeight() - decButtonFrame.getAssignedHeight();
}
public void setValue(GameUI gameUI, Viewport uiViewport, int percent) {
this.scrollValuePercent = Math.min(100,Math.max(0,percent));
updateThumbButtonPoint();
changeListener.onChange(gameUI, uiViewport, this.scrollValuePercent);
positionBounds(gameUI, uiViewport);
}
public int getValue() {
return scrollValuePercent;
}
public void updateThumbButtonPoint() {
float newYValue = scrollValuePercent / 100f * getMaxThumbButtonTravelDistance();
thumbButtonFrame.addSetPoint(new SetPoint(FramePoint.BOTTOM, decButtonFrame, FramePoint.TOP, 0, newYValue));
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
if (this.controlBackdrop != null) {
this.controlBackdrop.positionBounds(gameUI, viewport);
}
if (this.incButtonFrame != null) {
this.incButtonFrame.positionBounds(gameUI, viewport);
}
if (this.decButtonFrame != null) {
this.decButtonFrame.positionBounds(gameUI, viewport);
}
updateThumbButtonPoint();
if (this.thumbButtonFrame != null) {
this.thumbButtonFrame.positionBounds(gameUI, viewport);
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
if (this.controlBackdrop != null) {
controlBackdrop.render(batch, baseFont, glyphLayout);
}
if (this.incButtonFrame != null) {
this.incButtonFrame.render(batch, baseFont, glyphLayout);
}
if (this.decButtonFrame != null) {
this.decButtonFrame.render(batch, baseFont, glyphLayout);
}
if (this.thumbButtonFrame != null) {
this.thumbButtonFrame.render(batch, baseFont, glyphLayout);
}
}
@Override
public void mouseDown(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public void mouseUp(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public void mouseEnter(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public void mouseExit(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public void onClick(final int button) {
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
float maxThumbButtonTravelDistance = getMaxThumbButtonTravelDistance();
int newScrollValuePercent = Math.min(100,Math.max(0,(int)((y - renderBounds.y - decButtonFrame.getAssignedHeight() - thumbButtonFrame.getAssignedHeight()/2) / maxThumbButtonTravelDistance * 100)));
if(newScrollValuePercent != scrollValuePercent) {
setValue(rootFrame, uiViewport, newScrollValuePercent);
positionBounds(rootFrame, uiViewport);
}
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
UIFrame frameChildUnderMouse = thumbButtonFrame.touchUp(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = incButtonFrame.touchUp(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = decButtonFrame.touchUp(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = controlBackdrop.touchUp(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
return this;
}
return super.touchUp(screenX, screenY, button);
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
UIFrame frameChildUnderMouse = thumbButtonFrame.touchDown(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = incButtonFrame.touchDown(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = decButtonFrame.touchDown(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = controlBackdrop.touchDown(screenX, screenY, button);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
return this;
}
return super.touchDown(screenX, screenY, button);
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
UIFrame frameChildUnderMouse = thumbButtonFrame.getFrameChildUnderMouse(screenX, screenY);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = incButtonFrame.getFrameChildUnderMouse(screenX, screenY);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = decButtonFrame.getFrameChildUnderMouse(screenX, screenY);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
frameChildUnderMouse = controlBackdrop.getFrameChildUnderMouse(screenX, screenY);
if (frameChildUnderMouse != null) {
return frameChildUnderMouse;
}
return this;
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
public void setChangeListener(ScrollBarChangeListener changeListener) {
this.changeListener = changeListener;
}
public interface ScrollBarChangeListener {
void onChange(GameUI gameUI, Viewport uiViewport, int newValue);
ScrollBarChangeListener DO_NOTHING = new ScrollBarChangeListener() {
@Override
public void onChange(GameUI gameUI, Viewport uiViewport, int newValue) {
}
};
}
}

View File

@ -170,6 +170,11 @@ public class SimpleButtonFrame extends AbstractRenderableFrame implements Clicka
}
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {

View File

@ -144,6 +144,11 @@ public class War3Map implements DataSource {
return this.dataSource.getFile(filepath);
}
@Override
public File getDirectory(String filepath) throws IOException {
return this.dataSource.getDirectory(filepath);
}
@Override
public boolean has(final String filepath) {
return this.dataSource.has(filepath);

View File

@ -1,206 +1,35 @@
package com.etheller.warsmash.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;
import com.google.common.io.Files;
import com.hiveworkshop.rms.parsers.mdlx.MdlxAttachment;
import com.hiveworkshop.rms.parsers.mdlx.MdlxBone;
import com.hiveworkshop.rms.parsers.mdlx.MdlxExtent;
import com.hiveworkshop.rms.parsers.mdlx.MdlxGeoset;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer.FilterMode;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLight;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLight.Type;
import com.hiveworkshop.rms.parsers.mdlx.MdlxMaterial;
import com.hiveworkshop.rms.parsers.mdlx.MdlxModel;
import com.hiveworkshop.rms.parsers.mdlx.MdlxParticleEmitter;
import com.hiveworkshop.rms.parsers.mdlx.MdlxSequence;
import com.hiveworkshop.rms.parsers.mdlx.MdlxTexture;
import com.hiveworkshop.rms.parsers.mdlx.util.MdxUtils;
public class Test {
public static void main(final String[] args) {
final Pattern pattern = Pattern.compile("^\\[(.+?)\\]");
final Matcher matcher = pattern.matcher("[boat] // ocean");
if (matcher.matches()) {
final String name = matcher.group(1).trim().toLowerCase();
System.out.println(name);
final File mdxFile = new File("C:\\Users\\micro\\Downloads\\DrunkSnake\\NagaTridentyr.mdx");
final File mdlFile = new File("C:\\Users\\micro\\Downloads\\DrunkSnake\\NagaTridentyr.mdl");
try (FileInputStream stream = new FileInputStream(mdxFile)) {
final MdlxModel mdlx = MdxUtils.loadMdlx(stream);
final ByteBuffer mdl = mdlx.saveMdl();
try (FileChannel outChannel = FileChannel.open(mdlFile.toPath(), StandardOpenOption.CREATE,
StandardOpenOption.WRITE)) {
outChannel.write(mdl);
}
}
else {
System.out.println("no match");
}
// Quadtree<String> myQT = new Quadtree<>(new Rectangle(-, y, width, height))
final MdlxModel model = new MdlxModel();
upExtent(model.extent);
MdlxSequence sequence = new MdlxSequence();
sequence.name = "Stand";
sequence.interval = new long[] { 333, 332 };
upExtent(sequence.extent);
model.sequences.add(sequence);
sequence = new MdlxSequence();
sequence.name = "Stand";
sequence.interval = new long[] { 333, 332 };
upExtent(sequence.extent);
model.sequences.add(sequence);
sequence.name = "Stand";
sequence.interval = new long[] { 334, 333 };
upExtent(sequence.extent);
model.sequences.add(sequence);
sequence.name = "Stand";
sequence.interval = new long[] { 331, 330 };
upExtent(sequence.extent);
model.sequences.add(sequence);
MdlxGeoset mdlxGeoset = new MdlxGeoset();
upExtent(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.vertices = new float[] { -128f, -128f, 0f, 128f, -128f, 0f, 128f, 128f, 0f, -128f, 128f, 0f };
mdlxGeoset.vertexGroups = new short[] { 0, 0, 0, 0 };
mdlxGeoset.normals = new float[] { 0, 0, 1, 0, 128f, 1, 0, 0, Float.NaN, 0, 0, 1 };
mdlxGeoset.faceTypeGroups = new long[] { 1, 0 };
mdlxGeoset.faces = new int[] { 0, 1, 2, 3 };
mdlxGeoset.faceGroups = new long[] { 2, 2 };
mdlxGeoset.materialId = 0;
mdlxGeoset.matrixGroups = new long[] { 3 };
mdlxGeoset.matrixIndices = new long[] { 0, 1, 2 };
mdlxGeoset.uvSets = new float[][] { { 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f } };
model.geosets.add(mdlxGeoset);
final int n = 3600;
mdlxGeoset = new MdlxGeoset();
upExtent(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.sequenceExtents.add(mdlxGeoset.extent);
mdlxGeoset.vertices = new float[(n + 1) * 3];
for (int i = 1; i <= n; i++) {
final float distance = 4000;
final float down = (float) ((((((i / 360) % 10) + 1) / 10f) * Math.PI) / 2);
final float around = (float) (((i % 360) / 360f) * Math.PI * 2);
final float xyRad = (float) (Math.sin(down) * distance);
final float z = (float) (Math.cos(down) * distance);
mdlxGeoset.vertices[i * 3] = (float) (Math.cos(around) * xyRad);
mdlxGeoset.vertices[(i * 3) + 1] = (float) (Math.sin(around) * xyRad);
mdlxGeoset.vertices[(i * 3) + 2] = z;
}
mdlxGeoset.vertexGroups = new short[(n + 1)];
mdlxGeoset.normals = new float[(n + 1) * 3];
mdlxGeoset.faceTypeGroups = new long[n];
Arrays.fill(mdlxGeoset.faceTypeGroups, 1);
mdlxGeoset.faces = new int[n * 2];
for (int i = 0; i < n; i++) {
mdlxGeoset.faces[(i * 2) + 1] = i + 1;
}
mdlxGeoset.faceGroups = new long[n];
Arrays.fill(mdlxGeoset.faceGroups, 2);
mdlxGeoset.materialId = 0;
mdlxGeoset.matrixGroups = new long[] { 3 };
mdlxGeoset.matrixIndices = new long[] { 0, 1, 2 };
mdlxGeoset.uvSets = new float[][] { { 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f } };
model.geosets.add(mdlxGeoset);
final MdlxTexture texture = new MdlxTexture();
texture.setPath("Textures\\white.blp");
model.textures.add(texture);
final MdlxMaterial material = new MdlxMaterial();
final MdlxLayer layer = new MdlxLayer();
layer.alpha = 1.0f;
layer.textureId = 0;
layer.filterMode = FilterMode.NONE;
material.layers.add(layer);
model.materials.add(material);
final MdlxBone stupid1 = makeStupidBone("Bone_A");
stupid1.setObjectId(0);
stupid1.setParentId(-1);
model.bones.add(stupid1);
final MdlxBone stupid2 = makeStupidBone("Bone_B");
stupid2.setObjectId(1);
stupid1.setParentId(-1);
model.bones.add(stupid2);
final MdlxBone stupid3 = makeStupidBone("Bone_C");
stupid2.setObjectId(2);
stupid1.setParentId(-1);
model.bones.add(stupid3);
final MdlxLight light = new MdlxLight();
light.ambientColor[0] = -5;
light.ambientColor[1] = 0;
light.ambientColor[2] = Float.MAX_VALUE;
light.ambientIntensity = Float.MAX_VALUE;
light.intensity = Float.MAX_VALUE;
light.attenuation[0] = Float.MAX_VALUE;
light.attenuation[1] = Float.MAX_VALUE;
light.color[0] = -5;
light.color[1] = -5;
light.color[2] = Float.MAX_VALUE;
light.type = Type.OMNIDIRECTIONAL;
light.name = "#!@$!@#$";
light.objectId = 3;
light.parentId = -1;
model.lights.add(light);
final MdlxAttachment attachment = new MdlxAttachment();
attachment.setObjectId(4);
attachment.setParentId(-1);
attachment.setName("!@#$");
// attachment.setPath("war3mapImport\\stupidFan.mdl");
model.attachments.add(attachment);
final MdlxParticleEmitter mdlxParticleEmitter = new MdlxParticleEmitter();
mdlxParticleEmitter.emissionRate = 99999;
mdlxParticleEmitter.flags |= 0x8000;
mdlxParticleEmitter.lifeSpan = 99999;
mdlxParticleEmitter.name = "ATCH";
mdlxParticleEmitter.objectId = 5;
mdlxParticleEmitter.parentId = -1;
mdlxParticleEmitter.path = "Doodads\\Cinematic\\ArthasIllidanFight\\ArthasIllidanFight.mdl";
model.particleEmitters.add(mdlxParticleEmitter);
model.pivotPoints.add(new float[] { 0, 0, 0 });
model.pivotPoints.add(new float[] { 0, 0, 0 });
model.pivotPoints.add(new float[] { 0, 0, 0 });
model.pivotPoints.add(new float[] { 0, 0, 0 });
model.pivotPoints.add(new float[] { 0, 0, 0 });
model.pivotPoints.add(new float[] { 0, 0, 0 });
final ByteBuffer mdxBuffer = model.saveMdx();
try {
Files.write(mdxBuffer.array(), new File("C:\\Temp\\doomball.mdx"));
catch (final FileNotFoundException e) {
e.printStackTrace();
}
catch (final IOException e) {
e.printStackTrace();
}
}
private static void upExtent(final MdlxExtent extent) {
extent.boundsRadius = Float.MAX_VALUE;
extent.max[0] = Float.MAX_VALUE;
extent.max[1] = Float.MAX_VALUE;
extent.max[2] = Float.MAX_VALUE;
extent.min[0] = -Float.MAX_VALUE;
extent.min[1] = -Float.MAX_VALUE;
extent.min[2] = -Float.MAX_VALUE;
}
private static MdlxBone makeStupidBone(final String name) {
final MdlxBone stupid1 = new MdlxBone();
stupid1.setName(name);
stupid1.setGeosetId(-1);
stupid1.setGeosetAnimationId(-1);
return stupid1;
}
}

View File

@ -114,7 +114,7 @@ public abstract class SkeletalNode extends GenericNode {
computedRotation = rotationHeap;
computedRotation.set(this.parent.inverseWorldRotation);
if(scene!=null) {
if (scene != null) {
// TODO null scene is stupid, and happens rarely
computedRotation.mul(scene.camera.inverseRotation);
}
@ -194,6 +194,9 @@ public abstract class SkeletalNode extends GenericNode {
RenderMathUtils.mul(computedRotation, computedRotation, rotationHeap2);
}
else if (this.dontInheritRotation) {
RenderMathUtils.mul(computedRotation, this.parent.inverseWorldRotation, computedRotation);
}
}
if (!Float.isNaN(blendTimeRatio) && (blendTimeRatio > 0)) {

View File

@ -56,8 +56,8 @@ public class GenericObject extends AnimatedObject implements GenericIndexed {
final int flags = object.getFlags();
this.dontInheritTranslation = flags & 0x1;
this.dontInheritRotation = flags & 0x2;
this.dontInheritScaling = flags & 0x4;
this.dontInheritScaling = flags & 0x2;
this.dontInheritRotation = flags & 0x4;
this.billboarded = flags & 0x8;
this.billboardedX = flags & 0x10;
this.billboardedY = flags & 0x20;

View File

@ -234,7 +234,7 @@ public class MdxComplexInstance extends ModelInstance {
}
private void initNode(final MdxNode[] nodes, final SkeletalNode node, final GenericObject genericObject) {
initNode(nodes, node, genericObject, null);
this.initNode(nodes, node, genericObject, null);
}
/**
@ -251,7 +251,10 @@ public class MdxComplexInstance extends ModelInstance {
node.parent = nodes[genericObject.parentId];
}
/// TODO: single-axis billboarding
node.dontInheritTranslation = genericObject.dontInheritTranslation > 0;
node.dontInheritScaling = genericObject.dontInheritScaling > 0;
node.dontInheritRotation = genericObject.dontInheritRotation > 0;
if (genericObject.billboarded != 0) {
node.billboarded = true;
}
@ -575,11 +578,13 @@ public class MdxComplexInstance extends ModelInstance {
final long animEnd = interval[1] - 1;
if (this.floatingFrame >= animEnd) {
boolean sequenceRestarted = false;
if ((this.sequenceLoopMode == SequenceLoopMode.ALWAYS_LOOP)
|| ((this.sequenceLoopMode == SequenceLoopMode.MODEL_LOOP) && (sequence.getFlags() == 0))) {
this.floatingFrame = this.frame = (int) interval[0]; // TODO not cast
this.resetEventEmitters();
sequenceRestarted = true;
}
else if (this.sequenceLoopMode == SequenceLoopMode.LOOP_TO_NEXT_ANIMATION) { // faux queued animation
// mode
@ -592,6 +597,7 @@ public class MdxComplexInstance extends ModelInstance {
this.sequenceEnded = false;
this.resetEventEmitters();
this.forced = true;
sequenceRestarted = true;
}
else {
this.floatingFrame = this.frame = (int) animEnd; // TODO not cast
@ -599,10 +605,10 @@ public class MdxComplexInstance extends ModelInstance {
this.allowParticleSpawn = false;
}
if (this.sequenceLoopMode == SequenceLoopMode.NEVER_LOOP_AND_HIDE_WHEN_DONE) {
hide();
this.hide();
}
this.sequenceEnded = true;
this.sequenceEnded = !sequenceRestarted;
}
else {
this.sequenceEnded = false;
@ -807,7 +813,7 @@ public class MdxComplexInstance extends ModelInstance {
}
public boolean intersectRayBounds(final Ray ray, final Vector3 intersection) {
return CollisionShape.intersectRayBounds(getBounds(), this.worldMatrix, ray, intersection);
return CollisionShape.intersectRayBounds(this.getBounds(), this.worldMatrix, ray, intersection);
}
/**
@ -831,7 +837,7 @@ public class MdxComplexInstance extends ModelInstance {
intersected = true;
}
}
return intersected || (!this.hasAnyUnselectableMesh && intersectRayBounds(ray, intersection));
return intersected || (!this.hasAnyUnselectableMesh && this.intersectRayBounds(ray, intersection));
}
/**

View File

@ -117,6 +117,7 @@ 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.CRacePreference;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderComponent;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.SettableCommandErrorListener;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.sound.KeyedSounds;
@ -255,11 +256,11 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final WebGL webGL = this.webGL;
this.addHandler(new MdxHandler());
addHandler(new MdxHandler());
this.wc3PathSolver = PathSolver.DEFAULT;
this.worldScene = this.addWorldScene();
this.worldScene = addWorldScene();
if (!this.dynamicShadowManager.setup(webGL)) {
throw new IllegalStateException("FrameBuffer setup failed");
@ -270,11 +271,11 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
public void loadSLKs(final WorldEditStrings worldEditStrings) throws IOException {
final GenericResource terrain = this.loadMapGeneric("TerrainArt\\Terrain.slk", FetchDataTypeName.SLK,
final GenericResource terrain = loadMapGeneric("TerrainArt\\Terrain.slk", FetchDataTypeName.SLK,
stringDataCallback);
final GenericResource cliffTypes = this.loadMapGeneric("TerrainArt\\CliffTypes.slk", FetchDataTypeName.SLK,
final GenericResource cliffTypes = loadMapGeneric("TerrainArt\\CliffTypes.slk", FetchDataTypeName.SLK,
stringDataCallback);
final GenericResource water = this.loadMapGeneric("TerrainArt\\Water.slk", FetchDataTypeName.SLK,
final GenericResource water = loadMapGeneric("TerrainArt\\Water.slk", FetchDataTypeName.SLK,
stringDataCallback);
// == when loaded, which is always in our system ==
@ -283,13 +284,13 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.waterData.load(water.data.toString());
// emit terrain loaded??
final GenericResource doodads = this.loadMapGeneric("Doodads\\Doodads.slk", FetchDataTypeName.SLK,
final GenericResource doodads = loadMapGeneric("Doodads\\Doodads.slk", FetchDataTypeName.SLK,
stringDataCallback);
final GenericResource doodadMetaData = this.loadMapGeneric("Doodads\\DoodadMetaData.slk", FetchDataTypeName.SLK,
final GenericResource doodadMetaData = loadMapGeneric("Doodads\\DoodadMetaData.slk", FetchDataTypeName.SLK,
stringDataCallback);
final GenericResource destructableData = this.loadMapGeneric("Units\\DestructableData.slk",
final GenericResource destructableData = loadMapGeneric("Units\\DestructableData.slk",
FetchDataTypeName.SLK, stringDataCallback);
final GenericResource destructableMetaData = this.loadMapGeneric("Units\\DestructableMetaData.slk",
final GenericResource destructableMetaData = loadMapGeneric("Units\\DestructableMetaData.slk",
FetchDataTypeName.SLK, stringDataCallback);
// == when loaded, which is always in our system ==
@ -300,13 +301,13 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.destructableMetaData.load(destructableData.data.toString());
// emit doodads loaded
final GenericResource unitData = this.loadMapGeneric("Units\\UnitData.slk", FetchDataTypeName.SLK,
final GenericResource unitData = loadMapGeneric("Units\\UnitData.slk", FetchDataTypeName.SLK,
stringDataCallback);
final GenericResource unitUi = this.loadMapGeneric("Units\\unitUI.slk", FetchDataTypeName.SLK,
final GenericResource unitUi = loadMapGeneric("Units\\unitUI.slk", FetchDataTypeName.SLK,
stringDataCallback);
final GenericResource itemData = this.loadMapGeneric("Units\\ItemData.slk", FetchDataTypeName.SLK,
final GenericResource itemData = loadMapGeneric("Units\\ItemData.slk", FetchDataTypeName.SLK,
stringDataCallback);
final GenericResource unitMetaData = this.loadMapGeneric("Units\\UnitMetaData.slk", FetchDataTypeName.SLK,
final GenericResource unitMetaData = loadMapGeneric("Units\\UnitMetaData.slk", FetchDataTypeName.SLK,
stringDataCallback);
// == when loaded, which is always in our system ==
@ -412,10 +413,10 @@ public class War3MapViewer extends AbstractMdxModelViewer {
public GenericResource loadMapGeneric(final String path, final FetchDataTypeName dataType,
final LoadGenericCallback callback) {
if (this.mapMpq == null) {
return loadGeneric(path, dataType, callback);
return this.loadGeneric(path, dataType, callback);
}
else {
return loadGeneric(path, dataType, callback, this.dataSource);
return this.loadGeneric(path, dataType, callback, this.dataSource);
}
}
@ -549,367 +550,419 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.simulation = new CSimulation(this.mapConfig, this.miscData, this.allObjectData.getUnits(),
this.allObjectData.getItems(), this.allObjectData.getDestructibles(), this.allObjectData.getAbilities(),
new SimulationRenderController() {
private final Map<String, UnitSound> keyToCombatSound = new HashMap<>();
private final Map<String, UnitSound> keyToCombatSound = new HashMap<>();
@Override
public CAttackProjectile createAttackProjectile(final CSimulation simulation, final float launchX,
final float launchY, final float launchFacing, final CUnit source,
final CUnitAttackMissile unitAttack, final AbilityTarget target, final float damage,
final int bounceIndex, final CUnitAttackListener attackListener) {
final War3ID typeId = source.getTypeId();
final int projectileSpeed = unitAttack.getProjectileSpeed();
final float projectileArc = unitAttack.getProjectileArc();
final String missileArt = unitAttack.getProjectileArt();
final float projectileLaunchX = simulation.getUnitData().getProjectileLaunchX(typeId);
final float projectileLaunchY = simulation.getUnitData().getProjectileLaunchY(typeId);
final float projectileLaunchZ = simulation.getUnitData().getProjectileLaunchZ(typeId);
@Override
public CAttackProjectile createAttackProjectile(final CSimulation simulation, final float launchX,
final float launchY, final float launchFacing, final CUnit source,
final CUnitAttackMissile unitAttack, final AbilityTarget target, final float damage,
final int bounceIndex, final CUnitAttackListener attackListener) {
final War3ID typeId = source.getTypeId();
final int projectileSpeed = unitAttack.getProjectileSpeed();
final float projectileArc = unitAttack.getProjectileArc();
final String missileArt = unitAttack.getProjectileArt();
final float projectileLaunchX = simulation.getUnitData().getProjectileLaunchX(typeId);
final float projectileLaunchY = simulation.getUnitData().getProjectileLaunchY(typeId);
final float projectileLaunchZ = simulation.getUnitData().getProjectileLaunchZ(typeId);
final float facing = launchFacing;
final float sinFacing = (float) Math.sin(facing);
final float cosFacing = (float) Math.cos(facing);
final float x = (launchX + (projectileLaunchY * cosFacing)) + (projectileLaunchX * sinFacing);
final float y = (launchY + (projectileLaunchY * sinFacing)) - (projectileLaunchX * cosFacing);
final float facing = launchFacing;
final float sinFacing = (float) Math.sin(facing);
final float cosFacing = (float) Math.cos(facing);
final float x = (launchX + (projectileLaunchY * cosFacing)) + (projectileLaunchX * sinFacing);
final float y = (launchY + (projectileLaunchY * sinFacing)) - (projectileLaunchX * cosFacing);
final float height = War3MapViewer.this.terrain.getGroundHeight(x, y) + source.getFlyHeight()
+ projectileLaunchZ;
final CAttackProjectile simulationAttackProjectile = new CAttackProjectile(x, y,
projectileSpeed, target, source, damage, unitAttack, bounceIndex, attackListener);
final float height = War3MapViewer.this.terrain.getGroundHeight(x, y) + source.getFlyHeight()
+ projectileLaunchZ;
final CAttackProjectile simulationAttackProjectile = new CAttackProjectile(x, y,
projectileSpeed, target, source, damage, unitAttack, bounceIndex, attackListener);
final MdxModel model = loadModelMdx(missileArt);
final MdxComplexInstance modelInstance = (MdxComplexInstance) model.addInstance();
modelInstance.setTeamColor(source.getPlayerIndex());
modelInstance.setScene(War3MapViewer.this.worldScene);
if (bounceIndex == 0) {
SequenceUtils.randomBirthSequence(modelInstance);
}
else {
SequenceUtils.randomStandSequence(modelInstance);
}
modelInstance.setLocation(x, y, height);
final RenderAttackProjectile renderAttackProjectile = new RenderAttackProjectile(
simulationAttackProjectile, modelInstance, height, projectileArc, War3MapViewer.this);
final MdxModel model = loadModelMdx(missileArt);
final MdxComplexInstance modelInstance = (MdxComplexInstance) model.addInstance();
modelInstance.setTeamColor(source.getPlayerIndex());
modelInstance.setScene(War3MapViewer.this.worldScene);
if (bounceIndex == 0) {
SequenceUtils.randomBirthSequence(modelInstance);
}
else {
SequenceUtils.randomStandSequence(modelInstance);
}
modelInstance.setLocation(x, y, height);
final RenderAttackProjectile renderAttackProjectile = new RenderAttackProjectile(
simulationAttackProjectile, modelInstance, height, projectileArc, War3MapViewer.this);
War3MapViewer.this.projectiles.add(renderAttackProjectile);
War3MapViewer.this.projectiles.add(renderAttackProjectile);
return simulationAttackProjectile;
return simulationAttackProjectile;
}
@Override
public void createInstantAttackEffect(final CSimulation cSimulation, final CUnit source,
final CUnitAttackInstant unitAttack, final CWidget target) {
final War3ID typeId = source.getTypeId();
final String missileArt = unitAttack.getProjectileArt();
final float projectileLaunchX = War3MapViewer.this.simulation.getUnitData()
.getProjectileLaunchX(typeId);
final float projectileLaunchY = War3MapViewer.this.simulation.getUnitData()
.getProjectileLaunchY(typeId);
final float facing = (float) Math.toRadians(source.getFacing());
final float sinFacing = (float) Math.sin(facing);
final float cosFacing = (float) Math.cos(facing);
final float x = (source.getX() + (projectileLaunchY * cosFacing))
+ (projectileLaunchX * sinFacing);
final float y = (source.getY() + (projectileLaunchY * sinFacing))
- (projectileLaunchX * cosFacing);
final float targetX = target.getX();
final float targetY = target.getY();
final float angleToTarget = (float) Math.atan2(targetY - y, targetX - x);
final float height = War3MapViewer.this.terrain.getGroundHeight(targetX, targetY)
+ target.getFlyHeight() + target.getImpactZ();
final MdxModel model = loadModelMdx(missileArt);
final MdxComplexInstance modelInstance = (MdxComplexInstance) model.addInstance();
modelInstance.setTeamColor(source.getPlayerIndex());
SequenceUtils.randomBirthSequence(modelInstance);
modelInstance.setLocation(targetX, targetY, height);
modelInstance.setScene(War3MapViewer.this.worldScene);
War3MapViewer.this.projectiles
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this, angleToTarget));
}
@Override
public void spawnDamageSound(final CWidget damagedDestructable, final String weaponSound,
final String armorType) {
final RenderWidget damagedWidget = War3MapViewer.this.getRenderPeer(damagedDestructable);
if (damagedWidget == null) {
return;
}
final String key = weaponSound + armorType;
UnitSound combatSound = this.keyToCombatSound.get(key);
if (combatSound == null) {
combatSound = UnitSound.create(War3MapViewer.this.dataSource,
War3MapViewer.this.unitCombatSoundsTable, weaponSound, armorType);
this.keyToCombatSound.put(key, combatSound);
}
combatSound.play(War3MapViewer.this.worldScene.audioContext, damagedDestructable.getX(),
damagedDestructable.getY(), damagedWidget.getZ());
}
@Override
public void spawnUnitConstructionSound(final CUnit constructingUnit,
final CUnit constructedStructure) {
final UnitSound constructingBuilding = War3MapViewer.this.uiSounds
.getSound(War3MapViewer.this.gameUI.getSkinField("ConstructingBuilding"));
if (constructingBuilding != null) {
constructingBuilding.playUnitResponse(War3MapViewer.this.worldScene.audioContext,
War3MapViewer.this.unitToRenderPeer.get(constructedStructure));
}
}
@Override
public void removeUnit(final CUnit unit) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.remove(unit);
War3MapViewer.this.widgets.remove(renderUnit);
War3MapViewer.this.units.remove(renderUnit);
War3MapViewer.this.worldScene.removeInstance(renderUnit.instance);
renderUnit.onRemove(War3MapViewer.this);
}
@Override
public void removeDestructable(final CDestructable dest) {
final RenderDestructable renderPeer = War3MapViewer.this.destructableToRenderPeer.remove(dest);
War3MapViewer.this.worldScene.removeInstance(renderPeer.instance);
if (renderPeer.walkableBounds != null) {
War3MapViewer.this.walkableObjectsTree.remove((MdxComplexInstance) renderPeer.instance,
renderPeer.walkableBounds);
}
}
@Override
public BufferedImage getBuildingPathingPixelMap(final War3ID rawcode) {
return War3MapViewer.this
.getBuildingPathingPixelMap(War3MapViewer.this.allObjectData.getUnits().get(rawcode));
}
@Override
public BufferedImage getDestructablePathingDeathPixelMap(final War3ID rawcode) {
return War3MapViewer.this.getDestructablePathingDeathPixelMap(
War3MapViewer.this.allObjectData.getDestructibles().get(rawcode));
}
@Override
public BufferedImage getDestructablePathingPixelMap(final War3ID rawcode) {
return War3MapViewer.this.getDestructablePathingPixelMap(
War3MapViewer.this.allObjectData.getDestructibles().get(rawcode));
}
@Override
public void spawnUnitConstructionFinishSound(final CUnit constructedStructure) {
final UnitSound constructingBuilding = War3MapViewer.this.uiSounds
.getSound(War3MapViewer.this.gameUI.getSkinField("JobDoneSound"));
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(constructedStructure);
if ((constructingBuilding != null) && (renderUnit.getSimulationUnit()
.getPlayerIndex() == War3MapViewer.this.localPlayerIndex)) {
constructingBuilding.play(War3MapViewer.this.worldScene.audioContext,
constructedStructure.getX(), constructedStructure.getY(), renderUnit.getZ());
}
}
@Override
public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex,
final float x, final float y, final float facing) {
return (CUnit) War3MapViewer.this.createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y,
playerIndex, playerIndex, (float) Math.toRadians(facing));
}
@Override
public CDestructable createDestructable(final War3ID typeId, final float x, final float y,
final float facing, final float scale, final int variation) {
return createDestructableZ(typeId, x, y,
Math.max(War3MapViewer.this.getWalkableRenderHeight(x, y),
War3MapViewer.this.terrain.getGroundHeight(x, y)),
facing, scale, variation);
}
@Override
public CDestructable createDestructableZ(final War3ID typeId, final float x, final float y,
final float z, final float facing, final float scale, final int variation) {
final MutableGameObject row = War3MapViewer.this.allObjectData.getDestructibles().get(typeId);
final float[] location3d = { x, y, z };
final float[] scale3d = { scale, scale, scale };
final RenderDestructable newDestructable = War3MapViewer.this.createNewDestructable(typeId, row,
variation, location3d, (float) Math.toRadians(facing), (short) 100, scale3d);
return newDestructable.getSimulationDestructable();
}
@Override
public CItem createItem(final CSimulation simulation, final War3ID typeId, final float x,
final float y) {
return (CItem) War3MapViewer.this.createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y,
-1, -1, (float) Math.toRadians(
War3MapViewer.this.simulation.getGameplayConstants().getBuildingAngle()));
}
@Override
public void spawnBuildingDeathEffect(final CUnit source) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
if (renderUnit.specialArtModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) renderUnit.specialArtModel
.addInstance();
modelInstance.setTeamColor(source.getPlayerIndex());
modelInstance.setLocation(renderUnit.location);
modelInstance.setScene(War3MapViewer.this.worldScene);
SequenceUtils.randomBirthSequence(modelInstance);
War3MapViewer.this.projectiles
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this,
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing())));
}
}
@Override
public void spawnGainLevelEffect(final CUnit source) {
final AbilityUI heroUI = War3MapViewer.this.abilityDataUI.getUI(ABILITY_HERO_RAWCODE);
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
final String heroLevelUpArt = heroUI.getCasterArt(0);
War3MapViewer.this.spawnFxOnOrigin(renderUnit, heroLevelUpArt);
}
@Override
public void heroRevived(final CUnit source) {
final AbilityUI reviveUI = War3MapViewer.this.abilityDataUI.getUI(ABILITY_REVIVE_RAWCODE);
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
renderUnit.instance.additiveOverrideMeshMode = false;
renderUnit.instance.setVertexAlpha(1.0f);
final CPlayer player = War3MapViewer.this.simulation.getPlayer(source.getPlayerIndex());
final String heroReviveArt = reviveUI.getTargetArt(player.getRace().ordinal());
War3MapViewer.this.spawnFxOnOrigin(renderUnit, heroReviveArt);
final MutableGameObject row = War3MapViewer.this.allObjectData.getUnits()
.get(source.getTypeId());
// Recreate unit shadow.... is needed here
final String unitShadow = row.getFieldAsString(UNIT_SHADOW, 0);
final float unitX = source.getX();
final float unitY = source.getY();
if ((unitShadow != null) && !"_".equals(unitShadow)) {
final String texture = "ReplaceableTextures\\Shadows\\" + unitShadow + ".blp";
final float shadowX = row.getFieldAsFloat(UNIT_SHADOW_X, 0);
final float shadowY = row.getFieldAsFloat(UNIT_SHADOW_Y, 0);
final float shadowWidth = row.getFieldAsFloat(UNIT_SHADOW_W, 0);
final float shadowHeight = row.getFieldAsFloat(UNIT_SHADOW_H, 0);
if (War3MapViewer.this.mapMpq.has(texture)) {
final float x = unitX - shadowX;
final float y = unitY - shadowY;
renderUnit.shadow = War3MapViewer.this.terrain.addUnitShadowSplat(texture, x, y,
x + shadowWidth, y + shadowHeight, 3, 0.5f);
}
@Override
public void createInstantAttackEffect(final CSimulation cSimulation, final CUnit source,
final CUnitAttackInstant unitAttack, final CWidget target) {
final War3ID typeId = source.getTypeId();
final String missileArt = unitAttack.getProjectileArt();
final float projectileLaunchX = War3MapViewer.this.simulation.getUnitData()
.getProjectileLaunchX(typeId);
final float projectileLaunchY = War3MapViewer.this.simulation.getUnitData()
.getProjectileLaunchY(typeId);
final float facing = (float) Math.toRadians(source.getFacing());
final float sinFacing = (float) Math.sin(facing);
final float cosFacing = (float) Math.cos(facing);
final float x = (source.getX() + (projectileLaunchY * cosFacing))
+ (projectileLaunchX * sinFacing);
final float y = (source.getY() + (projectileLaunchY * sinFacing))
- (projectileLaunchX * cosFacing);
final float targetX = target.getX();
final float targetY = target.getY();
final float angleToTarget = (float) Math.atan2(targetY - y, targetX - x);
final float height = War3MapViewer.this.terrain.getGroundHeight(targetX, targetY)
+ target.getFlyHeight() + target.getImpactZ();
final MdxModel model = loadModelMdx(missileArt);
final MdxComplexInstance modelInstance = (MdxComplexInstance) model.addInstance();
modelInstance.setTeamColor(source.getPlayerIndex());
SequenceUtils.randomBirthSequence(modelInstance);
modelInstance.setLocation(targetX, targetY, height);
modelInstance.setScene(War3MapViewer.this.worldScene);
War3MapViewer.this.projectiles
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this, angleToTarget));
}
@Override
public void spawnDamageSound(final CWidget damagedDestructable, final String weaponSound,
final String armorType) {
final RenderWidget damagedWidget = getRenderPeer(damagedDestructable);
if (damagedWidget == null) {
return;
}
final String key = weaponSound + armorType;
UnitSound combatSound = this.keyToCombatSound.get(key);
if (combatSound == null) {
combatSound = UnitSound.create(War3MapViewer.this.dataSource,
War3MapViewer.this.unitCombatSoundsTable, weaponSound, armorType);
this.keyToCombatSound.put(key, combatSound);
}
combatSound.play(War3MapViewer.this.worldScene.audioContext, damagedDestructable.getX(),
damagedDestructable.getY(), damagedWidget.getZ());
}
@Override
public void spawnUnitConstructionSound(final CUnit constructingUnit,
final CUnit constructedStructure) {
final UnitSound constructingBuilding = War3MapViewer.this.uiSounds
.getSound(War3MapViewer.this.gameUI.getSkinField("ConstructingBuilding"));
if (constructingBuilding != null) {
constructingBuilding.playUnitResponse(War3MapViewer.this.worldScene.audioContext,
War3MapViewer.this.unitToRenderPeer.get(constructedStructure));
else {
final String textureFallback = "ReplaceableTextures\\Shadows\\" + unitShadow + ".dds";
if (War3MapViewer.this.mapMpq.has(textureFallback)) {
final float x = unitX - shadowX;
final float y = unitY - shadowY;
renderUnit.shadow = War3MapViewer.this.terrain.addUnitShadowSplat(textureFallback,
x, y, x + shadowWidth, y + shadowHeight, 3, 0.5f);
}
}
}
}
@Override
public void removeUnit(final CUnit unit) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.remove(unit);
War3MapViewer.this.widgets.remove(renderUnit);
War3MapViewer.this.units.remove(renderUnit);
War3MapViewer.this.worldScene.removeInstance(renderUnit.instance);
renderUnit.onRemove(War3MapViewer.this);
}
@Override
public void heroDeathEvent(final CUnit source) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
renderUnit.instance.additiveOverrideMeshMode = true;
}
@Override
public void removeDestructable(final CDestructable dest) {
final RenderDestructable renderPeer = War3MapViewer.this.destructableToRenderPeer.remove(dest);
War3MapViewer.this.worldScene.removeInstance(renderPeer.instance);
if (renderPeer.walkableBounds != null) {
War3MapViewer.this.walkableObjectsTree.remove((MdxComplexInstance) renderPeer.instance,
renderPeer.walkableBounds);
@Override
public void spawnEffectOnUnit(final CUnit unit, final String effectPath) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(unit);
final MdxModel spawnedEffectModel = loadModelMdx(effectPath);
if (spawnedEffectModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) spawnedEffectModel
.addInstance();
modelInstance.setTeamColor(unit.getPlayerIndex());
modelInstance.setLocation(renderUnit.location);
modelInstance.setScene(War3MapViewer.this.worldScene);
final RenderSpellEffect renderAttackInstant = new RenderSpellEffect(modelInstance,
War3MapViewer.this,
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing()),
RenderSpellEffect.DEFAULT_ANIMATION_QUEUE);
War3MapViewer.this.projectiles.add(renderAttackInstant);
}
}
@Override
public void spawnSpellEffectOnUnit(final CUnit unit, final War3ID alias) {
final AbilityUI abilityUI = War3MapViewer.this.abilityDataUI.getUI(alias);
spawnEffectOnUnit(unit, abilityUI.getTargetArt(0));
}
@Override
public SimulationRenderComponent createSpellEffectOverDestructable(final CUnit source, final CDestructable target, final War3ID alias, final float artAttachmentHeight) {
final AbilityUI abilityUI = War3MapViewer.this.abilityDataUI.getUI(alias);
final String effectPath = abilityUI.getTargetArt(0);
final RenderDestructable renderDestructable = War3MapViewer.this.destructableToRenderPeer.get(target);
final MdxModel spawnedEffectModel = loadModelMdx(effectPath);
if (spawnedEffectModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) spawnedEffectModel
.addInstance();
modelInstance.setTeamColor(War3MapViewer.this.simulation.getPlayer(source.getPlayerIndex()).getColor());
modelInstance.setLocation(renderDestructable.getX(), renderDestructable.getY(), renderDestructable.getZ() + artAttachmentHeight);
modelInstance.setScene(War3MapViewer.this.worldScene);
final RenderSpellEffect renderAttackInstant = new RenderSpellEffect(modelInstance,
War3MapViewer.this,
0,
RenderSpellEffect.STAND_ONLY);
renderAttackInstant.setAnimations(RenderSpellEffect.STAND_ONLY, false);
War3MapViewer.this.projectiles.add(renderAttackInstant);
return new SimulationRenderComponent() {
@Override
public void remove() {
renderAttackInstant.setAnimations(RenderSpellEffect.DEATH_ONLY, true);
}
}
};
}
return null;
}
@Override
public BufferedImage getBuildingPathingPixelMap(final War3ID rawcode) {
return War3MapViewer.this
.getBuildingPathingPixelMap(War3MapViewer.this.allObjectData.getUnits().get(rawcode));
}
@Override
public void spawnUnitReadySound(final CUnit trainedUnit) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(trainedUnit);
renderPeer.soundset.ready.playUnitResponse(War3MapViewer.this.worldScene.audioContext,
renderPeer);
}
@Override
public BufferedImage getDestructablePathingDeathPixelMap(final War3ID rawcode) {
return War3MapViewer.this.getDestructablePathingDeathPixelMap(
War3MapViewer.this.allObjectData.getDestructibles().get(rawcode));
}
@Override
public void unitRepositioned(final CUnit cUnit) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(cUnit);
renderPeer.repositioned(War3MapViewer.this);
}
@Override
public BufferedImage getDestructablePathingPixelMap(final War3ID rawcode) {
return War3MapViewer.this.getDestructablePathingPixelMap(
War3MapViewer.this.allObjectData.getDestructibles().get(rawcode));
}
@Override
public void spawnGainResourceTextTag(final CUnit gainingUnit, final ResourceType resourceType,
final int amount) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(gainingUnit);
switch (resourceType) {
case FOOD:
throw new IllegalArgumentException();
case GOLD:
War3MapViewer.this.textTags.add(new TextTag(new Vector3(renderPeer.location), "+" + amount,
PLACEHOLDER_GOLD_COLOR));
break;
case LUMBER:
War3MapViewer.this.textTags.add(new TextTag(new Vector3(renderPeer.location), "+" + amount,
PLACEHOLDER_LUMBER_COLOR));
break;
}
}
@Override
public void spawnUnitConstructionFinishSound(final CUnit constructedStructure) {
final UnitSound constructingBuilding = War3MapViewer.this.uiSounds
.getSound(War3MapViewer.this.gameUI.getSkinField("JobDoneSound"));
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(constructedStructure);
if ((constructingBuilding != null) && (renderUnit.getSimulationUnit()
.getPlayerIndex() == War3MapViewer.this.localPlayerIndex)) {
constructingBuilding.play(War3MapViewer.this.worldScene.audioContext,
constructedStructure.getX(), constructedStructure.getY(), renderUnit.getZ());
}
}
@Override
public void spawnUIUnitGetItemSound(final CUnit cUnit, final CItem item) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(cUnit);
if (localPlayerIndex == renderPeer.getSimulationUnit().getPlayerIndex()) {
War3MapViewer.this.uiSounds.getSound("ItemGet").play(
War3MapViewer.this.worldScene.audioContext, renderPeer.getX(), renderPeer.getY(),
renderPeer.getZ());
}
}
@Override
public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex,
final float x, final float y, final float facing) {
return (CUnit) createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y, playerIndex,
playerIndex, (float) Math.toRadians(facing));
}
@Override
public void spawnUIUnitDropItemSound(final CUnit cUnit, final CItem item) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(cUnit);
if (localPlayerIndex == renderPeer.getSimulationUnit().getPlayerIndex()) {
War3MapViewer.this.uiSounds.getSound("ItemDrop").play(
War3MapViewer.this.worldScene.audioContext, renderPeer.getX(), renderPeer.getY(),
renderPeer.getZ());
}
}
@Override
public CDestructable createDestructable(final War3ID typeId, final float x, final float y,
final float facing, final float scale, final int variation) {
return createDestructableZ(typeId, x, y, Math.max(getWalkableRenderHeight(x, y),
War3MapViewer.this.terrain.getGroundHeight(x, y)), facing, scale, variation);
}
@Override
public void spawnAbilitySoundEffect(final CUnit caster, final War3ID alias) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(caster);
final AbilityUI abilityUi = War3MapViewer.this.abilityDataUI.getUI(alias);
if (abilityUi.getEffectSound() != null) {
War3MapViewer.this.uiSounds.getSound(abilityUi.getEffectSound()).play(
War3MapViewer.this.worldScene.audioContext, renderPeer.getX(), renderPeer.getY(),
renderPeer.getZ());
}
}
@Override
public CDestructable createDestructableZ(final War3ID typeId, final float x, final float y,
final float z, final float facing, final float scale, final int variation) {
final MutableGameObject row = War3MapViewer.this.allObjectData.getDestructibles().get(typeId);
final float[] location3d = { x, y, z };
final float[] scale3d = { scale, scale, scale };
final RenderDestructable newDestructable = createNewDestructable(typeId, row, variation,
location3d, (float) Math.toRadians(facing), (short) 100, scale3d);
return newDestructable.getSimulationDestructable();
}
@Override
public void loopAbilitySoundEffect(final CUnit caster, final War3ID alias) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(caster);
final AbilityUI abilityUi = War3MapViewer.this.abilityDataUI.getUI(alias);
if (abilityUi.getEffectSoundLooped() != null) {
War3MapViewer.this.uiSounds.getSound(abilityUi.getEffectSoundLooped()).play(
War3MapViewer.this.worldScene.audioContext, renderPeer.getX(), renderPeer.getY(),
renderPeer.getZ());
}
}
@Override
public CItem createItem(final CSimulation simulation, final War3ID typeId, final float x,
final float y) {
return (CItem) createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y, -1, -1,
(float) Math.toRadians(
War3MapViewer.this.simulation.getGameplayConstants().getBuildingAngle()));
}
@Override
public void stopAbilitySoundEffect(final CUnit caster, final War3ID alias) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(caster);
final AbilityUI abilityUi = War3MapViewer.this.abilityDataUI.getUI(alias);
if (abilityUi.getEffectSoundLooped() != null) {
// TODO below this probably stops all instances of the sound, which is silly
// and busted. Would be better to keep a notion of sound instance
War3MapViewer.this.uiSounds.getSound(abilityUi.getEffectSoundLooped()).stop();
}
}
@Override
public void spawnBuildingDeathEffect(final CUnit source) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
if (renderUnit.specialArtModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) renderUnit.specialArtModel
.addInstance();
modelInstance.setTeamColor(source.getPlayerIndex());
modelInstance.setLocation(renderUnit.location);
modelInstance.setScene(War3MapViewer.this.worldScene);
SequenceUtils.randomBirthSequence(modelInstance);
War3MapViewer.this.projectiles
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this,
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing())));
}
}
@Override
public void unitPreferredSelectionReplacement(final CUnit oldUnit, final CUnit newUnit) {
final RenderUnit oldRenderPeer = War3MapViewer.this.unitToRenderPeer.get(oldUnit);
final RenderUnit newRenderPeer = War3MapViewer.this.unitToRenderPeer.get(newUnit);
oldRenderPeer.setPreferredSelectionReplacement(newRenderPeer);
@Override
public void spawnGainLevelEffect(final CUnit source) {
final AbilityUI heroUI = War3MapViewer.this.abilityDataUI.getUI(ABILITY_HERO_RAWCODE);
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
final String heroLevelUpArt = heroUI.getCasterArt(0);
spawnFxOnOrigin(renderUnit, heroLevelUpArt);
}
@Override
public void heroRevived(final CUnit source) {
final AbilityUI reviveUI = War3MapViewer.this.abilityDataUI.getUI(ABILITY_REVIVE_RAWCODE);
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
renderUnit.instance.additiveOverrideMeshMode = false;
renderUnit.instance.setVertexAlpha(1.0f);
final CPlayer player = War3MapViewer.this.simulation.getPlayer(source.getPlayerIndex());
final String heroReviveArt = reviveUI.getTargetArt(player.getRace().ordinal());
spawnFxOnOrigin(renderUnit, heroReviveArt);
final MutableGameObject row = War3MapViewer.this.allObjectData.getUnits()
.get(source.getTypeId());
// Recreate unit shadow.... is needed here
final String unitShadow = row.getFieldAsString(UNIT_SHADOW, 0);
final float unitX = source.getX();
final float unitY = source.getY();
if ((unitShadow != null) && !"_".equals(unitShadow)) {
final String texture = "ReplaceableTextures\\Shadows\\" + unitShadow + ".blp";
final float shadowX = row.getFieldAsFloat(UNIT_SHADOW_X, 0);
final float shadowY = row.getFieldAsFloat(UNIT_SHADOW_Y, 0);
final float shadowWidth = row.getFieldAsFloat(UNIT_SHADOW_W, 0);
final float shadowHeight = row.getFieldAsFloat(UNIT_SHADOW_H, 0);
if (War3MapViewer.this.mapMpq.has(texture)) {
final float x = unitX - shadowX;
final float y = unitY - shadowY;
renderUnit.shadow = War3MapViewer.this.terrain.addUnitShadowSplat(texture, x, y,
x + shadowWidth, y + shadowHeight, 3, 0.5f);
}
else {
final String textureFallback = "ReplaceableTextures\\Shadows\\" + unitShadow + ".dds";
if (War3MapViewer.this.mapMpq.has(textureFallback)) {
final float x = unitX - shadowX;
final float y = unitY - shadowY;
renderUnit.shadow = War3MapViewer.this.terrain.addUnitShadowSplat(textureFallback,
x, y, x + shadowWidth, y + shadowHeight, 3, 0.5f);
}
}
}
}
@Override
public void heroDeathEvent(final CUnit source) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
renderUnit.instance.additiveOverrideMeshMode = true;
}
@Override
public void spawnEffectOnUnit(final CUnit unit, final String effectPath) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(unit);
final MdxModel spawnedEffectModel = loadModelMdx(effectPath);
if (spawnedEffectModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) spawnedEffectModel
.addInstance();
modelInstance.setTeamColor(unit.getPlayerIndex());
modelInstance.setLocation(renderUnit.location);
modelInstance.setScene(War3MapViewer.this.worldScene);
final RenderSpellEffect renderAttackInstant = new RenderSpellEffect(modelInstance,
War3MapViewer.this,
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing()),
RenderSpellEffect.DEFAULT_ANIMATION_QUEUE);
War3MapViewer.this.projectiles.add(renderAttackInstant);
}
}
@Override
public void spawnSpellEffectOnUnit(final CUnit unit, final War3ID alias) {
final AbilityUI abilityUI = War3MapViewer.this.abilityDataUI.getUI(alias);
spawnEffectOnUnit(unit, abilityUI.getTargetArt(0));
}
@Override
public void spawnUnitReadySound(final CUnit trainedUnit) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(trainedUnit);
renderPeer.soundset.ready.playUnitResponse(War3MapViewer.this.worldScene.audioContext,
renderPeer);
}
@Override
public void unitRepositioned(final CUnit cUnit) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(cUnit);
renderPeer.repositioned(War3MapViewer.this);
}
@Override
public void spawnGainResourceTextTag(final CUnit gainingUnit, final ResourceType resourceType,
final int amount) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(gainingUnit);
switch (resourceType) {
case FOOD:
throw new IllegalArgumentException();
case GOLD:
War3MapViewer.this.textTags.add(new TextTag(new Vector3(renderPeer.location), "+" + amount,
PLACEHOLDER_GOLD_COLOR));
break;
case LUMBER:
War3MapViewer.this.textTags.add(new TextTag(new Vector3(renderPeer.location), "+" + amount,
PLACEHOLDER_LUMBER_COLOR));
break;
}
}
@Override
public void spawnUIUnitGetItemSound(final CUnit cUnit, final CItem item) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(cUnit);
if (localPlayerIndex == renderPeer.getSimulationUnit().getPlayerIndex()) {
War3MapViewer.this.uiSounds.getSound("ItemGet").play(
War3MapViewer.this.worldScene.audioContext, renderPeer.getX(), renderPeer.getY(),
renderPeer.getZ());
}
}
@Override
public void spawnUIUnitDropItemSound(final CUnit cUnit, final CItem item) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(cUnit);
if (localPlayerIndex == renderPeer.getSimulationUnit().getPlayerIndex()) {
War3MapViewer.this.uiSounds.getSound("ItemDrop").play(
War3MapViewer.this.worldScene.audioContext, renderPeer.getX(), renderPeer.getY(),
renderPeer.getZ());
}
}
@Override
public void spawnAbilitySoundEffect(final CUnit caster, final War3ID alias) {
final RenderUnit renderPeer = War3MapViewer.this.unitToRenderPeer.get(caster);
final AbilityUI abilityUi = War3MapViewer.this.abilityDataUI.getUI(alias);
if (abilityUi.getEffectSound() != null) {
War3MapViewer.this.uiSounds.getSound(abilityUi.getEffectSound()).play(
War3MapViewer.this.worldScene.audioContext, renderPeer.getX(), renderPeer.getY(),
renderPeer.getZ());
}
}
@Override
public void unitPreferredSelectionReplacement(final CUnit oldUnit, final CUnit newUnit) {
final RenderUnit oldRenderPeer = War3MapViewer.this.unitToRenderPeer.get(oldUnit);
final RenderUnit newRenderPeer = War3MapViewer.this.unitToRenderPeer.get(newUnit);
oldRenderPeer.setPreferredSelectionReplacement(newRenderPeer);
}
}, this.terrain.pathingGrid, this.terrain.getEntireMap(), this.seededRandom, this.commandErrorListener);
}
}, this.terrain.pathingGrid, this.terrain.getEntireMap(), this.seededRandom, this.commandErrorListener);
this.walkableObjectsTree = new Quadtree<>(this.terrain.getEntireMap());
if (this.doodadsAndDestructiblesLoaded) {
this.loadDoodadsAndDestructibles(this.allObjectData, w3iFile);
loadDoodadsAndDestructibles(this.allObjectData, w3iFile);
}
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
@ -973,7 +1026,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
*/
public void loadAfterUI() throws IOException {
if (this.unitsAndItemsLoaded) {
this.loadUnitsAndItems(this.allObjectData, this.lastLoadedMapInformation);
loadUnitsAndItems(this.allObjectData, this.lastLoadedMapInformation);
}
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
@ -986,9 +1039,9 @@ public class War3MapViewer extends AbstractMdxModelViewer {
private void loadDoodadsAndDestructibles(final Warcraft3MapObjectData modifications, final War3MapW3i w3iFile)
throws IOException {
this.applyModificationFile(this.doodadsData, this.doodadMetaData, modifications.getDoodads(),
applyModificationFile(this.doodadsData, this.doodadMetaData, modifications.getDoodads(),
WorldEditorDataType.DOODADS);
this.applyModificationFile(this.doodadsData, this.destructableMetaData, modifications.getDestructibles(),
applyModificationFile(this.doodadsData, this.destructableMetaData, modifications.getDestructibles(),
WorldEditorDataType.DESTRUCTIBLES);
final War3MapDoo doo = this.mapMpq.readDoodads(w3iFile);
@ -1003,8 +1056,8 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final float facingRadians = doodad.getAngle();
final short lifePercent = doodad.getLife();
final float[] scale = doodad.getScale();
createDestructableOrDoodad(doodadId, modifications, doodadVariation, location, facingRadians, lifePercent,
scale);
createDestructableOrDoodad(doodadId, modifications, doodadVariation, location, facingRadians,
lifePercent, scale);
}
// Cliff/Terrain doodads.
@ -1021,7 +1074,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
if (!file.toLowerCase().endsWith(".mdx")) {
file += ".mdx";
}
final MdxModel model = (MdxModel) this.load(file, this.mapPathSolver, this.solverParams);
final MdxModel model = (MdxModel) load(file, this.mapPathSolver, this.solverParams);
final String pathingTexture = row.readSLKTag("pathTex");
BufferedImage pathingTextureImage;
@ -1181,10 +1234,10 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
MdxModel model;
if (this.mapMpq.has(path)) {
model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
model = (MdxModel) load(path, this.mapPathSolver, this.solverParams);
}
else {
model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams);
model = (MdxModel) load(fileVar, this.mapPathSolver, this.solverParams);
}
return model;
}
@ -1288,7 +1341,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
// Hardcoded?
WorldEditorDataType type = null;
if (sloc.equals(unitId)) {
// path = "Objects\\StartLocation\\StartLocation.mdx";
// path = "Objects\\StartLocation\\StartLocation.mdx";
type = null; /// ??????
this.startLocations[playerIndex] = new Vector2(unitX, unitY);
}
@ -1329,7 +1382,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.terrain.splats.put(texture, splat);
}
this.terrain.splats.get(texture).locations
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 });
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 });
unitShadowSplat = this.terrain.splats.get(texture);
}
}
@ -1360,7 +1413,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final Element uberSplatInfo = this.terrain.uberSplatTable.get(uberSplat);
if (uberSplatInfo != null) {
final String texturePath = uberSplatInfo.getField("Dir") + "\\" + uberSplatInfo.getField("file")
+ ".blp";
+ ".blp";
final float s = uberSplatInfo.getFieldFloatValue("Scale");
if (this.unitsReady) {
buildingUberSplatDynamicIngame = this.terrain.addUberSplat(texturePath, unitX, unitY, 1, s,
@ -1402,7 +1455,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.terrain.splats.put(texture, splat);
}
this.terrain.splats.get(texture).locations
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 });
.add(new float[] { x, y, x + shadowWidth, y + shadowHeight, 3 });
unitShadowSplat = this.terrain.splats.get(texture);
}
}
@ -1427,7 +1480,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
if (path != null) {
final String unitSpecialArtPath = row.getFieldAsString(UNIT_SPECIAL, 0);
MdxModel specialArtModel;
if (unitSpecialArtPath != null) {
if ((unitSpecialArtPath != null) && !unitSpecialArtPath.isEmpty()) {
try {
specialArtModel = loadModelMdx(unitSpecialArtPath);
}
@ -1962,7 +2015,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
public RenderWidget rayPickUnit(final float x, final float y) {
return rayPickUnit(x, y, CWidgetFilterFunction.ACCEPT_ALL);
return this.rayPickUnit(x, y, CWidgetFilterFunction.ACCEPT_ALL);
}
public RenderWidget rayPickUnit(final float x, final float y, final CWidgetFilterFunction filter) {
@ -2088,11 +2141,11 @@ public class War3MapViewer extends AbstractMdxModelViewer {
private static final int pow2GreaterThan(final int capacity) {
int numElements = capacity - 1;
numElements |= numElements >>> 1;
numElements |= numElements >>> 2;
numElements |= numElements >>> 4;
numElements |= numElements >>> 8;
numElements |= numElements >>> 16;
return (numElements < 0) ? 1 : (numElements >= MAXIMUM_ACCEPTED) ? MAXIMUM_ACCEPTED : numElements + 1;
numElements |= numElements >>> 2;
numElements |= numElements >>> 4;
numElements |= numElements >>> 8;
numElements |= numElements >>> 16;
return (numElements < 0) ? 1 : (numElements >= MAXIMUM_ACCEPTED) ? MAXIMUM_ACCEPTED : numElements + 1;
}
public void standOnRepeat(final MdxComplexInstance instance) {
@ -2234,7 +2287,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
private static final class QuadtreeIntersectorFindsWalkableRenderHeight
implements QuadtreeIntersector<MdxComplexInstance> {
implements QuadtreeIntersector<MdxComplexInstance> {
private float z;
private final Ray ray = new Ray();
private final Vector3 intersection = new Vector3();
@ -2255,7 +2308,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
private static final class QuadtreeIntersectorFindsHighestWalkable
implements QuadtreeIntersector<MdxComplexInstance> {
implements QuadtreeIntersector<MdxComplexInstance> {
private float z;
private final Ray ray = new Ray();
private final Vector3 intersection = new Vector3();
@ -2331,7 +2384,27 @@ public class War3MapViewer extends AbstractMdxModelViewer {
if (spawnedEffectModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) spawnedEffectModel.addInstance();
modelInstance.setTeamColor(renderUnit.playerIndex);
modelInstance.setLocation(renderUnit.location);
{
final MdxModel model = (MdxModel) renderUnit.instance.model;
int index = -1;
for (int i = 0; i < model.attachments.size(); i++) {
final Attachment attachment = model.attachments.get(i);
if (attachment.getName().startsWith(attachPointName)) {
index = i;
break;
}
}
if (index != -1) {
modelInstance.detach();
final MdxNode attachment = renderUnit.instance.getAttachment(index);
modelInstance.setParent(attachment);
modelInstance.setLocation(0, 0, 0);
}
else {
// TODO This is not consistent with War3, is it? Should look nice though.
modelInstance.setLocation(renderUnit.location);
}
}
modelInstance.setScene(War3MapViewer.this.worldScene);
final RenderSpellEffect renderAttackInstant = new RenderSpellEffect(modelInstance, War3MapViewer.this,
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing()),

View File

@ -13,10 +13,13 @@ import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
public class RenderSpellEffect implements RenderEffect {
public static final PrimaryTag[] DEFAULT_ANIMATION_QUEUE = { PrimaryTag.BIRTH, PrimaryTag.STAND, PrimaryTag.DEATH };
public static final PrimaryTag[] STAND_ONLY = { PrimaryTag.STAND };
public static final PrimaryTag[] DEATH_ONLY = { PrimaryTag.DEATH };
private final MdxComplexInstance modelInstance;
private final PrimaryTag[] animationQueue;
private PrimaryTag[] animationQueue;
private int animationQueueIndex;
private final List<Sequence> sequences;
private boolean killWhenDone = true;
public RenderSpellEffect(final MdxComplexInstance modelInstance, final War3MapViewer war3MapViewer, final float yaw,
final PrimaryTag[] animationQueue) {
@ -24,7 +27,7 @@ public class RenderSpellEffect implements RenderEffect {
this.animationQueue = animationQueue;
final MdxModel model = (MdxModel) this.modelInstance.model;
this.sequences = model.getSequences();
this.modelInstance.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
this.modelInstance.setSequenceLoopMode(SequenceLoopMode.MODEL_LOOP);
this.modelInstance.localRotation.setFromAxisRad(0, 0, 1, yaw);
this.modelInstance.sequenceEnded = true;
playNextAnimation();
@ -33,11 +36,22 @@ public class RenderSpellEffect implements RenderEffect {
@Override
public boolean updateAnimations(final War3MapViewer war3MapViewer, final float deltaTime) {
playNextAnimation();
final boolean everythingDone = this.animationQueueIndex >= this.animationQueue.length;
if (everythingDone) {
war3MapViewer.worldScene.removeInstance(this.modelInstance);
if (this.killWhenDone) {
final boolean everythingDone = this.animationQueueIndex >= this.animationQueue.length;
if (everythingDone) {
if (this.modelInstance.parent != null) {
this.modelInstance.setParent(null);
}
war3MapViewer.worldScene.removeInstance(this.modelInstance);
}
return everythingDone;
}
else {
this.animationQueueIndex = 0;
playNextAnimation();
;
return false;
}
return everythingDone;
}
private void playNextAnimation() {
@ -50,4 +64,10 @@ public class RenderSpellEffect implements RenderEffect {
this.animationQueueIndex++;
}
}
public void setAnimations(final PrimaryTag[] animations, final boolean killWhenDone) {
this.animationQueue = animations;
this.animationQueueIndex = 0;
this.killWhenDone = killWhenDone;
}
}

View File

@ -2,14 +2,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Random;
import java.util.*;
import com.badlogic.gdx.math.Rectangle;
import com.etheller.interpreter.ast.scope.GlobalScope;
@ -49,6 +42,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.timers.CTimer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.enumtypes.CPlayerSlotState;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderComponent;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
@ -87,6 +81,7 @@ public class CSimulation implements CPlayerAPI {
private final List<TimeOfDayVariableEvent> timeOfDayVariableEvents = new ArrayList<>();
private boolean timeOfDaySuspended;
private boolean daytime;
private Set<CDestructable> ownedTreeSet = new HashSet<>();
public CSimulation(final War3MapConfig config, final DataTable miscData, final MutableObjectData parsedUnitData,
final MutableObjectData parsedItemData, final MutableObjectData parsedDestructableData,
@ -121,7 +116,7 @@ public class CSimulation implements CPlayerAPI {
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
final CBasePlayer configPlayer = config.getPlayer(i);
final War3MapConfigStartLoc startLoc = config.getStartLoc(configPlayer.getStartLocationIndex());
final CRace defaultRace = CRace.NIGHTELF;
final CRace defaultRace = CRace.ORC;
final CPlayer newPlayer = new CPlayer(defaultRace, new float[] { startLoc.getX(), startLoc.getY() },
configPlayer);
if (WarsmashConstants.LOCAL_TEMP_TEST_ALL_PLAYERS_PLAYING) {
@ -524,6 +519,14 @@ public class CSimulation implements CPlayerAPI {
this.simulationRenderController.spawnAbilitySoundEffect(caster, alias);
}
public void unitLoopSoundEffectEvent(final CUnit caster, final War3ID alias) {
this.simulationRenderController.loopAbilitySoundEffect(caster, alias);
}
public void unitStopSoundEffectEvent(final CUnit caster, final War3ID alias) {
this.simulationRenderController.stopAbilitySoundEffect(caster, alias);
}
public void unitPreferredSelectionReplacement(final CUnit unit, final CUnit newUnit) {
this.simulationRenderController.unitPreferredSelectionReplacement(unit, newUnit);
}
@ -564,6 +567,22 @@ public class CSimulation implements CPlayerAPI {
cItem.setLife(this, 0);
}
public SimulationRenderComponent createSpellEffectOverDestructable(CUnit source, CDestructable target, War3ID alias, float artAttachmentHeight) {
return simulationRenderController.createSpellEffectOverDestructable(source, target, alias, artAttachmentHeight);
}
public void tagTreeOwned(CDestructable target) {
ownedTreeSet.add(target);
}
public void untagTreeOwned(CDestructable target) {
ownedTreeSet.remove(target);
}
public boolean isTreeOwned(CDestructable tree) {
return ownedTreeSet.contains(tree);
}
private static final class TimeOfDayVariableEvent extends VariableEvent {
private final GlobalScope globalScope;

View File

@ -0,0 +1,155 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable;
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.generic.AbstractGenericSingleIconActiveAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.harvest.CBehaviorWispHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
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 java.util.EnumSet;
public class CAbilityWispHarvest extends AbstractGenericSingleIconActiveAbility {
public static final EnumSet<CTargetType> TREE_ALIVE_TYPE_ONLY = EnumSet.of(CTargetType.TREE, CTargetType.ALIVE);
private int lumberPerInterval;
private float artAttachmentHeight;
private float castRange;
private float periodicIntervalLength;
private int periodicIntervalLengthTicks;
private CBehaviorWispHarvest behaviorWispHarvest;
public CAbilityWispHarvest(final int handleId, final War3ID alias, final int lumberPerInterval, float artAttachmentHeight,
float castRange, final float periodicIntervalLength) {
super(handleId, alias);
this.lumberPerInterval = lumberPerInterval;
this.artAttachmentHeight = artAttachmentHeight;
this.castRange = castRange;
this.periodicIntervalLength = periodicIntervalLength;
this.periodicIntervalLengthTicks = (int)(periodicIntervalLength / WarsmashConstants.SIMULATION_STEP_TIME);
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
this.behaviorWispHarvest = new CBehaviorWispHarvest(unit, this);
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public void onTick(final CSimulation game, final CUnit unit) {
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
return this.behaviorWispHarvest.reset(target);
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId,
final AbilityPointTarget point) {
return caster.pollNextOrderBehavior(game);
}
@Override
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
return caster.pollNextOrderBehavior(game);
}
@Override
public int getBaseOrderId() {
return isToggleOn() ? OrderIds.returnresources : OrderIds.wispharvest;
}
@Override
public boolean isToggleOn() {
return false;
}
@Override
protected void innerCheckCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.useOk();
}
@Override
protected void innerCheckCanTarget(final CSimulation game, final CUnit unit, final int orderId,
final CWidget target, final AbilityTargetCheckReceiver<CWidget> receiver) {
if (target instanceof CDestructable) {
if (target.canBeTargetedBy(game, unit, TREE_ALIVE_TYPE_ONLY)) {
receiver.targetOk(target);
}
else {
receiver.mustTargetResources();
}
}
else {
receiver.mustTargetResources();
}
}
@Override
protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId,
final CWidget target, final AbilityTargetCheckReceiver<CWidget> receiver) {
innerCheckCanTarget(game, unit, orderId, target, receiver);
}
@Override
protected void innerCheckCanTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
protected void innerCheckCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
if ((orderId == OrderIds.returnresources) && isToggleOn()) {
receiver.targetOk(null);
}
else {
receiver.orderIdNotAccepted();
}
}
public float getArtAttachmentHeight() {
return artAttachmentHeight;
}
public float getPeriodicIntervalLength() {
return periodicIntervalLength;
}
public int getPeriodicIntervalLengthTicks() {
return periodicIntervalLengthTicks;
}
public int getLumberPerInterval() {
return lumberPerInterval;
}
public float getCastRange() {
return castRange;
}
@Override
public void onCancelFromQueue(final CSimulation game, final CUnit unit, final int orderId) {
}
}

View File

@ -0,0 +1,39 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.CAbilityTypeDefinition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl.CAbilityTypeHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl.CAbilityTypeWispHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl.CAbilityTypeWispHarvestLevelData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import java.util.EnumSet;
import java.util.List;
public class CAbilityTypeDefinitionWispHarvest extends AbstractCAbilityTypeDefinition<CAbilityTypeWispHarvestLevelData>
implements CAbilityTypeDefinition {
protected static final War3ID LUMBER_PER_INTERVAL = War3ID.fromString("Wha1");
// protected static final War3ID MAYBE_UNUSED = War3ID.fromString("Wha2");
protected static final War3ID ART_ATTACHMENT_HEIGHT = War3ID.fromString("Wha3");
@Override
protected CAbilityTypeWispHarvestLevelData createLevelData(final MutableGameObject abilityEditorData, final int level) {
final String targetsAllowedAtLevelString = abilityEditorData.getFieldAsString(TARGETS_ALLOWED, level);
final EnumSet<CTargetType> targetsAllowedAtLevel = CTargetType.parseTargetTypeSet(targetsAllowedAtLevelString);
final int lumberPerInterval = abilityEditorData.getFieldAsInteger(LUMBER_PER_INTERVAL, level);
final float artAttachmentHeight = abilityEditorData.getFieldAsFloat(ART_ATTACHMENT_HEIGHT, level);
final float castRange = abilityEditorData.getFieldAsFloat(CAST_RANGE, level);
final float duration = abilityEditorData.getFieldAsFloat(DURATION, level);
return new CAbilityTypeWispHarvestLevelData(targetsAllowedAtLevel, lumberPerInterval, artAttachmentHeight,
castRange, duration);
}
@Override
protected CAbilityType<?> innerCreateAbilityType(final War3ID alias, final MutableGameObject abilityEditorData,
final List<CAbilityTypeWispHarvestLevelData> levelData) {
return new CAbilityTypeWispHarvest(alias, abilityEditorData.getCode(), levelData);
}
}

View File

@ -0,0 +1,25 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityWispHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
import java.util.List;
public class CAbilityTypeWispHarvest extends CAbilityType<CAbilityTypeWispHarvestLevelData> {
public CAbilityTypeWispHarvest(final War3ID alias, final War3ID code,
final List<CAbilityTypeWispHarvestLevelData> levelData) {
super(alias, code, levelData);
}
@Override
public CAbility createAbility(final int handleId) {
final CAbilityTypeWispHarvestLevelData levelData = getLevelData(0);
return new CAbilityWispHarvest(handleId, getAlias(), levelData.getLumberPerInterval(), levelData.getArtAttachmentHeight(),
levelData.getCastRange(), levelData.getDuration());
}
}

View File

@ -0,0 +1,39 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityTypeLevelData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import java.util.EnumSet;
public class CAbilityTypeWispHarvestLevelData extends CAbilityTypeLevelData {
private final int lumberPerInterval;
private final float artAttachmentHeight;
private final float castRange;
private final float duration;
public CAbilityTypeWispHarvestLevelData(final EnumSet<CTargetType> targetsAllowed, final int lumberPerInterval,
float artAttachmentHeight, final float castRange, final float duration) {
super(targetsAllowed);
this.lumberPerInterval = lumberPerInterval;
this.artAttachmentHeight = artAttachmentHeight;
this.castRange = castRange;
this.duration = duration;
}
public int getLumberPerInterval() {
return lumberPerInterval;
}
public float getArtAttachmentHeight() {
return artAttachmentHeight;
}
public float getCastRange() {
return this.castRange;
}
public float getDuration() {
return this.duration;
}
}

View File

@ -9,6 +9,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityReturnResources;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityWispHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.mine.CAbilityGoldMine;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetStillAliveVisitor;

View File

@ -0,0 +1,154 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.harvest;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable;
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.harvest.CAbilityWispHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetStillAliveVisitor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderComponent;
public class CBehaviorWispHarvest extends CAbstractRangedBehavior {
private int lastIncomeTick;
private final CAbilityWispHarvest abilityWispHarvest;
private boolean harvesting = false;
private SimulationRenderComponent spellEffectOverDestructable;
public CBehaviorWispHarvest(CUnit unit, CAbilityWispHarvest abilityWispHarvest) {
super(unit);
this.abilityWispHarvest = abilityWispHarvest;
}
public CBehaviorWispHarvest reset(final CWidget target) {
innerReset(target, false);
return this;
}
@Override
protected CBehavior update(CSimulation simulation, boolean withinFacingWindow) {
if(target.getX() != unit.getX() || target.getY() != unit.getY()) {
unit.setX(target.getX(), simulation.getWorldCollision(), simulation.getRegionManager());
unit.setY(target.getY(), simulation.getWorldCollision(), simulation.getRegionManager());
simulation.unitRepositioned(unit); // dont interpolate, instant jump
}
int gameTurnTick = simulation.getGameTurnTick();
if (gameTurnTick - lastIncomeTick >= abilityWispHarvest.getPeriodicIntervalLengthTicks()) {
lastIncomeTick = gameTurnTick;
final CPlayer player = simulation.getPlayer(this.unit.getPlayerIndex());
player.setLumber(player.getLumber() + this.abilityWispHarvest.getLumberPerInterval());
simulation.unitGainResourceEvent(this.unit, ResourceType.LUMBER,
abilityWispHarvest.getLumberPerInterval());
}
if(!harvesting) {
onStartHarvesting(simulation);
harvesting = true;
}
return this;
}
private void onStartHarvesting(CSimulation simulation) {
unit.getUnitAnimationListener().addSecondaryTag(AnimationTokens.SecondaryTag.LUMBER);
simulation.unitLoopSoundEffectEvent(unit, abilityWispHarvest.getAlias());
// TODO maybe use visitor instead of cast
spellEffectOverDestructable = simulation.createSpellEffectOverDestructable(this.unit, (CDestructable) this.target, abilityWispHarvest.getAlias(), abilityWispHarvest.getArtAttachmentHeight());
simulation.tagTreeOwned((CDestructable)target);
}
private void onStopHarvesting(CSimulation simulation) {
unit.getUnitAnimationListener().removeSecondaryTag(AnimationTokens.SecondaryTag.LUMBER);
simulation.unitStopSoundEffectEvent(unit, abilityWispHarvest.getAlias());
simulation.untagTreeOwned((CDestructable)target);
// TODO maybe use visitor instead of cast
if(spellEffectOverDestructable != null) {
spellEffectOverDestructable.remove();
spellEffectOverDestructable = null;
}
}
@Override
protected CBehavior updateOnInvalidTarget(CSimulation simulation) {
if (this.target instanceof CDestructable) {
// wood
if(harvesting) {
onStopHarvesting(simulation);
harvesting = false;
}
final CDestructable nearestTree = findNearestTree(this.unit, this.abilityWispHarvest,
simulation, this.unit);
if (nearestTree != null) {
return reset(nearestTree);
}
}
return this.unit.pollNextOrderBehavior(simulation);
}
@Override
protected boolean checkTargetStillValid(CSimulation simulation) {
if(this.target instanceof CDestructable) {
if(!harvesting && simulation.isTreeOwned((CDestructable)this.target)) {
return false;
}
}
return this.target.visit(AbilityTargetStillAliveVisitor.INSTANCE);
}
@Override
protected void resetBeforeMoving(CSimulation simulation) {
if(harvesting) {
onStopHarvesting(simulation);
harvesting = false;
}
}
@Override
public boolean isWithinRange(CSimulation simulation) {
return this.unit.canReach(this.target, 0);
}
@Override
public void endMove(CSimulation game, boolean interrupted) {
}
@Override
public void begin(CSimulation game) {
}
@Override
public void end(CSimulation game, boolean interrupted) {
if(harvesting) {
onStopHarvesting(game);
harvesting = false;
}
}
@Override
public int getHighlightOrderId() {
return OrderIds.wispharvest;
}
public static CDestructable findNearestTree(final CUnit worker, final CAbilityWispHarvest abilityHarvest,
final CSimulation simulation, final CWidget toObject) {
CDestructable nearestMine = null;
double nearestMineDistance = abilityHarvest.getCastRange()*abilityHarvest.getCastRange();
for (final CDestructable unit : simulation.getDestructables()) {
if (!unit.isDead()
&& !simulation.isTreeOwned(unit)
&& unit.canBeTargetedBy(simulation, worker, CAbilityWispHarvest.TREE_ALIVE_TYPE_ONLY)) {
final double distance = unit.distanceSquaredNoCollision(toObject);
if (distance < nearestMineDistance) {
nearestMineDistance = distance;
nearestMine = unit;
}
}
}
return nearestMine;
}
}

View File

@ -10,22 +10,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityGeneric;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.CAbilityTypeDefinition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionChannelTest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionCoupleInstant;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionGoldMine;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHarvestLumber;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHumanRepair;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionInventory;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionInvulnerable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemAttackBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemDefenseBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemHeal;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemLifeBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemPermanentStatGain;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemStatBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionReturnResources;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.*;
public class CAbilityData {
@ -44,6 +29,7 @@ public class CAbilityData {
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Agld"), new CAbilityTypeDefinitionGoldMine());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Artn"), new CAbilityTypeDefinitionReturnResources());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Ahar"), new CAbilityTypeDefinitionHarvest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Awha"), new CAbilityTypeDefinitionWispHarvest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Ahrl"), new CAbilityTypeDefinitionHarvestLumber());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("ANcl"), new CAbilityTypeDefinitionChannelTest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("AInv"), new CAbilityTypeDefinitionInventory());

View File

@ -0,0 +1,5 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
public interface SimulationRenderComponent {
void remove();
}

View File

@ -67,10 +67,15 @@ public interface SimulationRenderController {
void spawnAbilitySoundEffect(CUnit caster, War3ID alias);
void loopAbilitySoundEffect(CUnit caster, War3ID alias);
void stopAbilitySoundEffect(CUnit caster, War3ID alias);
void unitPreferredSelectionReplacement(CUnit unit, CUnit newUnit);
void heroRevived(CUnit trainedUnit);
void heroDeathEvent(CUnit cUnit);
SimulationRenderComponent createSpellEffectOverDestructable(CUnit source, CDestructable target, War3ID alias, float artAttachmentHeight);
}

View File

@ -171,6 +171,11 @@ public class CommandCardIcon extends AbstractRenderableFrame implements Clickabl
}
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
}
@Override
public void mouseDown(final GameUI gameUI, final Viewport uiViewport) {
this.iconFrame.setWidth(this.defaultWidth * 0.95f);

View File

@ -3511,6 +3511,12 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
this.lastMouseClickLocation.set(clickLocationTemp);
}
else {
if (this.mouseDownUIFrame != null) {
this.mouseDownUIFrame.mouseDragged(this.rootFrame, this.uiViewport, screenCoordsVector.x,
screenCoordsVector.y);
}
}
}
return false;
}

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
@ -484,6 +485,7 @@ public class MenuUI {
// Create skirmish UI
this.skirmish = this.rootFrame.createFrame("Skirmish", this.rootFrame, 0, 0);
this.skirmish.setVisible(false);
this.mapInfoButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("MapInfoButton", 0);
this.advancedOptionsButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("AdvancedOptionsButton", 0);
this.mapInfoPanel = this.rootFrame.getFrameByName("MapInfoPanel", 0);
@ -497,6 +499,42 @@ public class MenuUI {
advancedOptionsPaneContainer.add(this.skirmishAdvancedOptionsPane);
this.skirmishMapInfoPane = new MapInfoPane(this.rootFrame, mapInfoPaneContainer);
final GlueTextButtonFrame playGameButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("PlayGameButton",
0);
final SimpleFrame mapListContainer = (SimpleFrame) this.rootFrame.getFrameByName("MapListContainer", 0);
final ListBoxFrame mapListBox = (ListBoxFrame) this.rootFrame.createFrameByType("LISTBOX", "MapListBox",
mapListContainer, "WITHCHILDREN", 0);
mapListBox.setSetAllPoints(true);
mapListBox.setFrameFont(profileListText.getFrameFont());
final Collection<String> listfile = this.dataSource.getListfile();
for (final String file : listfile) {
if ((file.toLowerCase().endsWith(".w3x") || file.toLowerCase().endsWith(".w3m")) && !file.contains("/")
&& !file.contains("\\")) {
mapListBox.addItem(file, this.rootFrame, this.uiViewport);
}
}
mapListContainer.add(mapListBox);
playGameButton.setOnClick(new Runnable() {
@Override
public void run() {
final String selectedItem = mapListBox.getSelectedItem();
if (selectedItem != null) {
MenuUI.this.campaignMenu.setVisible(false);
MenuUI.this.campaignBackButton.setVisible(false);
MenuUI.this.missionSelectFrame.setVisible(false);
MenuUI.this.campaignSelectFrame.setVisible(false);
MenuUI.this.campaignWarcraftIIILogo.setVisible(false);
MenuUI.this.campaignRootMenuUI.setVisible(false);
MenuUI.this.currentMissionSelectMenuUI.setVisible(false);
MenuUI.this.skirmish.setVisible(false);
MenuUI.this.glueSpriteLayerTopLeft.setSequence("SinglePlayerSkirmish Birth");
MenuUI.this.glueSpriteLayerTopRight.setSequence("SinglePlayerSkirmish Birth");
MenuUI.this.mapFilepathToStart = selectedItem;
}
}
});
this.skirmishCancelButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CancelButton", 0);
this.skirmishCancelButton.setOnClick(new Runnable() {
@Override
@ -1038,7 +1076,12 @@ public class MenuUI {
}
public boolean touchDragged(final int screenX, final int screenY, final float worldScreenY, final int pointer) {
mouseMoved(screenX, screenY, worldScreenY);
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
if (this.mouseDownUIFrame != null) {
this.mouseDownUIFrame.mouseDragged(this.rootFrame, this.uiViewport, screenCoordsVector.x,
screenCoordsVector.y);
}
return false;
}
@ -1053,9 +1096,7 @@ public class MenuUI {
}
if (mousedUIFrame instanceof ClickableFrame) {
this.mouseOverUIFrame = (ClickableFrame) mousedUIFrame;
if (this.mouseOverUIFrame != null) {
this.mouseOverUIFrame.mouseEnter(this.rootFrame, this.uiViewport);
}
this.mouseOverUIFrame.mouseEnter(this.rootFrame, this.uiViewport);
}
else {
this.mouseOverUIFrame = null;

View File

@ -87,6 +87,11 @@ public class MultiSelectionIcon extends AbstractRenderableFrame implements Click
this.clickListener.multiSelectIconClicked(this.queueIconIndexId);
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
}
@Override
public void setWidth(final float width) {
this.defaultWidth = width;

View File

@ -74,6 +74,11 @@ public class QueueIcon extends AbstractRenderableFrame implements ClickableActio
this.clickListener.queueIconClicked(this.queueIconIndexId);
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
}
@Override
public void setWidth(final float width) {
this.defaultWidth = width;

View File

@ -0,0 +1,315 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import java.io.IOException;
import java.io.InputStream;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
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.math.Vector2;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.SingleModelScreen;
import com.etheller.warsmash.WarsmashGdxMultiScreenGame;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.custom.WTS;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.util.WorldEditStrings;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.ClickableFrame;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.FocusableFrame;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.sound.KeyedSounds;
public class TestUI {
private static final Vector2 screenCoordsVector = new Vector2();
private static boolean ENABLE_NOT_YET_IMPLEMENTED_BUTTONS = false;
private final DataSource dataSource;
private final Scene uiScene;
private final Viewport uiViewport;
private final MdxViewer viewer;
private final RootFrameListener rootFrameListener;
private final float widthRatioCorrection;
private final float heightRatioCorrection;
private GameUI rootFrame;
private SpriteFrame cursorFrame;
private ClickableFrame mouseDownUIFrame;
private ClickableFrame mouseOverUIFrame;
private FocusableFrame focusUIFrame;
private WorldEditStrings worldEditStrings;
private DataTable uiSoundsTable;
private KeyedSounds uiSounds;
private final WarsmashGdxMultiScreenGame screenManager;
private final DataTable warsmashIni;
private final SingleModelScreen menuScreen;
private UIFrame main;
private final String customTOC;
public TestUI(final DataSource dataSource, final Viewport uiViewport, final Scene uiScene, final MdxViewer viewer,
final WarsmashGdxMultiScreenGame screenManager, final SingleModelScreen menuScreen,
final DataTable warsmashIni, final RootFrameListener rootFrameListener, final String customTOC) {
this.dataSource = dataSource;
this.uiViewport = uiViewport;
this.uiScene = uiScene;
this.viewer = viewer;
this.screenManager = screenManager;
this.menuScreen = menuScreen;
this.warsmashIni = warsmashIni;
this.rootFrameListener = rootFrameListener;
this.customTOC = customTOC;
this.widthRatioCorrection = this.getMinWorldWidth() / 1600f;
this.heightRatioCorrection = this.getMinWorldHeight() / 1200f;
}
public float getHeightRatioCorrection() {
return this.heightRatioCorrection;
}
/**
* Called "main" because this was originally written in JASS so that maps could
* override it, and I may convert it back to the JASS at some point.
*/
public void main() {
// =================================
// Load skins and templates
// =================================
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, WarsmashConstants.GAME_VERSION),
this.uiViewport, this.uiScene, this.viewer, 0, WTS.DO_NOTHING);
this.rootFrameListener.onCreate(this.rootFrame);
try {
this.rootFrame.loadTOCFile(this.customTOC);
}
catch (final IOException exc) {
throw new IllegalStateException(this.customTOC);
}
// Create main menu
this.main = this.rootFrame.createFrame("Main", this.rootFrame, 0, 0);
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);
if (WarsmashConstants.CATCH_CURSOR) {
Gdx.input.setCursorCatched(true);
}
// position all
this.rootFrame.positionBounds(this.rootFrame, this.uiViewport);
this.loadSounds();
}
private static String getStringWithWTS(final WTS wts, String string) {
if (string.startsWith("TRIGSTR_")) {
string = wts.get(Integer.parseInt(string.substring(8)));
}
return string;
}
public void resize() {
}
public void render(final SpriteBatch batch, final GlyphLayout glyphLayout) {
final BitmapFont font = this.rootFrame.getFont();
final BitmapFont font20 = this.rootFrame.getFont20();
font.setColor(Color.YELLOW);
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
glyphLayout.setText(font, fpsString);
font.draw(batch, fpsString, (this.getMinWorldWidth() - glyphLayout.width) / 2,
1100 * this.heightRatioCorrection);
this.rootFrame.render(batch, font20, glyphLayout);
}
private float getMinWorldWidth() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldWidth();
}
return this.uiViewport.getWorldWidth();
}
private float getMinWorldHeight() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldHeight();
}
return this.uiViewport.getWorldHeight();
}
public void update(final float deltaTime) {
if ((this.focusUIFrame != null) && !this.focusUIFrame.isVisibleOnScreen()) {
this.setFocusFrame(this.getNextFocusFrame());
}
final int baseMouseX = Gdx.input.getX();
int mouseX = baseMouseX;
final int baseMouseY = Gdx.input.getY();
int mouseY = baseMouseY;
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();
mouseX = Math.max(minX, Math.min(maxX, mouseX));
mouseY = Math.max(minY, Math.min(maxY, mouseY));
if (Gdx.input.isCursorCatched()) {
if (WarsmashConstants.CATCH_CURSOR) {
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);
this.cursorFrame.setSequence("Normal");
}
private FocusableFrame getNextFocusFrame() {
return this.rootFrame.getNextFocusFrame();
}
public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
final UIFrame clickedUIFrame = this.rootFrame.touchDown(screenCoordsVector.x, screenCoordsVector.y, button);
if (clickedUIFrame != null) {
if (clickedUIFrame instanceof ClickableFrame) {
this.mouseDownUIFrame = (ClickableFrame) clickedUIFrame;
this.mouseDownUIFrame.mouseDown(this.rootFrame, this.uiViewport);
}
if (clickedUIFrame instanceof FocusableFrame) {
final FocusableFrame clickedFocusableFrame = (FocusableFrame) clickedUIFrame;
if (clickedFocusableFrame.isFocusable()) {
this.setFocusFrame(clickedFocusableFrame);
}
}
}
return false;
}
private void setFocusFrame(final FocusableFrame clickedFocusableFrame) {
if (this.focusUIFrame != null) {
this.focusUIFrame.onFocusLost();
}
this.focusUIFrame = clickedFocusableFrame;
if (this.focusUIFrame != null) {
this.focusUIFrame.onFocusGained();
}
}
public boolean touchUp(final int screenX, final int screenY, final float worldScreenY, final int button) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
final UIFrame clickedUIFrame = this.rootFrame.touchUp(screenCoordsVector.x, screenCoordsVector.y, button);
if (this.mouseDownUIFrame != null) {
if (clickedUIFrame == this.mouseDownUIFrame) {
this.mouseDownUIFrame.onClick(button);
this.uiSounds.getSound("GlueScreenClick").play(this.uiScene.audioContext, 0, 0, 0);
}
this.mouseDownUIFrame.mouseUp(this.rootFrame, this.uiViewport);
}
this.mouseDownUIFrame = null;
return false;
}
public boolean touchDragged(final int screenX, final int screenY, final float worldScreenY, final int pointer) {
this.mouseMoved(screenX, screenY, worldScreenY);
return false;
}
public boolean mouseMoved(final int screenX, final int screenY, final float worldScreenY) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
final UIFrame mousedUIFrame = this.rootFrame.getFrameChildUnderMouse(screenCoordsVector.x,
screenCoordsVector.y);
if (mousedUIFrame != this.mouseOverUIFrame) {
if (this.mouseOverUIFrame != null) {
this.mouseOverUIFrame.mouseExit(this.rootFrame, this.uiViewport);
}
if (mousedUIFrame instanceof ClickableFrame) {
this.mouseOverUIFrame = (ClickableFrame) mousedUIFrame;
if (this.mouseOverUIFrame != null) {
this.mouseOverUIFrame.mouseEnter(this.rootFrame, this.uiViewport);
}
}
else {
this.mouseOverUIFrame = null;
}
}
return false;
}
private void loadSounds() {
this.worldEditStrings = new WorldEditStrings(this.dataSource);
this.uiSoundsTable = new DataTable(this.worldEditStrings);
try {
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("UI\\SoundInfo\\UISounds.slk")) {
this.uiSoundsTable.readSLK(miscDataTxtStream);
}
try (InputStream miscDataTxtStream = this.dataSource
.getResourceAsStream("UI\\SoundInfo\\AmbienceSounds.slk")) {
this.uiSoundsTable.readSLK(miscDataTxtStream);
}
}
catch (final IOException e) {
e.printStackTrace();
}
this.uiSounds = new KeyedSounds(this.uiSoundsTable, this.dataSource);
}
public KeyedSounds getUiSounds() {
return this.uiSounds;
}
public void hide() {
}
public void dispose() {
if (this.rootFrame != null) {
this.rootFrame.dispose();
}
}
public boolean keyDown(final int keycode) {
if (this.focusUIFrame != null) {
this.focusUIFrame.keyDown(keycode);
}
return false;
}
public boolean keyUp(final int keycode) {
if (this.focusUIFrame != null) {
this.focusUIFrame.keyUp(keycode);
}
return false;
}
public boolean keyTyped(final char character) {
if (this.focusUIFrame != null) {
this.focusUIFrame.keyTyped(character);
}
return false;
}
}

View File

@ -14,4 +14,6 @@ public interface ClickableFrame extends UIFrame {
void mouseExit(final GameUI gameUI, final Viewport uiViewport);
void onClick(int button);
void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y);
}

View File

@ -91,6 +91,11 @@ public class CampaignButtonUI extends AbstractUIFrame implements ClickableFrame
this.buttonArt.onClick(button);
}
@Override
public void mouseDragged(GameUI rootFrame, Viewport uiViewport, float x, float y) {
}
public void setHeaderText(final StringFrame headerText) {
this.headerText = headerText;
this.defaultHeaderColor = headerText.getColor();

View File

@ -37,19 +37,19 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
this.parentId = reader.readInt32();
this.flags = reader.readInt32();
readTimelines(reader, size - 96);
this.readTimelines(reader, size - 96);
}
@Override
public void writeMdx(final BinaryWriter writer, final int version) {
writer.writeUInt32(getGenericByteLength(version));
writer.writeUInt32(this.getGenericByteLength(version));
writer.writeWithNulls(this.name, 80);
writer.writeInt32(this.objectId);
writer.writeInt32(this.parentId);
writer.writeInt32(this.flags);
for (final MdlxTimeline<?> timeline : this.timelines) {
if (isGeneric(timeline)) {
if (this.isGeneric(timeline)) {
timeline.writeMdx(writer);
}
}
@ -57,7 +57,7 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
public void writeNonGenericAnimationChunks(final BinaryWriter writer) {
for (final MdlxTimeline<?> timeline : this.timelines) {
if (!isGeneric(timeline)) {
if (!this.isGeneric(timeline)) {
timeline.writeMdx(writer);
}
}
@ -65,7 +65,7 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
protected final Iterable<String> readMdlGeneric(final MdlTokenInputStream stream) {
this.name = stream.read();
return () -> new WrappedMdlTokenIterator(readAnimatedBlock(stream), MdlxGenericObject.this, stream);
return () -> new WrappedMdlTokenIterator(this.readAnimatedBlock(stream), MdlxGenericObject.this, stream);
}
public void writeGenericHeader(final MdlTokenOutputStream stream) {
@ -95,7 +95,7 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
stream.writeFlag(MdlUtils.TOKEN_CAMERA_ANCHORED);
}
if ((this.flags & 0x2) != 0) {
if ((this.flags & 0x4) != 0) {
stream.writeFlag(MdlUtils.TOKEN_DONT_INHERIT + " { " + MdlUtils.TOKEN_ROTATION + " }");
}
@ -103,22 +103,22 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
stream.writeFlag(MdlUtils.TOKEN_DONT_INHERIT + " { " + MdlUtils.TOKEN_TRANSLATION + " }");
}
if ((this.flags & 0x4) != 0) {
if ((this.flags & 0x2) != 0) {
stream.writeFlag(MdlUtils.TOKEN_DONT_INHERIT + " { " + MdlUtils.TOKEN_SCALING + " }");
}
}
public void writeGenericTimelines(final MdlTokenOutputStream stream) {
writeTimeline(stream, AnimationMap.KGTR);
writeTimeline(stream, AnimationMap.KGRT);
writeTimeline(stream, AnimationMap.KGSC);
this.writeTimeline(stream, AnimationMap.KGTR);
this.writeTimeline(stream, AnimationMap.KGRT);
this.writeTimeline(stream, AnimationMap.KGSC);
}
public long getGenericByteLength(final int version) {
long size = 96;
for (final MdlxTimeline<?> timeline : this.timelines) {
if (isGeneric(timeline)) {
if (this.isGeneric(timeline)) {
size += timeline.getByteLength();
}
}
@ -186,7 +186,7 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
@Override
public boolean hasNext() {
if (this.delegate.hasNext()) {
this.next = read();
this.next = this.read();
this.hasLoaded = true;
return this.next != null;
}
@ -196,7 +196,7 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
@Override
public String next() {
if (!this.hasLoaded) {
this.next = read();
this.next = this.read();
}
this.hasLoaded = false;
return this.next;
@ -242,13 +242,13 @@ public abstract class MdlxGenericObject extends MdlxAnimatedObject {
for (final String subToken : this.stream.readBlock()) {
switch (subToken) {
case MdlUtils.TOKEN_ROTATION:
this.updatingObject.flags |= 0x2;
this.updatingObject.flags |= 0x4;
break;
case MdlUtils.TOKEN_TRANSLATION:
this.updatingObject.flags |= 0x1;
break;
case MdlUtils.TOKEN_SCALING:
this.updatingObject.flags |= 0x0;
this.updatingObject.flags |= 0x2;
break;
}
}

View File

@ -13,6 +13,7 @@ import java.io.PrintStream;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL31;
import org.lwjgl.opengl.GL32;
@ -24,6 +25,7 @@ import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.backends.lwjgl.LwjglNativesLoader;
import com.etheller.warsmash.WarsmashGdxFDFTestRenderScreen;
import com.etheller.warsmash.WarsmashGdxMenuScreen;
import com.etheller.warsmash.WarsmashGdxMultiScreenGame;
import com.etheller.warsmash.audio.OpenALSound;
@ -104,11 +106,17 @@ public class DesktopLauncher {
Gdx.app.postRunnable(new Runnable() {
@Override
public void run() {
final WarsmashGdxMenuScreen menuScreen = new WarsmashGdxMenuScreen(warsmashIni,
warsmashGdxMultiScreenGame);
warsmashGdxMultiScreenGame.setScreen(menuScreen);
if (finalFileToLoad != null) {
menuScreen.startMap(finalFileToLoad);
if ((finalFileToLoad != null) && finalFileToLoad.toLowerCase().endsWith(".toc")) {
warsmashGdxMultiScreenGame.setScreen(new WarsmashGdxFDFTestRenderScreen(warsmashIni,
warsmashGdxMultiScreenGame, finalFileToLoad));
}
else {
final WarsmashGdxMenuScreen menuScreen = new WarsmashGdxMenuScreen(warsmashIni,
warsmashGdxMultiScreenGame);
warsmashGdxMultiScreenGame.setScreen(menuScreen);
if (finalFileToLoad != null) {
menuScreen.startMap(finalFileToLoad);
}
}
}
});
@ -188,7 +196,7 @@ public class DesktopLauncher {
@Override
public AudioContext createContext(final boolean world) {
Listener listener;
if (world) {
if (world && AL.isCreated()) {
listener = new Listener() {
private float x;
private float y;

View File

@ -1,5 +1,8 @@
package com.etheller.interpreter.ast;
import java.util.Collections;
import java.util.List;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
@ -8,6 +11,11 @@ import org.antlr.v4.runtime.Recognizer;
import com.etheller.interpreter.JassLexer;
import com.etheller.interpreter.JassParser;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.StringJassValueVisitor;
import com.etheller.interpreter.ast.visitors.JassProgramVisitor;
public class JassRunner {
@ -19,8 +27,19 @@ public class JassRunner {
return;
}
final JassProgramVisitor jassProgramVisitor = new JassProgramVisitor();
jassProgramVisitor.getJassNativeManager().createNative("BJDebugMsg", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
for (final JassValue argument : arguments) {
System.out.println(argument.visit(StringJassValueVisitor.getInstance()));
}
return null;
}
});
for (final String arg : args) {
try {
jassProgramVisitor.setCurrentFileName(arg);
final JassLexer lexer = new JassLexer(CharStreams.fromFileName(arg));
final JassParser parser = new JassParser(new CommonTokenStream(lexer));
parser.addErrorListener(new BaseErrorListener() {
@ -41,10 +60,13 @@ public class JassRunner {
}
});
jassProgramVisitor.visit(parser.program());
} catch (final Exception e) {
}
catch (final Exception e) {
e.printStackTrace();
}
}
jassProgramVisitor.getGlobals().getFunctionByName("main").call(Collections.emptyList(),
jassProgramVisitor.getGlobals(), null);
}
}

View File

@ -3,6 +3,7 @@ package com.etheller.interpreter.ast.expression;
import java.util.ArrayList;
import java.util.List;
import com.etheller.interpreter.ast.debug.JassException;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
@ -23,7 +24,7 @@ public class FunctionCallJassExpression implements JassExpression {
final TriggerExecutionScope triggerScope) {
final JassFunction functionByName = globalScope.getFunctionByName(this.functionName);
if (functionByName == null) {
throw new RuntimeException("Undefined function: " + this.functionName);
throw new JassException(globalScope, "Undefined function: " + this.functionName, new RuntimeException());
}
final List<JassValue> evaluatedExpressions = new ArrayList<>();
for (final JassExpression expr : this.arguments) {
@ -34,7 +35,7 @@ public class FunctionCallJassExpression implements JassExpression {
return functionByName.call(evaluatedExpressions, globalScope, triggerScope);
}
catch (final Exception exc) {
throw new RuntimeException("Function call by name failed for name: " + this.functionName, exc);
throw new JassException(globalScope, "Function call by name failed for name: " + this.functionName, exc);
}
}