Damage and armor UI and attack animation fixes

This commit is contained in:
Retera 2020-09-04 08:29:37 -04:00
parent 5abb9e3fd9
commit bf16b4f698
75 changed files with 3638 additions and 3091 deletions

View File

@ -1,13 +1,15 @@
[DataSources]
Count=4
Count=5
Type00=Folder
Path00="E:\Backups\Warcraft\Data\127"
Path00="E:\Backups\Warcraft III 1.30 but dead\War3mod.mpq"
Type01=Folder
Path01="..\..\resources"
Path01="E:\Backups\Warcraft\Data\127"
Type02=Folder
Path02="E:\Backups\Warsmash\Data"
Path02="..\..\resources"
Type03=Folder
Path03="."
Path03="E:\Backups\Warsmash\Data"
Type04=Folder
Path04="."
[Map]
FilePath="RuinedGround.w3x"
FilePath="PitchRoll.w3x"

View File

@ -38,7 +38,6 @@ import com.etheller.warsmash.datasources.DataSourceDescriptor;
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
import com.etheller.warsmash.datasources.MpqDataSourceDescriptor;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.jass.Jass2;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
@ -52,15 +51,19 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.ReplaceableIds;
import com.etheller.warsmash.viewer5.handlers.tga.TgaFile;
import com.etheller.warsmash.viewer5.handlers.w3x.StandSequence;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSoundset.UnitAckSound;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.CommandCardIcon;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityStop;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
private static final float HORIZONTAL_MAXIMUM = (float) Math.toRadians(56);
private static final float HORIZONTAL_MINIMUM = (float) -Math.toRadians(56);
private static final double HORIZONTAL_ANGLE_INCREMENT = Math.PI / 60;
private static final Vector3 clickLocationTemp = new Vector3();
private static final Vector2 clickLocationTemp2 = new Vector2();
private DataSource codebase;
@ -68,10 +71,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private CameraManager cameraManager;
private final Rectangle tempRect = new Rectangle();
private CameraManager portraitCameraManager;
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
// libGDX stuff
private OrthographicCamera uiCamera;
private BitmapFont font;
@ -82,8 +81,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private GlyphLayout glyphLayout;
private Texture consoleUITexture;
private final Vector2 projectionTemp1 = new Vector2();
private final Vector2 projectionTemp2 = new Vector2();
private RenderUnit selectedUnit;
private int selectedSoundCount = 0;
@ -165,17 +162,11 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1); // TODO remove white background
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
this.portraitScene = this.viewer.addSimpleScene();
this.portraitCameraManager = new CameraManager();
this.portraitCameraManager.setupCamera(this.portraitScene);
this.uiScene = this.viewer.addSimpleScene();
this.uiScene.alpha = true;
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3D_exp\\MainMenu3D_exp.mdx",
this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48));
// libGDX stuff
final float w = Gdx.graphics.getWidth();
final float h = Gdx.graphics.getHeight();
@ -196,7 +187,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.font24 = fontGenerator.generateFont(fontParam);
fontParam.size = 20;
this.font20 = fontGenerator.generateFont(fontParam);
fontGenerator.dispose();
this.glyphLayout = new GlyphLayout();
// Constructs a new OrthographicCamera, using the given viewport width and
@ -209,8 +199,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.uiCamera.position.set(this.uiCamera.viewportWidth / 2f, this.uiCamera.viewportHeight / 2f, 0);
this.uiCamera.update();
positionPortrait();
this.batch = new SpriteBatch();
// this.consoleUITexture = new Texture(new DataSourceFileHandle(this.viewer.dataSource, "AlphaUi.png"));
@ -273,12 +261,22 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.shapeRenderer = new ShapeRenderer();
this.talentTreeWindow = new Rectangle(100, 300, 1400, 800);
Jass2.loadJUI(this.codebase, this.uiViewport, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
WarsmashGdxMapGame.this.gameUI = rootFrame;
}
}, "Scripts\\common.jui", "Scripts\\melee.jui");
// Jass2.loadJUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, this.viewer,
// new RootFrameListener() {
// @Override
// public void onCreate(final GameUI rootFrame) {
// WarsmashGdxMapGame.this.gameUI = rootFrame;
// }
// }, "Scripts\\common.jui", "Scripts\\melee.jui");
this.meleeUI = new MeleeUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, this.viewer,
new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
}
});
this.meleeUI.main();
fontGenerator.dispose();
}
@Override
@ -292,7 +290,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.viewer.terrain.getGroundHeight(this.cameraManager.target.x, this.cameraManager.target.y),
this.viewer.terrain.getWaterHeight(this.cameraManager.target.x, this.cameraManager.target.y)) - 256;
this.cameraManager.updateCamera();
this.portraitCameraManager.updateCamera();
this.meleeUI.updatePortrait();
this.viewer.updateAndRender();
// gl.glDrawElements(GL20.GL_TRIANGLES, this.elements, GL20.GL_UNSIGNED_SHORT, this.faceOffset);
@ -301,12 +299,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
// this.font.draw(this.batch, Integer.toString(Gdx.graphics.getFramesPerSecond()), 0, 0);
// this.batch.end();
if ((this.portraitCameraManager.modelInstance != null)
&& (this.portraitCameraManager.modelInstance.sequenceEnded
|| (this.portraitCameraManager.modelInstance.sequence == -1))) {
StandSequence.randomPortraitSequence(this.portraitCameraManager.modelInstance);
}
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
Gdx.gl30.glDisable(GL30.GL_CULL_FACE);
@ -317,7 +309,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.uiViewport.apply();
this.batch.setProjectionMatrix(this.uiCamera.combined);
this.batch.begin();
this.gameUI.render(this.batch);
this.meleeUI.render(this.batch, this.font20, this.glyphLayout);
this.font.setColor(Color.YELLOW);
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
this.glyphLayout.setText(this.font, fpsString);
@ -428,25 +420,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.uiScene.camera.viewport(this.tempRect);
this.uiScene.camera.ortho(0f, 0.8f, 0f, 0.6f, -1f, 1);
positionPortrait();
this.meleeUI.resize();
}
private void positionPortrait() {
this.projectionTemp1.x = 422;
this.projectionTemp1.y = 57;
this.projectionTemp2.x = 422 + 167;
this.projectionTemp2.y = 57 + 170;
this.uiViewport.project(this.projectionTemp1);
this.uiViewport.project(this.projectionTemp2);
this.tempRect.x = this.projectionTemp1.x;
this.tempRect.y = this.projectionTemp1.y;
this.tempRect.width = this.projectionTemp2.x - this.projectionTemp1.x;
this.tempRect.height = this.projectionTemp2.y - this.projectionTemp1.y;
this.portraitScene.camera.viewport(this.tempRect);
}
class CameraManager {
public static class CameraManager {
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
public com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
private MdxComplexInstance modelInstance;
private CanvasProvider canvas;
@ -456,6 +435,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private float zoomFactor;
private float horizontalAngle;
private float verticalAngle;
private float verticalAngleAcceleration;
private float distance;
private Vector3 position;
private Vector3 target;
@ -463,17 +443,19 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private Vector3 vecHeap;
private Quaternion quatHeap;
private Quaternion quatHeap2;
private boolean insertDown;
private boolean deleteDown;
// 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) {
public void setupCamera(final Scene scene) {
this.canvas = scene.viewer.canvas;
this.camera = scene.camera;
this.moveSpeed = 2;
this.rotationSpeed = (float) (Math.PI / 180);
this.rotationSpeed = (float) HORIZONTAL_ANGLE_INCREMENT;
this.zoomFactor = 0.1f;
this.horizontalAngle = 0;// (float) (Math.PI / 2);
this.verticalAngle = (float) Math.toRadians(34);
@ -490,10 +472,45 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
// cameraUpdate();
}
private void updateCamera() {
public void updateCamera() {
this.quatHeap.idt();
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
if (this.insertDown && !this.deleteDown) {
this.horizontalAngle -= HORIZONTAL_ANGLE_INCREMENT;
if (this.horizontalAngle < HORIZONTAL_MINIMUM) {
this.horizontalAngle = HORIZONTAL_MINIMUM;
}
}
else if (this.deleteDown && !this.insertDown) {
this.horizontalAngle += HORIZONTAL_ANGLE_INCREMENT;
if (this.horizontalAngle > HORIZONTAL_MAXIMUM) {
this.horizontalAngle = HORIZONTAL_MAXIMUM;
}
}
else {
if (Math.abs(this.horizontalAngle) < HORIZONTAL_ANGLE_INCREMENT) {
this.horizontalAngle = 0;
}
else {
this.horizontalAngle -= HORIZONTAL_ANGLE_INCREMENT * Math.signum(this.horizontalAngle);
}
}
this.quatHeap2.idt();
this.verticalAngle += this.verticalAngleAcceleration;
this.verticalAngleAcceleration *= 0.975f;
if (this.verticalAngle > ((Math.PI / 2) - Math.toRadians(17))) {
this.verticalAngle = (float) ((Math.PI / 2) - Math.toRadians(17));
if (this.verticalAngleAcceleration > 0) {
this.verticalAngleAcceleration = 0;
}
}
if (this.verticalAngle < (float) Math.toRadians(34)) {
this.verticalAngle = (float) Math.toRadians(34);
if (this.verticalAngleAcceleration < 0) {
this.verticalAngleAcceleration = 0;
}
}
this.quatHeap2.setFromAxisRad(1, 0, 0, this.verticalAngle);
this.quatHeap.mul(this.quatHeap2);
@ -502,18 +519,16 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.position.scl(this.distance);
this.position = this.position.add(this.target);
if (this.modelCamera != null) {
this.modelCamera.getPositionTranslation(WarsmashGdxMapGame.this.cameraPositionTemp,
this.modelInstance.sequence, this.modelInstance.frame, this.modelInstance.counter);
this.modelCamera.getTargetTranslation(WarsmashGdxMapGame.this.cameraTargetTemp,
this.modelInstance.sequence, this.modelInstance.frame, this.modelInstance.counter);
this.modelCamera.getPositionTranslation(this.cameraPositionTemp, this.modelInstance.sequence,
this.modelInstance.frame, this.modelInstance.counter);
this.modelCamera.getTargetTranslation(this.cameraTargetTemp, this.modelInstance.sequence,
this.modelInstance.frame, this.modelInstance.counter);
this.position.set(this.modelCamera.position);
this.target.set(this.modelCamera.targetPosition);
this.position.add(WarsmashGdxMapGame.this.cameraPositionTemp[0],
WarsmashGdxMapGame.this.cameraPositionTemp[1], WarsmashGdxMapGame.this.cameraPositionTemp[2]);
this.target.add(WarsmashGdxMapGame.this.cameraTargetTemp[0],
WarsmashGdxMapGame.this.cameraTargetTemp[1], WarsmashGdxMapGame.this.cameraTargetTemp[2]);
this.position.add(this.cameraPositionTemp[0], this.cameraPositionTemp[1], this.cameraPositionTemp[2]);
this.target.add(this.cameraTargetTemp[0], this.cameraTargetTemp[1], this.cameraTargetTemp[2]);
this.camera.perspective(this.modelCamera.fieldOfView * 0.75f, this.camera.getAspect(),
this.modelCamera.nearClippingPlane, this.modelCamera.farClippingPlane);
}
@ -524,6 +539,16 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.camera.moveToAndFace(this.position, this.target, this.worldUp);
}
public void setModelInstance(final MdxComplexInstance modelInstance, final MdxModel portraitModel) {
this.modelInstance = modelInstance;
if (modelInstance == null) {
this.modelCamera = null;
}
else if ((portraitModel != null) && (portraitModel.getCameras().size() > 0)) {
this.modelCamera = portraitModel.getCameras().get(0);
}
}
// private void cameraUpdate() {
//
// }
@ -531,11 +556,10 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private final float cameraSpeed = 4096.0f; // per second
private final Vector2 cameraVelocity = new Vector2();
private Scene portraitScene;
private Texture minimapTexture;
private Rectangle talentTreeWindow;
private GameUI gameUI;
private Scene uiScene;
private MeleeUI meleeUI;
@Override
public boolean keyDown(final int keycode) {
@ -551,6 +575,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
else if (keycode == Input.Keys.UP) {
this.cameraVelocity.y = this.cameraSpeed;
}
else if (keycode == Input.Keys.INSERT) {
this.cameraManager.insertDown = true;
}
else if (keycode == Input.Keys.FORWARD_DEL) {
this.cameraManager.deleteDown = true;
}
return true;
}
@ -568,6 +598,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
else if (keycode == Input.Keys.UP) {
this.cameraVelocity.y = 0;
}
else if (keycode == Input.Keys.INSERT) {
this.cameraManager.insertDown = false;
}
else if (keycode == Input.Keys.FORWARD_DEL) {
this.cameraManager.deleteDown = false;
}
return true;
}
@ -613,7 +649,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
if ((rayPickUnit != null) && (this.selectedUnit != null)
&& (rayPickUnit.playerIndex != this.selectedUnit.playerIndex)) {
if (this.viewer.orderSmart(rayPickUnit)) {
StandSequence.randomPortraitTalkSequence(this.portraitCameraManager.modelInstance);
this.meleeUI.portraitTalk();
this.selectedSoundCount = 0;
}
}
@ -626,7 +662,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
System.out.println(x + "," + y);
this.viewer.terrain.logRomp(x, y);
if (this.viewer.orderSmart(clickLocationTemp.x, clickLocationTemp.y)) {
StandSequence.randomPortraitTalkSequence(this.portraitCameraManager.modelInstance);
this.meleeUI.portraitTalk();
this.selectedSoundCount = 0;
}
}
@ -662,32 +698,15 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
}
}
if (selectionChanged) {
final MdxModel portraitModel = unit.portraitModel;
if (portraitModel != null) {
if (this.portraitCameraManager.modelInstance != null) {
this.portraitScene.removeInstance(this.portraitCameraManager.modelInstance);
}
this.portraitCameraManager.modelInstance = (MdxComplexInstance) portraitModel.addInstance();
this.portraitCameraManager.modelInstance.setSequenceLoopMode(1);
this.portraitCameraManager.modelInstance.setScene(this.portraitScene);
this.portraitCameraManager.modelInstance.setVertexColor(unit.instance.vertexColor);
if (portraitModel.getCameras().size() > 0) {
this.portraitCameraManager.modelCamera = portraitModel.getCameras().get(0);
}
this.portraitCameraManager.modelInstance.setTeamColor(unit.playerIndex);
}
this.meleeUI.selectUnit(unit);
}
if (playedNewSound) {
StandSequence.randomPortraitTalkSequence(this.portraitCameraManager.modelInstance);
this.meleeUI.portraitTalk();
}
}
else {
this.selectedUnit = null;
if (this.portraitCameraManager.modelInstance != null) {
this.portraitScene.removeInstance(this.portraitCameraManager.modelInstance);
}
this.portraitCameraManager.modelInstance = null;
this.portraitCameraManager.modelCamera = null;
this.meleeUI.selectUnit(null);
}
}
return false;
@ -710,12 +729,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
@Override
public boolean scrolled(final int amount) {
this.cameraManager.verticalAngle -= amount / 10.f;
if (this.cameraManager.verticalAngle > (Math.PI / 2)) {
this.cameraManager.verticalAngle = (float) Math.PI / 2;
this.cameraManager.verticalAngleAcceleration -= amount / 100.f;
if (this.cameraManager.verticalAngleAcceleration > (Math.PI / 128)) {
this.cameraManager.verticalAngleAcceleration = (float) (Math.PI / 128);
}
if (this.cameraManager.verticalAngle < (float) Math.toRadians(34)) {
this.cameraManager.verticalAngle = (float) Math.toRadians(34);
if (this.cameraManager.verticalAngleAcceleration < (-Math.PI / 128)) {
this.cameraManager.verticalAngleAcceleration = -(float) (Math.PI / 128);
}
return true;
}

View File

@ -7,43 +7,66 @@ import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.fdfparser.FDFParser;
import com.etheller.warsmash.fdfparser.FrameDefinitionVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FontDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FrameClass;
import com.etheller.warsmash.parsers.fdf.datamodel.FrameDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FrameTemplateEnvironment;
import com.etheller.warsmash.parsers.fdf.datamodel.SetPointDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
import com.etheller.warsmash.parsers.fdf.frames.AbstractUIFrame;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.StringBundle;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
public final class GameUI extends AbstractUIFrame implements UIFrame {
private final DataSource dataSource;
private final Element skin;
private final Viewport viewport;
private final Scene uiScene;
private final War3MapViewer modelViewer;
private final FrameTemplateEnvironment templates;
private final Map<String, Texture> pathToTexture = new HashMap<>();
private final boolean autoPosition = false;
private final FreeTypeFontGenerator fontGenerator;
private final FreeTypeFontParameter fontParam;
private final Map<String, UIFrame> nameToFrame = new HashMap<>();
private final Viewport fdfCoordinateResolutionDummyViewport;
public GameUI(final DataSource dataSource, final Element skin, final Viewport viewport) {
public GameUI(final DataSource dataSource, final Element skin, final Viewport viewport,
final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final War3MapViewer modelViewer) {
super("GameUI", null);
this.dataSource = dataSource;
this.skin = skin;
this.viewport = viewport;
this.uiScene = uiScene;
this.modelViewer = modelViewer;
this.renderBounds.set(0, 0, viewport.getWorldWidth(), viewport.getWorldHeight());
this.templates = new FrameTemplateEnvironment();
this.fontGenerator = fontGenerator;
this.fontParam = new FreeTypeFontParameter();
this.fdfCoordinateResolutionDummyViewport = new FitViewport(0.8f, 0.6f);
}
public static Element loadSkin(final DataSource dataSource, final String skin) {
@ -67,6 +90,27 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return userSkin;
}
public static Element loadSkin(final DataSource dataSource, final int skinIndex) {
final DataTable skinsTable = new DataTable(StringBundle.EMPTY);
try (InputStream stream = dataSource.getResourceAsStream("UI\\war3skins.txt")) {
skinsTable.readTXT(stream, true);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
final Element main = skinsTable.get("Main");
final String skinsField = main.getField("Skins");
final String[] skins = skinsField.split(",");
final Element defaultSkin = skinsTable.get("Default");
final Element userSkin = skinsTable.get(skins[skinIndex]);
for (final String key : defaultSkin.keySet()) {
if (!userSkin.hasField(key)) {
userSkin.setField(key, defaultSkin.getField(key));
}
}
return userSkin;
}
public void loadTOCFile(final String tocFilePath) throws IOException {
final DataSourceFDFParserBuilder dataSourceFDFParserBuilder = new DataSourceFDFParserBuilder(this.dataSource);
final FrameDefinitionVisitor fdfVisitor = new FrameDefinitionVisitor(this.templates,
@ -85,14 +129,20 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
}
}
public UIFrame createFrame(final String name, final UIFrame owner, final int priority, final int createContext) {
throw new UnsupportedOperationException("Not yet implemented");
public String getSkinField(String file) {
if ((file != null) && this.skin.hasField(file)) {
file = this.skin.getField(file);
}
else {
throw new IllegalStateException("Decorated file name lookup not available: " + file);
}
return file;
}
public UIFrame createSimpleFrame(final String name, final UIFrame owner, final int createContext) {
public UIFrame createFrame(final String name, final UIFrame owner, final int priority, final int createContext) {
final FrameDefinition frameDefinition = this.templates.getFrame(name);
if (frameDefinition.getFrameClass() == FrameClass.Frame) {
if ("SIMPLEFRAME".equals(frameDefinition.getFrameType())) {
if ("SPRITE".equals(frameDefinition.getFrameType())) {
final UIFrame inflated = inflate(frameDefinition, owner, null);
if (this.autoPosition) {
inflated.positionBounds(this.viewport);
@ -101,67 +151,150 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return inflated;
}
}
throw new UnsupportedOperationException("Not yet implemented");
}
public UIFrame createSimpleFrame(final String name, final UIFrame owner, final int createContext) {
final FrameDefinition frameDefinition = this.templates.getFrame(name);
if (frameDefinition.getFrameClass() == FrameClass.Frame) {
final UIFrame inflated = inflate(frameDefinition, owner, null);
if (this.autoPosition) {
inflated.positionBounds(this.viewport);
}
add(inflated);
return inflated;
}
return null;
}
public UIFrame inflate(final FrameDefinition frameDefinition, final UIFrame parent,
final FrameDefinition parentDefinitionIfAvailable) {
UIFrame inflatedFrame = null;
BitmapFont frameFont = null;
Viewport viewport2 = this.viewport;
switch (frameDefinition.getFrameClass()) {
case Frame:
if ("SIMPLEFRAME".equals(frameDefinition.getFrameType())) {
final SimpleFrame simpleFrame = new SimpleFrame(frameDefinition.getName(), parent);
// TODO: we should not need to put ourselves in this map 2x
this.nameToFrame.put(frameDefinition.getName(), simpleFrame);
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
simpleFrame.add(inflate(childDefinition, simpleFrame, frameDefinition));
}
inflatedFrame = simpleFrame;
}
else if ("SPRITE".equals(frameDefinition.getFrameType())) {
final SpriteFrame spriteFrame = new SpriteFrame(frameDefinition.getName(), parent, this.uiScene);
String backgroundArt = frameDefinition.getString("BackgroundArt");
if (frameDefinition.has("DecorateFileNames") || ((parentDefinitionIfAvailable != null)
&& parentDefinitionIfAvailable.has("DecorateFileNames"))) {
if (this.skin.hasField(backgroundArt)) {
backgroundArt = this.skin.getField(backgroundArt);
}
else {
throw new IllegalStateException("Decorated file name lookup not available: " + backgroundArt);
}
}
if (backgroundArt.toLowerCase().endsWith(".mdl") || backgroundArt.toLowerCase().endsWith(".mdx")) {
backgroundArt = backgroundArt.substring(0, backgroundArt.length() - 4);
}
backgroundArt += ".mdx";
final MdxModel model = (MdxModel) this.modelViewer.load(backgroundArt, this.modelViewer.mapPathSolver,
this.modelViewer.solverParams);
spriteFrame.setModel(model);
spriteFrame.setSequence(0);
viewport2 = this.fdfCoordinateResolutionDummyViewport;
inflatedFrame = spriteFrame;
}
break;
case Layer:
// NOT HANDLED YET
break;
case String:
break;
case Texture:
String file = frameDefinition.getString("File");
if (frameDefinition.has("DecorateFileNames") || ((parentDefinitionIfAvailable != null)
&& parentDefinitionIfAvailable.has("DecorateFileNames"))) {
if (this.skin.hasField(file)) {
file = this.skin.getField(file);
}
else {
throw new IllegalStateException("Decorated file name lookup not available: " + file);
}
final Float textLength = frameDefinition.getFloat("TextLength");
TextJustify justifyH = frameDefinition.getTextJustify("FontJustificationH");
if (justifyH == null) {
justifyH = TextJustify.CENTER;
}
final Texture texture = loadTexture(file);
final Vector4Definition texCoord = frameDefinition.getVector4("TexCoord");
final TextureRegion texRegion;
if (texCoord != null) {
texRegion = new TextureRegion(texture, texCoord.getX(), texCoord.getZ(), texCoord.getY(),
texCoord.getW());
TextJustify justifyV = frameDefinition.getTextJustify("FontJustificationV");
if (justifyV == null) {
justifyV = TextJustify.MIDDLE;
}
Color fontColor;
final Vector4Definition fontColorDefinition = frameDefinition.getVector4("FontColor");
if (fontColorDefinition == null) {
fontColor = Color.WHITE;
}
else {
texRegion = new TextureRegion(texture);
fontColor = new Color(fontColorDefinition.getX(), fontColorDefinition.getY(),
fontColorDefinition.getZ(), fontColorDefinition.getW());
}
final TextureFrame textureFrame = new TextureFrame(frameDefinition.getName(), parent, texRegion);
final FontDefinition font = frameDefinition.getFont("Font");
this.fontParam.size = (int) convertY(viewport2, font.getFontSize());
if (this.fontParam.size == 0) {
this.fontParam.size = 24;
}
frameFont = this.fontGenerator.generateFont(this.fontParam);
final StringFrame stringFrame = new StringFrame(frameDefinition.getName(), parent, fontColor, justifyH,
justifyV, frameFont);
inflatedFrame = stringFrame;
String text = frameDefinition.getString("Text");
if (text != null) {
final String decoratedString = this.templates.getDecoratedString(text);
if (decoratedString != text) {
text = decoratedString;
}
stringFrame.setText(text);
}
break;
case Texture:
final String file = frameDefinition.getString("File");
final boolean decorateFileNames = frameDefinition.has("DecorateFileNames")
|| ((parentDefinitionIfAvailable != null) && parentDefinitionIfAvailable.has("DecorateFileNames"));
final Vector4Definition texCoord = frameDefinition.getVector4("TexCoord");
final TextureFrame textureFrame = new TextureFrame(frameDefinition.getName(), parent, decorateFileNames,
texCoord);
textureFrame.setTexture(file, this);
inflatedFrame = textureFrame;
break;
default:
break;
}
if (inflatedFrame != null) {
final Float width = frameDefinition.getFloat("Width");
if (frameDefinition.has("SetAllPoints")) {
inflatedFrame.setSetAllPoints(true);
}
Float width = frameDefinition.getFloat("Width");
if (width != null) {
inflatedFrame.setWidth(convertX(this.viewport, width));
inflatedFrame.setWidth(convertX(viewport2, width));
}
else {
width = frameDefinition.getFloat("TextLength");
if (width != null) {
if (frameFont != null) {
inflatedFrame.setWidth(convertX(viewport2, width * frameFont.getSpaceWidth()));
}
}
}
final Float height = frameDefinition.getFloat("Height");
if (height != null) {
inflatedFrame.setHeight(convertY(this.viewport, height));
inflatedFrame.setHeight(convertY(viewport2, height));
}
else if (frameDefinition.getFont("Font") != null) {
inflatedFrame.setHeight(convertY(viewport2, frameDefinition.getFont("Font").getFontSize()));
}
for (final AnchorDefinition anchor : frameDefinition.getAnchors()) {
inflatedFrame.addAnchor(new AnchorDefinition(anchor.getMyPoint(),
convertX(this.viewport, anchor.getX()), convertY(this.viewport, anchor.getY())));
inflatedFrame.addAnchor(new AnchorDefinition(anchor.getMyPoint(), convertX(viewport2, anchor.getX()),
convertY(viewport2, anchor.getY())));
}
for (final SetPointDefinition setPointDefinition : frameDefinition.getSetPoints()) {
inflatedFrame.addSetPoint(new SetPoint(setPointDefinition.getMyPoint(),
getFrameByName(setPointDefinition.getOther(), 0 /* TODO: createContext */),
setPointDefinition.getOtherPoint(), convertX(viewport2, setPointDefinition.getX()),
convertY(viewport2, setPointDefinition.getY())));
}
this.nameToFrame.put(frameDefinition.getName(), inflatedFrame);
}
else {
// TODO in production throw some kind of exception here
@ -174,6 +307,10 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
throw new UnsupportedOperationException("Not yet implemented");
}
public UIFrame getFrameByName(final String name, final int createContext) {
return this.nameToFrame.get(name);
}
public static float convertX(final Viewport viewport, final float fdfX) {
return (fdfX / 0.8f) * viewport.getWorldWidth();
}
@ -182,7 +319,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
return (fdfY / 0.6f) * viewport.getWorldHeight();
}
private Texture loadTexture(String path) {
public Texture loadTexture(String path) {
if (!path.contains(".")) {
path = path + ".blp";
}

View File

@ -3,28 +3,41 @@ package com.etheller.warsmash.parsers.fdf.frames;
import java.util.ArrayList;
import java.util.List;
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.Rectangle;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
public abstract class AbstractRenderableFrame implements UIFrame {
private static final boolean DEBUG_LOG = true;
protected String name;
protected UIFrame parent;
protected boolean visible;
protected boolean visible = true;
protected int level;
protected final Rectangle renderBounds = new Rectangle(0, 0, 0, 0); // in libgdx rendering space
protected List<AnchorDefinition> anchors = new ArrayList<>();
protected List<SetPoint> setPoints = new ArrayList<>();
private boolean setAllPoints;
public AbstractRenderableFrame(final String name, final UIFrame parent) {
this.name = name;
this.parent = parent;
}
@Override
public void setSetAllPoints(final boolean setAllPoints) {
this.setAllPoints = setAllPoints;
}
@Override
public void setWidth(final float width) {
this.renderBounds.width = width;
}
@Override
public void setHeight(final float height) {
this.renderBounds.height = height;
}
@ -133,6 +146,7 @@ public abstract class AbstractRenderableFrame implements UIFrame {
}
}
@Override
public void setFramePointX(final FramePoint framePoint, final float x) {
if (this.renderBounds.width == 0) {
this.renderBounds.x = x;
@ -192,6 +206,7 @@ public abstract class AbstractRenderableFrame implements UIFrame {
}
}
@Override
public void setFramePointY(final FramePoint framePoint, final float y) {
if (this.renderBounds.height == 0) {
this.renderBounds.y = y;
@ -235,6 +250,11 @@ public abstract class AbstractRenderableFrame implements UIFrame {
this.anchors.add(anchorDefinition);
}
@Override
public void addSetPoint(final SetPoint setPointDefinition) {
this.setPoints.add(setPointDefinition);
}
@Override
public void positionBounds(final Viewport viewport) {
if (this.parent == null) {
@ -244,7 +264,7 @@ public abstract class AbstractRenderableFrame implements UIFrame {
if ("ResourceBarFrame".equals(this.name)) {
System.out.println("doing resource bar");
}
if (this.anchors.isEmpty()) {
if (this.anchors.isEmpty() && this.setPoints.isEmpty()) {
this.renderBounds.x = this.parent.getFramePointX(FramePoint.LEFT);
this.renderBounds.y = this.parent.getFramePointY(FramePoint.BOTTOM);
}
@ -254,19 +274,35 @@ public abstract class AbstractRenderableFrame implements UIFrame {
final float parentPointY = this.parent.getFramePointY(anchor.getMyPoint());
setFramePointX(anchor.getMyPoint(), parentPointX + anchor.getX());
setFramePointY(anchor.getMyPoint(), parentPointY + anchor.getY());
System.out.println(getClass().getSimpleName() + ":" + this.name + " anchoring to: " + anchor);
if (DEBUG_LOG) {
System.out.println(getClass().getSimpleName() + ":" + this.name + " anchoring to: " + anchor);
}
}
for (final SetPoint setPoint : this.setPoints) {
final UIFrame other = setPoint.getOther();
if (other == null) {
continue;
}
final float parentPointX = other.getFramePointX(setPoint.getOtherPoint());
final float parentPointY = other.getFramePointY(setPoint.getOtherPoint());
setFramePointX(setPoint.getMyPoint(), parentPointX + setPoint.getX());
setFramePointY(setPoint.getMyPoint(), parentPointY + setPoint.getY());
}
}
if (this.renderBounds.width == 0) {
this.renderBounds.width = this.parent.getFramePointX(FramePoint.RIGHT)
- this.parent.getFramePointX(FramePoint.LEFT);
if (this.setAllPoints) {
if (this.renderBounds.width == 0) {
this.renderBounds.width = this.parent.getFramePointX(FramePoint.RIGHT)
- this.parent.getFramePointX(FramePoint.LEFT);
}
if (this.renderBounds.height == 0) {
this.renderBounds.height = this.parent.getFramePointY(FramePoint.TOP)
- this.parent.getFramePointY(FramePoint.BOTTOM);
}
}
if (this.renderBounds.height == 0) {
this.renderBounds.height = this.parent.getFramePointY(FramePoint.TOP)
- this.parent.getFramePointY(FramePoint.BOTTOM);
if (DEBUG_LOG) {
System.out.println(
getClass().getSimpleName() + ":" + this.name + " finishing position bounds: " + this.renderBounds);
}
System.out.println(
getClass().getSimpleName() + ":" + this.name + " finishing position bounds: " + this.renderBounds);
innerPositionBounds(viewport);
}
@ -280,6 +316,7 @@ public abstract class AbstractRenderableFrame implements UIFrame {
return this.level;
}
@Override
public void setVisible(final boolean visible) {
this.visible = visible;
}
@ -288,4 +325,13 @@ public abstract class AbstractRenderableFrame implements UIFrame {
this.level = level;
}
@Override
public final void render(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
if (this.visible) {
internalRender(batch, baseFont, glyphLayout);
}
}
protected abstract void internalRender(SpriteBatch batch, BitmapFont baseFont, GlyphLayout glyphLayout);
}

View File

@ -3,6 +3,8 @@ package com.etheller.warsmash.parsers.fdf.frames;
import java.util.ArrayList;
import java.util.List;
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;
@ -21,9 +23,9 @@ public abstract class AbstractUIFrame extends AbstractRenderableFrame implements
}
@Override
public void render(final SpriteBatch batch) {
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
for (final UIFrame childFrame : this.childFrames) {
childFrame.render(batch);
childFrame.render(batch, baseFont, glyphLayout);
}
}

View File

@ -0,0 +1,40 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
public class SetPoint {
private final FramePoint myPoint;
private final UIFrame other;
private final FramePoint otherPoint;
private final float x;
private final float y;
public SetPoint(final FramePoint myPoint, final UIFrame other, final FramePoint otherPoint, final float x,
final float y) {
this.myPoint = myPoint;
this.other = other;
this.otherPoint = otherPoint;
this.x = x;
this.y = y;
}
public FramePoint getMyPoint() {
return this.myPoint;
}
public UIFrame getOther() {
return this.other;
}
public FramePoint getOtherPoint() {
return this.otherPoint;
}
public float getX() {
return this.x;
}
public float getY() {
return this.y;
}
}

View File

@ -0,0 +1,52 @@
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.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
public class SpriteFrame extends AbstractRenderableFrame {
private final Scene scene;
private MdxComplexInstance instance;
public SpriteFrame(final String name, final UIFrame parent, final Scene scene) {
super(name, parent);
this.scene = scene;
}
public void setModel(final MdxModel model) {
if (this.instance != null) {
this.scene.removeInstance(this.instance);
}
if (model != null) {
this.instance = (MdxComplexInstance) model.addInstance();
this.instance.setSequenceLoopMode(1);
this.instance.setScene(this.scene);
this.instance.setLocation(this.renderBounds.x, this.renderBounds.y, 0);
}
else {
this.instance = null;
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
}
@Override
protected void innerPositionBounds(final Viewport viewport) {
}
public void setSequence(final int index) {
if (this.instance != null) {
this.instance.setSequence(index);
}
}
}

View File

@ -0,0 +1,72 @@
package com.etheller.warsmash.parsers.fdf.frames;
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.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
public class StringFrame extends AbstractRenderableFrame {
private Color color;
private String text = "Default string";
private final TextJustify justifyH;
private final TextJustify justifyV;
private final BitmapFont frameFont;
public StringFrame(final String name, final UIFrame parent, final Color color, final TextJustify justifyH,
final TextJustify justifyV, final BitmapFont frameFont) {
super(name, parent);
this.color = color;
this.justifyH = justifyH;
this.justifyV = justifyV;
this.frameFont = frameFont;
this.text = name;
}
public void setText(final String text) {
this.text = text;
}
public void setColor(final Color color) {
this.color = color;
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.frameFont.setColor(this.color);
glyphLayout.setText(this.frameFont, this.text);
final float x;
switch (this.justifyH) {
case CENTER:
x = this.renderBounds.x + ((this.renderBounds.width - glyphLayout.width) / 2);
break;
case RIGHT:
x = (this.renderBounds.x + this.renderBounds.width) - glyphLayout.width;
break;
case LEFT:
default:
x = this.renderBounds.x;
break;
}
final float y;
switch (this.justifyV) {
case MIDDLE:
y = this.renderBounds.y + ((this.renderBounds.height + this.frameFont.getLineHeight()) / 2);
break;
case TOP:
y = (this.renderBounds.y + this.renderBounds.height);
break;
case BOTTOM:
default:
y = this.renderBounds.y + this.frameFont.getLineHeight();
break;
}
this.frameFont.draw(batch, this.text, x, y);
}
@Override
protected void innerPositionBounds(final Viewport viewport) {
}
}

View File

@ -1,19 +1,28 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
public class TextureFrame extends AbstractRenderableFrame {
private final TextureRegion texture;
private TextureRegion texture;
private final boolean decorateFileNames;
private final Vector4Definition texCoord;
public TextureFrame(final String name, final UIFrame parent, final TextureRegion texture) {
public TextureFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final Vector4Definition texCoord) {
super(name, parent);
this.texture = texture;
this.decorateFileNames = decorateFileNames;
this.texCoord = texCoord;
}
@Override
public void render(final SpriteBatch batch) {
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
batch.draw(this.texture, this.renderBounds.x, this.renderBounds.y, this.renderBounds.width,
this.renderBounds.height);
}
@ -22,4 +31,27 @@ public class TextureFrame extends AbstractRenderableFrame {
protected void innerPositionBounds(final Viewport viewport) {
}
public void setTexture(String file, final GameUI gameUI) {
if (this.decorateFileNames) {
file = gameUI.getSkinField(file);
}
final Texture texture = gameUI.loadTexture(file);
setTexture(texture);
}
public void setTexture(final Texture texture) {
final TextureRegion texRegion;
if (this.texCoord != null) {
texRegion = new TextureRegion(texture, this.texCoord.getX(), this.texCoord.getZ(), this.texCoord.getY(),
this.texCoord.getW());
}
else {
texRegion = new TextureRegion(texture);
}
this.texture = texRegion;
}
public void setTexture(final TextureRegion texture) {
this.texture = texture;
}
}

View File

@ -1,22 +1,34 @@
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.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
public interface UIFrame {
public void render(SpriteBatch batch);
public void render(SpriteBatch batch, BitmapFont baseFont, GlyphLayout glyphLayout);
public float getFramePointX(FramePoint framePoint);
public float getFramePointY(FramePoint framePoint);
void setFramePointX(final FramePoint framePoint, final float x);
void setFramePointY(final FramePoint framePoint, final float y);
void positionBounds(final Viewport viewport);
void addAnchor(final AnchorDefinition anchorDefinition);
void addSetPoint(SetPoint setPointDefinition);
void setWidth(final float width);
void setHeight(final float height);
void setSetAllPoints(boolean setAllPoints);
void setVisible(boolean visible);
}

View File

@ -9,6 +9,8 @@ import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.interpreter.JassLexer;
import com.etheller.interpreter.JassParser;
@ -20,6 +22,7 @@ import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.StringJassValue;
import com.etheller.interpreter.ast.value.visitor.IntegerJassValueVisitor;
@ -32,6 +35,8 @@ import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.parsers.jass.triggers.BoolExprAnd;
import com.etheller.warsmash.parsers.jass.triggers.BoolExprCondition;
@ -41,16 +46,19 @@ import com.etheller.warsmash.parsers.jass.triggers.BoolExprOr;
import com.etheller.warsmash.parsers.jass.triggers.TriggerAction;
import com.etheller.warsmash.parsers.jass.triggers.TriggerCondition;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
public class Jass2 {
public static final boolean REPORT_SYNTAX_ERRORS = true;
public static JUIEnvironment loadJUI(final DataSource dataSource, final Viewport uiViewport,
final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final War3MapViewer war3MapViewer,
final RootFrameListener rootFrameListener, final String... files) {
final JassProgramVisitor jassProgramVisitor = new JassProgramVisitor();
final JUIEnvironment environment = new JUIEnvironment(jassProgramVisitor, dataSource, uiViewport,
rootFrameListener);
final JUIEnvironment environment = new JUIEnvironment(jassProgramVisitor, dataSource, uiViewport, fontGenerator,
uiScene, war3MapViewer, rootFrameListener);
for (final String jassFile : files) {
try {
JassLexer lexer;
@ -95,7 +103,8 @@ public class Jass2 {
private Element skin;
public JUIEnvironment(final JassProgramVisitor jassProgramVisitor, final DataSource dataSource,
final Viewport uiViewport, final RootFrameListener rootFrameListener) {
final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator, final Scene uiScene,
final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener) {
final GlobalScope globals = jassProgramVisitor.getGlobals();
final HandleJassType frameHandleType = globals.registerHandleType("framehandle");
final HandleJassType framePointType = globals.registerHandleType("framepointtype");
@ -128,7 +137,8 @@ public class Jass2 {
final TriggerExecutionScope triggerScope) {
final String skinArg = arguments.get(0).visit(StringJassValueVisitor.getInstance());
final Element skin = GameUI.loadSkin(dataSource, skinArg);
final GameUI gameUI = new GameUI(dataSource, skin, uiViewport);
final GameUI gameUI = new GameUI(dataSource, skin, uiViewport, fontGenerator, uiScene,
war3MapViewer);
JUIEnvironment.this.gameUI = gameUI;
JUIEnvironment.this.skin = skin;
rootFrameListener.onCreate(gameUI);
@ -163,7 +173,33 @@ public class Jass2 {
return new HandleJassValue(frameHandleType, simpleFrame);
}
});
jassProgramVisitor.getJassNativeManager().createNative("FrameSetAbsPoint", new JassFunction() {
jassProgramVisitor.getJassNativeManager().createNative("CreateFrame", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final String templateName = arguments.get(0).visit(StringJassValueVisitor.getInstance());
final UIFrame ownerFrame = arguments.get(1).visit(ObjectJassValueVisitor.<UIFrame>getInstance());
final int priority = arguments.get(2).visit(IntegerJassValueVisitor.getInstance());
final int createContext = arguments.get(3).visit(IntegerJassValueVisitor.getInstance());
final UIFrame simpleFrame = JUIEnvironment.this.gameUI.createFrame(templateName, ownerFrame,
priority, createContext);
return new HandleJassValue(frameHandleType, simpleFrame);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetFrameByName", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final String templateName = arguments.get(0).visit(StringJassValueVisitor.getInstance());
final int createContext = arguments.get(1).visit(IntegerJassValueVisitor.getInstance());
final UIFrame simpleFrame = JUIEnvironment.this.gameUI.getFrameByName(templateName, createContext);
return new HandleJassValue(frameHandleType, simpleFrame);
}
});
jassProgramVisitor.getJassNativeManager().createNative("FrameSetAnchor", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
@ -178,6 +214,71 @@ public class Jass2 {
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("FrameSetAbsPoint", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final UIFrame frame = arguments.get(0).visit(ObjectJassValueVisitor.<UIFrame>getInstance());
final FramePoint framePoint = arguments.get(1)
.visit(ObjectJassValueVisitor.<FramePoint>getInstance());
final double x = arguments.get(2).visit(RealJassValueVisitor.getInstance());
final double y = arguments.get(3).visit(RealJassValueVisitor.getInstance());
frame.setFramePointX(framePoint, GameUI.convertX(uiViewport, (float) x));
frame.setFramePointY(framePoint, GameUI.convertY(uiViewport, (float) y));
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("FrameSetPoint", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final UIFrame frame = arguments.get(0).visit(ObjectJassValueVisitor.<UIFrame>getInstance());
final FramePoint framePoint = arguments.get(1)
.visit(ObjectJassValueVisitor.<FramePoint>getInstance());
final UIFrame otherFrame = arguments.get(2).visit(ObjectJassValueVisitor.<UIFrame>getInstance());
final FramePoint otherPoint = arguments.get(3)
.visit(ObjectJassValueVisitor.<FramePoint>getInstance());
final double x = arguments.get(2).visit(RealJassValueVisitor.getInstance());
final double y = arguments.get(3).visit(RealJassValueVisitor.getInstance());
frame.addSetPoint(new SetPoint(framePoint, otherFrame, otherPoint,
GameUI.convertX(uiViewport, (float) x), GameUI.convertY(uiViewport, (float) y)));
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("FrameSetText", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final StringFrame frame = arguments.get(0).visit(ObjectJassValueVisitor.<StringFrame>getInstance());
final String text = arguments.get(1).visit(StringJassValueVisitor.getInstance());
frame.setText(text);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("FrameSetTextColor", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final StringFrame frame = arguments.get(0).visit(ObjectJassValueVisitor.<StringFrame>getInstance());
final int colorInt = arguments.get(1).visit(IntegerJassValueVisitor.getInstance());
frame.setColor(new Color(colorInt));
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("ConvertColor", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final int a = arguments.get(0).visit(IntegerJassValueVisitor.getInstance());
final int r = arguments.get(1).visit(IntegerJassValueVisitor.getInstance());
final int g = arguments.get(2).visit(IntegerJassValueVisitor.getInstance());
final int b = arguments.get(3).visit(IntegerJassValueVisitor.getInstance());
return new IntegerJassValue(a | (b << 8) | (g << 16) | (r << 24));
}
});
jassProgramVisitor.getJassNativeManager().createNative("FramePositionBounds", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,

View File

@ -25,7 +25,11 @@ public abstract class AnimatedObject implements Chunk, MdlxBlock {
public void readTimelines(final LittleEndianDataInputStream stream, long size) throws IOException {
while (size > 0) {
final War3ID name = new War3ID(Integer.reverseBytes(stream.readInt()));
final Timeline<?> timeline = AnimationMap.ID_TO_TAG.get(name).getImplementation().createTimeline();
final AnimationMap animationMap = AnimationMap.ID_TO_TAG.get(name);
if (animationMap == null) {
throw new IllegalStateException("Unable to parse: '" + name + "'");
}
final Timeline<?> timeline = animationMap.getImplementation().createTimeline();
timeline.readMdx(stream, name);

View File

@ -0,0 +1,24 @@
package com.etheller.warsmash.util;
public class FastNumberFormat {
private static final StringBuilder RECYCLE_STRING_BUILDER = new StringBuilder();
public static String formatWholeNumber(final float value) {
int intValue = (int) value;
RECYCLE_STRING_BUILDER.setLength(0);
do {
RECYCLE_STRING_BUILDER.append(intValue % 10);
intValue /= 10;
}
while (intValue > 0);
final int len = RECYCLE_STRING_BUILDER.length();
final int halfLength = len / 2;
for (int i = 0; i < halfLength; i++) {
final char swapCharA = RECYCLE_STRING_BUILDER.charAt(i);
final char swapCharB = RECYCLE_STRING_BUILDER.charAt(len - 1 - i);
RECYCLE_STRING_BUILDER.setCharAt(len - 1 - i, swapCharA);
RECYCLE_STRING_BUILDER.setCharAt(i, swapCharB);
}
return RECYCLE_STRING_BUILDER.toString();
}
}

View File

@ -63,6 +63,7 @@ public class MdxComplexInstance extends ModelInstance {
public FloatBuffer worldMatricesCopyHeap;
public DataTexture boneTexture;
public Texture[] replaceableTextures = new Texture[WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT];
private float animationSpeed = 1.0f;
public MdxComplexInstance(final MdxModel model) {
super(model);
@ -522,7 +523,7 @@ public class MdxComplexInstance extends ModelInstance {
if (sequenceId != -1) {
final Sequence sequence = model.sequences.get(sequenceId);
final long[] interval = sequence.getInterval();
final int frameTime = (int) (dt * 1000);
final int frameTime = (int) (dt * 1000 * this.animationSpeed);
this.frame += frameTime;
this.counter += frameTime;
@ -713,4 +714,8 @@ public class MdxComplexInstance extends ModelInstance {
}
return false;
}
public void setAnimationSpeed(final float speedRatio) {
this.animationSpeed = speedRatio;
}
}

View File

@ -9,13 +9,19 @@ import com.etheller.warsmash.viewer5.ModelInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
public class Doodad {
private static final int SAMPLE_RADIUS = 4;
private static final War3ID TEX_FILE = War3ID.fromString("btxf");
private static final War3ID TEX_ID = War3ID.fromString("btxi");
public final ModelInstance instance;
private final MutableGameObject row;
private final float maxPitch;
private final float maxRoll;
public Doodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type) {
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
final float maxPitch, final float maxRoll) {
this.maxPitch = maxPitch;
this.maxRoll = maxRoll;
final boolean isSimple = row.readSLKTagBoolean("lightweight");
ModelInstance instance;
@ -27,7 +33,38 @@ public class Doodad {
}
instance.move(doodad.getLocation());
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, doodad.getAngle()));
// TODO: the following pitch/roll system is a heuristic, and we probably want to
// revisit it later.
// Specifically, I was pretty convinced that whichever is applied first
// (pitch/roll) should be used to do a projection onto the already-tilted plane
// to find the angle used for the other of the two
// (instead of measuring down from an imaginary flat ground plane, as we do
// currently).
final float facingRadians = doodad.getAngle();
float pitch, roll;
final float x = doodad.getLocation()[0];
final float y = doodad.getLocation()[1];
final float pitchSampleForwardX = x + (SAMPLE_RADIUS * (float) Math.cos(facingRadians));
final float pitchSampleForwardY = y + (SAMPLE_RADIUS * (float) Math.sin(facingRadians));
final float pitchSampleBackwardX = x - (SAMPLE_RADIUS * (float) Math.cos(facingRadians));
final float pitchSampleBackwardY = y - (SAMPLE_RADIUS * (float) Math.sin(facingRadians));
final float pitchSampleGroundHeight1 = map.terrain.getGroundHeight(pitchSampleBackwardX, pitchSampleBackwardY);
final float pitchSampleGorundHeight2 = map.terrain.getGroundHeight(pitchSampleForwardX, pitchSampleForwardY);
pitch = Math.min(maxPitch,
(float) Math.atan2(pitchSampleGorundHeight2 - pitchSampleGroundHeight1, SAMPLE_RADIUS * 2));
final double leftOfFacingAngle = facingRadians + (Math.PI / 2);
final float rollSampleForwardX = x + (SAMPLE_RADIUS * (float) Math.cos(leftOfFacingAngle));
final float rollSampleForwardY = y + (SAMPLE_RADIUS * (float) Math.sin(leftOfFacingAngle));
final float rollSampleBackwardX = x - (SAMPLE_RADIUS * (float) Math.cos(leftOfFacingAngle));
final float rollSampleBackwardY = y - (SAMPLE_RADIUS * (float) Math.sin(leftOfFacingAngle));
final float rollSampleGroundHeight1 = map.terrain.getGroundHeight(rollSampleBackwardX, rollSampleBackwardY);
final float rollSampleGroundHeight2 = map.terrain.getGroundHeight(rollSampleForwardX, rollSampleForwardY);
roll = Math.min(maxRoll,
(float) Math.atan2(rollSampleGroundHeight2 - rollSampleGroundHeight1, SAMPLE_RADIUS * 2));
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, facingRadians));
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Y, -pitch));
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_X, roll));
// instance.rotate(new Quaternion().setEulerAnglesRad(facingRadians, 0, 0));
instance.scale(doodad.getScale());
if (type == WorldEditorDataType.DOODADS) {
final float defScale = row.readSLKTagFloat("defScale");

View File

@ -1,23 +1,31 @@
package com.etheller.warsmash.viewer5.handlers.w3x;
import java.awt.image.BufferedImage;
import com.badlogic.gdx.math.Quaternion;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.RenderMathUtils;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxSimpleInstance;
public class TerrainDoodad {
private static final float[] locationHeap = new float[3];
public final MdxSimpleInstance instance;
public final MdxComplexInstance instance;
private final MutableGameObject row;
public TerrainDoodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
final com.etheller.warsmash.parsers.w3x.doo.TerrainDoodad doodad) {
final com.etheller.warsmash.parsers.w3x.doo.TerrainDoodad doodad, final BufferedImage pathingTextureImage) {
final float[] centerOffset = map.terrain.centerOffset;
final MdxSimpleInstance instance = (MdxSimpleInstance) model.addInstance(1);
final MdxComplexInstance instance = (MdxComplexInstance) model.addInstance(0);
locationHeap[0] = (doodad.getLocation()[0] * 128) + centerOffset[0] + 128;
locationHeap[1] = (doodad.getLocation()[1] * 128) + centerOffset[1] + 128;
final int textureWidth = pathingTextureImage.getWidth();
final int textureHeight = pathingTextureImage.getHeight();
final int textureWidthTerrainCells = textureWidth / 4;
final int textureHeightTerrainCells = textureHeight / 4;
final int minCellX = ((int) doodad.getLocation()[0]);
final int minCellY = ((int) doodad.getLocation()[1]);
locationHeap[0] = ((minCellX * 128) + (textureWidthTerrainCells * 64) + centerOffset[0]);
locationHeap[1] = ((minCellY * 128) + (textureHeightTerrainCells * 64) + centerOffset[1]);
instance.move(locationHeap);
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z,

View File

@ -69,11 +69,12 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderItem;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CWidgetAbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.PointAbilityTargetCheckReceiver;
@ -143,6 +144,7 @@ public class War3MapViewer extends ModelViewer {
public List<RenderUnit> selected = new ArrayList<>();
private DataTable unitAckSoundsTable;
private DataTable miscData;
private DataTable unitGlobalStrings;
private MdxComplexInstance confirmationInstance;
public CSimulation simulation;
private float updateTime;
@ -231,6 +233,20 @@ public class War3MapViewer extends ModelViewer {
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("UI\\MiscData.txt")) {
this.miscData.readTXT(miscDataTxtStream, true);
}
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\MiscData.txt")) {
this.miscData.readTXT(miscDataTxtStream, true);
}
this.unitGlobalStrings = new DataTable(worldEditStrings);
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\UnitGlobalStrings.txt")) {
this.unitGlobalStrings.readTXT(miscDataTxtStream, true);
}
final Element categories = this.unitGlobalStrings.get("Categories");
for (final CUnitClassification unitClassification : CUnitClassification.values()) {
if (unitClassification.getLocaleKey() != null) {
final String displayName = categories.getField(unitClassification.getLocaleKey());
unitClassification.setDisplayName(displayName);
}
}
this.selectionCircleSizes.clear();
final Element selectionCircleData = this.miscData.get("SelectionCircle");
final int selectionCircleNumSizes = selectionCircleData.getFieldValue("NumSizes");
@ -335,7 +351,7 @@ public class War3MapViewer extends ModelViewer {
}
final Warcraft3MapObjectData modifications = this.mapMpq.readModifications();
this.simulation = new CSimulation(modifications.getUnits(), modifications.getAbilities(),
this.simulation = new CSimulation(this.miscData, modifications.getUnits(), modifications.getAbilities(),
new ProjectileCreator() {
@Override
public CAttackProjectile create(final CSimulation simulation, final CUnit source,
@ -443,6 +459,8 @@ public class War3MapViewer extends ModelViewer {
fileVar += ".mdx";
final float maxPitch = row.readSLKTagFloat("maxPitch");
final float maxRoll = row.readSLKTagFloat("maxRoll");
if (type == WorldEditorDataType.DESTRUCTIBLES) {
final String shadowString = row.readSLKTag("shadow");
if ((shadowString != null) && (shadowString.length() > 0) && !"_".equals(shadowString)) {
@ -490,14 +508,18 @@ public class War3MapViewer extends ModelViewer {
model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams);
}
this.doodads.add(new Doodad(this, model, row, doodad, type));
this.doodads.add(new Doodad(this, model, row, doodad, type, maxPitch, maxRoll));
}
}
// Cliff/Terrain doodads.
for (final com.etheller.warsmash.parsers.w3x.doo.TerrainDoodad doodad : doo.getTerrainDoodads()) {
final MutableGameObject row = modifications.getDoodads().get(doodad.getId());
String file = "UI\\Feedback\\WaypointFlags\\WaypointFlag.mdx";// row.readSLKTag("file");
String file = row.readSLKTag("file");//
if ("".equals(file)) {
final String blaBla = row.readSLKTag("file");
System.out.println("bla");
}
if (file.toLowerCase().endsWith(".mdl")) {
file = file.substring(0, file.length() - 4);
}
@ -506,7 +528,47 @@ public class War3MapViewer extends ModelViewer {
}
final MdxModel model = (MdxModel) this.load(file, this.mapPathSolver, this.solverParams);
this.terrainDoodads.add(new TerrainDoodad(this, model, row, doodad));
final String pathingTexture = row.readSLKTag("pathTex");
BufferedImage pathingTextureImage;
if ((pathingTexture != null) && (pathingTexture.length() > 0) && !"_".equals(pathingTexture)) {
pathingTextureImage = this.filePathToPathingMap.get(pathingTexture.toLowerCase());
if (pathingTextureImage == null) {
if (this.mapMpq.has(pathingTexture)) {
try {
pathingTextureImage = TgaFile.readTGA(pathingTexture,
this.mapMpq.getResourceAsStream(pathingTexture));
this.filePathToPathingMap.put(pathingTexture.toLowerCase(), pathingTextureImage);
}
catch (final Exception exc) {
exc.printStackTrace();
}
}
}
}
else {
pathingTextureImage = null;
}
if (pathingTextureImage != null) {
// blit out terrain cells under this TerrainDoodad
final int textureWidth = pathingTextureImage.getWidth();
final int textureHeight = pathingTextureImage.getHeight();
final int textureWidthTerrainCells = textureWidth / 4;
final int textureHeightTerrainCells = textureHeight / 4;
final int minCellX = ((int) doodad.getLocation()[0]);
final int minCellY = ((int) doodad.getLocation()[1]);
final int maxCellX = (minCellX + textureWidthTerrainCells) - 1;
final int maxCellY = (minCellY + textureHeightTerrainCells) - 1;
for (int j = minCellY; j <= maxCellY; j++) {
for (int i = minCellX; i <= maxCellX; i++) {
this.terrain.removeTerrainCellWithoutFlush(i, j);
}
}
this.terrain.flushRemovedTerrainCells();
}
System.out.println("Loading terrain doodad: " + file);
this.terrainDoodads.add(new TerrainDoodad(this, model, row, doodad, pathingTextureImage));
}
this.doodadsReady = true;

View File

@ -7,6 +7,7 @@ public class RenderCorner extends Corner {
public boolean romp;
public float rampAdjust;
public float depth;
public boolean hideCliff;
public RenderCorner(final Corner corner) {
super(corner);

View File

@ -544,7 +544,7 @@ public class Terrain {
final RenderCorner topLeft = this.corners[i][j + 1];
final RenderCorner topRight = this.corners[i + 1][j + 1];
if (bottomLeft.cliff) {
if (bottomLeft.cliff && !bottomLeft.hideCliff) {
final int base = Math.min(Math.min(bottomLeft.getLayerHeight(), bottomRight.getLayerHeight()),
Math.min(topLeft.getLayerHeight(), topRight.getLayerHeight()));
@ -672,6 +672,33 @@ public class Terrain {
uploadGroundTexture();
}
public void removeTerrainCell(final int i, final int j) {
this.groundTextureList[(((j * (this.columns - 1)) + i) * 4) + 3] |= 0b1000000000000000;
this.corners[i][j].hideCliff = true;
uploadGroundTexture();
try {
updateCliffMeshes(new Rectangle(i - 1, j - 1, 1, 1)); // TODO does this work?
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
public void removeTerrainCellWithoutFlush(final int i, final int j) {
this.groundTextureList[(((j * (this.columns - 1)) + i) * 4) + 3] |= 0b1000000000000000;
this.corners[i][j].hideCliff = true;
}
public void flushRemovedTerrainCells() {
uploadGroundTexture();
try {
updateCliffMeshes(new Rectangle(0, 0, this.columns - 1, this.rows - 1));
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
private void uploadGroundTexture() {
if (this.groundTextureData != -1) {
Gdx.gl30.glBindTexture(GL30.GL_TEXTURE_2D, this.groundTextureData);

View File

@ -0,0 +1,61 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
/**
* We observe this table during gameplay but I haven't found it anywhere in the
* data yet. So, I'm making my own.
*/
public enum OrientationInterpolation {
OI0(0.07f, 0.2f, 999f),
OI1(0.03f, 0.1f, 0.04f),
OI2(0.015f, 1.0f, 999),
OI3(0.005f, 0.1f, 0.0043f),
OI4(0.04f, 0.15f, 0.01f),
OI5(0.05f, 0.18f, 0.015f),
OI6(0.1f, 0.3f, 0.1f),
OI7(0.003f, 0.08f, 0.0027f),
OI8(0.001f, 0.05f, 0.001f);
public static OrientationInterpolation[] VALUES = values();
private float startingAcceleration;
private float maxVelocity;
private float endingNegativeAcceleration;
private float endingAccelCutoff;
private float startingAccelCutoff;
private OrientationInterpolation(final float startingAcceleration, final float maxVelocity,
final float endingNegativeAcceleration) {
this.startingAcceleration = startingAcceleration;
this.maxVelocity = maxVelocity;
this.endingNegativeAcceleration = endingNegativeAcceleration;
this.endingAccelCutoff = endingAccelCutoff(maxVelocity, endingNegativeAcceleration);
this.startingAccelCutoff = endingAccelCutoff(maxVelocity, startingAcceleration);
}
public float getStartingAcceleration() {
return this.startingAcceleration;
}
public float getMaxVelocity() {
return this.maxVelocity;
}
public float getEndingNegativeAcceleration() {
return this.endingNegativeAcceleration;
}
public float getEndingAccelCutoff() {
return this.endingAccelCutoff;
}
public float getStartingAccelCutoff() {
return this.startingAccelCutoff;
}
private static float endingAccelCutoff(final float maxVelocity, final float endingAccel) {
final float endingAccelFinishingTime = maxVelocity / endingAccel;
final float endingDistanceRequired = (maxVelocity * endingAccelFinishingTime)
- ((endingAccel / 2) * (endingAccelFinishingTime * endingAccelFinishingTime));
return endingDistanceRequired;
}
}

View File

@ -0,0 +1,49 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
public class ParseBogus {
public static void main(final String[] args) {
final File bogusDataFile = new File("E:\\Games\\Warcraft III Patch 1.22\\Logs\\MyReteraTest.pre");
final float[][] cubeIndexToData = new float[9][44];
try {
final List<String> allLines = Files.readAllLines(bogusDataFile.toPath());
for (final String line : allLines) {
final int cubeStringIndex = line.indexOf("Cube");
if (cubeStringIndex != -1) {
final int colonStringIndex = line.indexOf(':');
final int cubeIndex = Integer.parseInt(line.substring(cubeStringIndex + 4, colonStringIndex));
final int dataIndex = Integer.parseInt(line.substring(line.indexOf('"') + 1, cubeStringIndex));
final float value = Float.parseFloat(line.substring(colonStringIndex + 1, line.indexOf(".txt")));
cubeIndexToData[cubeIndex][dataIndex] = value;
}
}
}
catch (final IOException e) {
e.printStackTrace();
}
final boolean[] spun = new boolean[9];
for (int j = 0; j < cubeIndexToData[0].length; j++) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < cubeIndexToData.length; i++) {
if (sb.length() > 0) {
sb.append(',');
}
float value = cubeIndexToData[i][j];
if (value > 280) {
spun[i] = true;
}
else if ((value < 100) && spun[i]) {
value += 360;
}
sb.append(Math.toRadians(value));
}
System.out.println(sb);
}
}
}

View File

@ -0,0 +1,60 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
public class ParseBogus2 {
private static final int _383 = 280;
public static void main(final String[] args) {
final float[][] cubeIndexToData = new float[9][_383];
for (int fileIdx = 0; fileIdx < _383; fileIdx++) {
final File bogusDataFile = new File(
"E:\\Games\\Warcraft III Patch 1.22\\Logs\\MyReteraTest" + (fileIdx + 1) + ".pre");
try {
final List<String> allLines = Files.readAllLines(bogusDataFile.toPath());
for (final String line : allLines) {
final int cubeStringIndex = line.indexOf("Cube");
if (cubeStringIndex != -1) {
final int colonStringIndex = line.indexOf(':');
final int cubeIndex = Integer.parseInt(line.substring(cubeStringIndex + 4, colonStringIndex));
final int dataIndex = Integer.parseInt(line.substring(line.indexOf('"') + 1, cubeStringIndex));
final float value = Float
.parseFloat(line.substring(colonStringIndex + 1, line.indexOf(".txt")));
cubeIndexToData[cubeIndex][dataIndex] = value;
}
}
}
catch (final IOException e) {
e.printStackTrace();
}
}
final boolean[] spun = new boolean[9];
for (int j = 0; j < cubeIndexToData[0].length; j++) {
if ((j % 3) == 0) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < cubeIndexToData.length; i++) {
if (sb.length() > 0) {
sb.append(',');
}
float value = cubeIndexToData[i][j];
// if (value > 280) {
// spun[i] = true;
// }
// else if ((value < 100) && spun[i]) {
// value += 360;
// }
if ((j / 3) < 32) {
value += 360;
}
sb.append(Math.toRadians(value));
}
System.out.println(sb);
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
public class ParseBogus3 {
public static float endingAccelCutoff(final float maxVelocity, final float endingAccel) {
final float endingAccelFinishingTime = maxVelocity / endingAccel;
final float endingDistanceRequired = (maxVelocity * endingAccelFinishingTime)
- ((endingAccel / 2) * (endingAccelFinishingTime * endingAccelFinishingTime));
return endingDistanceRequired;
}
public static void main(final String[] args) {
System.out.println(endingAccelCutoff(0.1f, 0.04f));
for (final OrientationInterpolation oi : OrientationInterpolation.values()) {
System.out.println(oi + ": " + oi.getStartingAcceleration() + "," + oi.getMaxVelocity() + ","
+ oi.getEndingNegativeAcceleration() + "->" + oi.getEndingAccelCutoff());
}
}
}

View File

@ -0,0 +1,80 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
import java.util.Arrays;
public class ParseBogus4 {
public static void main(final String[] args) {
final OrientationInterpolation[] interpolations = OrientationInterpolation.values();
final float[] velocities = new float[interpolations.length];
final float[] signs = new float[interpolations.length];
Arrays.fill(signs, -1);
signs[1] = signs[6] = 1;
final float[] angles = new float[interpolations.length];
Arrays.fill(angles, (float) ((3 * Math.PI) / 2));
final boolean[] spun = new boolean[interpolations.length];
for (int j = 0; j < 140; j++) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < interpolations.length; i++) {
float simulationFacing = 90;
if (simulationFacing < 0) {
simulationFacing += 360;
}
float renderFacing = (float) Math.toDegrees(angles[i]);
if (renderFacing < 0) {
renderFacing += 360;
}
float facingDelta = simulationFacing - renderFacing;
if (facingDelta < -180) {
facingDelta = 360 + facingDelta;
}
if (facingDelta > 180) {
facingDelta = -360 + facingDelta;
}
final float absoluteFacingDelta = Math.abs(facingDelta);
final float absoluteFacingDeltaRadians = (float) Math.toRadians(absoluteFacingDelta);
float acceleration;
final boolean endPhase = (absoluteFacingDeltaRadians <= interpolations[i].getEndingAccelCutoff())
&& ((velocities[i] * signs[i]) > 0);
if (endPhase) {
acceleration = -interpolations[i].getEndingNegativeAcceleration() * signs[i];
if (((velocities[i] + acceleration) * signs[i]) <= 0.001) {
velocities[i] = absoluteFacingDeltaRadians * signs[i] * 0.25f;
}
else {
velocities[i] = velocities[i] + acceleration;
}
}
else {
acceleration = interpolations[i].getStartingAcceleration() * signs[i];
velocities[i] = velocities[i] + acceleration;
}
if ((velocities[i] * signs[i]) > interpolations[i].getMaxVelocity()) {
velocities[i] = interpolations[i].getMaxVelocity() * signs[i];
}
float angleToAdd = (float) (/* Math.signum(facingDelta) **/ Math
.toDegrees(velocities[i]) /* * deltaTime */);
if (absoluteFacingDelta < Math.abs(angleToAdd)) {
angleToAdd = facingDelta;
}
double newDegreesAngle = (((Math.toDegrees(angles[i]) + angleToAdd) % 360) + 360) % 360;
if (newDegreesAngle > 280) {
spun[i] = true;
}
else if ((newDegreesAngle < 100) && spun[i]) {
newDegreesAngle += 360;
}
angles[i] = (float) Math.toRadians(newDegreesAngle);
if (sb.length() > 0) {
sb.append(',');
}
sb.append(angles[i]);
}
System.out.println(sb.toString());
}
}
}

View File

@ -10,7 +10,7 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.IndexedSequence;
import com.etheller.warsmash.viewer5.handlers.w3x.StandSequence;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
public class RenderAttackProjectile {
private static final Quaternion pitchHeap = new Quaternion();
@ -45,7 +45,8 @@ public class RenderAttackProjectile {
final float d2DToTarget = (float) StrictMath.sqrt((dxToTarget * dxToTarget) + (dyToTarget * dyToTarget));
final float startingDistance = d2DToTarget + this.totalTravelDistance;
this.targetHeight = (war3MapViewer.terrain.getGroundHeight(targetX, targetY)
+ this.simulationProjectile.getTarget().getFlyHeight());
+ this.simulationProjectile.getTarget().getFlyHeight()
+ this.simulationProjectile.getTarget().getImpactZ());
this.arcPeakHeight = arc * startingDistance;
this.yaw = (float) StrictMath.atan2(dyToTarget, dxToTarget);
}

View File

@ -2,11 +2,12 @@ package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Quaternion;
import com.etheller.warsmash.parsers.mdlx.Sequence;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.RenderMathUtils;
@ -15,15 +16,15 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.IndexedSequence;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
import com.etheller.warsmash.viewer5.handlers.w3x.StandSequence;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSoundset;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitAnimationListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityHoldPosition;
@ -32,13 +33,13 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityP
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityStop;
public class RenderUnit {
private static final double GLOBAL_TURN_RATE = Math.toDegrees(7f);
private static final Quaternion tempQuat = new Quaternion();
private static final War3ID RED = War3ID.fromString("uclr");
private static final War3ID GREEN = War3ID.fromString("uclg");
private static final War3ID BLUE = War3ID.fromString("uclb");
private static final War3ID MODEL_SCALE = War3ID.fromString("usca");
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
private static final War3ID ORIENTATION_INTERPOLATION = War3ID.fromString("uori");
private static final float[] heapZ = new float[3];
public final MdxComplexInstance instance;
public final MutableGameObject row;
@ -48,8 +49,6 @@ public class RenderUnit {
public final MdxModel portraitModel;
public int playerIndex;
private final CUnit simulationUnit;
private COrder lastOrder;
private AnimationTokens.PrimaryTag lastOrderAnimation;
public SplatMover shadow;
public SplatMover selectionCircle;
private final List<CommandCardIcon> commandCardIcons = new ArrayList<>();
@ -60,10 +59,11 @@ public class RenderUnit {
private boolean swimming;
private boolean alreadyPlayedDeath = false;
private final boolean alreadyPlayedDeath = false;
private final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet
.noneOf(AnimationTokens.SecondaryTag.class);
private final UnitAnimationListenerImpl unitAnimationListenerImpl;
private OrientationInterpolation orientationInterpolation;
private float currentTurnVelocity = 0;
public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit, final UnitSoundset soundset,
@ -82,9 +82,11 @@ public class RenderUnit {
this.y = simulationUnit.getY();
instance.rotate(tempQuat.setFromAxisRad(RenderMathUtils.VEC3_UNIT_Z, angle));
instance.scale(unit.getScale());
this.playerIndex = unit.getPlayer();
this.playerIndex = unit.getPlayer() & 0xFFFF;
instance.setTeamColor(this.playerIndex);
instance.setScene(map.worldScene);
this.unitAnimationListenerImpl = new UnitAnimationListenerImpl(instance);
simulationUnit.setUnitAnimationListener(this.unitAnimationListenerImpl);
if (row != null) {
heapZ[2] = simulationUnit.getFlyHeight();
@ -104,6 +106,12 @@ public class RenderUnit {
instance.uniformScale(row.getFieldAsFloat(scale, 0));
this.selectionScale = row.getFieldAsFloat(War3MapViewer.UNIT_SELECT_SCALE, 0);
int orientationInterpolationOrdinal = row.getFieldAsInteger(ORIENTATION_INTERPOLATION, 0);
if ((orientationInterpolationOrdinal < 0)
|| (orientationInterpolationOrdinal >= OrientationInterpolation.VALUES.length)) {
orientationInterpolationOrdinal = 0;
}
this.orientationInterpolation = OrientationInterpolation.VALUES[orientationInterpolationOrdinal];
}
this.instance = instance;
@ -179,14 +187,11 @@ public class RenderUnit {
else {
groundHeight = map.terrain.getGroundHeight(x, y);
}
boolean changedAnimationTags = false;
if (swimming && !this.swimming) {
this.secondaryAnimationTags.add(AnimationTokens.SecondaryTag.SWIM);
changedAnimationTags = true;
this.unitAnimationListenerImpl.addSecondaryTag(AnimationTokens.SecondaryTag.SWIM);
}
else if (!swimming && this.swimming) {
this.secondaryAnimationTags.remove(AnimationTokens.SecondaryTag.SWIM);
changedAnimationTags = true;
this.unitAnimationListenerImpl.removeSecondaryTag(AnimationTokens.SecondaryTag.SWIM);
}
this.swimming = swimming;
this.location[2] = this.simulationUnit.getFlyHeight() + groundHeight;
@ -207,52 +212,41 @@ public class RenderUnit {
facingDelta = -360 + facingDelta;
}
final float absoluteFacingDelta = Math.abs(facingDelta);
float angleToAdd = (float) (Math.signum(facingDelta) * GLOBAL_TURN_RATE * deltaTime);
final float turningSign = Math.signum(facingDelta);
final float absoluteFacingDeltaRadians = (float) Math.toRadians(absoluteFacingDelta);
float acceleration;
final boolean endPhase = (absoluteFacingDeltaRadians <= this.orientationInterpolation.getEndingAccelCutoff())
&& ((this.currentTurnVelocity * turningSign) > 0);
if (endPhase) {
this.currentTurnVelocity = (1
- ((this.orientationInterpolation.getEndingAccelCutoff() - absoluteFacingDeltaRadians)
/ this.orientationInterpolation.getEndingAccelCutoff()))
* (this.orientationInterpolation.getMaxVelocity()) * turningSign;
}
else {
acceleration = this.orientationInterpolation.getStartingAcceleration() * turningSign;
this.currentTurnVelocity = this.currentTurnVelocity + acceleration;
}
if ((this.currentTurnVelocity * turningSign) > this.orientationInterpolation.getMaxVelocity()) {
this.currentTurnVelocity = this.orientationInterpolation.getMaxVelocity() * turningSign;
}
float angleToAdd = (float) ((Math.toDegrees(this.currentTurnVelocity) * deltaTime) / 0.03f);
if (absoluteFacingDelta < Math.abs(angleToAdd)) {
angleToAdd = facingDelta;
this.currentTurnVelocity = 0.0f;
}
this.facing = (((this.facing + angleToAdd) % 360) + 360) % 360;
this.instance.setLocalRotation(tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.facing));
map.worldScene.instanceMoved(this.instance, this.location[0], this.location[1]);
final MdxComplexInstance mdxComplexInstance = this.instance;
final COrder currentOrder = this.simulationUnit.getCurrentOrder();
if (this.simulationUnit.getLife() <= 0) {
final MdxModel model = (MdxModel) mdxComplexInstance.model;
final List<Sequence> sequences = model.getSequences();
IndexedSequence sequence = StandSequence.selectSequence("death", sequences);
if (!this.alreadyPlayedDeath && (sequence != null) && (mdxComplexInstance.sequence != sequence.index)) {
mdxComplexInstance.setSequence(sequence.index);
this.alreadyPlayedDeath = true;
}
else if (mdxComplexInstance.sequenceEnded && this.alreadyPlayedDeath) {
sequence = StandSequence.selectSequence("dissipate", sequences);
if ((sequence != null) && (mdxComplexInstance.sequence != sequence.index)) {
mdxComplexInstance.setSequence(sequence.index);
}
}
}
else if (mdxComplexInstance.sequenceEnded || (mdxComplexInstance.sequence == -1)
|| (currentOrder != this.lastOrder)
|| ((currentOrder != null) && (currentOrder.getAnimationName() != null)
&& !currentOrder.getAnimationName().equals(this.lastOrderAnimation))
|| changedAnimationTags) {
if (this.simulationUnit.getCurrentOrder() != null) {
final AnimationTokens.PrimaryTag animationName = this.simulationUnit.getCurrentOrder()
.getAnimationName();
StandSequence.randomSequence(mdxComplexInstance, animationName, this.secondaryAnimationTags);
this.lastOrderAnimation = animationName;
}
else {
StandSequence.randomSequence(mdxComplexInstance, PrimaryTag.STAND, this.secondaryAnimationTags);
}
}
this.lastOrder = currentOrder;
if (this.shadow != null) {
this.shadow.move(dx, dy, map.terrain.centerOffset);
}
if (this.selectionCircle != null) {
this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
}
this.unitAnimationListenerImpl.update();
}
public CUnit getSimulationUnit() {
@ -262,4 +256,80 @@ public class RenderUnit {
public List<CommandCardIcon> getCommandCardIcons() {
return this.commandCardIcons;
}
private static final class UnitAnimationListenerImpl implements CUnitAnimationListener {
private final MdxComplexInstance instance;
private final EnumSet<AnimationTokens.SecondaryTag> secondaryAnimationTags = EnumSet
.noneOf(AnimationTokens.SecondaryTag.class);
private final EnumSet<AnimationTokens.SecondaryTag> recycleSet = EnumSet
.noneOf(AnimationTokens.SecondaryTag.class);
private PrimaryTag currentAnimation;
private EnumSet<SecondaryTag> currentAnimationSecondaryTags;
private float currentSpeedRatio;
private final Queue<QueuedAnimation> animationQueue = new LinkedList<>();
public UnitAnimationListenerImpl(final MdxComplexInstance instance) {
this.instance = instance;
}
public void addSecondaryTag(final AnimationTokens.SecondaryTag tag) {
this.secondaryAnimationTags.add(tag);
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags, this.currentSpeedRatio);
}
public void removeSecondaryTag(final AnimationTokens.SecondaryTag tag) {
this.secondaryAnimationTags.remove(tag);
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags, this.currentSpeedRatio);
}
@Override
public void playAnimation(final boolean force, final PrimaryTag animationName,
final EnumSet<SecondaryTag> secondaryAnimationTags, final float speedRatio) {
this.animationQueue.clear();
if (force || (animationName != this.currentAnimation)) {
this.currentAnimation = animationName;
this.currentAnimationSecondaryTags = secondaryAnimationTags;
this.currentSpeedRatio = speedRatio;
this.recycleSet.clear();
this.recycleSet.addAll(this.secondaryAnimationTags);
this.recycleSet.addAll(secondaryAnimationTags);
this.instance.setAnimationSpeed(speedRatio);
StandSequence.randomSequence(this.instance, animationName, this.recycleSet);
}
}
@Override
public void queueAnimation(final PrimaryTag animationName, final EnumSet<SecondaryTag> secondaryAnimationTags) {
this.animationQueue.add(new QueuedAnimation(animationName, secondaryAnimationTags));
}
public void update() {
if (this.instance.sequenceEnded || (this.instance.sequence == -1)) {
// animation done
if ((this.instance.sequence != -1) && (((MdxModel) this.instance.model).getSequences()
.get(this.instance.sequence).getFlags() == 0)) {
// animation is a looping animation
playAnimation(true, this.currentAnimation, this.currentAnimationSecondaryTags,
this.currentSpeedRatio);
}
else {
final QueuedAnimation nextAnimation = this.animationQueue.poll();
if (nextAnimation != null) {
playAnimation(true, nextAnimation.animationName, nextAnimation.secondaryAnimationTags, 1.0f);
}
}
}
}
}
private static final class QueuedAnimation {
private final PrimaryTag animationName;
private final EnumSet<SecondaryTag> secondaryAnimationTags;
public QueuedAnimation(final PrimaryTag animationName, final EnumSet<SecondaryTag> secondaryAnimationTags) {
this.animationName = animationName;
this.secondaryAnimationTags = secondaryAnimationTags;
}
}
}

View File

@ -11,4 +11,8 @@ public class CDestructable extends CWidget {
return 0;
}
@Override
public float getImpactZ() {
return 0; // TODO maybe from DestructableType
}
}

View File

@ -0,0 +1,21 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
/**
* Stores some gameplay constants at runtime in a java object (symbol table) to
* maybe be faster than a map.
*/
public class CGameplayConstants {
private final float attackHalfAngle;
public CGameplayConstants(final DataTable parsedDataTable) {
final Element miscData = parsedDataTable.get("Misc");
this.attackHalfAngle = (miscData.getFieldFloatValue("AttackHalfAngle")); // TODO use
}
public float getAttackHalfAngle() {
return this.attackHalfAngle;
}
}

View File

@ -16,4 +16,8 @@ public class CItem extends CWidget {
return 0;
}
@Override
public float getImpactZ() {
return 0; // TODO probably from ItemType
}
}

View File

@ -1,7 +1,5 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens;
public interface COrder {
/**
* Executes one step of game simulation of the current order, returning true if
@ -20,12 +18,4 @@ public interface COrder {
* @return
*/
int getOrderId();
/**
* Gets the animation name used for visuals. Calling this function should not
* impact the game state of the CSimulation in any way.
*
* @return
*/
AnimationTokens.PrimaryTag getAnimationName();
}

View File

@ -6,13 +6,14 @@ import java.util.Iterator;
import java.util.List;
import com.badlogic.gdx.math.Rectangle;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.manager.MutableObjectData;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.data.CAbilityData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.data.CUnitData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CPathfindingProcessor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ProjectileCreator;
public class CSimulation {
@ -21,14 +22,17 @@ public class CSimulation {
private final List<CUnit> units;
private final List<CAttackProjectile> projectiles;
private final HandleIdAllocator handleIdAllocator;
private final ProjectileCreator projectileCreator;
private transient final ProjectileCreator projectileCreator;
private int gameTurnTick = 0;
private final PathingGrid pathingGrid;
private final CWorldCollision worldCollision;
private final CPathfindingProcessor pathfindingProcessor;
private final CGameplayConstants gameplayConstants;
public CSimulation(final MutableObjectData parsedUnitData, final MutableObjectData parsedAbilityData,
final ProjectileCreator projectileCreator, final PathingGrid pathingGrid, final Rectangle entireMapBounds) {
public CSimulation(final DataTable miscData, final MutableObjectData parsedUnitData,
final MutableObjectData parsedAbilityData, final ProjectileCreator projectileCreator,
final PathingGrid pathingGrid, final Rectangle entireMapBounds) {
this.gameplayConstants = new CGameplayConstants(miscData);
this.projectileCreator = projectileCreator;
this.pathingGrid = pathingGrid;
this.unitData = new CUnitData(parsedUnitData);
@ -101,4 +105,8 @@ public class CSimulation {
public CWorldCollision getWorldCollision() {
return this.worldCollision;
}
public CGameplayConstants getGameplayConstants() {
return this.gameplayConstants;
}
}

View File

@ -1,13 +1,17 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import com.badlogic.gdx.math.Rectangle;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
public class CUnit extends CWidget {
private War3ID typeId;
@ -16,6 +20,7 @@ public class CUnit extends CWidget {
private int maximumLife;
private int maximumMana;
private int speed;
private final int defense;
private int cooldownEndTime = 0;
private float flyHeight;
private int playerIndex;
@ -28,9 +33,13 @@ public class CUnit extends CWidget {
private Rectangle collisionRectangle;
private final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
private transient CUnitAnimationListener unitAnimationListener;
public CUnit(final int handleId, final int playerIndex, final float x, final float y, final float life,
final War3ID typeId, final float facing, final float mana, final int maximumLife, final int maximumMana,
final int speed, final CUnitType unitType) {
final int speed, final int defense, final CUnitType unitType) {
super(handleId, x, y, life);
this.typeId = typeId;
this.facing = facing;
@ -38,8 +47,19 @@ public class CUnit extends CWidget {
this.maximumLife = maximumLife;
this.maximumMana = maximumMana;
this.speed = speed;
this.defense = defense;
this.flyHeight = unitType.getDefaultFlyingHeight();
this.unitType = unitType;
this.classifications.addAll(unitType.getClassifications());
}
public void setUnitAnimationListener(final CUnitAnimationListener unitAnimationListener) {
this.unitAnimationListener = unitAnimationListener;
this.unitAnimationListener.playAnimation(true, PrimaryTag.STAND, CUnitAnimationListener.EMPTY, 1.0f);
}
public CUnitAnimationListener getUnitAnimationListener() {
return this.unitAnimationListener;
}
public void add(final CSimulation simulation, final CAbility ability) {
@ -110,6 +130,10 @@ public class CUnit extends CWidget {
// item from order queue
this.currentOrder = this.orderQueue.poll();
}
if (this.currentOrder == null) {
// maybe order "stop" here
this.unitAnimationListener.playAnimation(true, PrimaryTag.STAND, CUnitAnimationListener.EMPTY, 1.0f);
}
}
}
@ -193,4 +217,21 @@ public class CUnit extends CWidget {
}
}
public EnumSet<CUnitClassification> getClassifications() {
return this.classifications;
}
public int getDefense() {
return this.defense;
}
public void damage(final CUnit source, final CAttackType attackType, final CWeaponType weaponType,
final int damage) {
}
@Override
public float getImpactZ() {
return this.unitType.getImpactZ();
}
}

View File

@ -0,0 +1,16 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag;
public interface CUnitAnimationListener {
EnumSet<SecondaryTag> EMPTY = EnumSet.noneOf(SecondaryTag.class);
EnumSet<SecondaryTag> READY = EnumSet.of(SecondaryTag.READY);
void playAnimation(boolean force, final PrimaryTag animationName,
final EnumSet<SecondaryTag> secondaryAnimationTags, float speedRatio);
void queueAnimation(final PrimaryTag animationName, final EnumSet<SecondaryTag> secondaryAnimationTags);
}

View File

@ -0,0 +1,67 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import java.util.HashMap;
import java.util.Map;
/**
* We think in the original WC3 sourcecode, these are probably referred to as
* "Unit Types", but the community turn of phrase "Unit Type" has come to refer
* to what WC3 sourcecode calls "Unit Class", hence this is now named "Unit
* Classification" instead of "Unit Type" or "Unit Class" to disambiguate. This
* is consistent with the World Editor naming: "Stats - Unit Classification".
*/
public enum CUnitClassification {
GIANT("giant", "GiantClass"),
UNDEAD("undead", "UndeadClass"),
SUMMONED("summoned"),
MECHANICAL("mechanical", "MechanicalClass"),
PEON("peon"),
SAPPER("sapper"),
TOWNHALL("townhall"),
TREE("tree"),
WARD("ward"),
ANCIENT("ancient"),
STANDON("standon"),
NEURAL("neutral"),
TAUREN("tauren", "TaurenClass");
private static final Map<String, CUnitClassification> UNIT_EDITOR_KEY_TO_CLASSIFICATION = new HashMap<>();
static {
for (final CUnitClassification unitClassification : values()) {
UNIT_EDITOR_KEY_TO_CLASSIFICATION.put(unitClassification.getUnitDataKey(), unitClassification);
}
}
private String localeKey;
private String unitDataKey;
private String displayName;
private CUnitClassification(final String unitDataKey, final String localeKey) {
this.unitDataKey = unitDataKey;
this.localeKey = localeKey;
}
private CUnitClassification(final String unitDataKey) {
this.unitDataKey = unitDataKey;
this.localeKey = null;
}
public String getUnitDataKey() {
return this.unitDataKey;
}
public String getLocaleKey() {
return this.localeKey;
}
public String getDisplayName() {
return this.displayName;
}
public void setDisplayName(final String displayName) {
this.displayName = displayName;
}
public static CUnitClassification parseUnitClassification(final String unitEditorKey) {
return UNIT_EDITOR_KEY_TO_CLASSIFICATION.get(unitEditorKey.toLowerCase());
}
}

View File

@ -1,24 +1,51 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import java.util.EnumSet;
import java.util.List;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
/**
* The quick (symbol table instead of map) lookup for unit type values that we
* probably cannot change per unit instance.
*/
public class CUnitType {
private final String name;
private final boolean building;
private final PathingGrid.MovementType movementType;
private final float defaultFlyingHeight;
private final float collisionSize;
private final EnumSet<CUnitClassification> classifications;
private final List<CUnitAttack> attacks;
private final String armorType; // used for audio
private final boolean raise;
private final boolean decay;
private final CDefenseType defenseType;
private final float impactZ;
public CUnitType(final boolean isBldg, final MovementType movementType, final float defaultFlyingHeight,
final float collisionSize) {
public CUnitType(final String name, final boolean isBldg, final MovementType movementType,
final float defaultFlyingHeight, final float collisionSize,
final EnumSet<CUnitClassification> classifications, final List<CUnitAttack> attacks, final String armorType,
final boolean raise, final boolean decay, final CDefenseType defenseType, final float impactZ) {
this.name = name;
this.building = isBldg;
this.movementType = movementType;
this.defaultFlyingHeight = defaultFlyingHeight;
this.collisionSize = collisionSize;
this.classifications = classifications;
this.attacks = attacks;
this.armorType = armorType;
this.raise = raise;
this.decay = decay;
this.defenseType = defenseType;
this.impactZ = impactZ;
}
public String getName() {
return this.name;
}
public float getDefaultFlyingHeight() {
@ -36,4 +63,32 @@ public class CUnitType {
public boolean isBuilding() {
return this.building;
}
public EnumSet<CUnitClassification> getClassifications() {
return this.classifications;
}
public List<CUnitAttack> getAttacks() {
return this.attacks;
}
public boolean isRaise() {
return this.raise;
}
public boolean isDecay() {
return this.decay;
}
public String getArmorType() {
return this.armorType;
}
public CDefenseType getDefenseType() {
return this.defenseType;
}
public float getImpactZ() {
return this.impactZ;
}
}

View File

@ -47,4 +47,6 @@ public abstract class CWidget {
public abstract float getFlyHeight();
public abstract float getImpactZ();
}

View File

@ -47,7 +47,7 @@ public class CAbilityAttack implements CAbility {
@Override
public void onOrder(final CSimulation game, final CUnit caster, final CWidget target, final boolean queue) {
caster.order(new CAttackOrder(caster, target), queue);
caster.order(new CAttackOrder(caster, caster.getUnitType().getAttacks().get(0), target), queue);
}
@Override

View File

@ -0,0 +1,31 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat;
public enum CAttackType implements CodeKeyType {
UNKNOWN,
NORMAL,
PIERCE,
SIEGE,
SPELLS,
CHAOS,
MAGIC,
HERO;
private String codeKey;
private CAttackType() {
String name = name();
if (name.equals("SPELLS")) {
name = "MAGIC";
}
this.codeKey = name.charAt(0) + name.substring(1).toLowerCase();
}
@Override
public String getCodeKey() {
return this.codeKey;
}
public static CAttackType parseAttackType(final String attackTypeString) {
return valueOf(attackTypeString.toUpperCase());
}
}

View File

@ -0,0 +1,27 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat;
public enum CDefenseType implements CodeKeyType {
NONE,
NORMAL,
SMALL,
MEDIUM,
LARGE,
FORT,
HERO,
DIVINE;
private String codeKey;
private CDefenseType() {
this.codeKey = name().charAt(0) + name().substring(1).toLowerCase();
}
@Override
public String getCodeKey() {
return this.codeKey;
}
public static CDefenseType parseDefenseType(final String typeString) {
return valueOf(typeString.toUpperCase());
}
}

View File

@ -0,0 +1,13 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat;
public enum CRegenType {
NONE,
ALWAYS,
BLIGHT,
DAY,
NIGHT;
public static CRegenType parseRegenType(final String typeString) {
return valueOf(typeString.toUpperCase());
}
}

View File

@ -0,0 +1,139 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat;
import java.util.EnumSet;
public enum CTargetType {
AIR,
ALIVE,
ALLIES,
DEAD,
DEBRIS,
ENEMIES,
GROUND,
HERO,
INVULNERABLE,
ITEM,
MECHANICAL,
NEUTRAL,
NONE,
NONHERO,
NONSAPPER,
NOTSELF,
ORGANIC,
PLAYERUNITS,
SAPPER,
SELF,
STRUCTURE,
TERRAIN,
TREE,
VULNERABLE,
WALL,
WARD,
ANCIENT,
NONANCIENT,
FRIEND,
BRIDGE,
DECORATION;
public static CTargetType parseTargetType(final String targetTypeString) {
if (targetTypeString == null) {
return null;
}
switch (targetTypeString.toLowerCase()) {
case "air":
return AIR;
case "alive":
case "aliv":
return ALIVE;
case "allies":
case "alli":
case "ally":
return ALLIES;
case "dead":
return DEAD;
case "debris":
case "debr":
return DEBRIS;
case "enemies":
case "enem":
case "enemy":
return ENEMIES;
case "ground":
case "grou":
return GROUND;
case "hero":
return HERO;
case "invulnerable":
case "invu":
return INVULNERABLE;
case "item":
return ITEM;
case "mechanical":
case "mech":
return MECHANICAL;
case "neutral":
case "neut":
return NEUTRAL;
case "none":
return NONE;
case "nonhero":
case "nonh":
return NONHERO;
case "nonsapper":
return NONSAPPER;
case "notself":
case "nots":
return NOTSELF;
case "organic":
case "orga":
return ORGANIC;
case "player":
case "play":
return PLAYERUNITS;
case "sapper":
return SAPPER;
case "self":
return SELF;
case "structure":
case "stru":
return STRUCTURE;
case "terrain":
case "terr":
return TERRAIN;
case "tree":
return TREE;
case "vulnerable":
case "vuln":
return VULNERABLE;
case "wall":
return WALL;
case "ward":
return WARD;
case "ancient":
return ANCIENT;
case "nonancient":
return NONANCIENT;
case "friend":
case "frie":
return FRIEND;
case "bridge":
return BRIDGE;
case "decoration":
case "deco":
return DECORATION;
default:
return null;
}
}
public static EnumSet<CTargetType> parseTargetTypeSet(final String targetTypeString) {
final EnumSet<CTargetType> types = EnumSet.noneOf(CTargetType.class);
for (final String type : targetTypeString.split(",")) {
final CTargetType parsedType = parseTargetType(type);
if (parsedType != null) {
types.add(parsedType);
}
}
return types;
}
}

View File

@ -0,0 +1,13 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat;
public enum CUpgradeClass {
ARMOR,
ARTILLERY,
MELEE,
RANGED,
CASTER;
public static CUpgradeClass parseUpgradeClass(final String upgradeClassString) {
return valueOf(upgradeClassString.toUpperCase());
}
}

View File

@ -0,0 +1,16 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat;
public enum CWeaponType {
NORMAL,
INSTANT,
ARTILLERY,
ALINE,
MISSILE,
MSPLASH,
MBOUNCE,
MLINE;
public static CWeaponType parseWeaponType(final String weaponTypeString) {
return valueOf(weaponTypeString.toUpperCase());
}
}

View File

@ -0,0 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat;
public interface CodeKeyType {
String getCodeKey();
int ordinal();
}

View File

@ -0,0 +1,198 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
/**
* The base class for unit-data-based combat attacks.
*
* I really wanted to split this out into sub classes based on weapon type, but
* I came to realize the Ballista in RoC probably had the spill distance effect
* & area of effect both after it upgrades Impaling Bolt, and this would point
* out that the behaviors were not mutually exclusive.
*
* Then I reviewed it and decided that in RoC, the Impaling Bolts upgrade did
* not interact with the damage spill combat settings from the UnitWeapons.slk,
* because many of those settings did not exist. So I will attempt to emulate
* these attacks as best as possible.
*/
public class CUnitAttack {
private float animationBackswingPoint;
private float animationDamagePoint;
private CAttackType attackType;
private float cooldownTime;
private int damageBase;
private int damageDice;
private int damageSidesPerDie;
private int damageUpgradeAmount;
private int range;
private float rangeMotionBuffer;
private boolean showUI;
private EnumSet<CTargetType> targetsAllowed;
private String weaponSound;
private CWeaponType weaponType;
// calculate
private int minDamage;
private int maxDamage;
public CUnitAttack(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
final int damageSidesPerDie, final int damageUpgradeAmount, final int range, final float rangeMotionBuffer,
final boolean showUI, final EnumSet<CTargetType> targetsAllowed, final String weaponSound,
final CWeaponType weaponType) {
this.animationBackswingPoint = animationBackswingPoint;
this.animationDamagePoint = animationDamagePoint;
this.attackType = attackType;
this.cooldownTime = cooldownTime;
this.damageBase = damageBase;
this.damageDice = damageDice;
this.damageSidesPerDie = damageSidesPerDie;
this.damageUpgradeAmount = damageUpgradeAmount;
this.range = range;
this.rangeMotionBuffer = rangeMotionBuffer;
this.showUI = showUI;
this.targetsAllowed = targetsAllowed;
this.weaponSound = weaponSound;
this.weaponType = weaponType;
computeDerivedFields();
}
private void computeDerivedFields() {
this.minDamage = this.damageBase + this.damageDice;
this.maxDamage = this.damageBase + (this.damageDice * this.damageSidesPerDie);
if (this.minDamage < 0) {
this.minDamage = 0;
}
if (this.maxDamage < 0) {
this.maxDamage = 0;
}
}
public float getAnimationBackswingPoint() {
return this.animationBackswingPoint;
}
public float getAnimationDamagePoint() {
return this.animationDamagePoint;
}
public CAttackType getAttackType() {
return this.attackType;
}
public float getCooldownTime() {
return this.cooldownTime;
}
public int getDamageBase() {
return this.damageBase;
}
public int getDamageDice() {
return this.damageDice;
}
public int getDamageSidesPerDie() {
return this.damageSidesPerDie;
}
public int getDamageUpgradeAmount() {
return this.damageUpgradeAmount;
}
public int getRange() {
return this.range;
}
public float getRangeMotionBuffer() {
return this.rangeMotionBuffer;
}
public boolean isShowUI() {
return this.showUI;
}
public EnumSet<CTargetType> getTargetsAllowed() {
return this.targetsAllowed;
}
public String getWeaponSound() {
return this.weaponSound;
}
public CWeaponType getWeaponType() {
return this.weaponType;
}
public void setAnimationBackswingPoint(final float animationBackswingPoint) {
this.animationBackswingPoint = animationBackswingPoint;
}
public void setAnimationDamagePoint(final float animationDamagePoint) {
this.animationDamagePoint = animationDamagePoint;
}
public void setAttackType(final CAttackType attackType) {
this.attackType = attackType;
}
public void setCooldownTime(final float cooldownTime) {
this.cooldownTime = cooldownTime;
}
public void setDamageBase(final int damageBase) {
this.damageBase = damageBase;
computeDerivedFields();
}
public void setDamageDice(final int damageDice) {
this.damageDice = damageDice;
computeDerivedFields();
}
public void setDamageSidesPerDie(final int damageSidesPerDie) {
this.damageSidesPerDie = damageSidesPerDie;
computeDerivedFields();
}
public void setDamageUpgradeAmount(final int damageUpgradeAmount) {
this.damageUpgradeAmount = damageUpgradeAmount;
}
public void setRange(final int range) {
this.range = range;
}
public void setRangeMotionBuffer(final float rangeMotionBuffer) {
this.rangeMotionBuffer = rangeMotionBuffer;
}
public void setShowUI(final boolean showUI) {
this.showUI = showUI;
}
public void setTargetsAllowed(final EnumSet<CTargetType> targetsAllowed) {
this.targetsAllowed = targetsAllowed;
}
public void setWeaponSound(final String weaponSound) {
this.weaponSound = weaponSound;
}
public void setWeaponType(final CWeaponType weaponType) {
this.weaponType = weaponType;
}
public int getMinDamage() {
return this.minDamage;
}
public int getMaxDamage() {
return this.maxDamage;
}
}

View File

@ -0,0 +1,31 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
public class CUnitAttackInstant extends CUnitAttack {
private String projectileArt;
public CUnitAttackInstant(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
final int damageSidesPerDie, final int damageUpgradeAmount, final int range, final float rangeMotionBuffer,
final boolean showUI, final EnumSet<CTargetType> targetsAllowed, final String weaponSound,
final CWeaponType weaponType, final String projectileArt) {
super(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime, damageBase, damageDice,
damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType);
this.projectileArt = projectileArt;
}
public String getProjectileArt() {
return this.projectileArt;
}
public void setProjectileArt(final String projectileArt) {
this.projectileArt = projectileArt;
}
}

View File

@ -0,0 +1,62 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
public class CUnitAttackMissile extends CUnitAttack {
private float projectileArc;
private String projectileArt;
private boolean projectileHomingEnabled;
private int projectileSpeed;
public CUnitAttackMissile(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
final int damageSidesPerDie, final int damageUpgradeAmount, final int range, final float rangeMotionBuffer,
final boolean showUI, final EnumSet<CTargetType> targetsAllowed, final String weaponSound,
final CWeaponType weaponType, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed) {
super(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime, damageBase, damageDice,
damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType);
this.projectileArc = projectileArc;
this.projectileArt = projectileArt;
this.projectileHomingEnabled = projectileHomingEnabled;
this.projectileSpeed = projectileSpeed;
}
public float getProjectileArc() {
return this.projectileArc;
}
public String getProjectileArt() {
return this.projectileArt;
}
public boolean isProjectileHomingEnabled() {
return this.projectileHomingEnabled;
}
public int getProjectileSpeed() {
return this.projectileSpeed;
}
public void setProjectileArc(final float projectileArc) {
this.projectileArc = projectileArc;
}
public void setProjectileArt(final String projectileArt) {
this.projectileArt = projectileArt;
}
public void setProjectileHomingEnabled(final boolean projectileHomingEnabled) {
this.projectileHomingEnabled = projectileHomingEnabled;
}
public void setProjectileSpeed(final int projectileSpeed) {
this.projectileSpeed = projectileSpeed;
}
}

View File

@ -0,0 +1,43 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
public class CUnitAttackMissileBounce extends CUnitAttackMissile {
private float damageLossFactor;
private int maximumNumberOfTargets;
public CUnitAttackMissileBounce(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
final int damageSidesPerDie, final int damageUpgradeAmount, final int range, final float rangeMotionBuffer,
final boolean showUI, final EnumSet<CTargetType> targetsAllowed, final String weaponSound,
final CWeaponType weaponType, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final float damageLossFactor,
final int maximumNumberOfTargets) {
super(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime, damageBase, damageDice,
damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed);
this.damageLossFactor = damageLossFactor;
this.maximumNumberOfTargets = maximumNumberOfTargets;
}
public float getDamageLossFactor() {
return this.damageLossFactor;
}
public int getMaximumNumberOfTargets() {
return this.maximumNumberOfTargets;
}
public void setDamageLossFactor(final float damageLossFactor) {
this.damageLossFactor = damageLossFactor;
}
public void setMaximumNumberOfTargets(final int maximumNumberOfTargets) {
this.maximumNumberOfTargets = maximumNumberOfTargets;
}
}

View File

@ -0,0 +1,43 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
public class CUnitAttackMissileLine extends CUnitAttackMissile {
private float damageSpillDistance;
private float damageSpillRadius;
public CUnitAttackMissileLine(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
final int damageSidesPerDie, final int damageUpgradeAmount, final int range, final float rangeMotionBuffer,
final boolean showUI, final EnumSet<CTargetType> targetsAllowed, final String weaponSound,
final CWeaponType weaponType, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final float damageSpillDistance,
final float damageSpillRadius) {
super(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime, damageBase, damageDice,
damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed);
this.damageSpillDistance = damageSpillDistance;
this.damageSpillRadius = damageSpillRadius;
}
public float getDamageSpillDistance() {
return this.damageSpillDistance;
}
public float getDamageSpillRadius() {
return this.damageSpillRadius;
}
public void setDamageSpillDistance(final float damageSpillDistance) {
this.damageSpillDistance = damageSpillDistance;
}
public void setDamageSpillRadius(final float damageSpillRadius) {
this.damageSpillRadius = damageSpillRadius;
}
}

View File

@ -0,0 +1,85 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
public class CUnitAttackMissileSplash extends CUnitAttackMissile {
private int areaOfEffectFullDamage;
private int areaOfEffectMediumDamage;
private int areaOfEffectSmallDamage;
private EnumSet<CTargetType> areaOfEffectTargets;
private float damageFactorMedium;
private float damageFactorSmall;
public CUnitAttackMissileSplash(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
final int damageSidesPerDie, final int damageUpgradeAmount, final int range, final float rangeMotionBuffer,
final boolean showUI, final EnumSet<CTargetType> targetsAllowed, final String weaponSound,
final CWeaponType weaponType, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final int areaOfEffectFullDamage,
final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
final EnumSet<CTargetType> areaOfEffectTargets, final float damageFactorMedium,
final float damageFactorSmall) {
super(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime, damageBase, damageDice,
damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed);
this.areaOfEffectFullDamage = areaOfEffectFullDamage;
this.areaOfEffectMediumDamage = areaOfEffectMediumDamage;
this.areaOfEffectSmallDamage = areaOfEffectSmallDamage;
this.areaOfEffectTargets = areaOfEffectTargets;
this.damageFactorMedium = damageFactorMedium;
this.damageFactorSmall = damageFactorSmall;
}
public int getAreaOfEffectFullDamage() {
return this.areaOfEffectFullDamage;
}
public int getAreaOfEffectMediumDamage() {
return this.areaOfEffectMediumDamage;
}
public int getAreaOfEffectSmallDamage() {
return this.areaOfEffectSmallDamage;
}
public EnumSet<CTargetType> getAreaOfEffectTargets() {
return this.areaOfEffectTargets;
}
public float getDamageFactorMedium() {
return this.damageFactorMedium;
}
public float getDamageFactorSmall() {
return this.damageFactorSmall;
}
public void setAreaOfEffectFullDamage(final int areaOfEffectFullDamage) {
this.areaOfEffectFullDamage = areaOfEffectFullDamage;
}
public void setAreaOfEffectMediumDamage(final int areaOfEffectMediumDamage) {
this.areaOfEffectMediumDamage = areaOfEffectMediumDamage;
}
public void setAreaOfEffectSmallDamage(final int areaOfEffectSmallDamage) {
this.areaOfEffectSmallDamage = areaOfEffectSmallDamage;
}
public void setAreaOfEffectTargets(final EnumSet<CTargetType> areaOfEffectTargets) {
this.areaOfEffectTargets = areaOfEffectTargets;
}
public void setDamageFactorMedium(final float damageFactorMedium) {
this.damageFactorMedium = damageFactorMedium;
}
public void setDamageFactorSmall(final float damageFactorSmall) {
this.damageFactorSmall = damageFactorSmall;
}
}

View File

@ -0,0 +1,21 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
public class CUnitAttackNormal extends CUnitAttack {
public CUnitAttackNormal(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
final int damageSidesPerDie, final int damageUpgradeAmount, final int range, final float rangeMotionBuffer,
final boolean showUI, final EnumSet<CTargetType> targetsAllowed, final String weaponSound,
final CWeaponType weaponType) {
super(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime, damageBase, damageDice,
damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType);
}
}

View File

@ -1,4 +1,4 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.projectile;
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;

View File

@ -1,6 +1,9 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.data;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.etheller.warsmash.units.manager.MutableObjectData;
@ -9,12 +12,24 @@ import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityHoldPosition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityPatrol;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityStop;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackInstant;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissileBounce;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissileLine;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissileSplash;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackNormal;
public class CUnitData {
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
@ -28,24 +43,76 @@ public class CUnitData {
private static final War3ID PROJECTILE_LAUNCH_X = War3ID.fromString("ulpx");
private static final War3ID PROJECTILE_LAUNCH_Y = War3ID.fromString("ulpy");
private static final War3ID PROJECTILE_LAUNCH_Z = War3ID.fromString("ulpz");
private static final War3ID ATTACKS_ENABLED = War3ID.fromString("uaen");
private static final War3ID ATTACK1_BACKSWING_POINT = War3ID.fromString("ubs1");
private static final War3ID ATTACK1_DAMAGE_POINT = War3ID.fromString("udp1");
private static final War3ID ATTACK1_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua1f");
private static final War3ID ATTACK1_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua1h");
private static final War3ID ATTACK1_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua1q");
private static final War3ID ATTACK1_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua1p");
private static final War3ID ATTACK1_ATTACK_TYPE = War3ID.fromString("ua1t");
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
private static final War3ID ATTACK1_DMG_BASE = War3ID.fromString("ua1b");
private static final War3ID ATTACK1_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd1");
private static final War3ID ATTACK1_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd1");
private static final War3ID ATTACK1_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl1");
private static final War3ID ATTACK1_DMG_DICE = War3ID.fromString("ua1d");
private static final War3ID ATTACK1_DMG_SIDES_PER_DIE = War3ID.fromString("ua1s");
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
private static final War3ID ATTACK1_DMG_SPILL_DIST = War3ID.fromString("usd1");
private static final War3ID ATTACK1_DMG_SPILL_RADIUS = War3ID.fromString("usr1");
private static final War3ID ATTACK1_DMG_UPGRADE_AMT = War3ID.fromString("udu1");
private static final War3ID ATTACK1_TARGET_COUNT = War3ID.fromString("utc1");
private static final War3ID ATTACK1_PROJECTILE_ARC = War3ID.fromString("uma1");
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
private static final War3ID ATTACK1_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh1");
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
private static final War3ID ATTACK1_RANGE = War3ID.fromString("ua1r");
private static final War3ID ATTACK1_RANGE_MOTION_BUFFER = War3ID.fromString("urb1");
private static final War3ID ATTACK1_SHOW_UI = War3ID.fromString("uwu1");
private static final War3ID ATTACK1_TARGETS_ALLOWED = War3ID.fromString("ua1g");
private static final War3ID ATTACK1_WEAPON_SOUND = War3ID.fromString("ucs1");
private static final War3ID ATTACK1_WEAPON_TYPE = War3ID.fromString("ua1w");
private static final War3ID ATTACK2_BACKSWING_POINT = War3ID.fromString("ubs2");
private static final War3ID ATTACK2_DAMAGE_POINT = War3ID.fromString("udp2");
private static final War3ID ATTACK2_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua2f");
private static final War3ID ATTACK2_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua2h");
private static final War3ID ATTACK2_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua2q");
private static final War3ID ATTACK2_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua2p");
private static final War3ID ATTACK2_ATTACK_TYPE = War3ID.fromString("ua2t");
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
private static final War3ID ATTACK2_DMG_BASE = War3ID.fromString("ua2b");
private static final War3ID ATTACK2_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd2");
private static final War3ID ATTACK2_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd2");
private static final War3ID ATTACK2_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl2");
private static final War3ID ATTACK2_DMG_DICE = War3ID.fromString("ua2d");
private static final War3ID ATTACK2_DMG_SIDES_PER_DIE = War3ID.fromString("ua2s");
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
private static final War3ID ATTACK2_DMG_SPILL_DIST = War3ID.fromString("usd2");
private static final War3ID ATTACK2_DMG_SPILL_RADIUS = War3ID.fromString("usr2");
private static final War3ID ATTACK2_DMG_UPGRADE_AMT = War3ID.fromString("udu2");
private static final War3ID ATTACK2_TARGET_COUNT = War3ID.fromString("utc2");
private static final War3ID ATTACK2_PROJECTILE_ARC = War3ID.fromString("uma2");
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
private static final War3ID ATTACK2_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh2");
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
private static final War3ID ATTACK2_RANGE = War3ID.fromString("ua2r");
private static final War3ID ATTACK2_RANGE_MOTION_BUFFER = War3ID.fromString("urb2");
private static final War3ID ATTACK2_SHOW_UI = War3ID.fromString("uwu2");
private static final War3ID ATTACK2_TARGETS_ALLOWED = War3ID.fromString("ua2g");
private static final War3ID ATTACK2_WEAPON_SOUND = War3ID.fromString("ucs2");
private static final War3ID ATTACK2_WEAPON_TYPE = War3ID.fromString("ua2w");
private static final War3ID PROJECTILE_IMPACT_Z = War3ID.fromString("uimz");
private static final War3ID DEATH_TYPE = War3ID.fromString("udea");
private static final War3ID ARMOR_TYPE = War3ID.fromString("uarm");
private static final War3ID DEFENSE = War3ID.fromString("udef");
private static final War3ID DEFENSE_TYPE = War3ID.fromString("udty");
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
private static final War3ID MOVE_TYPE = War3ID.fromString("umvt");
private static final War3ID COLLISION_SIZE = War3ID.fromString("ucol");
private static final War3ID CLASSIFICATION = War3ID.fromString("utyp");
private final MutableObjectData unitData;
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
@ -65,8 +132,113 @@ public class CUnitData {
final float collisionSize = unitType.getFieldAsFloat(COLLISION_SIZE, 0);
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
final PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
final String unitName = unitType.getFieldAsString(NAME, 0);
final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
if (classificationString != null) {
final String[] classificationValues = classificationString.split(",");
for (final String unitEditorKey : classificationValues) {
final CUnitClassification unitClassification = CUnitClassification
.parseUnitClassification(unitEditorKey);
if (unitClassification != null) {
classifications.add(unitClassification);
}
}
}
final List<CUnitAttack> attacks = new ArrayList<>();
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
if ((attacksEnabled & 0x1) != 0) {
// attack one
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_QUARTER_DMG, 0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK1_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK1_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK1_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK1_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK1_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK1_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK1_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK1_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK1_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK1_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK1_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK1_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK1_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType, cooldownTime,
damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice, damageSidesPerDie,
damageSpillDistance, damageSpillRadius, damageUpgradeAmount, maximumNumberOfTargets, projectileArc,
projectileArt, projectileHomingEnabled, projectileSpeed, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType));
}
if ((attacksEnabled & 0x2) != 0) {
// attack two
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_QUARTER_DMG, 0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK2_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK2_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK2_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK2_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK2_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK2_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK2_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK2_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK2_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK2_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK2_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK2_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK2_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType, cooldownTime,
damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice, damageSidesPerDie,
damageSpillDistance, damageSpillRadius, damageUpgradeAmount, maximumNumberOfTargets, projectileArc,
projectileArt, projectileHomingEnabled, projectileSpeed, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType));
}
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
final boolean raise = (deathType & 0x1) != 0;
final boolean decay = (deathType & 0x2) != 0;
final String armorType = unitType.getFieldAsString(ARMOR_TYPE, 0);
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
final float impactZ = unitType.getFieldAsFloat(PROJECTILE_IMPACT_Z, 0);
final CDefenseType defenseType = CDefenseType.parseDefenseType(unitType.getFieldAsString(DEFENSE_TYPE, 0));
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
speed, new CUnitType(isBldg, movementType, moveHeight, collisionSize));
speed, defense, new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize,
classifications, attacks, armorType, raise, decay, defenseType, impactZ));
if (speed > 0) {
unit.add(simulation, CAbilityMove.INSTANCE);
unit.add(simulation, CAbilityPatrol.INSTANCE);
@ -81,6 +253,60 @@ public class CUnitData {
return unit;
}
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
final EnumSet<CTargetType> areaOfEffectTargets, final CAttackType attackType, final float cooldownTime,
final int damageBase, final float damageFactorMedium, final float damageFactorSmall,
final float damageLossFactor, final int damageDice, final int damageSidesPerDie,
final float damageSpillDistance, final float damageSpillRadius, final int damageUpgradeAmount,
final int maximumNumberOfTargets, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final int range,
final float rangeMotionBuffer, final boolean showUI, final EnumSet<CTargetType> targetsAllowed,
final String weaponSound, final CWeaponType weaponType) {
final CUnitAttack attack;
switch (weaponType) {
case MISSILE:
attack = new CUnitAttackMissile(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed);
break;
case MBOUNCE:
attack = new CUnitAttackMissileBounce(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, damageLossFactor, maximumNumberOfTargets);
break;
case MSPLASH:
case ARTILLERY:
attack = new CUnitAttackMissileSplash(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, areaOfEffectFullDamage, areaOfEffectMediumDamage,
areaOfEffectSmallDamage, areaOfEffectTargets, damageFactorMedium, damageFactorSmall);
break;
case MLINE:
case ALINE:
attack = new CUnitAttackMissileLine(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, damageSpillDistance, damageSpillRadius);
break;
case INSTANT:
attack = new CUnitAttackInstant(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArt);
break;
default:
case NORMAL:
attack = new CUnitAttackNormal(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType);
break;
}
return attack;
}
public float getPropulsionWindow(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROPULSION_WINDOW, 0);
}

View File

@ -1,20 +1,25 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitAnimationListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
public class CAttackOrder implements COrder {
private final CUnit unit;
private boolean wasWithinPropWindow = false;
private final CUnitAttack unitAttack;
private final CWidget target;
private int backswingLaunchTime;
public CAttackOrder(final CUnit unit, final CWidget target) {
public CAttackOrder(final CUnit unit, final CUnitAttack unitAttack, final CWidget target) {
this.unit = unit;
this.unitAttack = unitAttack;
this.target = target;
}
@ -31,9 +36,8 @@ public class CAttackOrder implements COrder {
}
float facing = this.unit.getFacing();
float delta = goalAngle - facing;
final float propulsionWindow = simulation.getUnitData().getPropulsionWindow(this.unit.getTypeId());
final float propulsionWindow = simulation.getGameplayConstants().getAttackHalfAngle();
final float turnRate = simulation.getUnitData().getTurnRate(this.unit.getTypeId());
final int speed = this.unit.getSpeed();
if (delta < -180) {
delta = 360 + delta;
@ -65,11 +69,30 @@ public class CAttackOrder implements COrder {
final int cooldownEndTime = this.unit.getCooldownEndTime();
final int currentTurnTick = simulation.getGameTurnTick();
if (currentTurnTick >= cooldownEndTime) {
final float a1Cooldown = simulation.getUnitData().getA1Cooldown(this.unit.getTypeId());
final int a1CooldownSteps = (int) (a1Cooldown / WarsmashConstants.SIMULATION_STEP_TIME);
this.unit.setCooldownEndTime(currentTurnTick + a1CooldownSteps);
simulation.createProjectile(this.unit, 0, this.target);
if (this.wasWithinPropWindow) {
if (this.backswingLaunchTime != 0) {
if (currentTurnTick >= this.backswingLaunchTime) {
simulation.createProjectile(this.unit, 0, this.target);
this.backswingLaunchTime = 0;
}
}
else if (currentTurnTick >= cooldownEndTime) {
final float cooldownTime = this.unitAttack.getCooldownTime();
final float animationBackswingPoint = this.unitAttack.getAnimationBackswingPoint();
final int a1CooldownSteps = (int) (cooldownTime / WarsmashConstants.SIMULATION_STEP_TIME);
final int a1BackswingSteps = (int) (animationBackswingPoint / WarsmashConstants.SIMULATION_STEP_TIME);
final int a1DamagePointSteps = (int) (this.unitAttack.getAnimationDamagePoint()
/ WarsmashConstants.SIMULATION_STEP_TIME);
this.unit.setCooldownEndTime(currentTurnTick + a1CooldownSteps);
this.backswingLaunchTime = currentTurnTick + a1DamagePointSteps;
this.unit.getUnitAnimationListener().playAnimation(true, PrimaryTag.ATTACK,
CUnitAnimationListener.EMPTY, 1.0f);
this.unit.getUnitAnimationListener().queueAnimation(PrimaryTag.STAND, CUnitAnimationListener.READY);
}
}
else {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, CUnitAnimationListener.READY,
1.0f);
}
return false;
@ -80,9 +103,4 @@ public class CAttackOrder implements COrder {
return CAbilityAttack.ORDER_ID;
}
@Override
public AnimationTokens.PrimaryTag getAnimationName() {
return AnimationTokens.PrimaryTag.ATTACK;
}
}

View File

@ -1,6 +1,5 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
@ -21,9 +20,4 @@ public class CDoNothingOrder implements COrder {
return this.orderId;
}
@Override
public AnimationTokens.PrimaryTag getAnimationName() {
return AnimationTokens.PrimaryTag.STAND;
}
}

View File

@ -6,12 +6,13 @@ import java.util.List;
import com.badlogic.gdx.math.Rectangle;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.COrder;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitAnimationListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWorldCollision;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CPathfindingProcessor;
@ -207,6 +208,10 @@ public class CMoveOrder implements COrder {
}
absDelta = Math.abs(delta);
if (absDelta >= propulsionWindow) {
if (this.wasWithinPropWindow) {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND,
CUnitAnimationListener.EMPTY, 1.0f);
}
this.wasWithinPropWindow = false;
return false;
}
@ -224,6 +229,10 @@ public class CMoveOrder implements COrder {
this.path.add(this.target);
}
}
if (!this.wasWithinPropWindow) {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.WALK,
CUnitAnimationListener.EMPTY, 1.0f);
}
this.wasWithinPropWindow = true;
}
while (continueDistance > 0);
@ -231,6 +240,10 @@ public class CMoveOrder implements COrder {
else {
// If this happens, the unit is facing the wrong way, and has to turn before
// moving.
if (this.wasWithinPropWindow) {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND,
CUnitAnimationListener.EMPTY, 1.0f);
}
this.wasWithinPropWindow = false;
}
@ -242,12 +255,4 @@ public class CMoveOrder implements COrder {
return CAbilityMove.ORDER_ID;
}
@Override
public AnimationTokens.PrimaryTag getAnimationName() {
if (!this.wasWithinPropWindow) {
return AnimationTokens.PrimaryTag.STAND;
}
return AnimationTokens.PrimaryTag.WALK;
}
}

View File

@ -3,7 +3,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
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.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
public interface ProjectileCreator {
CAttackProjectile create(CSimulation simulation, CUnit source, int attackIndex, CWidget target);

View File

@ -0,0 +1,372 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import java.io.IOException;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.WarsmashGdxMapGame;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.util.FastNumberFormat;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.StandSequence;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CodeKeyType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
public class MeleeUI {
private final DataSource dataSource;
private final Viewport uiViewport;
private final FreeTypeFontGenerator fontGenerator;
private final Scene uiScene;
private final War3MapViewer war3MapViewer;
private final RootFrameListener rootFrameListener;
private GameUI rootFrame;
private UIFrame consoleUI;
private UIFrame resourceBar;
private UIFrame timeIndicator;
private UIFrame unitPortrait;
private StringFrame unitLifeText;
private StringFrame unitManaText;
private Portrait portrait;
private final Rectangle tempRect = new Rectangle();
private final Vector2 projectionTemp1 = new Vector2();
private final Vector2 projectionTemp2 = new Vector2();
private UIFrame simpleInfoPanelUnitDetail;
private StringFrame simpleNameValue;
private StringFrame simpleClassValue;
private StringFrame simpleBuildingActionLabel;
private UIFrame attack1Icon;
private TextureFrame attack1IconBackdrop;
private StringFrame attack1InfoPanelIconValue;
private StringFrame attack1InfoPanelIconLevel;
private UIFrame attack2Icon;
private TextureFrame attack2IconBackdrop;
private StringFrame attack2InfoPanelIconValue;
private StringFrame attack2InfoPanelIconLevel;
private UIFrame armorIcon;
private TextureFrame armorIconBackdrop;
private StringFrame armorInfoPanelIconValue;
private StringFrame armorInfoPanelIconLevel;
private InfoPanelIconBackdrops damageBackdrops;
private InfoPanelIconBackdrops defenseBackdrops;
public MeleeUI(final DataSource dataSource, final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator,
final Scene uiScene, final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener) {
this.dataSource = dataSource;
this.uiViewport = uiViewport;
this.fontGenerator = fontGenerator;
this.uiScene = uiScene;
this.war3MapViewer = war3MapViewer;
this.rootFrameListener = rootFrameListener;
}
/**
* 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, 1), this.uiViewport,
this.fontGenerator, this.uiScene, this.war3MapViewer);
try {
this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
}
catch (final IOException exc) {
throw new IllegalStateException("Unable to load FrameDef.toc", exc);
}
try {
this.rootFrame.loadTOCFile("UI\\FrameDef\\SmashFrameDef.toc");
}
catch (final IOException exc) {
throw new IllegalStateException("Unable to load SmashFrameDef.toc", exc);
}
this.damageBackdrops = new InfoPanelIconBackdrops(CAttackType.values(), this.rootFrame, "Damage", "Neutral");
this.defenseBackdrops = new InfoPanelIconBackdrops(CDefenseType.values(), this.rootFrame, "Armor", "Neutral");
// =================================
// Load major UI components
// =================================
// Console UI is the background with the racial theme
this.consoleUI = this.rootFrame.createSimpleFrame("ConsoleUI", this.rootFrame, 0);
this.consoleUI.setSetAllPoints(true);
// Resource bar is a 3 part bar with Gold, Lumber, and Food.
// Its template does not specify where to put it, so we must
// put it in the "TOPRIGHT" corner.
this.resourceBar = this.rootFrame.createSimpleFrame("ResourceBarFrame", this.consoleUI, 0);
this.resourceBar.addSetPoint(new SetPoint(FramePoint.TOPRIGHT, this.consoleUI, FramePoint.TOPRIGHT, 0, 0));
// Create the Time Indicator (clock)
this.timeIndicator = this.rootFrame.createFrame("TimeOfDayIndicator", this.rootFrame, 0, 0);
// Create the unit portrait stuff
this.portrait = new Portrait(this.war3MapViewer);
positionPortrait();
this.unitPortrait = this.rootFrame.createSimpleFrame("UnitPortrait", this.consoleUI, 0);
this.unitLifeText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitHitPointText", 0);
this.unitManaText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitManaPointText", 0);
this.simpleInfoPanelUnitDetail = this.rootFrame.createSimpleFrame("SimpleInfoPanelUnitDetail", this.consoleUI,
0);
this.simpleInfoPanelUnitDetail
.addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f)));
this.simpleInfoPanelUnitDetail.setWidth(GameUI.convertY(this.uiViewport, 0.180f));
this.simpleInfoPanelUnitDetail.setHeight(GameUI.convertY(this.uiViewport, 0.105f));
this.simpleNameValue = (StringFrame) this.rootFrame.getFrameByName("SimpleNameValue", 0);
this.simpleClassValue = (StringFrame) this.rootFrame.getFrameByName("SimpleClassValue", 0);
this.simpleBuildingActionLabel = (StringFrame) this.rootFrame.getFrameByName("SimpleBuildingActionLabel", 0);
this.attack1Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail,
0);
this.attack1Icon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail,
FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f)));
this.attack1IconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 0);
this.attack1InfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 0);
this.attack1InfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 0);
this.attack2Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail,
1);
this.attack2Icon
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0.1f), GameUI.convertY(this.uiViewport, -0.030125f)));
this.attack2IconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 1);
this.attack2InfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 1);
this.attack2InfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 1);
this.armorIcon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconArmor", this.simpleInfoPanelUnitDetail,
1);
this.armorIcon.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f)));
this.armorIconBackdrop = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconBackdrop", 0);
this.armorInfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 0);
this.armorInfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 0);
this.rootFrame.positionBounds(this.uiViewport);
selectUnit(null);
}
public void updatePortrait() {
this.portrait.update();
}
public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
this.rootFrame.render(batch, font20, glyphLayout);
}
public void portraitTalk() {
this.portrait.talk();
}
private static final class Portrait {
private MdxComplexInstance modelInstance;
private final WarsmashGdxMapGame.CameraManager portraitCameraManager;
private final Scene portraitScene;
public Portrait(final War3MapViewer war3MapViewer) {
this.portraitScene = war3MapViewer.addSimpleScene();
this.portraitCameraManager = new WarsmashGdxMapGame.CameraManager();
this.portraitCameraManager.setupCamera(this.portraitScene);
this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48));
}
public void update() {
this.portraitCameraManager.updateCamera();
if ((this.modelInstance != null)
&& (this.modelInstance.sequenceEnded || (this.modelInstance.sequence == -1))) {
StandSequence.randomPortraitSequence(this.modelInstance);
}
}
public void talk() {
StandSequence.randomPortraitTalkSequence(this.modelInstance);
}
public void setSelectedUnit(final RenderUnit unit) {
if (unit == null) {
if (this.modelInstance != null) {
this.portraitScene.removeInstance(this.modelInstance);
}
this.modelInstance = null;
this.portraitCameraManager.setModelInstance(null, null);
}
else {
final MdxModel portraitModel = unit.portraitModel;
if (portraitModel != null) {
if (this.modelInstance != null) {
this.portraitScene.removeInstance(this.modelInstance);
}
this.modelInstance = (MdxComplexInstance) portraitModel.addInstance();
this.portraitCameraManager.setModelInstance(this.modelInstance, portraitModel);
this.modelInstance.setSequenceLoopMode(1);
this.modelInstance.setScene(this.portraitScene);
this.modelInstance.setVertexColor(unit.instance.vertexColor);
this.modelInstance.setTeamColor(unit.playerIndex);
}
}
}
}
public void selectUnit(final RenderUnit unit) {
this.portrait.setSelectedUnit(unit);
if (unit == null) {
this.simpleNameValue.setText("");
this.unitLifeText.setText("");
this.unitManaText.setText("");
this.simpleClassValue.setText("");
this.simpleBuildingActionLabel.setText("");
this.attack1Icon.setVisible(false);
this.attack2Icon.setVisible(false);
this.attack1InfoPanelIconLevel.setText("");
this.attack2InfoPanelIconLevel.setText("");
this.armorIcon.setVisible(false);
this.armorInfoPanelIconLevel.setText("");
}
else {
this.simpleNameValue.setText(unit.getSimulationUnit().getUnitType().getName());
String classText = null;
for (final CUnitClassification classification : unit.getSimulationUnit().getClassifications()) {
if (classification.getDisplayName() != null) {
classText = classification.getDisplayName();
}
}
if (classText != null) {
this.simpleClassValue.setText(classText);
}
else {
this.simpleClassValue.setText("");
}
this.unitLifeText.setText(FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getLife()) + " / "
+ unit.getSimulationUnit().getMaximumLife());
final int maximumMana = unit.getSimulationUnit().getMaximumMana();
if (maximumMana > 0) {
this.unitManaText.setText(
FastNumberFormat.formatWholeNumber(unit.getSimulationUnit().getMana()) + " / " + maximumMana);
}
else {
this.unitManaText.setText("");
}
this.simpleBuildingActionLabel.setText("");
if (unit.getSimulationUnit().getUnitType().getAttacks().size() > 0) {
final CUnitAttack attackOne = unit.getSimulationUnit().getUnitType().getAttacks().get(0);
this.attack1Icon.setVisible(attackOne.isShowUI());
this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType()));
this.attack1InfoPanelIconValue.setText(attackOne.getMinDamage() + " - " + attackOne.getMaxDamage());
if (unit.getSimulationUnit().getUnitType().getAttacks().size() > 1) {
final CUnitAttack attackTwo = unit.getSimulationUnit().getUnitType().getAttacks().get(1);
this.attack2Icon.setVisible(attackTwo.isShowUI());
this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType()));
this.attack2InfoPanelIconValue.setText(attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage());
}
else {
this.attack2Icon.setVisible(false);
}
}
else {
this.attack1Icon.setVisible(false);
this.attack2Icon.setVisible(false);
}
this.armorIcon.setVisible(true);
this.armorIconBackdrop.setTexture(
this.defenseBackdrops.getTexture(unit.getSimulationUnit().getUnitType().getDefenseType()));
this.armorInfoPanelIconValue.setText(Integer.toString(unit.getSimulationUnit().getDefense()));
}
}
public void resize() {
positionPortrait();
}
public void positionPortrait() {
this.projectionTemp1.x = 422;
this.projectionTemp1.y = 57;
this.projectionTemp2.x = 422 + 167;
this.projectionTemp2.y = 57 + 170;
this.uiViewport.project(this.projectionTemp1);
this.uiViewport.project(this.projectionTemp2);
this.tempRect.x = this.projectionTemp1.x;
this.tempRect.y = this.projectionTemp1.y;
this.tempRect.width = this.projectionTemp2.x - this.projectionTemp1.x;
this.tempRect.height = this.projectionTemp2.y - this.projectionTemp1.y;
this.portrait.portraitScene.camera.viewport(this.tempRect);
}
private static final class InfoPanelIconBackdrops {
private final Texture[] damageBackdropTextures;
public InfoPanelIconBackdrops(final CodeKeyType[] attackTypes, final GameUI gameUI, final String prefix,
final String suffix) {
this.damageBackdropTextures = new Texture[attackTypes.length];
for (int index = 0; index < attackTypes.length; index++) {
final CodeKeyType attackType = attackTypes[index];
String skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey() + suffix;
try {
this.damageBackdropTextures[index] = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey));
}
catch (final Exception exc) {
skinLookupKey = "InfoPanelIcon" + prefix + attackType.getCodeKey();
this.damageBackdropTextures[index] = gameUI.loadTexture(gameUI.getSkinField(skinLookupKey));
}
}
}
public Texture getTexture(final CodeKeyType attackType) {
if (attackType != null) {
final int ordinal = attackType.ordinal();
if ((ordinal >= 0) && (ordinal < this.damageBackdropTextures.length)) {
return this.damageBackdropTextures[ordinal];
}
}
return this.damageBackdropTextures[0];
}
private static String getSuffix(final CAttackType attackType) {
switch (attackType) {
case CHAOS:
return "Chaos";
case HERO:
return "Hero";
case MAGIC:
return "Magic";
case NORMAL:
return "Normal";
case PIERCE:
return "Pierce";
case SIEGE:
return "Siege";
case SPELLS:
return "Magic";
case UNKNOWN:
return "Unknown";
default:
throw new IllegalArgumentException("Unknown attack type: " + attackType);
}
}
}
}

View File

@ -84,10 +84,12 @@ public class DesktopLauncher {
config.gles30ContextMajorVersion = 3;
config.gles30ContextMinorVersion = 3;
config.samples = 16;
config.fullscreen = true;
final DisplayMode desktopDisplayMode = LwjglApplicationConfiguration.getDesktopDisplayMode();
config.width = desktopDisplayMode.width;
config.height = desktopDisplayMode.height;
config.fullscreen = false;
if (config.fullscreen) {
final DisplayMode desktopDisplayMode = LwjglApplicationConfiguration.getDesktopDisplayMode();
config.width = desktopDisplayMode.width;
config.height = desktopDisplayMode.height;
}
new LwjglApplication(new WarsmashGdxMapGame(warsmashIni), config);
}
}

View File

@ -9,7 +9,9 @@ import java.util.Set;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetFloatFieldVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetFontFieldVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetStringFieldVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetTextJustifyFieldVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetVector4FieldVisitor;
/**
@ -123,4 +125,20 @@ public class FrameDefinition {
}
return null;
}
public FontDefinition getFont(final String id) {
final FrameDefinitionField frameDefinitionField = this.nameToField.get(id);
if (frameDefinitionField != null) {
return frameDefinitionField.visit(GetFontFieldVisitor.INSTANCE);
}
return null;
}
public TextJustify getTextJustify(final String id) {
final FrameDefinitionField frameDefinitionField = this.nameToField.get(id);
if (frameDefinitionField != null) {
return frameDefinitionField.visit(GetTextJustifyFieldVisitor.INSTANCE);
}
return null;
}
}

View File

@ -0,0 +1,57 @@
package com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor;
import com.etheller.warsmash.parsers.fdf.datamodel.FontDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FloatFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FontFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionFieldVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringPairFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.TextJustifyFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector2FrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector3FrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector4FrameDefinitionField;
public class GetFontFieldVisitor implements FrameDefinitionFieldVisitor<FontDefinition> {
public static GetFontFieldVisitor INSTANCE = new GetFontFieldVisitor();
@Override
public FontDefinition accept(final StringFrameDefinitionField field) {
return null;
}
@Override
public FontDefinition accept(final StringPairFrameDefinitionField field) {
return null;
}
@Override
public FontDefinition accept(final FloatFrameDefinitionField field) {
return null;
}
@Override
public FontDefinition accept(final Vector3FrameDefinitionField field) {
return null;
}
@Override
public FontDefinition accept(final Vector4FrameDefinitionField field) {
return null;
}
@Override
public FontDefinition accept(final Vector2FrameDefinitionField field) {
return null;
}
@Override
public FontDefinition accept(final FontFrameDefinitionField field) {
return field.getValue();
}
@Override
public FontDefinition accept(final TextJustifyFrameDefinitionField field) {
return null;
}
}

View File

@ -0,0 +1,57 @@
package com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FloatFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FontFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionFieldVisitor;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringPairFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.TextJustifyFrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector2FrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector3FrameDefinitionField;
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector4FrameDefinitionField;
public class GetTextJustifyFieldVisitor implements FrameDefinitionFieldVisitor<TextJustify> {
public static GetTextJustifyFieldVisitor INSTANCE = new GetTextJustifyFieldVisitor();
@Override
public TextJustify accept(final StringFrameDefinitionField field) {
return null;
}
@Override
public TextJustify accept(final StringPairFrameDefinitionField field) {
return null;
}
@Override
public TextJustify accept(final FloatFrameDefinitionField field) {
return null;
}
@Override
public TextJustify accept(final Vector3FrameDefinitionField field) {
return null;
}
@Override
public TextJustify accept(final Vector4FrameDefinitionField field) {
return null;
}
@Override
public TextJustify accept(final Vector2FrameDefinitionField field) {
return null;
}
@Override
public TextJustify accept(final FontFrameDefinitionField field) {
return null;
}
@Override
public TextJustify accept(final TextJustifyFrameDefinitionField field) {
return field.getValue();
}
}

1
jassparser/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build/

View File

@ -19,7 +19,7 @@ program :
typeDefinition :
TYPE ID EXTENDS ID newlines
;
;
type :
ID # BasicType

View File

@ -1,317 +0,0 @@
// Generated from Jass.g4 by ANTLR 4.7
package com.etheller.interpreter;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
/**
* This class provides an empty implementation of {@link JassVisitor},
* which can be extended to create a visitor which only needs to handle a subset
* of the available methods.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public class JassBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements JassVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitProgram(JassParser.ProgramContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeDefinition(JassParser.TypeDefinitionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitBasicType(JassParser.BasicTypeContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitArrayType(JassParser.ArrayTypeContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNothingType(JassParser.NothingTypeContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitBasicGlobal(JassParser.BasicGlobalContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDefinitionGlobal(JassParser.DefinitionGlobalContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAssignTail(JassParser.AssignTailContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitReferenceExpression(JassParser.ReferenceExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitStringLiteralExpression(JassParser.StringLiteralExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIntegerLiteralExpression(JassParser.IntegerLiteralExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionReferenceExpression(JassParser.FunctionReferenceExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNullExpression(JassParser.NullExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTrueExpression(JassParser.TrueExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFalseExpression(JassParser.FalseExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitArrayReferenceExpression(JassParser.ArrayReferenceExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionCallExpression(JassParser.FunctionCallExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParentheticalExpression(JassParser.ParentheticalExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNotExpression(JassParser.NotExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionExpression(JassParser.FunctionExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSingleArgument(JassParser.SingleArgumentContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitListArgument(JassParser.ListArgumentContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitCallStatement(JassParser.CallStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSetStatement(JassParser.SetStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitArrayedAssignmentStatement(JassParser.ArrayedAssignmentStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitReturnStatement(JassParser.ReturnStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIfStatement(JassParser.IfStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSimpleIfStatement(JassParser.SimpleIfStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIfElseStatement(JassParser.IfElseStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitIfElseIfStatement(JassParser.IfElseIfStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParam(JassParser.ParamContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSingleParameter(JassParser.SingleParameterContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitListParameter(JassParser.ListParameterContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNothingParameter(JassParser.NothingParameterContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGlobalsBlock(JassParser.GlobalsBlockContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeDefinitionBlock(JassParser.TypeDefinitionBlockContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNativeBlock(JassParser.NativeBlockContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitBlock(JassParser.BlockContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionBlock(JassParser.FunctionBlockContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitStatements(JassParser.StatementsContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNewlines(JassParser.NewlinesContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNewlines_opt(JassParser.Newlines_optContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPnewlines(JassParser.PnewlinesContext ctx) { return visitChildren(ctx); }
}

View File

@ -1,224 +0,0 @@
// Generated from Jass.g4 by ANTLR 4.7
package com.etheller.interpreter;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class JassLexer extends Lexer {
static { RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, EQUALS=6, GLOBALS=7, ENDGLOBALS=8,
NATIVE=9, FUNCTION=10, TAKES=11, RETURNS=12, ENDFUNCTION=13, NOTHING=14,
CALL=15, SET=16, RETURN=17, ARRAY=18, TYPE=19, EXTENDS=20, IF=21, THEN=22,
ELSE=23, ENDIF=24, ELSEIF=25, CONSTANT=26, STRING_LITERAL=27, INTEGER=28,
NULL=29, TRUE=30, FALSE=31, NOT=32, ID=33, WS=34, NEWLINE=35;
public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
public static String[] modeNames = {
"DEFAULT_MODE"
};
public static final String[] ruleNames = {
"T__0", "T__1", "T__2", "T__3", "T__4", "EQUALS", "GLOBALS", "ENDGLOBALS",
"NATIVE", "FUNCTION", "TAKES", "RETURNS", "ENDFUNCTION", "NOTHING", "CALL",
"SET", "RETURN", "ARRAY", "TYPE", "EXTENDS", "IF", "THEN", "ELSE", "ENDIF",
"ELSEIF", "CONSTANT", "STRING_LITERAL", "INTEGER", "NULL", "TRUE", "FALSE",
"NOT", "ID", "WS", "NEWLINE"
};
private static final String[] _LITERAL_NAMES = {
null, "'['", "']'", "'('", "')'", "','", "'='", "'globals'", "'endglobals'",
"'native'", "'function'", "'takes'", "'returns'", "'endfunction'", "'nothing'",
"'call'", "'set'", "'return'", "'array'", "'type'", "'extends'", "'if'",
"'then'", "'else'", "'endif'", "'elseif'", "'constant'", null, null, "'null'",
"'true'", "'false'", "'not'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, null, null, null, null, null, "EQUALS", "GLOBALS", "ENDGLOBALS",
"NATIVE", "FUNCTION", "TAKES", "RETURNS", "ENDFUNCTION", "NOTHING", "CALL",
"SET", "RETURN", "ARRAY", "TYPE", "EXTENDS", "IF", "THEN", "ELSE", "ENDIF",
"ELSEIF", "CONSTANT", "STRING_LITERAL", "INTEGER", "NULL", "TRUE", "FALSE",
"NOT", "ID", "WS", "NEWLINE"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
public JassLexer(CharStream input) {
super(input);
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
@Override
public String getGrammarFileName() { return "Jass.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public String[] getChannelNames() { return channelNames; }
@Override
public String[] getModeNames() { return modeNames; }
@Override
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2%\u0139\b\1\4\2\t"+
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
"\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+
"\t!\4\"\t\"\4#\t#\4$\t$\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3"+
"\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t"+
"\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\13\3\13"+
"\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16"+
"\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17"+
"\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21"+
"\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\24"+
"\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\26\3\26"+
"\3\26\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\31\3\31\3\31"+
"\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3\33"+
"\3\33\3\33\3\33\3\33\3\33\3\34\3\34\7\34\u00e3\n\34\f\34\16\34\u00e6\13"+
"\34\3\34\3\34\3\35\3\35\3\35\7\35\u00ed\n\35\f\35\16\35\u00f0\13\35\5"+
"\35\u00f2\n\35\3\36\3\36\3\36\3\36\3\36\3\37\3\37\3\37\3\37\3\37\3 \3"+
" \3 \3 \3 \3 \3!\3!\3!\3!\3\"\3\"\7\"\u010a\n\"\f\"\16\"\u010d\13\"\3"+
"#\6#\u0110\n#\r#\16#\u0111\3#\3#\3$\3$\3$\3$\7$\u011a\n$\f$\16$\u011d"+
"\13$\3$\3$\3$\3$\3$\3$\7$\u0125\n$\f$\16$\u0128\13$\3$\3$\3$\3$\3$\7$"+
"\u012f\n$\f$\16$\u0132\13$\3$\3$\3$\3$\5$\u0138\n$\6\u00e4\u011b\u0126"+
"\u0130\2%\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33"+
"\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34\67"+
"\359\36;\37= ?!A\"C#E$G%\3\2\t\3\2\62\62\3\2\63;\3\2\62;\5\2C\\aac|\6"+
"\2\62;C\\aac|\4\2\13\13\"\"\4\2\f\f\17\17\2\u0144\2\3\3\2\2\2\2\5\3\2"+
"\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21"+
"\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2"+
"\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3"+
"\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3"+
"\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3"+
"\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\3I\3\2\2\2\5K\3\2\2"+
"\2\7M\3\2\2\2\tO\3\2\2\2\13Q\3\2\2\2\rS\3\2\2\2\17U\3\2\2\2\21]\3\2\2"+
"\2\23h\3\2\2\2\25o\3\2\2\2\27x\3\2\2\2\31~\3\2\2\2\33\u0086\3\2\2\2\35"+
"\u0092\3\2\2\2\37\u009a\3\2\2\2!\u009f\3\2\2\2#\u00a3\3\2\2\2%\u00aa\3"+
"\2\2\2\'\u00b0\3\2\2\2)\u00b5\3\2\2\2+\u00bd\3\2\2\2-\u00c0\3\2\2\2/\u00c5"+
"\3\2\2\2\61\u00ca\3\2\2\2\63\u00d0\3\2\2\2\65\u00d7\3\2\2\2\67\u00e0\3"+
"\2\2\29\u00f1\3\2\2\2;\u00f3\3\2\2\2=\u00f8\3\2\2\2?\u00fd\3\2\2\2A\u0103"+
"\3\2\2\2C\u0107\3\2\2\2E\u010f\3\2\2\2G\u0137\3\2\2\2IJ\7]\2\2J\4\3\2"+
"\2\2KL\7_\2\2L\6\3\2\2\2MN\7*\2\2N\b\3\2\2\2OP\7+\2\2P\n\3\2\2\2QR\7."+
"\2\2R\f\3\2\2\2ST\7?\2\2T\16\3\2\2\2UV\7i\2\2VW\7n\2\2WX\7q\2\2XY\7d\2"+
"\2YZ\7c\2\2Z[\7n\2\2[\\\7u\2\2\\\20\3\2\2\2]^\7g\2\2^_\7p\2\2_`\7f\2\2"+
"`a\7i\2\2ab\7n\2\2bc\7q\2\2cd\7d\2\2de\7c\2\2ef\7n\2\2fg\7u\2\2g\22\3"+
"\2\2\2hi\7p\2\2ij\7c\2\2jk\7v\2\2kl\7k\2\2lm\7x\2\2mn\7g\2\2n\24\3\2\2"+
"\2op\7h\2\2pq\7w\2\2qr\7p\2\2rs\7e\2\2st\7v\2\2tu\7k\2\2uv\7q\2\2vw\7"+
"p\2\2w\26\3\2\2\2xy\7v\2\2yz\7c\2\2z{\7m\2\2{|\7g\2\2|}\7u\2\2}\30\3\2"+
"\2\2~\177\7t\2\2\177\u0080\7g\2\2\u0080\u0081\7v\2\2\u0081\u0082\7w\2"+
"\2\u0082\u0083\7t\2\2\u0083\u0084\7p\2\2\u0084\u0085\7u\2\2\u0085\32\3"+
"\2\2\2\u0086\u0087\7g\2\2\u0087\u0088\7p\2\2\u0088\u0089\7f\2\2\u0089"+
"\u008a\7h\2\2\u008a\u008b\7w\2\2\u008b\u008c\7p\2\2\u008c\u008d\7e\2\2"+
"\u008d\u008e\7v\2\2\u008e\u008f\7k\2\2\u008f\u0090\7q\2\2\u0090\u0091"+
"\7p\2\2\u0091\34\3\2\2\2\u0092\u0093\7p\2\2\u0093\u0094\7q\2\2\u0094\u0095"+
"\7v\2\2\u0095\u0096\7j\2\2\u0096\u0097\7k\2\2\u0097\u0098\7p\2\2\u0098"+
"\u0099\7i\2\2\u0099\36\3\2\2\2\u009a\u009b\7e\2\2\u009b\u009c\7c\2\2\u009c"+
"\u009d\7n\2\2\u009d\u009e\7n\2\2\u009e \3\2\2\2\u009f\u00a0\7u\2\2\u00a0"+
"\u00a1\7g\2\2\u00a1\u00a2\7v\2\2\u00a2\"\3\2\2\2\u00a3\u00a4\7t\2\2\u00a4"+
"\u00a5\7g\2\2\u00a5\u00a6\7v\2\2\u00a6\u00a7\7w\2\2\u00a7\u00a8\7t\2\2"+
"\u00a8\u00a9\7p\2\2\u00a9$\3\2\2\2\u00aa\u00ab\7c\2\2\u00ab\u00ac\7t\2"+
"\2\u00ac\u00ad\7t\2\2\u00ad\u00ae\7c\2\2\u00ae\u00af\7{\2\2\u00af&\3\2"+
"\2\2\u00b0\u00b1\7v\2\2\u00b1\u00b2\7{\2\2\u00b2\u00b3\7r\2\2\u00b3\u00b4"+
"\7g\2\2\u00b4(\3\2\2\2\u00b5\u00b6\7g\2\2\u00b6\u00b7\7z\2\2\u00b7\u00b8"+
"\7v\2\2\u00b8\u00b9\7g\2\2\u00b9\u00ba\7p\2\2\u00ba\u00bb\7f\2\2\u00bb"+
"\u00bc\7u\2\2\u00bc*\3\2\2\2\u00bd\u00be\7k\2\2\u00be\u00bf\7h\2\2\u00bf"+
",\3\2\2\2\u00c0\u00c1\7v\2\2\u00c1\u00c2\7j\2\2\u00c2\u00c3\7g\2\2\u00c3"+
"\u00c4\7p\2\2\u00c4.\3\2\2\2\u00c5\u00c6\7g\2\2\u00c6\u00c7\7n\2\2\u00c7"+
"\u00c8\7u\2\2\u00c8\u00c9\7g\2\2\u00c9\60\3\2\2\2\u00ca\u00cb\7g\2\2\u00cb"+
"\u00cc\7p\2\2\u00cc\u00cd\7f\2\2\u00cd\u00ce\7k\2\2\u00ce\u00cf\7h\2\2"+
"\u00cf\62\3\2\2\2\u00d0\u00d1\7g\2\2\u00d1\u00d2\7n\2\2\u00d2\u00d3\7"+
"u\2\2\u00d3\u00d4\7g\2\2\u00d4\u00d5\7k\2\2\u00d5\u00d6\7h\2\2\u00d6\64"+
"\3\2\2\2\u00d7\u00d8\7e\2\2\u00d8\u00d9\7q\2\2\u00d9\u00da\7p\2\2\u00da"+
"\u00db\7u\2\2\u00db\u00dc\7v\2\2\u00dc\u00dd\7c\2\2\u00dd\u00de\7p\2\2"+
"\u00de\u00df\7v\2\2\u00df\66\3\2\2\2\u00e0\u00e4\7$\2\2\u00e1\u00e3\13"+
"\2\2\2\u00e2\u00e1\3\2\2\2\u00e3\u00e6\3\2\2\2\u00e4\u00e5\3\2\2\2\u00e4"+
"\u00e2\3\2\2\2\u00e5\u00e7\3\2\2\2\u00e6\u00e4\3\2\2\2\u00e7\u00e8\7$"+
"\2\2\u00e88\3\2\2\2\u00e9\u00f2\t\2\2\2\u00ea\u00ee\t\3\2\2\u00eb\u00ed"+
"\t\4\2\2\u00ec\u00eb\3\2\2\2\u00ed\u00f0\3\2\2\2\u00ee\u00ec\3\2\2\2\u00ee"+
"\u00ef\3\2\2\2\u00ef\u00f2\3\2\2\2\u00f0\u00ee\3\2\2\2\u00f1\u00e9\3\2"+
"\2\2\u00f1\u00ea\3\2\2\2\u00f2:\3\2\2\2\u00f3\u00f4\7p\2\2\u00f4\u00f5"+
"\7w\2\2\u00f5\u00f6\7n\2\2\u00f6\u00f7\7n\2\2\u00f7<\3\2\2\2\u00f8\u00f9"+
"\7v\2\2\u00f9\u00fa\7t\2\2\u00fa\u00fb\7w\2\2\u00fb\u00fc\7g\2\2\u00fc"+
">\3\2\2\2\u00fd\u00fe\7h\2\2\u00fe\u00ff\7c\2\2\u00ff\u0100\7n\2\2\u0100"+
"\u0101\7u\2\2\u0101\u0102\7g\2\2\u0102@\3\2\2\2\u0103\u0104\7p\2\2\u0104"+
"\u0105\7q\2\2\u0105\u0106\7v\2\2\u0106B\3\2\2\2\u0107\u010b\t\5\2\2\u0108"+
"\u010a\t\6\2\2\u0109\u0108\3\2\2\2\u010a\u010d\3\2\2\2\u010b\u0109\3\2"+
"\2\2\u010b\u010c\3\2\2\2\u010cD\3\2\2\2\u010d\u010b\3\2\2\2\u010e\u0110"+
"\t\7\2\2\u010f\u010e\3\2\2\2\u0110\u0111\3\2\2\2\u0111\u010f\3\2\2\2\u0111"+
"\u0112\3\2\2\2\u0112\u0113\3\2\2\2\u0113\u0114\b#\2\2\u0114F\3\2\2\2\u0115"+
"\u0116\7\61\2\2\u0116\u0117\7\61\2\2\u0117\u011b\3\2\2\2\u0118\u011a\13"+
"\2\2\2\u0119\u0118\3\2\2\2\u011a\u011d\3\2\2\2\u011b\u011c\3\2\2\2\u011b"+
"\u0119\3\2\2\2\u011c\u011e\3\2\2\2\u011d\u011b\3\2\2\2\u011e\u011f\7\17"+
"\2\2\u011f\u0138\7\f\2\2\u0120\u0121\7\61\2\2\u0121\u0122\7\61\2\2\u0122"+
"\u0126\3\2\2\2\u0123\u0125\13\2\2\2\u0124\u0123\3\2\2\2\u0125\u0128\3"+
"\2\2\2\u0126\u0127\3\2\2\2\u0126\u0124\3\2\2\2\u0127\u0129\3\2\2\2\u0128"+
"\u0126\3\2\2\2\u0129\u0138\7\f\2\2\u012a\u012b\7\61\2\2\u012b\u012c\7"+
"\61\2\2\u012c\u0130\3\2\2\2\u012d\u012f\13\2\2\2\u012e\u012d\3\2\2\2\u012f"+
"\u0132\3\2\2\2\u0130\u0131\3\2\2\2\u0130\u012e\3\2\2\2\u0131\u0133\3\2"+
"\2\2\u0132\u0130\3\2\2\2\u0133\u0138\7\17\2\2\u0134\u0135\7\17\2\2\u0135"+
"\u0138\7\f\2\2\u0136\u0138\t\b\2\2\u0137\u0115\3\2\2\2\u0137\u0120\3\2"+
"\2\2\u0137\u012a\3\2\2\2\u0137\u0134\3\2\2\2\u0137\u0136\3\2\2\2\u0138"+
"H\3\2\2\2\f\2\u00e4\u00ee\u00f1\u010b\u0111\u011b\u0126\u0130\u0137\3"+
"\b\2\2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
}
}
}

View File

@ -1,302 +0,0 @@
// Generated from Jass.g4 by ANTLR 4.7
package com.etheller.interpreter;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
/**
* This interface defines a complete generic visitor for a parse tree produced
* by {@link JassParser}.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public interface JassVisitor<T> extends ParseTreeVisitor<T> {
/**
* Visit a parse tree produced by {@link JassParser#program}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitProgram(JassParser.ProgramContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#typeDefinition}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeDefinition(JassParser.TypeDefinitionContext ctx);
/**
* Visit a parse tree produced by the {@code BasicType}
* labeled alternative in {@link JassParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitBasicType(JassParser.BasicTypeContext ctx);
/**
* Visit a parse tree produced by the {@code ArrayType}
* labeled alternative in {@link JassParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitArrayType(JassParser.ArrayTypeContext ctx);
/**
* Visit a parse tree produced by the {@code NothingType}
* labeled alternative in {@link JassParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNothingType(JassParser.NothingTypeContext ctx);
/**
* Visit a parse tree produced by the {@code BasicGlobal}
* labeled alternative in {@link JassParser#global}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitBasicGlobal(JassParser.BasicGlobalContext ctx);
/**
* Visit a parse tree produced by the {@code DefinitionGlobal}
* labeled alternative in {@link JassParser#global}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDefinitionGlobal(JassParser.DefinitionGlobalContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#assignTail}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAssignTail(JassParser.AssignTailContext ctx);
/**
* Visit a parse tree produced by the {@code ReferenceExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitReferenceExpression(JassParser.ReferenceExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code StringLiteralExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitStringLiteralExpression(JassParser.StringLiteralExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code IntegerLiteralExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIntegerLiteralExpression(JassParser.IntegerLiteralExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code FunctionReferenceExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunctionReferenceExpression(JassParser.FunctionReferenceExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code NullExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNullExpression(JassParser.NullExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code TrueExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTrueExpression(JassParser.TrueExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code FalseExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFalseExpression(JassParser.FalseExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code ArrayReferenceExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitArrayReferenceExpression(JassParser.ArrayReferenceExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code FunctionCallExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunctionCallExpression(JassParser.FunctionCallExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code ParentheticalExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParentheticalExpression(JassParser.ParentheticalExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code NotExpression}
* labeled alternative in {@link JassParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNotExpression(JassParser.NotExpressionContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#functionExpression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunctionExpression(JassParser.FunctionExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code SingleArgument}
* labeled alternative in {@link JassParser#argsList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSingleArgument(JassParser.SingleArgumentContext ctx);
/**
* Visit a parse tree produced by the {@code ListArgument}
* labeled alternative in {@link JassParser#argsList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitListArgument(JassParser.ListArgumentContext ctx);
/**
* Visit a parse tree produced by the {@code CallStatement}
* labeled alternative in {@link JassParser#statement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitCallStatement(JassParser.CallStatementContext ctx);
/**
* Visit a parse tree produced by the {@code SetStatement}
* labeled alternative in {@link JassParser#statement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSetStatement(JassParser.SetStatementContext ctx);
/**
* Visit a parse tree produced by the {@code ArrayedAssignmentStatement}
* labeled alternative in {@link JassParser#statement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitArrayedAssignmentStatement(JassParser.ArrayedAssignmentStatementContext ctx);
/**
* Visit a parse tree produced by the {@code ReturnStatement}
* labeled alternative in {@link JassParser#statement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitReturnStatement(JassParser.ReturnStatementContext ctx);
/**
* Visit a parse tree produced by the {@code IfStatement}
* labeled alternative in {@link JassParser#statement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIfStatement(JassParser.IfStatementContext ctx);
/**
* Visit a parse tree produced by the {@code SimpleIfStatement}
* labeled alternative in {@link JassParser#ifStatementPartial}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSimpleIfStatement(JassParser.SimpleIfStatementContext ctx);
/**
* Visit a parse tree produced by the {@code IfElseStatement}
* labeled alternative in {@link JassParser#ifStatementPartial}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIfElseStatement(JassParser.IfElseStatementContext ctx);
/**
* Visit a parse tree produced by the {@code IfElseIfStatement}
* labeled alternative in {@link JassParser#ifStatementPartial}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitIfElseIfStatement(JassParser.IfElseIfStatementContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#param}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParam(JassParser.ParamContext ctx);
/**
* Visit a parse tree produced by the {@code SingleParameter}
* labeled alternative in {@link JassParser#paramList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSingleParameter(JassParser.SingleParameterContext ctx);
/**
* Visit a parse tree produced by the {@code ListParameter}
* labeled alternative in {@link JassParser#paramList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitListParameter(JassParser.ListParameterContext ctx);
/**
* Visit a parse tree produced by the {@code NothingParameter}
* labeled alternative in {@link JassParser#paramList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNothingParameter(JassParser.NothingParameterContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#globalsBlock}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGlobalsBlock(JassParser.GlobalsBlockContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#typeDefinitionBlock}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeDefinitionBlock(JassParser.TypeDefinitionBlockContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#nativeBlock}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNativeBlock(JassParser.NativeBlockContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#block}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitBlock(JassParser.BlockContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#functionBlock}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunctionBlock(JassParser.FunctionBlockContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#statements}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitStatements(JassParser.StatementsContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#newlines}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNewlines(JassParser.NewlinesContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#newlines_opt}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNewlines_opt(JassParser.Newlines_optContext ctx);
/**
* Visit a parse tree produced by {@link JassParser#pnewlines}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPnewlines(JassParser.PnewlinesContext ctx);
}

View File

@ -80,10 +80,28 @@ native LoadTOCFile takes string TOCFile returns fra
// that.
native CreateSimpleFrame takes string name, framehandle owner, integer createContext returns framehandle
// Spawn a FRAME element that was defined in an FDF
// template onto the screen. The "name" field must
// match the name of a template to spawn, loaded with LoadTOCFile.
// As noted on CreateSimpleFrame, for now createContext is pointless.
// Likewise for priority -- until it fixed.
native CreateFrame takes string name, framehandle owner, integer priority, integer createContext returns framehandle
// Set the absolute point (often called Anchor) for the frame handle.
// See FDF template files for examples
native FrameSetAnchor takes framehandle frame, framepointtype point, real x, real y returns nothing
// Tasyen said: "takes one point of a Frame unbound that point and places it to a specific coordinates on the screen."
native FrameSetAbsPoint takes framehandle frame, framepointtype point, real x, real y returns nothing
// Set the relative point (called SetPoint in FDF templates) for the frame handle.
// See FDF template files for examples
// Tasyen said: places a point of FrameA relative to a point of FrameB. When FrameB moves FrameA's point will keep this rule and moves with it.
// Note for Project Warsmash: "When FrameB moves..." might not be true... call FramePositionBounds() for now
native FrameSetPoint takes framehandle frame, framepointtype point, framehandle relative, framepointtype relativePoint, real x, real y returns nothing
// Created for Warsmash engine, not a part of 1.31 UI apis,
// and at some point it might be removed. Basically
// this function will apply Anchors and SetPoints assigned
@ -98,6 +116,19 @@ native FramePositionBounds takes framehandle frame returns
// when the "Human" skin was loaded with CreateRootFrame
native SkinGetField takes string field returns string
// Sets the text value on a String Frame, currently it crashes otherwise
native FrameSetText takes framehandle frame, string text returns nothing
// Sets the text color on a String Frame, currently it crashes otherwise
native FrameSetTextColor takes framehandle frame, integer color returns nothing
native ConvertColor takes integer a, integer r, integer g, integer b returns integer
// Gets a previously created Frame using its name ( from an FDF template file that was
// previously spawned ). See previous notes about createContext. Mostly pointless?
native GetFrameByName takes string name, integer createContext returns framehandle
//============================================================================
// Native trigger interface
//

View File

@ -6,6 +6,15 @@ globals
framehandle ROOT_FRAME
framehandle CONSOLE_UI
framehandle RESOURCE_BAR
framehandle RESOURCE_BAR_GOLD_TEXT
framehandle RESOURCE_BAR_LUMBER_TEXT
framehandle RESOURCE_BAR_SUPPLY_TEXT
framehandle RESOURCE_BAR_UPKEEP_TEXT
framehandle TIME_INDICATOR
framehandle SIMPLE_INFO_PANEL_UNIT_DETAIL
framehandle UNIT_PORTRAIT
framehandle UNIT_LIFE_TEXT
framehandle UNIT_MANA_TEXT
endglobals
@ -17,6 +26,9 @@ function main takes nothing returns nothing
if not LoadTOCFile("UI\\FrameDef\\FrameDef.toc") then
call LogError("Unable to load FrameDef.toc")
endif
if not LoadTOCFile("UI\\FrameDef\\SmashFrameDef.toc") then
call LogError("Unable to load SmashFrameDef.toc")
endif
// =================================
// Load major UI components
// =================================
@ -26,7 +38,33 @@ function main takes nothing returns nothing
// Its template does not specify where to put it, so we must
// put it in the "TOPRIGHT" corner.
set RESOURCE_BAR = CreateSimpleFrame("ResourceBarFrame", CONSOLE_UI, 0)
call FrameSetAbsPoint(RESOURCE_BAR, FRAMEPOINT_TOPRIGHT, 0, 0)
call FrameSetPoint(RESOURCE_BAR, FRAMEPOINT_TOPRIGHT, CONSOLE_UI, FRAMEPOINT_TOPRIGHT, 0, 0)
// Create the Time Indicator (clock)
set TIME_INDICATOR = CreateFrame("TimeOfDayIndicator", ROOT_FRAME, 0, 0)
// Create the unit portrait stuff (for now this doesn't actually create the 3D, only HP/mana)
set UNIT_PORTRAIT = CreateSimpleFrame("UnitPortrait", CONSOLE_UI, 0)
set UNIT_LIFE_TEXT = GetFrameByName("UnitPortraitHitPointText", 0)
set UNIT_MANA_TEXT = GetFrameByName("UnitPortraitManaPointText", 0)
// Set default values
call FrameSetText(UNIT_LIFE_TEXT, "706 / 725")
call FrameSetText(UNIT_MANA_TEXT, "405 / 405")
// Retrieve inflated sub-frames and store references
set RESOURCE_BAR_GOLD_TEXT = GetFrameByName("ResourceBarGoldText", 0)
set RESOURCE_BAR_LUMBER_TEXT = GetFrameByName("ResourceBarLumberText", 0)
set RESOURCE_BAR_SUPPLY_TEXT = GetFrameByName("ResourceBarSupplyText", 0)
set RESOURCE_BAR_UPKEEP_TEXT = GetFrameByName("ResourceBarUpkeepText", 0)
// Set default values
call FrameSetText(RESOURCE_BAR_GOLD_TEXT, "500")
call FrameSetText(RESOURCE_BAR_LUMBER_TEXT, "150")
call FrameSetText(RESOURCE_BAR_SUPPLY_TEXT, "5/10")
call FrameSetText(RESOURCE_BAR_UPKEEP_TEXT, "No Upkeep")
call FrameSetTextColor(RESOURCE_BAR_UPKEEP_TEXT, ConvertColor(255, 0, 255, 0))
// Assemble the UI and resolve the location of every component that
// has Anchors and SetPoints (maybe in future version this call

View File

@ -0,0 +1,2 @@
UI\FrameDef\SmashUI\TimeOfDayIndicator.fdf
UI\FrameDef\SmashUI\UnitPortrait.fdf

View File

@ -0,0 +1,81 @@
// I had to override this because the Blizzard version is missing the "ConsoleTexture01Top" names.
Frame "SIMPLEFRAME" "ConsoleUI" {
DecorateFileNames,
// The top of the UI console
Texture "ConsoleTexture01Top" {
File "ConsoleTexture01",
Width 0.256,
Height 0.032,
TexCoord 0, 1, 0, 0.125,
AlphaMode "ALPHAKEY",
Anchor TOPLEFT,0,0,
}
Texture "ConsoleTexture02Top" {
File "ConsoleTexture02",
Width 0.087,
Height 0.032,
TexCoord 0, 0.33984375, 0, 0.125,
AlphaMode "ALPHAKEY",
Anchor TOPLEFT,0.256, 0,
}
Texture "ConsoleTexture02Top" {
File "ConsoleTexture02",
Width 0.053,
Height 0.032,
TexCoord 0.79296875, 1, 0, 0.125,
AlphaMode "ALPHAKEY",
Anchor TOPRIGHT,-0.288, 0,
}
Texture "ConsoleTexture03Top" {
File "ConsoleTexture03",
Width 0.256,
Height 0.032,
TexCoord 0, 1, 0, 0.125,
AlphaMode "ALPHAKEY",
Anchor TOPRIGHT,-0.032, 0,
}
Texture "ConsoleTexture04Top" {
File "ConsoleTexture04",
Width 0.032,
Height 0.032,
TexCoord 0, 1, 0, 0.125,
AlphaMode "ALPHAKEY",
Anchor TOPRIGHT,0,0,
}
// The bottom of the UI console
Texture "ConsoleTexture01Bottom" {
File "ConsoleTexture01",
Width 0.256,
Height 0.176,
TexCoord 0, 1, 0.3125, 1,
AlphaMode "ALPHAKEY",
Anchor BOTTOMLEFT,0,0,
}
Texture "ConsoleTexture02Bottom" {
File "ConsoleTexture02",
Width 0.256,
Height 0.15,
TexCoord 0, 1, 0.4140625, 1,
AlphaMode "ALPHAKEY",
Anchor BOTTOMLEFT,0.256,0,
}
Texture "ConsoleTexture03Bottom" {
File "ConsoleTexture03",
Width 0.256,
Height 0.176,
TexCoord 0, 1, 0.3125, 1,
AlphaMode "ALPHAKEY",
Anchor BOTTOMRIGHT,-0.032,0.0,
}
Texture "ConsoleTexture04Bottom" {
File "ConsoleTexture04",
Width 0.032,
Height 0.176,
TexCoord 0, 1, 0.3125, 1,
AlphaMode "ALPHAKEY",
Anchor BOTTOMRIGHT,0,0,
}
}

View File

@ -0,0 +1,6 @@
Frame "SPRITE" "TimeOfDayIndicator" {
DecorateFileNames,
BackgroundArt "TimeOfDayIndicator",
SetPoint BOTTOMLEFT,"ConsoleUI",BOTTOMLEFT,0,0,
}

View File

@ -0,0 +1,44 @@
/*
* UnitPortrait.fdf
* ---------------------
* Right now the actual 3d portrait is hardcoded like the
* original game, eventually that should be a config file
* like this so that a map can override it.
*/
String "UnitPortraitTextTemplate" {
Font "MasterFont",0.011,
Height 0.01640625,
TextLength 20,
}
Frame "SIMPLEFRAME" "UnitPortrait" {
DecorateFileNames,
SetPoint BOTTOMLEFT,"ConsoleUI",BOTTOMLEFT,0.211,0,
Width 0.0835,
Height 0.114,
Frame "SIMPLEFRAME" "UnitPortraitModel" {
DecorateFileNames,
SetPoint BOTTOM,"UnitPortrait",BOTTOM,0,0.0285,
Width 0.0835,
Height 0.085,
//Texture {
//File "IdlePeon",
// AlphaMode "ALPHAKEY",
//}
}
String "UnitPortraitHitPointText" INHERITS "UnitPortraitTextTemplate" {
Anchor BOTTOM, 0, 0.0115,
FontJustificationH JUSTIFYCENTER,
FontColor 0.0 1.0 0.0 1.0,
}
String "UnitPortraitManaPointText" INHERITS "UnitPortraitTextTemplate" {
Anchor BOTTOM, 0, -0.0030,
FontJustificationH JUSTIFYCENTER,
FontColor 1.0 1.0 1.0 1.0,
}
}

View File

@ -0,0 +1,447 @@
// --- TEXT -----------------------------------------------------------------------
String "SimpleInfoPanelTitleTextTemplate" {
FontColor 1.0 1.0 1.0 1.0,
FontShadowColor 0.0 0.0 0.0 0.9,
FontShadowOffset 0.002 -0.002,
Font "InfoPanelTextFont",0.013,
}
String "SimpleInfoPanelTitleTextDisabledTemplate" INHERITS "SimpleInfoPanelTitleTextTemplate" {
FontColor 0.2 0.2 0.2 1.0,
}
String "SimpleInfoPanelDescriptionTextTemplate" {
FontColor 0.99 0.827 0.0705 1.0,
FontShadowColor 0.0 0.0 0.0 0.9,
FontShadowOffset 0.001 -0.001,
Font "InfoPanelTextFont",0.01,
}
String "SimpleInfoPanelDescriptionHighlightTextTemplate" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
FontColor 1.0 1.0 1.0 1.0,
}
String "SimpleInfoPanelDescriptionDisabledTextTemplate" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
FontColor 0.2 0.2 0.2 1.0,
}
String "SimpleInfoPanelLabelTextTemplate" {
FontJustificationH JUSTIFYLEFT,
FontJustificationV JUSTIFYTOP,
FontColor 0.99 0.827 0.0705 1.0,
FontShadowColor 0.0 0.0 0.0 0.9,
FontShadowOffset 0.001 -0.001,
Font "InfoPanelTextFont",0.0085,
}
String "SimpleInfoPanelLabelHighlightTextTemplate" INHERITS "SimpleInfoPanelLabelTextTemplate" {
FontColor 1.0 1.0 1.0 1.0,
}
String "SimpleInfoPanelLabelDisabledTextTemplate" INHERITS "SimpleInfoPanelLabelTextTemplate" {
FontColor 0.2 0.2 0.2 1.0,
}
String "SimpleInfoPanelValueTextTemplate" INHERITS "SimpleInfoPanelLabelTextTemplate" {
FontColor 1.0 1.0 1.0 1.0,
}
String "SimpleInfoPanelAttributeTextTemplate" {
FontColor 1.0 1.0 1.0 1.0,
FontShadowColor 0.0 0.0 0.0 0.9,
FontShadowOffset 0.001 -0.001,
Font "InfoPanelTextFont",0.009,
}
String "SimpleInfoPanelAttributeDisabledTextTemplate" INHERITS "SimpleInfoPanelAttributeTextTemplate" {
FontColor 0.2 0.2 0.2 1.0,
}
Texture "InfoPanelIconTemplate" {
Width 0.032,
Height 0.032,
Anchor TOPLEFT, 0.004, -0.001,
}
Texture "ResourceIconTemplate" {
Width 0.014,
Height 0.014,
}
String "ResourceTextTemplate" INHERITS "SimpleInfoPanelValueTextTemplate" {
Font "InfoPanelTextFont", 0.0085,
}
// -- FRAMES ----------------------------------------------------------------
Frame "SIMPLEFRAME" "SimpleInfoPanelUnitDetail" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
// --- unit name frame --------------------------------------------------
String "SimpleNameValue" INHERITS "SimpleInfoPanelTitleTextTemplate" {
Anchor TOP,0,0,
}
// --- hero level bar ---------------------------------------------------
Frame "SIMPLESTATUSBAR" "SimpleHeroLevelBar" {
UseActiveContext,
SetPoint TOP, "SimpleNameValue", BOTTOM, 0.0, -0.0015,
Height 0.015625,
}
// --- timed life bar ----------------------------------------------------
Frame "SIMPLESTATUSBAR" "SimpleProgressIndicator" {
UseActiveContext,
SetPoint TOP, "SimpleNameValue", BOTTOM, 0.0, -0.0015,
Height 0.015625,
}
// --- building build queue panel -------------------------------------------------
Frame "SIMPLESTATUSBAR" "SimpleBuildTimeIndicator" {
UseActiveContext,
SetPoint TOPLEFT, "SimpleInfoPanelUnitDetail", TOPLEFT, 0.061250, -0.038125,
}
String "SimpleBuildingActionLabel" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
SetPoint CENTER, "SimpleInfoPanelUnitDetail", TOPLEFT, 0.11375, -0.029875,
Text "Retarded text",
}
// --- unit stats panel -------------------------------------------------
// This is required to make sure the class text appears above the status bars.
Frame "SIMPLEFRAME" "SimpleUnitStatsPanel" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
// --- class ------------------------------------------------------------
String "SimpleClassValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOP, "SimpleNameValue", BOTTOM, 0.0, -0.0055,
FontJustificationH JUSTIFYCENTER,
}
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelCargoDetail" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
// --- unit name frame --------------------------------------------------
String "SimpleHoldNameValue" INHERITS "SimpleInfoPanelTitleTextTemplate" {
Anchor TOP,0,0,
}
String "SimpleHoldDescriptionValue" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
SetPoint TOP, "SimpleHoldNameValue", BOTTOM, 0.0, -0.007,
Width 0.188,
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelBuildingDetail" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
String "SimpleBuildingNameValue" INHERITS "SimpleInfoPanelTitleTextTemplate" {
Anchor TOP,0,0,
}
String "SimpleBuildingDescriptionValue" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
SetPoint TOP, "SimpleBuildingNameValue", BOTTOM, 0.0, -0.007,
Width 0.188,
}
// --- building build queue panel -------------------------------------------------
Frame "SIMPLESTATUSBAR" "SimpleBuildTimeIndicator" {
UseActiveContext,
SetPoint TOPLEFT, "SimpleInfoPanelBuildingDetail", TOPLEFT, 0.061250, -0.038125,
}
String "SimpleBuildingActionLabel" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
SetPoint CENTER, "SimpleInfoPanelBuildingDetail", TOPLEFT, 0.11375, -0.029875,
Text "Retarded text",
}
Layer "ARTWORK" {
Texture "SimpleBuildQueueBackdrop" {
SetPoint BOTTOMLEFT, "SimpleInfoPanelBuildingDetail", BOTTOMLEFT, 0.0, 0.0,
SetPoint BOTTOMRIGHT, "SimpleInfoPanelBuildingDetail", BOTTOMRIGHT, 0.0, 0.0,
Height 0.1,
File "BuildQueueBackdrop",
}
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelItemDetail" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
// --- item name frame --------------------------------------------------
String "SimpleItemNameValue" INHERITS "SimpleInfoPanelTitleTextTemplate" {
Anchor TOP,0,0,
}
// --- item description frame -------------------------------------------
String "SimpleItemDescriptionValue" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
Width 0.188,
SetPoint TOP, "SimpleItemNameValue", BOTTOM, 0.0, -0.008,
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelDestructableDetail" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
// --- destructable name frame --------------------------------------------------
String "SimpleDestructableNameValue" INHERITS "SimpleInfoPanelTitleTextTemplate" {
Anchor TOP,0,0,
}
// --- destructable description frame -------------------------------------------
//String "SimpleDestructableDescriptionValue" INHERITS "SimpleInfoPanelDescriptionTextTemplate" {
// Width 0.188,
// SetPoint TOP, "SimpleDestructableNameValue", BOTTOM, 0.0, -0.008,
//}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconDamage" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
Height 0.03125,
// --- icon -------------------------------------------------------------
Texture "InfoPanelIconBackdrop" INHERITS "InfoPanelIconTemplate" {
File "HeroStrengthIcon",
}
// --- icon # -----------------------------------------------------------
String "InfoPanelIconLevel" INHERITS "SimpleInfoPanelAttributeTextTemplate" {
SetPoint CENTER, "InfoPanelIconBackdrop", BOTTOMRIGHT, -0.007625, 0.006875,
}
// --- label ------------------------------------------------------------
String "InfoPanelIconLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconBackdrop", TOPRIGHT, 0.0, -0.003,
Text "COLON_DAMAGE",
}
// --- value ------------------------------------------------------------
String "InfoPanelIconValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconLabel", BOTTOMLEFT, 0.005, -0.003,
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconArmor" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
Height 0.03125,
// --- icon -------------------------------------------------------------
Texture "InfoPanelIconBackdrop" INHERITS "InfoPanelIconTemplate" {
File "HeroStrengthIcon",
}
// --- icon # -----------------------------------------------------------
String "InfoPanelIconLevel" INHERITS "SimpleInfoPanelAttributeTextTemplate" {
SetPoint CENTER, "InfoPanelIconBackdrop", BOTTOMRIGHT, -0.007625, 0.006875,
}
// --- label ------------------------------------------------------------
String "InfoPanelIconLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconBackdrop", TOPRIGHT, 0.0, -0.003,
Text "COLON_ARMOR",
}
// --- value ------------------------------------------------------------
String "InfoPanelIconValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconLabel", BOTTOMLEFT, 0.005, -0.003,
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconRank" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
Height 0.03125,
// --- icon -------------------------------------------------------------
Texture "InfoPanelIconBackdrop" INHERITS "InfoPanelIconTemplate" {
File "HeroStrengthIcon",
}
// --- icon # -----------------------------------------------------------
String "InfoPanelIconLevel" INHERITS "SimpleInfoPanelAttributeTextTemplate" {
SetPoint CENTER, "InfoPanelIconBackdrop", BOTTOMRIGHT, -0.007625, 0.006875,
}
// --- label ------------------------------------------------------------
String "InfoPanelIconLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconBackdrop", TOPRIGHT, 0.0, -0.003,
Text "COLON_RANK",
}
// --- value ------------------------------------------------------------
String "InfoPanelIconValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconLabel", BOTTOMLEFT, 0.005, -0.003,
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconFood" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
Height 0.03125,
// --- icon -------------------------------------------------------------
Texture "InfoPanelIconBackdrop" INHERITS "InfoPanelIconTemplate" {
File "InfoPanelIconFood",
}
// --- icon # -----------------------------------------------------------
String "InfoPanelIconLevel" INHERITS "SimpleInfoPanelAttributeTextTemplate" {
SetPoint CENTER, "InfoPanelIconBackdrop", BOTTOMRIGHT, -0.007625, 0.006875,
}
// --- label ------------------------------------------------------------
String "InfoPanelIconLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconBackdrop", TOPRIGHT, 0.0, -0.003,
Text "COLON_FOOD",
}
// --- value ------------------------------------------------------------
String "InfoPanelIconValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconLabel", BOTTOMLEFT, 0.005, -0.003,
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconGold" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
Height 0.03125,
// --- icon -------------------------------------------------------------
Texture "InfoPanelIconBackdrop" INHERITS "InfoPanelIconTemplate" {
File "InfoPanelIconGold",
}
// --- icon # -----------------------------------------------------------
String "InfoPanelIconLevel" INHERITS "SimpleInfoPanelAttributeTextTemplate" {
SetPoint CENTER, "InfoPanelIconBackdrop", BOTTOMRIGHT, -0.007625, 0.006875,
}
// --- label ------------------------------------------------------------
String "InfoPanelIconLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconBackdrop", TOPRIGHT, 0.0, -0.003,
Text "COLON_GOLD",
}
// --- value ------------------------------------------------------------
String "InfoPanelIconValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconLabel", BOTTOMLEFT, 0.005, -0.003,
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconHero" {
UseActiveContext,
SetAllPoints,
DecorateFileNames,
Height 0.0625,
// --- icon -------------------------------------------------------------
Texture "InfoPanelIconHeroIcon" INHERITS "InfoPanelIconTemplate" {
File "HeroStrengthIcon",
Anchor LEFT, 0.004, 0.0,
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconHeroText" {
UseActiveContext,
DecorateFileNames,
SetPoint LEFT, "InfoPanelIconHeroIcon", RIGHT, 0.0, 0.0,
SetPoint RIGHT, "SimpleInfoPanelIconHero", RIGHT, 0.0, 0.0,
SetPoint TOP, "SimpleInfoPanelIconHero", TOP, 0.0, 0.0,
SetPoint BOTTOM, "SimpleInfoPanelIconHero", BOTTOM, 0.0, 0.0,
// --- strength ---------------------------------------------------------
String "InfoPanelIconHeroStrengthLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
Anchor TOPLEFT, 0.0, -0.003,
Text "COLON_STRENGTH",
}
String "InfoPanelIconHeroStrengthValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconHeroStrengthLabel", BOTTOMLEFT, 0.005, 0.0,
}
// --- agility ----------------------------------------------------------
String "InfoPanelIconHeroAgilityLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconHeroStrengthValue", BOTTOMLEFT, -0.005, -0.004,
Text "COLON_AGILITY",
}
String "InfoPanelIconHeroAgilityValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconHeroAgilityLabel", BOTTOMLEFT, 0.005, 0.0,
}
// --- intellect --------------------------------------------------------
String "InfoPanelIconHeroIntellectLabel" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconHeroAgilityValue", BOTTOMLEFT, -0.005, -0.004,
Text "COLON_INTELLECT",
}
String "InfoPanelIconHeroIntellectValue" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconHeroIntellectLabel", BOTTOMLEFT, 0.005, 0.0,
}
}
}
Frame "SIMPLEFRAME" "SimpleInfoPanelIconAlly" {
UseActiveContext,
DecorateFileNames,
Height 0.0625,
// --- title ------------------------------------------------------------
String "InfoPanelIconAllyTitle" INHERITS "SimpleInfoPanelLabelTextTemplate" {
SetPoint TOPLEFT, "SimpleInfoPanelIconAlly", TOPLEFT, 0.0, 0.0,
Text "ALLY_RESOURCES",
}
// --- gold -------------------------------------------------------------
Texture "InfoPanelIconAllyGoldIcon" INHERITS "ResourceIconTemplate" {
SetPoint TOPLEFT, "SimpleInfoPanelIconAlly", TOPLEFT, 0.0, -0.009,
File "GoldIcon",
}
String "InfoPanelIconAllyGoldValue" INHERITS "ResourceTextTemplate" {
SetPoint LEFT, "InfoPanelIconAllyGoldIcon", RIGHT, 0.005, 0.0,
}
// --- wood -------------------------------------------------------------
Texture "InfoPanelIconAllyWoodIcon" INHERITS "ResourceIconTemplate" {
SetPoint TOPLEFT, "InfoPanelIconAllyGoldIcon", BOTTOMLEFT, 0.0, 0.0,
File "LumberIcon",
}
String "InfoPanelIconAllyWoodValue" INHERITS "ResourceTextTemplate" {
SetPoint LEFT, "InfoPanelIconAllyWoodIcon", RIGHT, 0.005, 0.0,
}
// --- food -------------------------------------------------------------
Texture "InfoPanelIconAllyFoodIcon" INHERITS "ResourceIconTemplate" {
SetPoint TOPLEFT, "InfoPanelIconAllyWoodIcon", BOTTOMLEFT, 0.0, 0.0,
File "SupplyIcon",
}
String "InfoPanelIconAllyFoodValue" INHERITS "ResourceTextTemplate" {
SetPoint LEFT, "InfoPanelIconAllyFoodIcon", RIGHT, 0.005, 0.0,
}
// --- upkeep -----------------------------------------------------------
String "InfoPanelIconAllyUpkeep" INHERITS "SimpleInfoPanelValueTextTemplate" {
SetPoint TOPLEFT, "InfoPanelIconAllyFoodValue", BOTTOMLEFT, 0.0, -0.005,
Text "Upkeep",
}
}