mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Merge
This commit is contained in:
commit
01f22540a2
@ -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() {
|
||||
}
|
||||
}
|
@ -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)) {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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
@ -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) {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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()),
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
|
||||
|
||||
public interface SimulationRenderComponent {
|
||||
void remove();
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user