Fun with some menu button support and hero stats and levels

This commit is contained in:
Retera 2021-03-06 12:46:51 -05:00
parent 27ee234574
commit 22e07de19a
76 changed files with 2518 additions and 871 deletions

View File

@ -1,26 +1,53 @@
[DataSources]
Count=5
Type00=Folder
Path00="D:\Games\Warcraft III CASC 1.31\war3.w3mod"
Type01=Folder
Path01="D:\Games\Warcraft III CASC 1.31\war3.w3mod\_locales\enus.w3mod"
Type02=Folder
Path02="..\..\resources"
Type03=Folder
Path03="D:\Backups\Warsmash\Data"
Count=8
Type00=MPQ
Path00="D:\Games\Warcraft III Patch 1.22\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Patch 1.22\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Patch 1.22\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Patch 1.22\War3Patch.mpq"
Type04=Folder
Path04="."
Path04="..\..\resources"
Type05=Folder
Path05="D:\Backups\Warsmash\Data"
Type06=Folder
Path06="D:\Games\Warcraft III Patch 1.22\Maps"
Type07=Folder
Path07="."
[Map]
//FilePath="CombatUnitTests.w3x"
//FilePath="PitchRoll.w3x"
//FilePath="ReforgedGeorgeVacation.w3x"
//FilePath="PeonStartingBase_Simple.w3x"
FilePath="PeonStartingBase_Scythe.w3x"
//FilePath="MyStromguarde.w3m"
//FilePath="ColdArrows.w3m"
//FilePath="DungeonGoldMine.w3m"
//FilePath="PlayerPeasants.w3m"
//FilePath="FireLord.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PrivateDontShare/Cult 8.w3x"
//FilePath="PhoenixAttack.w3x"
//FilePath="LightEnvironmentTest.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x"
//FilePath="PeonStartingBase.w3x"
//FilePath="PhoenixAttack.w3x"
//FilePath="OperationReforged.w3x"
//FilePath="AzerothRoleplay1.909t03DecoratedV2.w3x"
//FilePath="American Colo EX 1.0 unpro.w3x"
FilePath="TheSheepAttack.w3x"
//FilePath="FrostyVsFarm.w3m"
//FilePath="ModelTest.w3x"
//FilePath="SpinningSample.w3x"
//FilePath="Maps\Campaign\Prologue02.w3m"
//FilePath="Pathing.w3x"
//FilePath="ItemFacing.w3x"
//FilePath=SomeParticleTests.w3x
//FilePath="PeonMiningMultiHall.w3x"
//FilePath="QuadtreeBugs.w3x"
//FilePath="test2.w3x"
//FilePath="FarseerHoldPositionTest.w3x"
//FilePath="Ramps.w3m"
//FilePath="V1\Farm.w3x"
//FilePath="PenguinWorld.w3x"
//FilePath="Maps\FrozenThrone\Campaign\UndeadX09.w3x"
//FilePath="LavellaLagoon.w3x"
//FilePath="WiceOrc.w3x"
//FilePath="NorthrendPathingDoodle.w3x"
//FilePath="Maps\Campaign\Prologue01.w3m"

View File

@ -1,51 +0,0 @@
[DataSources]
Count=8
Type00=MPQ
Path00="D:\Games\Warcraft III Patch 1.22\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Patch 1.22\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Patch 1.22\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Patch 1.22\War3Patch.mpq"
Type04=Folder
Path04="..\..\resources"
Type05=Folder
Path05="D:\Backups\Warsmash\Data"
Type06=Folder
Path06="D:\Games\Warcraft III Patch 1.22\Maps"
Type07=Folder
Path07="."
[Map]
//FilePath="CombatUnitTests.w3x"
//FilePath="PitchRoll.w3x"
//FilePath="PeonStartingBase_Simple.w3x"
//FilePath="MyStromguarde.w3m"
//FilePath="ColdArrows.w3m"
//FilePath="DungeonGoldMine.w3m"
//FilePath="PlayerPeasants.w3m"
//FilePath="FireLord.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PhoenixAttack.w3x"
//FilePath="LightEnvironmentTest.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x"
//FilePath="FrostyVsFarm.w3m"
//FilePath="ModelTest.w3x"
//FilePath="SpinningSample.w3x"
//FilePath="Maps\Campaign\Prologue02.w3m"
//FilePath="Pathing.w3x"
//FilePath="ItemFacing.w3x"
//FilePath=SomeParticleTests.w3x
//FilePath="PeonMiningMultiHall.w3x"
//FilePath="QuadtreeBugs.w3x"
//FilePath="test2.w3x"
//FilePath="FarseerHoldPositionTest.w3x"
//FilePath="Ramps.w3m"
//FilePath="V1\Farm.w3x"
//FilePath="PenguinWorld.w3x"
//FilePath="Maps\FrozenThrone\Campaign\UndeadX09.w3x"
//FilePath="LavellaLagoon.w3x"
//FilePath="WiceOrc.w3x"
FilePath="TheSheepAttack.w3x"

View File

@ -0,0 +1,26 @@
[DataSources]
Count=5
Type00=Folder
Path00="D:\Games\Warcraft III CASC 1.31\war3.w3mod"
Type01=Folder
Path01="D:\Games\Warcraft III CASC 1.31\war3.w3mod\_locales\enus.w3mod"
Type02=Folder
Path02="..\..\resources"
Type03=Folder
Path03="D:\Backups\Warsmash\Data"
Type04=Folder
Path04="."
[Map]
//FilePath="PitchRoll.w3x"
//FilePath="ReforgedGeorgeVacation.w3x"
//FilePath="Maps\Campaign\NightElf03.w3m"
//FilePath="PrivateDontShare/Cult 8.w3x"
//FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x"
//FilePath="PeonStartingBase.w3x"
//FilePath="PhoenixAttack.w3x"
//FilePath="OperationReforged.w3x"
//FilePath="AzerothRoleplay1.909t03DecoratedV2.w3x"
//FilePath="American Colo EX 1.0 unpro.w3x"
FilePath="TheSheepAttack.w3x"

View File

@ -4,23 +4,23 @@
[DataSources]
Count=9
Type00=MPQ
Path00="E:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3.mpq"
Path00="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3.mpq"
Type01=MPQ
Path01="E:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3x.mpq"
Path01="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3x.mpq"
Type02=MPQ
Path02="E:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3xlocal.mpq"
Path02="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3xlocal.mpq"
Type03=MPQ
Path03="E:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3patch.mpq"
Path03="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3patch.mpq"
Type04=MPQ
Path04="E:\Games\Warcraft III Project Revolution\PRSCMOD\Revolution.mpq"
Path04="D:\Games\Warcraft III Project Revolution\PRSCMOD\Revolution.mpq"
Type05=MPQ
Path05="E:\Games\Warcraft III Project Revolution\PRSCMOD\Sound.mpq"
Path05="D:\Games\Warcraft III Project Revolution\PRSCMOD\Sound.mpq"
Type06=Folder
Path06="E:\Games\Warcraft III Project Revolution\ProjectRevolusmash"
Path06="D:\Games\Warcraft III Project Revolution\ProjectRevolusmash"
Type07=Folder
Path07="..\..\resources"
Type08=Folder
Path08="E:\Games\Warcraft III Project Revolution\PRSCMOD\PR-Maps"
Path08="D:\Games\Warcraft III Project Revolution\PRSCMOD\PR-Maps"
[Map]
FilePath="ProjectRevolusmash.w3x"

View File

@ -2,7 +2,7 @@
Count=5
Type00=CASC
Path00="C:\Program Files\Warcraft III"
Prefixes00=war3.w3mod,war3.w3mod\_deprecated.w3mod,war3.w3mod\_locales\enus.w3mod
Prefixes00=war3.w3mod,war3.w3mod\_deprecated.w3mod,war3.w3mod\_locales\enus.w3mod,war3.w3mod\_hd.w3mod,war3.w3mod\_hd.w3mod\_locales\enus.w3mod
Type01=Folder
Path01="..\..\resources"
Type02=Folder

View File

@ -0,0 +1,22 @@
// This is the Warsmash INI file for Project Revolution
// PRSCMOD
[DataSources]
Count=7
Type00=MPQ
Path00="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\war3patch_TTOR.mpq"
Type04=Folder
Path04="D:\Games\Warcraft III Project Revolution\ProjectRevolusmash"
Type05=Folder
Path05="..\..\resources"
Type06=Folder
Path06="D:\Games\Warcraft III Project Revolution\War3\The Sheep Attack\Maps"
[Map]
FilePath="(2)BootyBay.w3m"

View File

@ -0,0 +1,22 @@
// This is the Warsmash INI file for Project Revolution
// PRSCMOD
[DataSources]
Count=7
Type00=MPQ
Path00="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\war3.mpq"
Type01=MPQ
Path01="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\War3x.mpq"
Type02=MPQ
Path02="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\War3xlocal.mpq"
Type03=MPQ
Path03="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\war3patch.mpq"
Type04=MPQ
Path04="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\War3Mod.mpq"
Type05=Folder
Path05="..\..\resources"
Type06=Folder
Path06="D:\Games\Warcraft III Patch 1.27 Redownload\Warcraft III\Maps"
[Map]
FilePath="Maps\Campaign\Prologue01.w3m"

View File

@ -1,7 +1,15 @@
package com.etheller.warsmash;
import com.etheller.warsmash.util.War3ID;
public class TestMain {
public static void main(final String[] args) {
if (true) {
System.out.println(War3ID.fromString("hwat").getValue());
System.out.println(Integer.toHexString(War3ID.fromString("hwat").getValue()));
System.out.println(new War3ID(0x68776174));
return;
}
// System.out.println(Integer.parseInt("4294967295"));
for (int i = 1; i <= 30; i++) {
// System.out.println(a(i));

View File

@ -62,7 +62,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
final String renderer = Gdx.gl.glGetString(GL20.GL_RENDERER);
System.err.println("Renderer: " + renderer);
this.codebase = WarsmashGdxMapGame.parseDataSources(this.warsmashIni);
this.codebase = WarsmashGdxMapScreen.parseDataSources(this.warsmashIni);
this.viewer = new MdxViewer(this.codebase, this);
this.viewer.addHandler(new MdxHandler());

View File

@ -9,20 +9,16 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.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.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
@ -56,7 +52,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayerUnit
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.SettableCommandErrorListener;
public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
public class WarsmashGdxMapScreen implements CanvasProvider, InputProcessor, Screen {
private static final boolean ENABLE_AUDIO = true;
private static final boolean ENABLE_MUSIC = false;
private DataSource codebase;
@ -65,8 +61,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
// libGDX stuff
private OrthographicCamera uiCamera;
private BitmapFont font;
private BitmapFont font20;
private SpriteBatch batch;
private ExtendViewport uiViewport;
private GlyphLayout glyphLayout;
@ -80,10 +74,13 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
private Scene uiScene;
private MeleeUI meleeUI;
private FreeTypeFontGenerator fontGenerator;
public WarsmashGdxMapGame(final DataTable warsmashIni) {
private Music currentMusic;
private final String fileToLoad;
public WarsmashGdxMapScreen(final DataTable warsmashIni, final String fileToLoad) {
this.warsmashIni = warsmashIni;
this.fileToLoad = fileToLoad;
}
/*
@ -92,7 +89,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
* @see com.badlogic.gdx.ApplicationAdapter#create()
*/
@Override
public void create() {
public void show() {
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
@ -115,7 +112,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.viewer.enableAudio();
}
try {
this.viewer.loadMap(this.warsmashIni.get("Map").getField("FilePath"), 0);
this.viewer.loadMap(this.fileToLoad, 0);
}
catch (final IOException e) {
throw new RuntimeException(e);
@ -155,13 +152,6 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
final int width = Gdx.graphics.getWidth();
final int height = Gdx.graphics.getHeight();
this.fontGenerator = new FreeTypeFontGenerator(
new DataSourceFileHandle(this.viewer.dataSource, "fonts\\FRIZQT__.TTF"));
final FreeTypeFontParameter fontParam = new FreeTypeFontParameter();
fontParam.size = 32;
this.font = this.fontGenerator.generateFont(fontParam);
fontParam.size = 20;
this.font20 = this.fontGenerator.generateFont(fontParam);
this.glyphLayout = new GlyphLayout();
// Constructs a new OrthographicCamera, using the given viewport width and
@ -207,24 +197,25 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"),
cameraRatesElement.getFieldFloatValue("Distance"), cameraRatesElement.getFieldFloatValue("Forward"),
cameraRatesElement.getFieldFloatValue("Strafe"));
this.meleeUI = new MeleeUI(this.viewer.mapMpq, this.uiViewport, this.fontGenerator, this.uiScene, portraitScene,
cameraPresets, cameraRates, this.viewer, new RootFrameListener() {
this.meleeUI = new MeleeUI(this.viewer.mapMpq, this.uiViewport, this.uiScene, portraitScene, cameraPresets,
cameraRates, this.viewer, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
WarsmashGdxMapScreen.this.viewer.setGameUI(rootFrame);
if (ENABLE_MUSIC) {
final String musicField = rootFrame.getSkinField("Music_V1");
final String[] musics = musicField.split(";");
String musicPath = musics[(int) (Math.random() * musics.length)];
if (true) {
if (false) {
musicPath = "Sound\\Music\\mp3Music\\PH1.mp3";
}
final Music music = Gdx.audio.newMusic(
new DataSourceFileHandle(WarsmashGdxMapGame.this.viewer.dataSource, musicPath));
new DataSourceFileHandle(WarsmashGdxMapScreen.this.viewer.dataSource, musicPath));
music.setVolume(0.2f);
music.setLooping(true);
music.play();
WarsmashGdxMapScreen.this.currentMusic = music;
}
}
}, new CPlayerUnitOrderExecutor(this.viewer.simulation, commandErrorListener));
@ -292,7 +283,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
}
@Override
public void render() {
public void render(final float delta) {
this.uiCamera.update();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final float deltaTime = Gdx.graphics.getDeltaTime();
@ -322,12 +313,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.uiViewport.apply();
this.batch.setProjectionMatrix(this.uiCamera.combined);
this.batch.begin();
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);
this.font.draw(this.batch, fpsString, (this.uiViewport.getMinWorldWidth() - this.glyphLayout.width) / 2,
1100 * this.meleeUI.getHeightRatioCorrection());
this.meleeUI.render(this.batch, this.glyphLayout);
this.batch.end();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
@ -336,7 +322,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
@Override
public void dispose() {
this.fontGenerator.dispose();
this.meleeUI.dispose();
}
@Override
@ -351,7 +337,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
@Override
public void resize(final int width, final int height) {
super.resize(width, height);
// super.resize(width, height);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
@ -529,4 +515,19 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
}
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void hide() {
if (this.currentMusic != null) {
this.currentMusic.stop();
}
}
}

View File

@ -5,20 +5,16 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.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.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Rectangle;
@ -30,6 +26,7 @@ import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.util.DataSourceFileHandle;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Camera;
import com.etheller.warsmash.viewer5.CanvasProvider;
import com.etheller.warsmash.viewer5.Model;
@ -50,7 +47,7 @@ import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MenuUI;
public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements CanvasProvider, InputProcessor {
public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Screen {
private static final boolean ENABLE_AUDIO = true;
private static final boolean ENABLE_MUSIC = true;
private DataSource codebase;
@ -61,8 +58,6 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
// libGDX stuff
private OrthographicCamera uiCamera;
private BitmapFont font;
private BitmapFont font20;
private SpriteBatch batch;
private ExtendViewport uiViewport;
private GlyphLayout glyphLayout;
@ -71,14 +66,16 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
private Scene uiScene;
private Texture solidGreenTexture;
private MenuUI menuUI;
private final WarsmashGdxMultiScreenGame game;
private Music currentMusic;
public WarsmashGdxMenuTestGame(final DataTable warsmashIni) {
public WarsmashGdxMenuScreen(final DataTable warsmashIni, final WarsmashGdxMultiScreenGame game) {
this.warsmashIni = warsmashIni;
this.game = game;
}
@Override
public void create() {
public void show() {
final ByteBuffer tempByteBuffer = ByteBuffer.allocateDirect(4);
tempByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
final IntBuffer temp = tempByteBuffer.asIntBuffer();
@ -91,7 +88,7 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
final String renderer = Gdx.gl.glGetString(GL20.GL_RENDERER);
System.err.println("Renderer: " + renderer);
this.codebase = WarsmashGdxMapGame.parseDataSources(this.warsmashIni);
this.codebase = WarsmashGdxMapScreen.parseDataSources(this.warsmashIni);
this.viewer = new MdxViewer(this.codebase, this);
this.viewer.addHandler(new MdxHandler());
@ -108,13 +105,6 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
final int width = Gdx.graphics.getWidth();
final int height = Gdx.graphics.getHeight();
final FreeTypeFontGenerator fontGenerator = new FreeTypeFontGenerator(
new DataSourceFileHandle(this.viewer.dataSource, "fonts\\FRIZQT__.TTF"));
final FreeTypeFontParameter fontParam = new FreeTypeFontParameter();
fontParam.size = 32;
this.font = fontGenerator.generateFont(fontParam);
fontParam.size = 20;
this.font20 = fontGenerator.generateFont(fontParam);
this.glyphLayout = new GlyphLayout();
// Constructs a new OrthographicCamera, using the given viewport width and
@ -184,27 +174,30 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1);
this.menuUI = new MenuUI(this.viewer.dataSource, this.uiViewport, fontGenerator, this.uiScene, this.viewer,
new RootFrameListener() {
this.menuUI = new MenuUI(this.viewer.dataSource, this.uiViewport, this.uiScene, this.viewer, this.game,
this.warsmashIni, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
// WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
if (ENABLE_MUSIC) {
final String musicField = rootFrame.getSkinField("GlueMusic_V1");
final String musicField = rootFrame
.getSkinField("GlueMusic_V" + WarsmashConstants.GAME_VERSION);
final String[] musics = musicField.split(";");
final String musicPath = musics[(int) (Math.random() * musics.length)];
final Music music = Gdx.audio.newMusic(new DataSourceFileHandle(
WarsmashGdxMenuTestGame.this.viewer.dataSource, musicPath));
final Music music = Gdx.audio.newMusic(
new DataSourceFileHandle(WarsmashGdxMenuScreen.this.viewer.dataSource, musicPath));
music.setVolume(0.2f);
music.setLooping(true);
music.play();
WarsmashGdxMenuScreen.this.currentMusic = music;
}
singleModelScene(scene,
War3MapViewer.mdx(rootFrame.getSkinField("GlueSpriteLayerBackground_V1")), "Stand");
WarsmashGdxMenuTestGame.this.modelCamera = WarsmashGdxMenuTestGame.this.mainModel.cameras
.get(0);
War3MapViewer.mdx(rootFrame
.getSkinField("GlueSpriteLayerBackground_V" + WarsmashConstants.GAME_VERSION)),
"Stand");
WarsmashGdxMenuScreen.this.modelCamera = WarsmashGdxMenuScreen.this.mainModel.cameras.get(0);
}
});
@ -213,7 +206,6 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
libgdxContentInstance.setLocation(0f, 0f, -0.5f);
libgdxContentInstance.setScene(this.uiScene);
this.menuUI.main();
fontGenerator.dispose();
updateUIScene();
@ -487,7 +479,7 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
private final boolean firstFrame = true;
@Override
public void render() {
public void render(final float delta) {
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
final float deltaTime = Gdx.graphics.getDeltaTime();
@ -507,6 +499,7 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
@Override
public void dispose() {
this.menuUI.dispose();
}
@Override
@ -525,7 +518,7 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
this.tempRect.height = height;
this.cameraManager.camera.viewport(this.tempRect);
super.resize(width, height);
// super.resize(width, height);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
@ -595,20 +588,16 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
this.quatHeap.transform(this.position);
this.position.scl(this.distance);
this.position = this.position.add(this.target);
if (WarsmashGdxMenuTestGame.this.modelCamera != null) {
WarsmashGdxMenuTestGame.this.modelCamera.getPositionTranslation(
WarsmashGdxMenuTestGame.this.cameraPositionTemp,
WarsmashGdxMenuTestGame.this.mainInstance.sequence,
WarsmashGdxMenuTestGame.this.mainInstance.frame,
WarsmashGdxMenuTestGame.this.mainInstance.counter);
WarsmashGdxMenuTestGame.this.modelCamera.getTargetTranslation(
WarsmashGdxMenuTestGame.this.cameraTargetTemp,
WarsmashGdxMenuTestGame.this.mainInstance.sequence,
WarsmashGdxMenuTestGame.this.mainInstance.frame,
WarsmashGdxMenuTestGame.this.mainInstance.counter);
if (WarsmashGdxMenuScreen.this.modelCamera != null) {
WarsmashGdxMenuScreen.this.modelCamera.getPositionTranslation(
WarsmashGdxMenuScreen.this.cameraPositionTemp, WarsmashGdxMenuScreen.this.mainInstance.sequence,
WarsmashGdxMenuScreen.this.mainInstance.frame, WarsmashGdxMenuScreen.this.mainInstance.counter);
WarsmashGdxMenuScreen.this.modelCamera.getTargetTranslation(WarsmashGdxMenuScreen.this.cameraTargetTemp,
WarsmashGdxMenuScreen.this.mainInstance.sequence, WarsmashGdxMenuScreen.this.mainInstance.frame,
WarsmashGdxMenuScreen.this.mainInstance.counter);
this.position.set(WarsmashGdxMenuTestGame.this.modelCamera.position);
this.target.set(WarsmashGdxMenuTestGame.this.modelCamera.targetPosition);
this.position.set(WarsmashGdxMenuScreen.this.modelCamera.position);
this.target.set(WarsmashGdxMenuScreen.this.modelCamera.targetPosition);
// this.vecHeap2.set(this.target);
// this.vecHeap2.sub(this.position);
// this.vecHeap.set(this.vecHeap2);
@ -618,16 +607,15 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
// this.vecHeap.scl(this.camera.rect.height / 2f);
// this.position.add(this.vecHeap);
this.position.add(WarsmashGdxMenuTestGame.this.cameraPositionTemp[0],
WarsmashGdxMenuTestGame.this.cameraPositionTemp[1],
WarsmashGdxMenuTestGame.this.cameraPositionTemp[2]);
this.target.add(WarsmashGdxMenuTestGame.this.cameraTargetTemp[0],
WarsmashGdxMenuTestGame.this.cameraTargetTemp[1],
WarsmashGdxMenuTestGame.this.cameraTargetTemp[2]);
this.camera.perspective(WarsmashGdxMenuTestGame.this.modelCamera.fieldOfView * 0.75f,
this.position.add(WarsmashGdxMenuScreen.this.cameraPositionTemp[0],
WarsmashGdxMenuScreen.this.cameraPositionTemp[1],
WarsmashGdxMenuScreen.this.cameraPositionTemp[2]);
this.target.add(WarsmashGdxMenuScreen.this.cameraTargetTemp[0],
WarsmashGdxMenuScreen.this.cameraTargetTemp[1], WarsmashGdxMenuScreen.this.cameraTargetTemp[2]);
this.camera.perspective(WarsmashGdxMenuScreen.this.modelCamera.fieldOfView * 0.75f,
Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight(),
WarsmashGdxMenuTestGame.this.modelCamera.nearClippingPlane,
WarsmashGdxMenuTestGame.this.modelCamera.farClippingPlane);
WarsmashGdxMenuScreen.this.modelCamera.nearClippingPlane,
WarsmashGdxMenuScreen.this.modelCamera.farClippingPlane);
}
else {
this.camera.perspective(70, this.camera.getAspect(), 100, 5000);
@ -665,25 +653,39 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
@Override
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
// TODO Auto-generated method stub
final float worldScreenY = getHeight() - screenY;
if (this.menuUI.touchDown(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchUp(final int screenX, final int screenY, final int pointer, final int button) {
// TODO Auto-generated method stub
final float worldScreenY = getHeight() - screenY;
if (this.menuUI.touchUp(screenX, screenY, worldScreenY, button)) {
return false;
}
return false;
}
@Override
public boolean touchDragged(final int screenX, final int screenY, final int pointer) {
// TODO Auto-generated method stub
final float worldScreenY = getHeight() - screenY;
if (this.menuUI.touchDragged(screenX, screenY, worldScreenY, pointer)) {
return false;
}
return false;
}
@Override
public boolean mouseMoved(final int screenX, final int screenY) {
// TODO Auto-generated method stub
final float worldScreenY = getHeight() - screenY;
if (this.menuUI.mouseMoved(screenX, screenY, worldScreenY)) {
return false;
}
return false;
}
@ -706,14 +708,7 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
this.uiViewport.apply();
this.batch.setProjectionMatrix(this.uiCamera.combined);
this.batch.begin();
this.menuUI.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);
if (false) {
this.font.draw(this.batch, fpsString, (this.uiViewport.getMinWorldWidth() - this.glyphLayout.width) / 2,
1100 * this.menuUI.getHeightRatioCorrection());
}
this.menuUI.render(this.batch, this.glyphLayout);
this.batch.end();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);
@ -804,4 +799,20 @@ public class WarsmashGdxMenuTestGame extends ApplicationAdapter implements Canva
}
}
@Override
public void hide() {
if (this.currentMusic != null) {
this.currentMusic.stop();
}
this.menuUI.hide();
}
@Override
public void pause() {
}
@Override
public void resume() {
}
}

View File

@ -0,0 +1,11 @@
package com.etheller.warsmash;
import com.badlogic.gdx.Game;
public class WarsmashGdxMultiScreenGame extends Game {
@Override
public void create() {
}
}

View File

@ -59,7 +59,7 @@ public class WarsmashPreviewApplication extends ApplicationAdapter implements Ca
final String renderer = Gdx.gl.glGetString(GL20.GL_RENDERER);
System.err.println("Renderer: " + renderer);
this.codebase = WarsmashGdxMapGame.parseDataSources(this.warsmashIni);
this.codebase = WarsmashGdxMapScreen.parseDataSources(this.warsmashIni);
this.viewer = new MdxViewer(this.codebase, this);
this.mdxHandler = new MdxHandler();

View File

@ -0,0 +1,44 @@
package com.etheller.warsmash.parsers.fdf;
import java.util.HashMap;
import java.util.Map;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.util.DataSourceFileHandle;
public class DynamicFontGeneratorHolder {
private final DataSource dataSource;
private final Element skin;
private final Map<String, FreeTypeFontGenerator> fontNameToGenerator;
public DynamicFontGeneratorHolder(final DataSource dataSource, final Element skin) {
this.dataSource = dataSource;
this.skin = skin;
this.fontNameToGenerator = new HashMap<>();
}
public FreeTypeFontGenerator getFontGenerator(final String font) {
FreeTypeFontGenerator fontGenerator = this.fontNameToGenerator.get(font);
if (fontGenerator == null) {
final String fontName = this.skin.getField(font);
if (fontName == null) {
throw new IllegalStateException("No such font: " + font);
}
if (!this.dataSource.has(fontName)) {
throw new IllegalStateException("No such font file: " + fontName + " (for \"" + font + "\")");
}
fontGenerator = new FreeTypeFontGenerator(new DataSourceFileHandle(this.dataSource, fontName));
this.fontNameToGenerator.put(font, fontGenerator);
}
return fontGenerator;
}
public void dispose() {
for (final FreeTypeFontGenerator generator : this.fontNameToGenerator.values()) {
generator.dispose();
}
this.fontNameToGenerator.clear();
}
}

View File

@ -23,6 +23,7 @@ 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.BackdropCornerFlags;
import com.etheller.warsmash.parsers.fdf.datamodel.ControlStyle;
import com.etheller.warsmash.parsers.fdf.datamodel.FontDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FrameClass;
import com.etheller.warsmash.parsers.fdf.datamodel.FrameDefinition;
@ -34,6 +35,8 @@ import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
import com.etheller.warsmash.parsers.fdf.frames.AbstractUIFrame;
import com.etheller.warsmash.parsers.fdf.frames.BackdropFrame;
import com.etheller.warsmash.parsers.fdf.frames.FilterModeTextureFrame;
import com.etheller.warsmash.parsers.fdf.frames.GlueButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.GlueTextButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
import com.etheller.warsmash.parsers.fdf.frames.SimpleStatusBarFrame;
@ -52,6 +55,7 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer.FilterMode;
public final class GameUI extends AbstractUIFrame implements UIFrame {
private static final boolean PIN_FAIL_IS_FATAL = false;
private final DataSource dataSource;
private final Element skin;
private final Viewport viewport;
@ -69,10 +73,12 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
private final Element errorStrings;
private final GlyphLayout glyphLayout;
private final WTS mapStrings;
private final BitmapFont font;
private final BitmapFont font20;
private final DynamicFontGeneratorHolder dynamicFontGeneratorHolder;
public GameUI(final DataSource dataSource, final Element skin, final Viewport viewport,
final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final AbstractMdxModelViewer modelViewer,
final int racialCommandIndex, final WTS mapStrings) {
public GameUI(final DataSource dataSource, final Element skin, final Viewport viewport, final Scene uiScene,
final AbstractMdxModelViewer modelViewer, final int racialCommandIndex, final WTS mapStrings) {
super("GameUI", null);
this.dataSource = dataSource;
this.skin = skin;
@ -88,7 +94,14 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
this.renderBounds.set(0, 0, viewport.getWorldWidth(), viewport.getWorldHeight());
}
this.templates = new FrameTemplateEnvironment();
this.fontGenerator = fontGenerator;
this.dynamicFontGeneratorHolder = new DynamicFontGeneratorHolder(this.modelViewer.dataSource, skin);
this.fontGenerator = this.dynamicFontGeneratorHolder.getFontGenerator("MasterFont");
final FreeTypeFontParameter fontParam = new FreeTypeFontParameter();
fontParam.size = 32;
this.font = this.fontGenerator.generateFont(fontParam);
fontParam.size = 20;
this.font20 = this.fontGenerator.generateFont(fontParam);
this.fontParam = new FreeTypeFontParameter();
this.fdfCoordinateResolutionDummyViewport = new FitViewport(0.8f, 0.6f);
this.skinData = new DataTable(modelViewer.getWorldEditStrings());
@ -393,7 +406,8 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
if (this.fontParam.size == 0) {
this.fontParam.size = 24;
}
frameFont = this.fontGenerator.generateFont(this.fontParam);
frameFont = this.dynamicFontGeneratorHolder.getFontGenerator(font.getFontName())
.generateFont(this.fontParam);
String textString = frameDefinition.getName();
String text = frameDefinition.getString("Text");
if (text != null) {
@ -415,41 +429,116 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
}
else if ("GLUETEXTBUTTON".equals(frameDefinition.getFrameType())) {
// ButtonText & ControlBackdrop
final SimpleFrame simpleFrame = new SimpleFrame(frameDefinition.getName(), parent);
final GlueTextButtonFrame glueButtonFrame = new GlueTextButtonFrame(frameDefinition.getName(), parent);
// TODO: we should not need to put ourselves in this map 2x, but we do
// since there are nested inflate calls happening before the general case
// mapping
this.nameToFrame.put(frameDefinition.getName(), simpleFrame);
final String buttonTextKey = frameDefinition.getString("ButtonText");
this.nameToFrame.put(frameDefinition.getName(), glueButtonFrame);
final String controlBackdropKey = frameDefinition.getString("ControlBackdrop");
final String controlPushedBackdropKey = frameDefinition.getString("ControlPushedBackdrop");
final String controlDisabledBackdropKey = frameDefinition.getString("ControlDisabledBackdrop");
final String controlMouseOverHighlightKey = frameDefinition.getString("ControlMouseOverHighlight");
final String buttonTextKey = frameDefinition.getString("ButtonText");
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
if (childDefinition.getName().equals(buttonTextKey)
|| childDefinition.getName().equals(controlBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, simpleFrame, frameDefinition,
if (childDefinition.getName().equals(controlBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
simpleFrame.add(inflatedChild);
glueButtonFrame.setControlBackdrop(inflatedChild);
}
else if (childDefinition.getName().equals(controlPushedBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
glueButtonFrame.setControlPushedBackdrop(inflatedChild);
}
else if (childDefinition.getName().equals(controlDisabledBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
glueButtonFrame.setControlDisabledBackdrop(inflatedChild);
}
else if (childDefinition.getName().equals(controlMouseOverHighlightKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
glueButtonFrame.setControlMouseOverHighlight(inflatedChild);
}
else if (childDefinition.getName().equals(buttonTextKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
glueButtonFrame.setButtonText(inflatedChild);
}
}
inflatedFrame = simpleFrame;
final EnumSet<ControlStyle> controlStyle = ControlStyle
.parseControlStyle(frameDefinition.getString("ControlStyle"));
if (controlStyle.contains(ControlStyle.AUTOTRACK)
&& controlStyle.contains(ControlStyle.HIGHLIGHTONMOUSEOVER)) {
glueButtonFrame.setHighlightOnMouseOver(true);
}
inflatedFrame = glueButtonFrame;
}
else if ("GLUEBUTTON".equals(frameDefinition.getFrameType())) {
// ButtonText & ControlBackdrop
final SimpleFrame simpleFrame = new SimpleFrame(frameDefinition.getName(), parent);
final GlueButtonFrame glueButtonFrame = new GlueButtonFrame(frameDefinition.getName(), parent);
// TODO: we should not need to put ourselves in this map 2x, but we do
// since there are nested inflate calls happening before the general case
// mapping
this.nameToFrame.put(frameDefinition.getName(), simpleFrame);
this.nameToFrame.put(frameDefinition.getName(), glueButtonFrame);
final String controlBackdropKey = frameDefinition.getString("ControlBackdrop");
final String controlPushedBackdropKey = frameDefinition.getString("ControlPushedBackdrop");
final String controlDisabledBackdropKey = frameDefinition.getString("ControlDisabledBackdrop");
final String controlMouseOverHighlightKey = frameDefinition.getString("ControlMouseOverHighlight");
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
if (childDefinition.getName().equals(controlBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, simpleFrame, frameDefinition,
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
simpleFrame.add(inflatedChild);
glueButtonFrame.setControlBackdrop(inflatedChild);
}
else if (childDefinition.getName().equals(controlPushedBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
glueButtonFrame.setControlPushedBackdrop(inflatedChild);
}
else if (childDefinition.getName().equals(controlDisabledBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
glueButtonFrame.setControlDisabledBackdrop(inflatedChild);
}
else if (childDefinition.getName().equals(controlMouseOverHighlightKey)) {
final UIFrame inflatedChild = inflate(childDefinition, glueButtonFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
glueButtonFrame.setControlMouseOverHighlight(inflatedChild);
}
}
inflatedFrame = simpleFrame;
final EnumSet<ControlStyle> controlStyle = ControlStyle
.parseControlStyle(frameDefinition.getString("ControlStyle"));
if (controlStyle.contains(ControlStyle.AUTOTRACK)
&& controlStyle.contains(ControlStyle.HIGHLIGHTONMOUSEOVER)) {
glueButtonFrame.setHighlightOnMouseOver(true);
}
inflatedFrame = glueButtonFrame;
}
else if ("HIGHLIGHT".equals(frameDefinition.getFrameType())) {
final String highlightType = frameDefinition.getString("HighlightType");
if (!"FILETEXTURE".equals(highlightType)) {
throw new IllegalStateException(
"Our engine does not know how to handle a non-FILETEXTURE highlight");
}
final String highlightAlphaFile = frameDefinition.getString("HighlightAlphaFile");
final String highlightAlphaMode = frameDefinition.getString("HighlightAlphaMode");
final FilterModeTextureFrame textureFrame = new FilterModeTextureFrame(frameDefinition.getName(),
parent, false, null);
textureFrame.setTexture(highlightAlphaFile, this);
if ("ADD".equals(highlightAlphaMode)) {
textureFrame.setFilterMode(FilterMode.ADDALPHA);
}
return textureFrame;
}
else if ("BACKDROP".equals(frameDefinition.getFrameType())) {
final boolean tileBackground = frameDefinition.has("BackdropTileBackground");
@ -480,10 +569,10 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
String edgeFileString = frameDefinition.getString("BackdropEdgeFile");
System.out.println(frameDefinition.getName() + " wants edge file: " + edgeFileString);
if (decorateFileNames && (edgeFileString != null)) {
edgeFileString = getSkinField(edgeFileString);
edgeFileString = trySkinField(edgeFileString);
}
if (decorateFileNames && (edgeFileString != null)) {
backgroundString = getSkinField(backgroundString);
backgroundString = trySkinField(backgroundString);
}
final Texture background = backgroundString == null ? null : loadTexture(backgroundString);
final Texture edgeFile = edgeFileString == null ? null : loadTexture(edgeFileString);
@ -534,7 +623,8 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
if (this.fontParam.size == 0) {
this.fontParam.size = 24;
}
frameFont = this.fontGenerator.generateFont(this.fontParam);
frameFont = this.dynamicFontGeneratorHolder.getFontGenerator(font.getFontName())
.generateFont(this.fontParam);
String textString = frameDefinition.getName();
String text = frameDefinition.getString("Text");
if (text != null) {
@ -591,12 +681,18 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
final UIFrame otherFrameByName = getFrameByName(setPointDefinition.getOther(),
0 /* TODO: createContext */);
if (otherFrameByName == null) {
throw new IllegalStateException("Failing to pin " + frameDefinition.getName() + " to "
System.err.println("Failing to pin " + frameDefinition.getName() + " to "
+ setPointDefinition.getOther() + " because it was null!");
if (PIN_FAIL_IS_FATAL) {
throw new IllegalStateException("Failing to pin " + frameDefinition.getName() + " to "
+ setPointDefinition.getOther() + " because it was null!");
}
}
else {
inflatedFrame.addSetPoint(new SetPoint(setPointDefinition.getMyPoint(), otherFrameByName,
setPointDefinition.getOtherPoint(), convertX(this.viewport, setPointDefinition.getX()),
convertY(this.viewport, setPointDefinition.getY())));
}
inflatedFrame.addSetPoint(new SetPoint(setPointDefinition.getMyPoint(), otherFrameByName,
setPointDefinition.getOtherPoint(), convertX(this.viewport, setPointDefinition.getX()),
convertY(this.viewport, setPointDefinition.getY())));
}
this.nameToFrame.put(frameDefinition.getName(), inflatedFrame);
}
@ -659,9 +755,13 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
}
public Texture loadTexture(String path) {
if (!path.contains(".")) {
final int lastDotIndex = path.lastIndexOf('.');
if (lastDotIndex == -1) {
path = path + ".blp";
}
else {
path = path.substring(0, lastDotIndex) + ".blp";
}
Texture texture = this.pathToTexture.get(path);
if (texture == null) {
try {
@ -714,4 +814,20 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
public void setText(final StringFrame stringFrame, final String text) {
stringFrame.setText(text, this, this.viewport);
}
public BitmapFont getFont() {
return this.font;
}
public BitmapFont getFont20() {
return this.font20;
}
public FreeTypeFontGenerator getFontGenerator() {
return this.fontGenerator;
}
public void dispose() {
this.dynamicFontGeneratorHolder.dispose();
}
}

View File

@ -314,9 +314,9 @@ public abstract class AbstractRenderableFrame implements UIFrame {
}
@Override
public final void render(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
public final void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
if (this.visible) {
internalRender(batch, baseFont, glyphLayout);
internalRender(batch, font20, glyphLayout);
}
}

View File

@ -46,10 +46,12 @@ public abstract class AbstractUIFrame extends AbstractRenderableFrame implements
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.touchDown(screenX, screenY, button);
if (clickedChild != null) {
return clickedChild;
if (isVisible()) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.touchDown(screenX, screenY, button);
if (clickedChild != null) {
return clickedChild;
}
}
}
return super.touchDown(screenX, screenY, button);
@ -57,10 +59,12 @@ public abstract class AbstractUIFrame extends AbstractRenderableFrame implements
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.touchUp(screenX, screenY, button);
if (clickedChild != null) {
return clickedChild;
if (isVisible()) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.touchUp(screenX, screenY, button);
if (clickedChild != null) {
return clickedChild;
}
}
}
return super.touchUp(screenX, screenY, button);
@ -68,10 +72,12 @@ public abstract class AbstractUIFrame extends AbstractRenderableFrame implements
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.getFrameChildUnderMouse(screenX, screenY);
if (clickedChild != null) {
return clickedChild;
if (isVisible()) {
for (final UIFrame childFrame : this.childFrames) {
final UIFrame clickedChild = childFrame.getFrameChildUnderMouse(screenX, screenY);
if (clickedChild != null) {
return clickedChild;
}
}
}
return super.getFrameChildUnderMouse(screenX, screenY);

View File

@ -0,0 +1,151 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.ClickableFrame;
public class GlueButtonFrame extends AbstractRenderableFrame implements ClickableFrame {
private UIFrame controlBackdrop;
private UIFrame controlPushedBackdrop;
private UIFrame controlDisabledBackdrop;
private UIFrame controlMouseOverHighlight;
private boolean enabled = true;
private boolean highlightOnMouseOver;
private boolean mouseOver = false;
private UIFrame activeChild;
private Runnable onClick;
public GlueButtonFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
}
public void setControlPushedBackdrop(final UIFrame controlPushedBackdrop) {
this.controlPushedBackdrop = controlPushedBackdrop;
}
public void setControlDisabledBackdrop(final UIFrame controlDisabledBackdrop) {
this.controlDisabledBackdrop = controlDisabledBackdrop;
}
public void setControlMouseOverHighlight(final UIFrame controlMouseOverHighlight) {
this.controlMouseOverHighlight = controlMouseOverHighlight;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
if (this.enabled) {
this.activeChild = this.controlBackdrop;
}
else {
this.activeChild = this.controlDisabledBackdrop;
}
}
public void setHighlightOnMouseOver(final boolean highlightOnMouseOver) {
this.highlightOnMouseOver = highlightOnMouseOver;
}
public void setOnClick(final Runnable onClick) {
this.onClick = onClick;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
if (this.controlBackdrop != null) {
this.controlBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlPushedBackdrop != null) {
this.controlPushedBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlDisabledBackdrop != null) {
this.controlDisabledBackdrop.positionBounds(gameUI, viewport);
}
if (this.controlMouseOverHighlight != null) {
this.controlMouseOverHighlight.positionBounds(gameUI, viewport);
}
if (this.enabled) {
this.activeChild = this.controlBackdrop;
}
else {
this.activeChild = this.controlDisabledBackdrop;
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
if (this.activeChild != null) {
this.activeChild.render(batch, baseFont, glyphLayout);
}
if (this.mouseOver) {
this.controlMouseOverHighlight.render(batch, baseFont, glyphLayout);
}
}
@Override
public void mouseDown(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlPushedBackdrop;
}
}
@Override
public void mouseUp(final GameUI gameUI, final Viewport uiViewport) {
if (this.enabled) {
this.activeChild = this.controlBackdrop;
}
}
@Override
public void mouseEnter(final GameUI gameUI, final Viewport uiViewport) {
if (this.highlightOnMouseOver) {
this.mouseOver = true;
}
}
@Override
public void mouseExit(final GameUI gameUI, final Viewport uiViewport) {
this.mouseOver = false;
}
@Override
public void onClick(final int button) {
if (this.onClick != null) {
this.onClick.run();
}
}
@Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.touchUp(screenX, screenY, button);
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.touchDown(screenX, screenY, button);
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.enabled && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.getFrameChildUnderMouse(screenX, screenY);
}
}

View File

@ -0,0 +1,35 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
public class GlueTextButtonFrame extends GlueButtonFrame {
private UIFrame buttonText;
public GlueTextButtonFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setButtonText(final UIFrame buttonText) {
this.buttonText = buttonText;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
super.innerPositionBounds(gameUI, viewport);
if (this.buttonText != null) {
this.buttonText.positionBounds(gameUI, viewport);
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
super.internalRender(batch, baseFont, glyphLayout);
if (this.buttonText != null) {
this.buttonText.render(batch, baseFont, glyphLayout);
}
}
}

View File

@ -1,5 +1,6 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
@ -13,6 +14,7 @@ public class TextureFrame extends AbstractRenderableFrame {
private TextureRegion texture;
private final boolean decorateFileNames;
private final Vector4Definition texCoord;
private Color color;
public TextureFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final Vector4Definition texCoord) {
@ -26,14 +28,24 @@ public class TextureFrame extends AbstractRenderableFrame {
if (this.texture == null) {
return;
}
if (this.color != null) {
batch.setColor(this.color);
}
batch.draw(this.texture, this.renderBounds.x, this.renderBounds.y, this.renderBounds.width,
this.renderBounds.height);
if (this.color != null) {
batch.setColor(1f, 1f, 1f, 1f);
}
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
}
public void setColor(final Color color) {
this.color = color;
}
public void setTexture(String file, final GameUI gameUI) {
if (this.decorateFileNames) {
file = gameUI.getSkinField(file);

View File

@ -10,7 +10,6 @@ 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;
@ -52,13 +51,12 @@ 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) {
public static JUIEnvironment loadJUI(final DataSource dataSource, final Viewport uiViewport, 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, fontGenerator,
uiScene, war3MapViewer, rootFrameListener);
final JUIEnvironment environment = new JUIEnvironment(jassProgramVisitor, dataSource, uiViewport, uiScene,
war3MapViewer, rootFrameListener);
for (final String jassFile : files) {
try {
JassLexer lexer;
@ -103,8 +101,8 @@ public class Jass2 {
private Element skin;
public JUIEnvironment(final JassProgramVisitor jassProgramVisitor, final DataSource dataSource,
final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator, final Scene uiScene,
final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener) {
final Viewport uiViewport, 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");
@ -137,8 +135,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, fontGenerator, uiScene,
war3MapViewer, 0, war3MapViewer.getAllObjectData().getWts());
final GameUI gameUI = new GameUI(dataSource, skin, uiViewport, uiScene, war3MapViewer, 0,
war3MapViewer.getAllObjectData().getWts());
JUIEnvironment.this.gameUI = gameUI;
JUIEnvironment.this.skin = skin;
rootFrameListener.onCreate(gameUI);

View File

@ -98,7 +98,7 @@ public final class ImageUtils {
}
public boolean isNeedsSRGBFix() {
return false;
return this.needsSRGBFix;
}
}
@ -217,9 +217,6 @@ public final class ImageUtils {
* @return Resulting sRGB image.
*/
public static BufferedImage forceBufferedImagesRGB(final BufferedImage in) {
if (true) {
return in;
}
// Resolve input ColorSpace.
final ColorSpace inCS = in.getColorModel().getColorSpace();
final ColorSpace sRGBCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);

View File

@ -1,7 +1,12 @@
package com.etheller.warsmash.util;
public class WarsmashConstants {
public static final int MAX_PLAYERS = 28;
public static final int MAX_PLAYERS = 16;
/*
* With version, we use 0 for RoC, 1 for TFT emulation, and probably 2+ or
* whatever for custom mods and other stuff
*/
public static int GAME_VERSION = 0;
public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
public static final float SIMULATION_STEP_TIME = 1 / 20f;
public static final int PORT_NUMBER = 6115;
@ -14,4 +19,8 @@ public class WarsmashConstants {
// High - 1.5f
public static final float MODEL_DETAIL_PARTICLE_FACTOR = 1.5f;
public static final float MODEL_DETAIL_PARTICLE_FACTOR_INVERSE = 1f / MODEL_DETAIL_PARTICLE_FACTOR;
// I know this default string is from somewhere, maybe a language file? Didn't
// find it yet so I used this
public static final String DEFAULT_STRING = "Default string";
}

View File

@ -11,11 +11,12 @@ public class AudioBufferSource {
this.panner = panner;
}
public void start(final int value, final float volume, final float pitch) {
public void start(final int value, final float volume, final float pitch, final boolean looping) {
if (this.buffer != null) {
if (!this.panner.listener.is3DSupported() || this.panner.isWithinListenerDistance()) {
Extensions.audio.play(this.buffer, volume, pitch, this.panner.x, this.panner.y, this.panner.z,
this.panner.listener.is3DSupported(), this.panner.maxDistance, this.panner.refDistance);
this.panner.listener.is3DSupported(), this.panner.maxDistance, this.panner.refDistance,
looping);
}
}
}

View File

@ -91,8 +91,7 @@ public abstract class RawOpenGLTextureResource extends Texture {
final GL20 gl = this.viewer.gl;
}
public void update(final BufferedImage image, boolean sRGBFix) {
sRGBFix = false;
public void update(final BufferedImage image, final boolean sRGBFix) {
final GL20 gl = this.viewer.gl;
final int imageWidth = image.getWidth();

View File

@ -12,6 +12,7 @@ public abstract class SkeletalNode extends GenericNode {
protected static final Vector3 billboardAxisHeap = new Vector3();
protected static final Quaternion rotationHeap = new Quaternion();
protected static final Quaternion rotationHeap2 = new Quaternion();
protected static final Quaternion rotationHeap3 = new Quaternion();
protected static final Vector3 scalingHeap = new Vector3();
protected static final Vector3 blendLocationHeap = new Vector3();
protected static final Vector3 blendHeap = new Vector3();
@ -133,10 +134,33 @@ public abstract class SkeletalNode extends GenericNode {
computedRotation = rotationHeap;
cameraRayHeap.set(camera.billboardedVectors[6]);
computedRotation.set(this.parent.inverseWorldRotation);
// Compute local rotation
if (!Float.isNaN(blendTimeRatio) && (blendTimeRatio > 0)) {
rotationHeap2.set(this.localRotation).slerp(this.localBlendRotation, blendTimeRatio);
}
else {
rotationHeap2.set(this.localRotation);
}
// Inverse that local rotation
rotationHeap2.x = -rotationHeap2.x;
rotationHeap2.y = -rotationHeap2.y;
rotationHeap2.z = -rotationHeap2.z;
rotationHeap3.set(computedRotation);
RenderMathUtils.mul(computedRotation, rotationHeap2, rotationHeap3);
computedRotation.transform(cameraRayHeap);
billboardAxisHeap.set(0, 1, 0);
final float angle = (float) Math.atan2(cameraRayHeap.z, -cameraRayHeap.x);
computedRotation.setFromAxisRad(billboardAxisHeap, angle);
// Inverse that local rotation back to what it was
rotationHeap2.x = -rotationHeap2.x;
rotationHeap2.y = -rotationHeap2.y;
rotationHeap2.z = -rotationHeap2.z;
rotationHeap3.set(computedRotation);
RenderMathUtils.mul(computedRotation, rotationHeap2, rotationHeap3);
}
else if (this.billboardedZ) {
final Camera camera = scene.camera;

View File

@ -9,5 +9,5 @@ public interface AudioExtension {
float getDuration(Sound sound);
void play(Sound buffer, final float volume, final float pitch, final float x, final float y, final float z,
final boolean is3DSound, float maxDistance, float refDistance);
final boolean is3DSound, float maxDistance, float refDistance, boolean looping);
}

View File

@ -17,6 +17,7 @@ public class AttachmentInstance implements UpdatableObject {
internalInstance.dontInheritScaling = false;
internalInstance.hide();
internalInstance.setParent(instance.nodes[attachment.objectId]);
internalInstance.setAnimationSpeed(instance.getAnimationSpeed());
this.instance = instance;
this.attachment = attachment;

View File

@ -48,7 +48,8 @@ public class EventObjectSnd extends EmittedObject<MdxComplexInstance, EventObjec
// Make a sound.
source.start(0, emitterObject.volume,
(emitterObject.pitch + ((float) Math.random() * emitterObject.pitchVariance * 2))
- emitterObject.pitchVariance);
- emitterObject.pitchVariance,
false);
}
}

View File

@ -778,6 +778,15 @@ public class MdxComplexInstance extends ModelInstance {
public void setAnimationSpeed(final float speedRatio) {
this.animationSpeed = speedRatio;
for (final AttachmentInstance attachmentInstance : this.attachments) {
if (attachmentInstance.internalInstance != null) {
attachmentInstance.internalInstance.setAnimationSpeed(speedRatio);
}
}
}
public float getAnimationSpeed() {
return this.animationSpeed;
}
public void setBlendTime(final float blendTime) {
@ -796,6 +805,11 @@ public class MdxComplexInstance extends ModelInstance {
+ ((currentlyPlayingSequence.getInterval()[1] - currentlyPlayingSequence.getInterval()[0])
* ratioOfAnimationCompleted);
this.frame = (int) this.floatingFrame;
for (final AttachmentInstance attachmentInstance : this.attachments) {
if (attachmentInstance.internalInstance != null) {
attachmentInstance.internalInstance.setFrameByRatio(ratioOfAnimationCompleted);
}
}
}
}
}

View File

@ -8,7 +8,7 @@ public class TextTag {
private float screenCoordsZHeight;
private final String text;
private final Color color;
private int lifetime = 0;
private float lifetime = 0;
public TextTag(final Vector3 position, final String text, final Color color) {
this.position = position;
@ -17,16 +17,20 @@ public class TextTag {
position.z += 64f;
}
public boolean update() {
this.screenCoordsZHeight += 1.0f;
this.lifetime++;
return this.lifetime > 196;
public boolean update(final float deltaTime) {
this.screenCoordsZHeight += 60.0f * deltaTime;
this.lifetime += deltaTime;
return this.lifetime > 3.5f;
}
public Vector3 getPosition() {
return this.position;
}
public float getRemainingLife() {
return 3.5f - this.lifetime;
}
public Color getColor() {
return this.color;
}

View File

@ -17,7 +17,7 @@ import com.etheller.warsmash.viewer5.gl.Extensions;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
public final class UnitSound {
private static final UnitSound SILENT = new UnitSound(0, 0, 0, 0, 0, 0);
private static final UnitSound SILENT = new UnitSound(0, 0, 0, 0, 0, 0, false);
private final List<Sound> sounds = new ArrayList<>();
private final float volume;
@ -26,6 +26,7 @@ public final class UnitSound {
private final float minDistance;
private final float maxDistance;
private final float distanceCutoff;
private final boolean looping;
private Sound lastPlayedSound;
@ -49,7 +50,15 @@ public final class UnitSound {
final float minDistance = row.getFieldFloatValue("MinDistance");
final float maxDistance = row.getFieldFloatValue("MaxDistance");
final float distanceCutoff = row.getFieldFloatValue("DistanceCutoff");
final UnitSound sound = new UnitSound(volume, pitch, pitchVariance, minDistance, maxDistance, distanceCutoff);
final String[] flags = row.getField("Flags").split(",");
boolean looping = false;
for (final String flag : flags) {
if ("LOOPING".equals(flag)) {
looping = true;
}
}
final UnitSound sound = new UnitSound(volume, pitch, pitchVariance, minDistance, maxDistance, distanceCutoff,
looping);
for (final String fileName : fileNames.split(",")) {
String filePath = directoryBase + fileName;
final int lastDotIndex = filePath.lastIndexOf('.');
@ -64,13 +73,14 @@ public final class UnitSound {
}
public UnitSound(final float volume, final float pitch, final float pitchVariation, final float minDistance,
final float maxDistance, final float distanceCutoff) {
final float maxDistance, final float distanceCutoff, final boolean looping) {
this.volume = volume;
this.pitch = pitch;
this.pitchVariance = pitchVariation;
this.minDistance = minDistance;
this.maxDistance = maxDistance;
this.distanceCutoff = distanceCutoff;
this.looping = looping;
}
public boolean playUnitResponse(final AudioContext audioContext, final RenderUnit unit) {
@ -116,7 +126,7 @@ public final class UnitSound {
// Make a sound.
source.start(0, this.volume,
(this.pitch + ((float) Math.random() * this.pitchVariance * 2)) - this.pitchVariance);
(this.pitch + ((float) Math.random() * this.pitchVariance * 2)) - this.pitchVariance, this.looping);
this.lastPlayedSound = source.buffer;
return true;
}
@ -124,4 +134,10 @@ public final class UnitSound {
public int getSoundCount() {
return this.sounds.size();
}
public void stop() {
for (final Sound sound : this.sounds) {
sound.stop();
}
}
}

View File

@ -67,9 +67,11 @@ import com.etheller.warsmash.viewer5.Texture;
import com.etheller.warsmash.viewer5.WorldScene;
import com.etheller.warsmash.viewer5.gl.WebGL;
import com.etheller.warsmash.viewer5.handlers.AbstractMdxModelViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.Attachment;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxHandler;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxNode;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.tga.TgaFile;
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
@ -87,6 +89,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnitTypeData;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityUI;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
@ -107,6 +110,7 @@ import mpq.MPQArchive;
import mpq.MPQException;
public class War3MapViewer extends AbstractMdxModelViewer {
private static final War3ID ABILITY_HERO_RAWCODE = War3ID.fromString("AHer");
private static final Color PLACEHOLDER_LUMBER_COLOR = new Color(0.0f, 200f / 255f, 80f / 255f, 1.0f);
private static final Color PLACEHOLDER_GOLD_COLOR = new Color(1.0f, 220f / 255f, 0f, 1.0f);
private static final War3ID UNIT_FILE = War3ID.fromString("umdl");
@ -636,6 +640,42 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
}
@Override
public void spawnGainLevelEffect(final CUnit source) {
final AbilityUI heroUI = War3MapViewer.this.abilityDataUI.getUI(ABILITY_HERO_RAWCODE);
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
final String heroLevelUpArt = heroUI.getCasterArt(0);
final MdxModel heroLevelUpModel = loadModel(heroLevelUpArt);
if (heroLevelUpModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) heroLevelUpModel
.addInstance();
modelInstance.setTeamColor(source.getPlayerIndex());
final MdxModel model = (MdxModel) renderUnit.instance.model;
int index = -1;
for (int i = 0; i < model.attachments.size(); i++) {
final Attachment attachment = model.attachments.get(i);
if (attachment.getName().startsWith("origin ref")) {
index = i;
break;
}
}
if (index != -1) {
final MdxNode attachment = renderUnit.instance.getAttachment(index);
modelInstance.setParent(attachment);
}
else {
modelInstance.setLocation(renderUnit.location);
}
modelInstance.setScene(War3MapViewer.this.worldScene);
SequenceUtils.randomBirthSequence(modelInstance);
War3MapViewer.this.projectiles
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this,
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing())));
}
}
@Override
public void spawnEffectOnUnit(final CUnit unit, final String effectPath) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(unit);
@ -1253,7 +1293,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final Iterator<TextTag> textTagIterator = this.textTags.iterator();
while (textTagIterator.hasNext()) {
if (textTagIterator.next().update()) {
if (textTagIterator.next().update(Gdx.graphics.getDeltaTime())) {
textTagIterator.remove();
}
}
@ -1619,6 +1659,10 @@ public class War3MapViewer extends AbstractMdxModelViewer {
return mdxPath;
}
public MdxModel loadModel(final String path) {
return (MdxModel) load(mdx(path), PathSolver.DEFAULT, null);
}
@Override
public SceneLightManager createLightManager(final boolean simple) {
if (simple) {
@ -1637,7 +1681,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
public void setGameUI(final GameUI gameUI) {
this.gameUI = gameUI;
this.abilityDataUI = new AbilityDataUI(this.allObjectData.getAbilities(), this.allObjectData.getUnits(),
this.allObjectData.getUpgrades(), gameUI);
this.allObjectData.getUpgrades(), gameUI, this);
}
public GameUI getGameUI() {

View File

@ -1,6 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -11,6 +12,7 @@ import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.units.manager.MutableObjectData;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
public class AbilityDataUI {
// Standard ability icon fields
@ -30,6 +32,13 @@ public class AbilityDataUI {
private static final War3ID ABILITY_RESEARCH_TIP = War3ID.fromString("aret");
private static final War3ID ABILITY_RESEARCH_UBER_TIP = War3ID.fromString("arut");
private static final War3ID CASTER_ART = War3ID.fromString("acat");
private static final War3ID TARGET_ART = War3ID.fromString("atat");
private static final War3ID SPECIAL_ART = War3ID.fromString("asat");
private static final War3ID EFFECT_ART = War3ID.fromString("aeat");
private static final War3ID AREA_EFFECT_ART = War3ID.fromString("aaea");
private static final War3ID MISSILE_ART = War3ID.fromString("amat");
private static final War3ID UNIT_ICON_NORMAL_X = War3ID.fromString("ubpx");
private static final War3ID UNIT_ICON_NORMAL_Y = War3ID.fromString("ubpy");
private static final War3ID UNIT_ICON_NORMAL = War3ID.fromString("uico");
@ -43,7 +52,7 @@ public class AbilityDataUI {
private static final War3ID UPGRADE_TIP = War3ID.fromString("gtp1");
private static final War3ID UPGRADE_UBER_TIP = War3ID.fromString("gub1");
private final Map<War3ID, AbilityIconUI> rawcodeToUI = new HashMap<>();
private final Map<War3ID, AbilityUI> rawcodeToUI = new HashMap<>();
private final Map<War3ID, IconUI> rawcodeToUnitUI = new HashMap<>();
private final Map<War3ID, List<IconUI>> rawcodeToUpgradeUI = new HashMap<>();
private final IconUI moveUI;
@ -62,9 +71,10 @@ public class AbilityDataUI {
private final IconUI cancelBuildUI;
private final IconUI cancelTrainUI;
private final IconUI rallyUI;
private final IconUI selectSkillUI;
public AbilityDataUI(final MutableObjectData abilityData, final MutableObjectData unitData,
final MutableObjectData upgradeData, final GameUI gameUI) {
final MutableObjectData upgradeData, final GameUI gameUI, final War3MapViewer viewer) {
final String disabledPrefix = gameUI.getSkinField("CommandButtonDisabledArtPath");
for (final War3ID alias : abilityData.keySet()) {
final MutableGameObject abilityTypeData = abilityData.get(alias);
@ -89,13 +99,23 @@ public class AbilityDataUI {
final Texture iconNormalDisabled = gameUI.loadTexture(disable(iconNormalPath, disabledPrefix));
final Texture iconTurnOff = gameUI.loadTexture(iconTurnOffPath);
final Texture iconTurnOffDisabled = gameUI.loadTexture(disable(iconTurnOffPath, disabledPrefix));
final List<String> casterArt = Arrays.asList(abilityTypeData.getFieldAsString(CASTER_ART, 0).split(","));
final List<String> targetArt = Arrays.asList(abilityTypeData.getFieldAsString(TARGET_ART, 0).split(","));
final List<String> specialArt = Arrays.asList(abilityTypeData.getFieldAsString(SPECIAL_ART, 0).split(","));
final List<String> effectArt = Arrays.asList(abilityTypeData.getFieldAsString(EFFECT_ART, 0).split(","));
final List<String> areaEffectArt = Arrays
.asList(abilityTypeData.getFieldAsString(AREA_EFFECT_ART, 0).split(","));
final List<String> missileArt = Arrays.asList(abilityTypeData.getFieldAsString(MISSILE_ART, 0).split(","));
this.rawcodeToUI.put(alias,
new AbilityIconUI(
new AbilityUI(
new IconUI(iconResearch, iconResearchDisabled, iconResearchX, iconResearchY,
iconResearchTip, iconResearchUberTip),
new IconUI(iconNormal, iconNormalDisabled, iconNormalX, iconNormalY, iconTip, iconUberTip),
new IconUI(iconTurnOff, iconTurnOffDisabled, iconTurnOffX, iconTurnOffY, iconTurnOffTip,
iconTurnOffUberTip)));
iconTurnOffUberTip),
casterArt, targetArt, specialArt, effectArt, areaEffectArt, missileArt));
}
for (final War3ID alias : unitData.keySet()) {
final MutableGameObject abilityTypeData = unitData.get(alias);
@ -143,6 +163,7 @@ public class AbilityDataUI {
this.cancelBuildUI = createBuiltInIconUI(gameUI, "CmdCancelBuild", disabledPrefix);
this.cancelTrainUI = createBuiltInIconUI(gameUI, "CmdCancelTrain", disabledPrefix);
this.rallyUI = createBuiltInIconUI(gameUI, "CmdRally", disabledPrefix);
this.selectSkillUI = createBuiltInIconUI(gameUI, "CmdSelectSkill", disabledPrefix);
}
private IconUI createBuiltInIconUI(final GameUI gameUI, final String key, final String disabledPrefix) {
@ -157,7 +178,7 @@ public class AbilityDataUI {
return new IconUI(icon, iconDisabled, buttonPositionX, buttonPositionY, tip, uberTip);
}
public AbilityIconUI getUI(final War3ID rawcode) {
public AbilityUI getUI(final War3ID rawcode) {
return this.rawcodeToUI.get(rawcode);
}
@ -251,4 +272,8 @@ public class AbilityDataUI {
return this.rallyUI;
}
public IconUI getSelectSkillUI() {
return this.selectSkillUI;
}
}

View File

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

View File

@ -0,0 +1,72 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability;
import java.util.List;
public class AbilityUI {
private final IconUI learnIconUI;
private final IconUI onIconUI;
private final IconUI offIconUI;
private final List<String> casterArt;
private final List<String> targetArt;
private final List<String> specialArt;
private final List<String> effectArt;
private final List<String> areaEffectArt;
private final List<String> missileArt;
public AbilityUI(final IconUI learnIconUI, final IconUI onIconUI, final IconUI offIconUI,
final List<String> casterArt, final List<String> targetArt, final List<String> specialArt,
final List<String> effectArt, final List<String> areaEffectArt, final List<String> missileArt) {
this.learnIconUI = learnIconUI;
this.onIconUI = onIconUI;
this.offIconUI = offIconUI;
this.casterArt = casterArt;
this.targetArt = targetArt;
this.specialArt = specialArt;
this.effectArt = effectArt;
this.areaEffectArt = areaEffectArt;
this.missileArt = missileArt;
}
public IconUI getLearnIconUI() {
return this.learnIconUI;
}
public IconUI getOnIconUI() {
return this.onIconUI;
}
public IconUI getOffIconUI() {
return this.offIconUI;
}
public String getCasterArt(final int index) {
return tryGet(this.casterArt, index);
}
public String getTargetArt(final int index) {
return tryGet(this.targetArt, index);
}
public String getSpecialArt(final int index) {
return tryGet(this.specialArt, index);
}
public String getEffectArt(final int index) {
return tryGet(this.effectArt, index);
}
public String getAreaEffectArt(final int index) {
return tryGet(this.areaEffectArt, index);
}
public String getMissileArt(final int index) {
return tryGet(this.missileArt, index);
}
private static String tryGet(final List<String> items, final int index) {
if (index < items.size()) {
return items.get(index);
}
return items.get(items.size() - 1);
}
}

View File

@ -1,13 +1,13 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.badlogic.gdx.graphics.Texture;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityIconUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityUI;
public class AbilityCommandButton implements CommandButton {
private final AbilityIconUI abilityIconUI;
private final AbilityUI abilityIconUI;
private final int orderId;
public AbilityCommandButton(final AbilityIconUI abilityIconUI, final int orderId) {
public AbilityCommandButton(final AbilityUI abilityIconUI, final int orderId) {
this.abilityIconUI = abilityIconUI;
this.orderId = orderId;
}

View File

@ -3,7 +3,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityIconUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.IconUI;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
@ -24,6 +24,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat.CAbilityColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericNoIconAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericSingleIconActiveAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbilityHero;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityRally;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
@ -63,7 +64,7 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
addCommandButton(ability, this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack, 0,
false, false);
boolean attackGroundEnabled = false;
for (final CUnitAttack attack : this.unit.getUnitType().getAttacks()) {
for (final CUnitAttack attack : this.unit.getAttacks()) {
if (attack.getWeaponType().isAttackGroundSupported()) {
attackGroundEnabled = true;
break;
@ -100,8 +101,13 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
@Override
public Void accept(final CAbilityGeneric ability) {
if ((this.menuBaseOrderId == 0) && ability.isIconShowing()) {
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(),
ability.getHandleId(), 0, 0, false, false);
final AbilityUI abilityUI = this.abilityDataUI.getUI(ability.getRawcode());
if (abilityUI != null) {
addCommandButton(ability, abilityUI.getOnIconUI(), ability.getHandleId(), 0, 0, false, false);
}
else {
addCommandButton(ability, this.abilityDataUI.getStopUI(), ability.getHandleId(), 0, 0, false, false);
}
}
return null;
}
@ -109,7 +115,7 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
@Override
public Void accept(final GenericSingleIconActiveAbility ability) {
if ((this.menuBaseOrderId == 0) && ability.isIconShowing()) {
final AbilityIconUI ui = this.abilityDataUI.getUI(ability.getAlias());
final AbilityUI ui = this.abilityDataUI.getUI(ability.getAlias());
addCommandButton(ability, ability.isToggleOn() ? ui.getOffIconUI() : ui.getOnIconUI(),
ability.getHandleId(), ability.getBaseOrderId(), 0, false, false);
}
@ -329,4 +335,10 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
return this.requirementsTextBuilder.toString();
}
}
@Override
public Void accept(final CAbilityHero ability) {
// TODO
return null;
}
}

View File

@ -27,6 +27,44 @@ public class CGameplayConstants {
private final float buildingAngle;
private final float rootAngle;
private final float defenseArmor;
private final int heroExpRange;
private final int maxHeroLevel;
private final int maxUnitLevel;
private final int[] needHeroXp;
private final int[] needHeroXpSum;
private final int[] grantHeroXp;
private final int[] grantNormalXp;
private final int[] heroFactorXp;
private final float summonedKillFactor;
private final float strAttackBonus;
private final float strHitPointBonus;
private final float strRegenBonus;
private final float intManaBonus;
private final float intRegenBonus;
private final float agiDefenseBonus;
private final float agiDefenseBase;
private final int agiMoveBonus;
private final float agiAttackSpeedBonus;
private final int needHeroXPFormulaA;
private final int needHeroXPFormulaB;
private final int needHeroXPFormulaC;
private final int grantHeroXPFormulaA;
private final int grantHeroXPFormulaB;
private final int grantHeroXPFormulaC;
private final int grantNormalXPFormulaA;
private final int grantNormalXPFormulaB;
private final int grantNormalXPFormulaC;
private final int heroAbilityLevelSkip;
private final boolean globalExperience;
private final boolean maxLevelHeroesDrainExp;
private final boolean buildingKillsGiveExp;
public CGameplayConstants(final DataTable parsedDataTable) {
final Element miscData = parsedDataTable.get("Misc");
// TODO use radians for half angle
@ -67,6 +105,56 @@ public class CGameplayConstants {
}
}
}
this.defenseArmor = miscData.getFieldFloatValue("DefenseArmor");
this.globalExperience = miscData.getFieldValue("GlobalExperience") != 0;
this.maxLevelHeroesDrainExp = miscData.getFieldValue("MaxLevelHeroesDrainExp") != 0;
this.buildingKillsGiveExp = miscData.getFieldValue("BuildingKillsGiveExp") != 0;
this.heroExpRange = miscData.getFieldValue("HeroExpRange");
this.maxHeroLevel = miscData.getFieldValue("MaxHeroLevel");
this.maxUnitLevel = miscData.getFieldValue("MaxUnitLevel");
this.needHeroXPFormulaA = miscData.getFieldValue("NeedHeroXPFormulaA");
this.needHeroXPFormulaB = miscData.getFieldValue("NeedHeroXPFormulaB");
this.needHeroXPFormulaC = miscData.getFieldValue("NeedHeroXPFormulaC");
this.grantHeroXPFormulaA = miscData.getFieldValue("GrantHeroXPFormulaA");
this.grantHeroXPFormulaB = miscData.getFieldValue("GrantHeroXPFormulaB");
this.grantHeroXPFormulaC = miscData.getFieldValue("GrantHeroXPFormulaC");
this.grantNormalXPFormulaA = miscData.getFieldValue("GrantNormalXPFormulaA");
this.grantNormalXPFormulaB = miscData.getFieldValue("GrantNormalXPFormulaB");
this.grantNormalXPFormulaC = miscData.getFieldValue("GrantNormalXPFormulaC");
this.needHeroXp = parseTable(miscData.getField("NeedHeroXP"), this.needHeroXPFormulaA, this.needHeroXPFormulaB,
this.needHeroXPFormulaC, this.maxHeroLevel);
this.needHeroXpSum = new int[this.needHeroXp.length];
for (int i = 0; i < this.needHeroXpSum.length; i++) {
if (i == 0) {
this.needHeroXpSum[i] = this.needHeroXp[i];
}
else {
this.needHeroXpSum[i] = this.needHeroXp[i] + this.needHeroXpSum[i - 1];
}
}
this.grantHeroXp = parseTable(miscData.getField("GrantHeroXP"), this.grantHeroXPFormulaA,
this.grantHeroXPFormulaB, this.grantHeroXPFormulaC, this.maxHeroLevel);
this.grantNormalXp = parseTable(miscData.getField("GrantNormalXP"), this.grantNormalXPFormulaA,
this.grantNormalXPFormulaB, this.grantNormalXPFormulaC, this.maxUnitLevel);
this.heroFactorXp = parseIntArray(miscData.getField("HeroFactorXP"));
this.summonedKillFactor = miscData.getFieldFloatValue("SummonedKillFactor");
this.strAttackBonus = miscData.getFieldFloatValue("StrAttackBonus");
this.strHitPointBonus = miscData.getFieldFloatValue("StrHitPointBonus");
this.strRegenBonus = miscData.getFieldFloatValue("StrRegenBonus");
this.intManaBonus = miscData.getFieldFloatValue("IntManaBonus");
this.intRegenBonus = miscData.getFieldFloatValue("IntRegenBonus");
this.agiDefenseBonus = miscData.getFieldFloatValue("AgiDefenseBonus");
this.agiDefenseBase = miscData.getFieldFloatValue("AgiDefenseBase");
this.agiMoveBonus = miscData.getFieldValue("AgiMoveBonus");
this.agiAttackSpeedBonus = miscData.getFieldFloatValue("AgiAttackSpeedBonus");
this.heroAbilityLevelSkip = miscData.getFieldValue("HeroAbilityLevelSkip");
}
public float getAttackHalfAngle() {
@ -124,4 +212,134 @@ public class CGameplayConstants {
public float getRootAngle() {
return this.rootAngle;
}
public float getDefenseArmor() {
return this.defenseArmor;
}
public boolean isGlobalExperience() {
return this.globalExperience;
}
public boolean isMaxLevelHeroesDrainExp() {
return this.maxLevelHeroesDrainExp;
}
public boolean isBuildingKillsGiveExp() {
return this.buildingKillsGiveExp;
}
public int getHeroAbilityLevelSkip() {
return this.heroAbilityLevelSkip;
}
public int getHeroExpRange() {
return this.heroExpRange;
}
public int getMaxHeroLevel() {
return this.maxHeroLevel;
}
public int getMaxUnitLevel() {
return this.maxUnitLevel;
}
public float getSummonedKillFactor() {
return this.summonedKillFactor;
}
public float getStrAttackBonus() {
return this.strAttackBonus;
}
public float getStrHitPointBonus() {
return this.strHitPointBonus;
}
public float getStrRegenBonus() {
return this.strRegenBonus;
}
public float getIntManaBonus() {
return this.intManaBonus;
}
public float getIntRegenBonus() {
return this.intRegenBonus;
}
public float getAgiDefenseBonus() {
return this.agiDefenseBonus;
}
public float getAgiDefenseBase() {
return this.agiDefenseBase;
}
public int getAgiMoveBonus() {
return this.agiMoveBonus;
}
public float getAgiAttackSpeedBonus() {
return this.agiAttackSpeedBonus;
}
public float getHeroFactorXp(final int level) {
return getTableValue(this.heroFactorXp, level) / 100f;
}
public int getNeedHeroXP(final int level) {
return getTableValue(this.needHeroXp, level);
}
public int getNeedHeroXPSum(final int level) {
return getTableValue(this.needHeroXpSum, level);
}
public int getGrantHeroXP(final int level) {
return getTableValue(this.grantHeroXp, level);
}
public int getGrantNormalXP(final int level) {
return getTableValue(this.grantNormalXp, level);
}
private static int getTableValue(final int[] table, int level) {
if (level <= 0) {
return 0;
}
if (level > table.length) {
level = table.length;
}
return table[level - 1];
}
/*
* This incorporates the function "f(x)" documented both on
* http://classic.battle.net/war3/basics/heroes.shtml and also on MiscGame.txt.
*/
private static int[] parseTable(final String txt, final int formulaA, final int formulaB, final int formulaC,
final int tableSize) {
final String[] splitTxt = txt.split(",");
final int[] result = new int[tableSize];
for (int i = 0; i < tableSize; i++) {
if (i < splitTxt.length) {
result[i] = Integer.parseInt(splitTxt[i]);
}
else {
result[i] = (formulaA * result[i - 1]) + (formulaB * i) + formulaC;
}
}
return result;
}
private static int[] parseIntArray(final String txt) {
final String[] splitTxt = txt.split(",");
final int[] result = new int[splitTxt.length];
for (int i = 0; i < splitTxt.length; i++) {
result[i] = Integer.parseInt(splitTxt[i]);
}
return result;
}
}

View File

@ -0,0 +1,5 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
public class CItemType {
}

View File

@ -52,6 +52,7 @@ public class CSimulation {
private final PathingGrid pathingGrid;
private final CWorldCollision worldCollision;
private final CPathfindingProcessor[] pathfindingProcessors;
private final List<CUnit>[] playerHeroes;
private final CGameplayConstants gameplayConstants;
private final Random seededRandom;
private float currentGameDayTimeElapsed;
@ -69,7 +70,8 @@ public class CSimulation {
this.simulationRenderController = simulationRenderController;
this.pathingGrid = pathingGrid;
this.abilityData = new CAbilityData(parsedAbilityData);
this.unitData = new CUnitData(parsedUnitData, this.abilityData, this.simulationRenderController);
this.unitData = new CUnitData(this.gameplayConstants, parsedUnitData, this.abilityData,
this.simulationRenderController);
this.destructableData = new CDestructableData(parsedDestructableData, simulationRenderController);
this.units = new ArrayList<>();
this.newUnits = new ArrayList<>();
@ -79,8 +81,10 @@ public class CSimulation {
this.handleIdAllocator = new HandleIdAllocator();
this.worldCollision = new CWorldCollision(entireMapBounds, this.gameplayConstants.getMaxCollisionRadius());
this.pathfindingProcessors = new CPathfindingProcessor[WarsmashConstants.MAX_PLAYERS];
for (int i = 0; i < this.pathfindingProcessors.length; i++) {
this.playerHeroes = new ArrayList[WarsmashConstants.MAX_PLAYERS];
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
this.pathfindingProcessors[i] = new CPathfindingProcessor(pathingGrid, this.worldCollision);
this.playerHeroes[i] = new ArrayList<>();
}
this.seededRandom = seededRandom;
this.players = new ArrayList<>();
@ -211,6 +215,7 @@ public class CSimulation {
}
this.handleIdToUnit.remove(unit.getHandleId());
this.simulationRenderController.removeUnit(unit);
this.playerHeroes[unit.getPlayerIndex()].remove(unit);
}
}
finishAddingNewUnits();
@ -304,6 +309,18 @@ public class CSimulation {
this.simulationRenderController.spawnGainResourceTextTag(unit, resourceType, amount);
}
public void unitGainLevelEvent(final CUnit unit) {
this.simulationRenderController.spawnGainLevelEffect(unit);
}
public void heroCreateEvent(final CUnit hero) {
this.playerHeroes[hero.getPlayerIndex()].add(hero);
}
public List<CUnit> getPlayerHeroes(final int playerIndex) {
return this.playerHeroes[playerIndex];
}
public void unitsLoaded() {
// called on startup after the system loads the map's units layer, but not any
// custom scripts yet
@ -331,4 +348,5 @@ public class CSimulation {
public void createEffectOnUnit(final CUnit unit, final String effectPath) {
this.simulationRenderController.spawnEffectOnUnit(unit, effectPath);
}
}

View File

@ -19,6 +19,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener.
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbilityHero;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.mine.CAbilityGoldMine;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTarget;
@ -51,7 +52,13 @@ public class CUnit extends CWidget {
private int maximumLife;
private int maximumMana;
private int speed;
private final int defense;
private int agilityDefenseBonus;
private int permanentDefenseBonus;
private int temporaryDefenseBonus;
private int currentDefenseDisplay;
private int currentDefense;
private int cooldownEndTime = 0;
private float flyHeight;
private int playerIndex;
@ -103,10 +110,11 @@ public class CUnit extends CWidget {
private int foodMade;
private int foodUsed;
private List<CUnitAttack> unitSpecificAttacks;
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 int defense, final CUnitType unitType,
final RemovablePathingMapInstance pathingInstance) {
final int speed, final CUnitType unitType, final RemovablePathingMapInstance pathingInstance) {
super(handleId, x, y, life);
this.playerIndex = playerIndex;
this.typeId = typeId;
@ -115,7 +123,6 @@ public class CUnit extends CWidget {
this.maximumLife = maximumLife;
this.maximumMana = maximumMana;
this.speed = speed;
this.defense = defense;
this.pathingInstance = pathingInstance;
this.flyHeight = unitType.getDefaultFlyingHeight();
this.unitType = unitType;
@ -126,6 +133,34 @@ public class CUnit extends CWidget {
this.currentBehavior = this.defaultBehavior;
}
private void computeDerivedFields() {
this.currentDefenseDisplay = this.unitType.getDefense() + this.agilityDefenseBonus + this.permanentDefenseBonus;
this.currentDefense = this.currentDefenseDisplay + this.temporaryDefenseBonus;
}
public void setAgilityDefenseBonus(final int agilityDefenseBonus) {
this.agilityDefenseBonus = agilityDefenseBonus;
computeDerivedFields();
}
public void setPermanentDefenseBonus(final int permanentDefenseBonus) {
this.permanentDefenseBonus = permanentDefenseBonus;
computeDerivedFields();
}
public void setTemporaryDefenseBonus(final int temporaryDefenseBonus) {
this.temporaryDefenseBonus = temporaryDefenseBonus;
computeDerivedFields();
}
public int getTemporaryDefenseBonus() {
return this.temporaryDefenseBonus;
}
public int getCurrentDefenseDisplay() {
return this.currentDefenseDisplay;
}
public void setUnitAnimationListener(final CUnitAnimationListener unitAnimationListener) {
this.unitAnimationListener = unitAnimationListener;
this.unitAnimationListener.playAnimation(true, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, true);
@ -365,8 +400,7 @@ public class CUnit extends CWidget {
}
public boolean autoAcquireAttackTargets(final CSimulation game, final boolean disableMove) {
if (!this.unitType.getAttacks().isEmpty()
&& !this.unitType.getClassifications().contains(CUnitClassification.PEON)) {
if (!this.getAttacks().isEmpty() && !this.unitType.getClassifications().contains(CUnitClassification.PEON)) {
if (this.collisionRectangle != null) {
tempRect.set(this.collisionRectangle);
}
@ -587,7 +621,7 @@ public class CUnit extends CWidget {
}
public int getDefense() {
return this.defense;
return this.currentDefense;
}
@Override
@ -647,11 +681,13 @@ public class CUnit extends CWidget {
final float damageRatioFromArmorClass = simulation.getGameplayConstants().getDamageRatioAgainst(attackType,
this.unitType.getDefenseType());
final float damageRatioFromDefense;
if (this.defense >= 0) {
damageRatioFromDefense = 1f - (float) (((this.defense) * 0.06) / (1 + (0.06 * this.defense)));
final int defense = this.currentDefense;
if (defense >= 0) {
damageRatioFromDefense = 1f - (((defense) * simulation.getGameplayConstants().getDefenseArmor())
/ (1 + (simulation.getGameplayConstants().getDefenseArmor() * defense)));
}
else {
damageRatioFromDefense = 2f - (float) StrictMath.pow(0.94, -this.defense);
damageRatioFromDefense = 2f - (float) StrictMath.pow(0.94, -defense);
}
final float trueDamage = damageRatioFromArmorClass * damageRatioFromDefense * damage;
this.life -= trueDamage;
@ -660,14 +696,14 @@ public class CUnit extends CWidget {
simulation.unitDamageEvent(this, weaponType, this.unitType.getArmorType());
if (!this.invulnerable && isDead()) {
if (!wasDead) {
kill(simulation);
kill(simulation, source);
}
}
else {
if ((this.currentBehavior == null) || (this.currentBehavior == this.defaultBehavior)) {
if (!simulation.getPlayer(getPlayerIndex()).hasAlliance(source.getPlayerIndex(),
CAllianceType.PASSIVE)) {
for (final CUnitAttack attack : this.unitType.getAttacks()) {
for (final CUnitAttack attack : this.getAttacks()) {
if (source.canBeTargetedBy(simulation, this, attack.getTargetsAllowed())) {
this.currentBehavior = getAttackBehavior().reset(OrderIds.attack, attack, source, false,
CBehaviorAttackListener.DO_NOTHING);
@ -680,7 +716,7 @@ public class CUnit extends CWidget {
}
}
private void kill(final CSimulation simulation) {
private void kill(final CSimulation simulation, final CUnit source) {
if (this.currentBehavior != null) {
this.currentBehavior.end(simulation, true);
}
@ -704,6 +740,55 @@ public class CUnit extends CWidget {
if (this.foodUsed != 0) {
player.setUnitFoodUsed(this, 0);
}
// Award hero experience
if (source != null) {
final CPlayer sourcePlayer = simulation.getPlayer(source.getPlayerIndex());
if (!sourcePlayer.hasAlliance(this.playerIndex, CAllianceType.PASSIVE)) {
final CGameplayConstants gameplayConstants = simulation.getGameplayConstants();
if (gameplayConstants.isBuildingKillsGiveExp() || !source.getUnitType().isBuilding()) {
final CUnit killedUnit = this;
final CAbilityHero killedUnitHeroData = getHeroData();
final boolean killedUnitIsAHero = killedUnitHeroData != null;
int availableAwardXp;
if (killedUnitIsAHero) {
availableAwardXp = gameplayConstants.getGrantHeroXP(killedUnitHeroData.getHeroLevel());
}
else {
availableAwardXp = gameplayConstants.getGrantNormalXP(this.unitType.getLevel());
}
final List<CUnit> xpReceivingHeroes = new ArrayList<>();
final int heroExpRange = gameplayConstants.getHeroExpRange();
simulation.getWorldCollision().enumUnitsInRect(new Rectangle(this.getX() - heroExpRange,
this.getY() - heroExpRange, heroExpRange * 2, heroExpRange * 2), new CUnitEnumFunction() {
@Override
public boolean call(final CUnit unit) {
if ((unit.distance(killedUnit) <= heroExpRange)
&& sourcePlayer.hasAlliance(unit.getPlayerIndex(), CAllianceType.SHARED_XP)
&& (unit.getHeroData() != null)) {
xpReceivingHeroes.add(unit);
}
return false;
}
});
if (xpReceivingHeroes.isEmpty()) {
if (gameplayConstants.isGlobalExperience()) {
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
if (sourcePlayer.hasAlliance(i, CAllianceType.SHARED_XP)) {
xpReceivingHeroes.addAll(simulation.getPlayerHeroes(i));
}
}
}
}
for (final CUnit receivingHero : xpReceivingHeroes) {
final CAbilityHero heroData = receivingHero.getHeroData();
heroData.addXp(simulation, receivingHero,
(int) (availableAwardXp * (1f / xpReceivingHeroes.size())
* gameplayConstants.getHeroFactorXp(heroData.getHeroLevel())));
}
}
}
}
}
public boolean canReach(final AbilityTarget target, final float range) {
@ -881,7 +966,7 @@ public class CUnit extends CWidget {
public boolean call(final CUnit unit) {
if (!this.game.getPlayer(this.source.getPlayerIndex()).hasAlliance(unit.getPlayerIndex(),
CAllianceType.PASSIVE)) {
for (final CUnitAttack attack : this.source.unitType.getAttacks()) {
for (final CUnitAttack attack : this.source.getAttacks()) {
if (this.source.canReach(unit, this.source.acquisitionRange)
&& unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed())
&& (this.source.distance(unit) >= this.source.getUnitType().getMinimumAttackRange())) {
@ -1020,7 +1105,7 @@ public class CUnit extends CWidget {
final boolean wasDead = isDead();
super.setLife(simulation, life);
if (isDead() && !wasDead) {
kill(simulation);
kill(simulation, null);
}
this.stateNotifier.lifeChanged();
}
@ -1138,6 +1223,10 @@ public class CUnit extends CWidget {
this.stateNotifier.rallyPointChanged();
}
public void internalPublishHeroStatsChanged() {
this.stateNotifier.heroStatsChanged();
}
public AbilityTarget getRallyPoint() {
return this.rallyPoint;
}
@ -1275,4 +1364,28 @@ public class CUnit extends CWidget {
public COrder getCurrentOrder() {
return this.lastStartedOrder;
}
public CAbilityHero getHeroData() {
for (final CAbility ability : this.abilities) {
if (ability instanceof CAbilityHero) {
return (CAbilityHero) ability;
}
}
return null;
}
public void setUnitSpecificAttacks(final List<CUnitAttack> unitSpecificAttacks) {
this.unitSpecificAttacks = unitSpecificAttacks;
}
public List<CUnitAttack> getUnitSpecificAttacks() {
return this.unitSpecificAttacks;
}
public List<CUnitAttack> getAttacks() {
if (this.unitSpecificAttacks != null) {
return this.unitSpecificAttacks;
}
return this.unitType.getAttacks();
}
}

View File

@ -13,6 +13,8 @@ public interface CUnitStateListener {
void waypointsChanged();
void heroStatsChanged();
public static final class CUnitStateNotifier extends SubscriberSetNotifier<CUnitStateListener>
implements CUnitStateListener {
@Override
@ -49,5 +51,12 @@ public interface CUnitStateListener {
listener.waypointsChanged();
}
}
@Override
public void heroStatsChanged() {
for (final CUnitStateListener listener : set) {
listener.heroStatsChanged();
}
}
}
}

View File

@ -7,6 +7,7 @@ import java.util.List;
import com.etheller.warsmash.util.War3ID;
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.abilities.hero.CPrimaryAttribute;
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.attacks.CUnitAttack;
@ -58,6 +59,18 @@ public class CUnitType {
private final float propWindow;
private final float turnRate;
private final List<CUnitTypeRequirement> requirements;
private final int level;
private final boolean hero;
private final int startingStrength;
private final float strengthPerLevel;
private final int startingAgility;
private final float agilityPerLevel;
private final int startingIntelligence;
private final float intelligencePerLevel;
private final CPrimaryAttribute primaryAttribute;
private final List<War3ID> heroAbilityList;
private final List<String> heroProperNames;
private final int properNamesCount;
public CUnitType(final String name, final int life, final int manaInitial, final int manaMaximum, final int speed,
final int defense, final String abilityList, final boolean isBldg, final MovementType movementType,
@ -70,7 +83,10 @@ public class CUnitType {
final int goldCost, final int lumberCost, final int foodUsed, final int foodMade, final int buildTime,
final EnumSet<CBuildingPathingType> preventedPathingTypes,
final EnumSet<CBuildingPathingType> requiredPathingTypes, final float propWindow, final float turnRate,
final List<CUnitTypeRequirement> requirements) {
final List<CUnitTypeRequirement> requirements, final int level, final boolean hero, final int strength,
final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence,
final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute,
final List<War3ID> heroAbilityList, final List<String> heroProperNames, final int properNamesCount) {
this.name = name;
this.life = life;
this.manaInitial = manaInitial;
@ -108,6 +124,18 @@ public class CUnitType {
this.propWindow = propWindow;
this.turnRate = turnRate;
this.requirements = requirements;
this.level = level;
this.hero = hero;
this.startingStrength = strength;
this.strengthPerLevel = strengthPerLevel;
this.startingAgility = agility;
this.agilityPerLevel = agilityPerLevel;
this.startingIntelligence = intelligence;
this.intelligencePerLevel = intelligencePerLevel;
this.primaryAttribute = primaryAttribute;
this.heroAbilityList = heroAbilityList;
this.heroProperNames = heroProperNames;
this.properNamesCount = properNamesCount;
}
public String getName() {
@ -257,4 +285,52 @@ public class CUnitType {
public List<CUnitTypeRequirement> getRequirements() {
return this.requirements;
}
public int getLevel() {
return this.level;
}
public boolean isHero() {
return this.hero;
}
public int getStartingStrength() {
return this.startingStrength;
}
public float getStrengthPerLevel() {
return this.strengthPerLevel;
}
public int getStartingAgility() {
return this.startingAgility;
}
public float getAgilityPerLevel() {
return this.agilityPerLevel;
}
public int getStartingIntelligence() {
return this.startingIntelligence;
}
public float getIntelligencePerLevel() {
return this.intelligencePerLevel;
}
public CPrimaryAttribute getPrimaryAttribute() {
return this.primaryAttribute;
}
public List<War3ID> getHeroAbilityList() {
return this.heroAbilityList;
}
public List<String> getHeroProperNames() {
return this.heroProperNames;
}
public int getProperNamesCount() {
return this.properNamesCount;
}
}

View File

@ -44,7 +44,7 @@ public class CAbilityAttack extends AbstractCAbility {
}
if ((orderId == OrderIds.smart) || (orderId == OrderIds.attack)) {
boolean canTarget = false;
for (final CUnitAttack attack : unit.getUnitType().getAttacks()) {
for (final CUnitAttack attack : unit.getAttacks()) {
if (target.canBeTargetedBy(game, unit, attack.getTargetsAllowed())) {
canTarget = true;
break;
@ -77,7 +77,7 @@ public class CAbilityAttack extends AbstractCAbility {
break;
case OrderIds.attackground:
boolean allowAttackGround = false;
for (final CUnitAttack attack : unit.getUnitType().getAttacks()) {
for (final CUnitAttack attack : unit.getAttacks()) {
if (attack.getWeaponType().isAttackGroundSupported()) {
allowAttackGround = true;
break;
@ -118,7 +118,7 @@ public class CAbilityAttack extends AbstractCAbility {
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
for (final CUnitAttack attack : caster.getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
behavior = caster.getAttackBehavior().reset(OrderIds.attack, attack, target, false,
CBehaviorAttackListener.DO_NOTHING);
@ -142,7 +142,7 @@ public class CAbilityAttack extends AbstractCAbility {
return caster.getMoveBehavior().reset(OrderIds.attack, point);
case OrderIds.attackground:
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
for (final CUnitAttack attack : caster.getAttacks()) {
if (attack.getWeaponType().isAttackGroundSupported()) {
behavior = caster.getAttackBehavior().reset(OrderIds.attackground, attack, point, false,
CBehaviorAttackListener.DO_NOTHING);

View File

@ -10,6 +10,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat.CAbilityColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericNoIconAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericSingleIconActiveAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbilityHero;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityRally;
@ -51,4 +52,6 @@ public interface CAbilityVisitor<T> {
T accept(CAbilityRally ability);
T accept(GenericNoIconAbility ability);
T accept(CAbilityHero ability);
}

View File

@ -105,7 +105,7 @@ public class CAbilityColdArrows extends AbstractCAbility {
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
for (final CUnitAttack attack : caster.getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
behavior = caster.getAttackBehavior().reset(OrderIds.coldarrowstarg, attack, target, false,
CBehaviorAttackListener.DO_NOTHING);

View File

@ -53,7 +53,7 @@ public class CAbilityHarvest extends AbstractGenericSingleIconActiveAbility {
this.behaviorHarvest = new CBehaviorHarvest(unit, this);
this.behaviorReturnResources = new CBehaviorReturnResources(unit, this);
final List<CUnitAttack> unitAttacks = unit.getUnitType().getAttacks();
final List<CUnitAttack> unitAttacks = unit.getAttacks();
CUnitAttack bestFitTreeAttack = null;
for (final CUnitAttack attack : unitAttacks) {
if (attack.getTargetsAllowed().contains(CTargetType.TREE)) {

View File

@ -1,5 +1,275 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero;
public class CAbilityHero {
import java.util.List;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CGameplayConstants;
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.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.AbstractCAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
public class CAbilityHero extends AbstractCAbility {
private final List<War3ID> skillsAvailable;
private int xp;
private int heroLevel;
private int skillPoints;
private HeroStatValue strength;
private HeroStatValue agility;
private HeroStatValue intelligence;
private String properName;
public CAbilityHero(final int handleId, final List<War3ID> skillsAvailable) {
super(handleId);
this.skillsAvailable = skillsAvailable;
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
this.heroLevel = 1;
this.xp = 0;
final CUnitType unitType = unit.getUnitType();
this.strength = new HeroStatValue(unitType.getStartingStrength(), unitType.getStrengthPerLevel());
this.agility = new HeroStatValue(unitType.getStartingAgility(), unitType.getAgilityPerLevel());
this.intelligence = new HeroStatValue(unitType.getStartingIntelligence(), unitType.getIntelligencePerLevel());
calculateDerivatedFields(game, unit);
final int nameIndex = game.getSeededRandom().nextInt(unitType.getProperNamesCount());
String properName;
final List<String> heroProperNames = unitType.getHeroProperNames();
if (heroProperNames.size() > 0) {
if (nameIndex < heroProperNames.size()) {
properName = heroProperNames.get(nameIndex);
}
else {
properName = heroProperNames.get(heroProperNames.size() - 1);
}
}
else {
properName = WarsmashConstants.DEFAULT_STRING;
}
this.properName = properName;
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public void onTick(final CSimulation game, final CUnit unit) {
}
@Override
public void onCancelFromQueue(final CSimulation game, final CUnit unit, final int orderId) {
}
@Override
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId) {
return true;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
return null;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId,
final AbilityPointTarget point) {
return null;
}
@Override
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
return null;
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public <T> T visit(final CAbilityVisitor<T> visitor) {
return visitor.accept(this);
}
@Override
protected void innerCheckCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.useOk();
}
public int getSkillPoints() {
return this.skillPoints;
}
public void setSkillPoints(final int skillPoints) {
this.skillPoints = skillPoints;
}
public int getXp() {
return this.xp;
}
public void setXp(final int xp) {
this.xp = xp;
}
public int getHeroLevel() {
return this.heroLevel;
}
public void setHeroLevel(final int level) {
this.heroLevel = level;
}
public HeroStatValue getStrength() {
return this.strength;
}
public HeroStatValue getAgility() {
return this.agility;
}
public HeroStatValue getIntelligence() {
return this.intelligence;
}
public String getProperName() {
return this.properName;
}
public void addXp(final CSimulation simulation, final CUnit unit, final int xp) {
this.xp += xp;
final CGameplayConstants gameplayConstants = simulation.getGameplayConstants();
while ((this.heroLevel < gameplayConstants.getMaxHeroLevel())
&& (this.xp >= gameplayConstants.getNeedHeroXPSum(this.heroLevel))) {
this.heroLevel++;
this.skillPoints++;
calculateDerivatedFields(simulation, unit);
simulation.unitGainLevelEvent(unit);
}
unit.internalPublishHeroStatsChanged();
}
private HeroStatValue getStat(final CPrimaryAttribute attribute) {
switch (attribute) {
case AGILITY:
return this.agility;
case INTELLIGENCE:
return this.intelligence;
default:
case STRENGTH:
return this.strength;
}
}
private void calculateDerivatedFields(final CSimulation game, final CUnit unit) {
final CGameplayConstants gameplayConstants = game.getGameplayConstants();
final int prevStrength = this.strength.getCurrent();
final int prevAgility = this.agility.getCurrent();
final int prevIntelligence = this.intelligence.getCurrent();
this.strength.calculate(this.heroLevel);
this.agility.calculate(this.heroLevel);
this.intelligence.calculate(this.heroLevel);
final int deltaStrength = this.strength.getCurrent() - prevStrength;
final int deltaIntelligence = this.intelligence.getCurrent() - prevIntelligence;
final int currentAgility = this.agility.getCurrent();
final int deltaAgility = currentAgility - prevAgility;
final int primaryAttribute = getStat(unit.getUnitType().getPrimaryAttribute()).getCurrent();
for (final CUnitAttack attack : unit.getUnitSpecificAttacks()) {
attack.setPrimaryAttributeDamageBonus((int) (primaryAttribute * gameplayConstants.getStrAttackBonus()));
}
final float hitPointIncrease = gameplayConstants.getStrHitPointBonus() * deltaStrength;
final int oldMaximumLife = unit.getMaximumLife();
final float oldLife = unit.getLife();
final int newMaximumLife = Math.round(oldMaximumLife + hitPointIncrease);
final float newLife = (oldLife * (newMaximumLife)) / oldMaximumLife;
unit.setMaximumLife(newMaximumLife);
unit.setLife(game, newLife);
final float manaPointIncrease = gameplayConstants.getIntManaBonus() * deltaIntelligence;
final int oldMaximumMana = unit.getMaximumMana();
final float oldMana = unit.getMana();
final int newMaximumMana = Math.round(oldMaximumMana + manaPointIncrease);
final float newMana = (oldMana * (newMaximumMana)) / oldMaximumMana;
unit.setMaximumMana(newMaximumMana);
unit.setMana(newMana);
final int agilityDefenseBonus = Math.round(
gameplayConstants.getAgiDefenseBase() + (gameplayConstants.getAgiDefenseBonus() * currentAgility));
unit.setAgilityDefenseBonus(agilityDefenseBonus);
}
public static final class HeroStatValue {
private final float perLevelFactor;
private int base;
private int bonus;
private int currentBase;
private int current;
private HeroStatValue(final int base, final float perLevelFactor) {
this.base = base;
this.perLevelFactor = perLevelFactor;
}
public void calculate(final int level) {
this.currentBase = this.base + (int) ((level - 1) * this.perLevelFactor);
this.current = this.currentBase + this.bonus;
}
public void setBase(final int base) {
this.base = base;
}
public void setBonus(final int bonus) {
this.bonus = bonus;
}
public int getCurrent() {
return this.current;
}
public String getDisplayText() {
String text = Integer.toString(this.currentBase);
if (this.bonus != 0) {
if (this.bonus > 0) {
text += "|cFF00FF00 (+" + this.bonus + ")";
}
else {
text += "|cFFFF0000 (+" + this.bonus + ")";
}
}
return text;
}
}
}

View File

@ -0,0 +1,23 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero;
public enum CPrimaryAttribute {
STRENGTH,
INTELLIGENCE,
AGILITY;
public static CPrimaryAttribute parsePrimaryAttribute(final String targetTypeString) {
if (targetTypeString == null) {
return STRENGTH;
}
switch (targetTypeString.toUpperCase()) {
case "STR":
return STRENGTH;
case "INT":
return INTELLIGENCE;
case "AGI":
return AGILITY;
default:
return STRENGTH;
}
}
}

View File

@ -14,6 +14,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat.CAbilityColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericNoIconAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericSingleIconActiveAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbilityHero;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityRally;
@ -125,4 +126,11 @@ public class AbilityDisableWhileUnderConstructionVisitor implements CAbilityVisi
return null;
}
@Override
public Void accept(final CAbilityHero ability) {
ability.setDisabled(true);
ability.setIconShowing(false);
return null;
}
}

View File

@ -41,6 +41,12 @@ public abstract class CUnitAttack {
// calculate
private int minDamage;
private int maxDamage;
private int minDamageDisplay;
private int maxDamageDisplay;
private int primaryAttributeDamageBonus;
private int permanentDamageBonus;
private int temporaryDamageBonus;
public CUnitAttack(final float animationBackswingPoint, final float animationDamagePoint,
final CAttackType attackType, final float cooldownTime, final int damageBase, final int damageDice,
@ -64,15 +70,42 @@ public abstract class CUnitAttack {
computeDerivedFields();
}
public CUnitAttack(final CUnitAttack other) {
this.animationBackswingPoint = other.animationBackswingPoint;
this.animationDamagePoint = other.animationDamagePoint;
this.attackType = other.attackType;
this.cooldownTime = other.cooldownTime;
this.damageBase = other.damageBase;
this.damageDice = other.damageDice;
this.damageSidesPerDie = other.damageSidesPerDie;
this.damageUpgradeAmount = other.damageUpgradeAmount;
this.range = other.range;
this.rangeMotionBuffer = other.rangeMotionBuffer;
this.showUI = other.showUI;
this.targetsAllowed = other.targetsAllowed;
this.weaponSound = other.weaponSound;
this.weaponType = other.weaponType;
this.primaryAttributeDamageBonus = other.primaryAttributeDamageBonus;
this.permanentDamageBonus = other.permanentDamageBonus;
this.temporaryDamageBonus = other.temporaryDamageBonus;
computeDerivedFields();
}
public abstract CUnitAttack copy();
private void computeDerivedFields() {
this.minDamage = this.damageBase + this.damageDice;
this.maxDamage = this.damageBase + (this.damageDice * this.damageSidesPerDie);
if (this.minDamage < 0) {
this.minDamage = 0;
final int baseDamage = this.damageBase + this.primaryAttributeDamageBonus + this.permanentDamageBonus;
this.minDamageDisplay = baseDamage + this.damageDice;
this.maxDamageDisplay = baseDamage + (this.damageDice * this.damageSidesPerDie);
if (this.minDamageDisplay < 0) {
this.minDamageDisplay = 0;
}
if (this.maxDamage < 0) {
this.maxDamage = 0;
if (this.maxDamageDisplay < 0) {
this.maxDamageDisplay = 0;
}
this.minDamage = this.minDamageDisplay + this.temporaryDamageBonus;
this.maxDamage = this.maxDamageDisplay + this.temporaryDamageBonus;
}
public float getAnimationBackswingPoint() {
@ -198,6 +231,41 @@ public abstract class CUnitAttack {
return this.maxDamage;
}
public int getMinDamageDisplay() {
return this.minDamageDisplay;
}
public int getMaxDamageDisplay() {
return this.maxDamageDisplay;
}
public void setPrimaryAttributeDamageBonus(final int primaryAttributeDamageBonus) {
this.primaryAttributeDamageBonus = primaryAttributeDamageBonus;
computeDerivedFields();
}
public void setPermanentDamageBonus(final int permanentDamageBonus) {
this.permanentDamageBonus = permanentDamageBonus;
computeDerivedFields();
}
public void setTemporaryDamageBonus(final int temporaryDamageBonus) {
this.temporaryDamageBonus = temporaryDamageBonus;
computeDerivedFields();
}
public int getPrimaryAttributeDamageBonus() {
return this.primaryAttributeDamageBonus;
}
public int getPermanentDamageBonus() {
return this.permanentDamageBonus;
}
public int getTemporaryDamageBonus() {
return this.temporaryDamageBonus;
}
public abstract void launch(CSimulation simulation, CUnit unit, AbilityTarget target, float damage,
CUnitAttackListener attackListener);
}

View File

@ -25,6 +25,14 @@ public class CUnitAttackInstant extends CUnitAttack {
this.projectileArt = projectileArt;
}
@Override
public CUnitAttack copy() {
return new CUnitAttackInstant(getAnimationBackswingPoint(), getAnimationDamagePoint(), getAttackType(),
getCooldownTime(), getDamageBase(), getDamageDice(), getDamageSidesPerDie(), getDamageUpgradeAmount(),
getRange(), getRangeMotionBuffer(), isShowUI(), getTargetsAllowed(), getWeaponSound(), getWeaponType(),
this.projectileArt);
}
public String getProjectileArt() {
return this.projectileArt;
}

View File

@ -32,6 +32,14 @@ public class CUnitAttackMissile extends CUnitAttack {
this.projectileSpeed = projectileSpeed;
}
@Override
public CUnitAttack copy() {
return new CUnitAttackMissile(this.getAnimationBackswingPoint(), getAnimationDamagePoint(), getAttackType(),
getCooldownTime(), getDamageBase(), getDamageDice(), getDamageSidesPerDie(), getDamageUpgradeAmount(),
getRange(), getRangeMotionBuffer(), isShowUI(), getTargetsAllowed(), getWeaponSound(), getWeaponType(),
this.projectileArc, this.projectileArt, this.projectileHomingEnabled, this.projectileSpeed);
}
public float getProjectileArc() {
return this.projectileArc;
}

View File

@ -36,6 +36,16 @@ public class CUnitAttackMissileBounce extends CUnitAttackMissile {
this.areaOfEffectTargets = areaOfEffectTargets;
}
@Override
public CUnitAttack copy() {
return new CUnitAttackMissileBounce(getAnimationBackswingPoint(), getAnimationDamagePoint(), getAttackType(),
getCooldownTime(), getDamageBase(), getDamageDice(), getDamageSidesPerDie(), getDamageUpgradeAmount(),
getRange(), getRangeMotionBuffer(), isShowUI(), getTargetsAllowed(), getWeaponSound(), getWeaponType(),
getProjectileArc(), getProjectileArt(), isProjectileHomingEnabled(), getProjectileSpeed(),
this.damageLossFactor, this.maximumNumberOfTargets, this.areaOfEffectFullDamage,
this.areaOfEffectTargets);
}
public float getDamageLossFactor() {
return this.damageLossFactor;
}

View File

@ -24,6 +24,15 @@ public class CUnitAttackMissileLine extends CUnitAttackMissile {
this.damageSpillRadius = damageSpillRadius;
}
@Override
public CUnitAttack copy() {
return new CUnitAttackMissileLine(getAnimationBackswingPoint(), getAnimationDamagePoint(), getAttackType(),
getCooldownTime(), getDamageBase(), getDamageDice(), getDamageSidesPerDie(), getDamageUpgradeAmount(),
getRange(), getRangeMotionBuffer(), isShowUI(), getTargetsAllowed(), getWeaponSound(), getWeaponType(),
getProjectileArc(), getProjectileArt(), isProjectileHomingEnabled(), getProjectileSpeed(),
this.damageSpillDistance, this.damageSpillRadius);
}
public float getDamageSpillDistance() {
return this.damageSpillDistance;
}

View File

@ -39,6 +39,16 @@ public class CUnitAttackMissileSplash extends CUnitAttackMissile {
this.damageFactorSmall = damageFactorSmall;
}
@Override
public CUnitAttack copy() {
return new CUnitAttackMissileSplash(getAnimationBackswingPoint(), getAnimationDamagePoint(), getAttackType(),
getCooldownTime(), getDamageBase(), getDamageDice(), getDamageSidesPerDie(), getDamageUpgradeAmount(),
getRange(), getRangeMotionBuffer(), isShowUI(), getTargetsAllowed(), getWeaponSound(), getWeaponType(),
getProjectileArc(), getProjectileArt(), isProjectileHomingEnabled(), getProjectileSpeed(),
this.areaOfEffectFullDamage, this.areaOfEffectMediumDamage, this.areaOfEffectSmallDamage,
this.areaOfEffectTargets, this.damageFactorMedium, this.damageFactorSmall);
}
@Override
public int getRange() {
return super.getRange();

View File

@ -23,6 +23,13 @@ public class CUnitAttackNormal extends CUnitAttack {
weaponType);
}
@Override
public CUnitAttack copy() {
return new CUnitAttackNormal(getAnimationBackswingPoint(), getAnimationDamagePoint(), getAttackType(),
getCooldownTime(), getDamageBase(), getDamageDice(), getDamageSidesPerDie(), getDamageUpgradeAmount(),
getRange(), getRangeMotionBuffer(), isShowUI(), getTargetsAllowed(), getWeaponSound(), getWeaponType());
}
@Override
public void launch(final CSimulation simulation, final CUnit unit, final AbilityTarget target, final float damage,
final CUnitAttackListener attackListener) {

View File

@ -40,6 +40,9 @@ public class CAbilityData {
CAbilityType<?> abilityType = this.aliasToAbilityType.get(alias);
if (abilityType == null) {
final MutableGameObject mutableGameObject = this.abilityData.get(alias);
if (mutableGameObject == null) {
return null;
}
final War3ID code = mutableGameObject.getCode();
final CAbilityTypeDefinition abilityTypeDefinition = this.codeToAbilityTypeDefinition.get(code);
if (abilityTypeDefinition != null) {

View File

@ -0,0 +1,8 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.data;
import com.etheller.warsmash.units.manager.MutableObjectData;
public class CItemData {
public CItemData(final MutableObjectData itemData) {
}
}

View File

@ -2,6 +2,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.data;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
@ -13,6 +14,7 @@ import com.etheller.warsmash.util.War3ID;
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.environment.PathingGrid.RemovablePathingMapInstance;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CGameplayConstants;
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;
@ -28,6 +30,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityNightElfBuild;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityOrcBuild;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityUndeadBuild;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbilityHero;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CPrimaryAttribute;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityRally;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
@ -53,6 +57,8 @@ public class CUnitData {
private static final War3ID TURN_RATE = War3ID.fromString("umvr");
private static final War3ID IS_BLDG = War3ID.fromString("ubdg");
private static final War3ID NAME = War3ID.fromString("unam");
private static final War3ID PROPER_NAMES = War3ID.fromString("upro");
private static final War3ID PROPER_NAMES_COUNT = War3ID.fromString("upru");
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");
@ -133,6 +139,7 @@ public class CUnitData {
private static final War3ID TARGETED_AS = War3ID.fromString("utar");
private static final War3ID ABILITIES_NORMAL = War3ID.fromString("uabi");
private static final War3ID ABILITIES_HERO = War3ID.fromString("uhab");
private static final War3ID STRUCTURES_BUILT = War3ID.fromString("ubui");
private static final War3ID UNITS_TRAINED = War3ID.fromString("utra");
@ -151,13 +158,25 @@ public class CUnitData {
private static final War3ID REQUIRE_PLACE = War3ID.fromString("upar");
private static final War3ID PREVENT_PLACE = War3ID.fromString("upap");
private static final War3ID UNIT_LEVEL = War3ID.fromString("ulev");
private static final War3ID STR = War3ID.fromString("ustr");
private static final War3ID STR_PLUS = War3ID.fromString("ustp");
private static final War3ID AGI = War3ID.fromString("uagi");
private static final War3ID AGI_PLUS = War3ID.fromString("uagp");
private static final War3ID INT = War3ID.fromString("uint");
private static final War3ID INT_PLUS = War3ID.fromString("uinp");
private static final War3ID PRIMARY_ATTRIBUTE = War3ID.fromString("upra");
private final CGameplayConstants gameplayConstants;
private final MutableObjectData unitData;
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
private final CAbilityData abilityData;
private final SimulationRenderController simulationRenderController;
public CUnitData(final MutableObjectData unitData, final CAbilityData abilityData,
final SimulationRenderController simulationRenderController) {
public CUnitData(final CGameplayConstants gameplayConstants, final MutableObjectData unitData,
final CAbilityData abilityData, final SimulationRenderController simulationRenderController) {
this.gameplayConstants = gameplayConstants;
this.unitData = unitData;
this.abilityData = abilityData;
this.simulationRenderController = simulationRenderController;
@ -174,14 +193,20 @@ public class CUnitData {
final int manaInitial = unitTypeInstance.getManaInitial();
final int manaMaximum = unitTypeInstance.getManaMaximum();
final int speed = unitTypeInstance.getSpeed();
final int defense = unitTypeInstance.getDefense();
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
speed, defense, unitTypeInstance, pathingInstance);
speed, unitTypeInstance, pathingInstance);
if (speed > 0) {
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
}
if (!unitTypeInstance.getAttacks().isEmpty()) {
if (unitTypeInstance.isHero()) {
final List<CUnitAttack> heroAttacks = new ArrayList<>();
for (final CUnitAttack attack : unitTypeInstance.getAttacks()) {
heroAttacks.add(attack.copy());
}
unit.setUnitSpecificAttacks(heroAttacks);
}
if (!unit.getAttacks().isEmpty()) {
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
}
final List<War3ID> structuresBuilt = unitTypeInstance.getStructuresBuilt();
@ -218,6 +243,12 @@ public class CUnitData {
if (!unitsTrained.isEmpty()) {
unit.add(simulation, new CAbilityRally(handleIdAllocator.createId()));
}
if (unitTypeInstance.isHero()) {
final List<War3ID> heroAbilityList = unitTypeInstance.getHeroAbilityList();
unit.add(simulation, new CAbilityHero(handleIdAllocator.createId(), heroAbilityList));
// reset initial mana after the value is adjusted for hero data
unit.setMana(manaInitial);
}
for (final String ability : unitTypeInstance.getAbilityList().split(",")) {
if ((ability.length() > 0) && !"_".equals(ability)) {
final CAbility createAbility = this.abilityData.createAbility(ability, handleIdAllocator.createId());
@ -239,6 +270,8 @@ public class CUnitData {
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
final String abilityList = unitType.getFieldAsString(ABILITIES_NORMAL, 0);
final String heroAbilityListString = unitType.getFieldAsString(ABILITIES_HERO, 0);
final int unitLevel = unitType.getFieldAsInteger(UNIT_LEVEL, 0);
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
@ -246,6 +279,22 @@ public class CUnitData {
final float propWindow = unitType.getFieldAsFloat(PROPULSION_WINDOW, 0);
final float turnRate = unitType.getFieldAsFloat(TURN_RATE, 0);
final float strPlus = unitType.getFieldAsFloat(STR_PLUS, 0);
final float agiPlus = unitType.getFieldAsFloat(AGI_PLUS, 0);
final float intPlus = unitType.getFieldAsFloat(INT_PLUS, 0);
final int strength = unitType.getFieldAsInteger(STR, 0);
final int agility = unitType.getFieldAsInteger(AGI, 0);
final int intelligence = unitType.getFieldAsInteger(INT, 0);
if (typeId.toString().equals("Hjai")) {
System.out.println("bp");
}
final CPrimaryAttribute primaryAttribute = CPrimaryAttribute
.parsePrimaryAttribute(unitType.getFieldAsString(PRIMARY_ATTRIBUTE, 0));
final String properNames = unitType.getFieldAsString(PROPER_NAMES, 0);
final int properNamesCount = unitType.getFieldAsInteger(PROPER_NAMES_COUNT, 0);
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
if (movementType == null) {
@ -424,6 +473,14 @@ public class CUnitData {
}
}
final String[] heroAbilityListStringItems = heroAbilityListString.split(",");
final List<War3ID> heroAbilityList = new ArrayList<>();
for (final String heroAbilityItem : heroAbilityListStringItems) {
if (heroAbilityItem.length() == 4) {
heroAbilityList.add(War3ID.fromString(heroAbilityItem));
}
}
final String requirementsString = unitType.getFieldAsString(REQUIRES, 0);
final String requirementsLevelsString = unitType.getFieldAsString(REQUIRES_AMOUNT, 0);
final String[] requirementsStringItems = requirementsString.split(",");
@ -466,17 +523,38 @@ public class CUnitData {
final String raceString = unitType.getFieldAsString(UNIT_RACE, 0);
final CUnitRace unitRace = CUnitRace.parseRace(raceString);
final boolean hero = Character.isUpperCase(typeId.charAt(0));
final List<String> heroProperNames = Arrays.asList(properNames.split(","));
unitTypeInstance = new CUnitType(unitName, life, manaInitial, manaMaximum, speed, defense, abilityList,
isBldg, movementType, moveHeight, collisionSize, classifications, attacks, armorType, raise, decay,
defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs, acquisitionRange,
minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable, unitRace, goldCost,
lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes, propWindow,
turnRate, requirements);
turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus, intelligence, intPlus,
primaryAttribute, heroAbilityList, heroProperNames, properNamesCount);
this.unitIdToUnitType.put(typeId, unitTypeInstance);
}
return unitTypeInstance;
}
private static int[] populateHeroStatTable(final int maxHeroLevel, final float statPerLevel) {
final int[] table = new int[maxHeroLevel];
float sumBonusAtLevel = 0f;
for (int i = 0; i < table.length; i++) {
final float newSumBonusAtLevel = sumBonusAtLevel + statPerLevel;
if (i == 0) {
table[i] = (int) newSumBonusAtLevel;
}
else {
table[i] = (int) newSumBonusAtLevel - table[i - 1];
}
sumBonusAtLevel = newSumBonusAtLevel;
}
return table;
}
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,

View File

@ -41,6 +41,8 @@ public interface SimulationRenderController {
void spawnBuildingDeathEffect(CUnit cUnit);
void spawnGainLevelEffect(CUnit cUnit);
void spawnUnitReadySound(CUnit trainedUnit);
void unitRepositioned(CUnit cUnit);

View File

@ -176,6 +176,14 @@ public class CommandCardIcon extends AbstractRenderableFrame implements Clickabl
positionBounds(gameUI, uiViewport);
}
@Override
public void mouseEnter(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public void mouseExit(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {

View File

@ -21,7 +21,6 @@ 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.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.math.Rectangle;
@ -82,6 +81,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataU
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.IconUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons.CommandButtonListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CGameplayConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CItem;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CPlayerStateListener;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
@ -108,6 +108,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAb
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.combat.CAbilityColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericNoIconAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic.GenericSingleIconActiveAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbilityHero;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CPrimaryAttribute;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityRally;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
@ -154,7 +156,6 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private static final AbilityPointTarget clickLocationTemp2 = new AbilityPointTarget();
private final DataSource dataSource;
private final ExtendViewport uiViewport;
private final FreeTypeFontGenerator fontGenerator;
private final Scene uiScene;
private final Scene portraitScene;
private final GameCameraManager cameraManager;
@ -189,6 +190,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private StringFrame simpleClassValue;
private StringFrame simpleBuildingActionLabel;
private SimpleStatusBarFrame simpleBuildTimeIndicator;
private SimpleStatusBarFrame simpleHeroLevelBar;
private UIFrame simpleInfoPanelBuildingDetail;
private StringFrame simpleBuildingNameValue;
@ -213,6 +215,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private InfoPanelIconBackdrops damageBackdrops;
private InfoPanelIconBackdrops defenseBackdrops;
private UIFrame heroInfoPanel;
private final CommandCardIcon[][] commandCard = new CommandCardIcon[COMMAND_CARD_HEIGHT][COMMAND_CARD_WIDTH];
private RenderUnit selectedUnit;
@ -264,14 +268,18 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private BitmapFont textTagFont;
private SetPoint uberTipNoResourcesSetPoint;
private SetPoint uberTipWithResourcesSetPoint;
private TextureFrame primaryAttributeIcon;
private StringFrame strengthValue;
private StringFrame agilityValue;
private StringFrame intelligenceValue;
private SimpleFrame smashHeroInfoPanelWrapper;
public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport,
final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final Scene portraitScene,
final CameraPreset[] cameraPresets, final CameraRates cameraRates, final War3MapViewer war3MapViewer,
final RootFrameListener rootFrameListener, final CPlayerUnitOrderListener unitOrderListener) {
public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport, final Scene uiScene,
final Scene portraitScene, final CameraPreset[] cameraPresets, final CameraRates cameraRates,
final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener,
final CPlayerUnitOrderListener unitOrderListener) {
this.dataSource = dataSource;
this.uiViewport = uiViewport;
this.fontGenerator = fontGenerator;
this.uiScene = uiScene;
this.portraitScene = portraitScene;
this.war3MapViewer = war3MapViewer;
@ -333,41 +341,40 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
// Load skins and templates
// =================================
final CRace race = this.localPlayer.getRace();
final int racialSkinIndex;
final String racialSkinKey;
int racialCommandIndex;
if (race == null) {
racialSkinIndex = 1;
racialSkinKey = "Human";
racialCommandIndex = 0;
}
else {
switch (race) {
case HUMAN:
racialSkinIndex = 1;
racialSkinKey = "Human";
racialCommandIndex = 0;
break;
case ORC:
racialSkinIndex = 0;
racialSkinKey = "Orc";
racialCommandIndex = 1;
break;
case NIGHTELF:
racialSkinIndex = 2;
racialSkinKey = "NightElf";
racialCommandIndex = 3;
break;
case UNDEAD:
racialSkinIndex = 3;
racialSkinKey = "Undead";
racialCommandIndex = 2;
break;
case DEMON:
case OTHER:
default:
racialSkinIndex = -1;
racialSkinKey = "Human";
racialCommandIndex = 0;
break;
}
}
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, racialSkinIndex), this.uiViewport,
this.fontGenerator, this.uiScene, this.war3MapViewer, racialCommandIndex,
this.war3MapViewer.getAllObjectData().getWts());
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, racialSkinKey), this.uiViewport,
this.uiScene, this.war3MapViewer, racialCommandIndex, this.war3MapViewer.getAllObjectData().getWts());
this.rootFrameListener.onCreate(this.rootFrame);
try {
this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
@ -418,7 +425,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.unitManaText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitManaPointText", 0);
final float infoPanelUnitDetailWidth = GameUI.convertY(this.uiViewport, 0.180f);
final float infoPanelUnitDetailHeight = GameUI.convertY(this.uiViewport, 0.110f);
final float infoPanelUnitDetailHeight = GameUI.convertY(this.uiViewport, 0.112f);
this.smashSimpleInfoPanel = this.rootFrame.createSimpleFrame("SmashSimpleInfoPanel", this.rootFrame, 0);
this.smashSimpleInfoPanel
.addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f)));
@ -442,6 +449,14 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.simpleBuildTimeIndicator.setWidth(buildTimeIndicatorWidth);
this.simpleBuildTimeIndicator.setHeight(buildTimeIndicatorHeight);
this.simpleHeroLevelBar = (SimpleStatusBarFrame) this.rootFrame.getFrameByName("SimpleHeroLevelBar", 0);
final TextureFrame simpleHeroLevelBarBar = this.simpleHeroLevelBar.getBarFrame();
simpleHeroLevelBarBar.setTexture("SimpleXpBarConsole", this.rootFrame);
simpleHeroLevelBarBar.setColor(new Color(138f / 255f, 0, 131f / 255f, 1f));
final TextureFrame simpleHeroLevelBarBorder = this.simpleHeroLevelBar.getBorderFrame();
simpleHeroLevelBarBorder.setTexture("SimpleXpBarBorder", this.rootFrame);
this.simpleHeroLevelBar.setWidth(infoPanelUnitDetailWidth);
// Create Simple Info Panel Building Detail
this.simpleInfoPanelBuildingDetail = this.rootFrame.createSimpleFrame("SimpleInfoPanelBuildingDetail",
this.smashSimpleInfoPanel, 0);
@ -515,7 +530,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.smashAttack1IconWrapper = (SimpleFrame) this.rootFrame.createSimpleFrame("SmashSimpleInfoPanelIconDamage",
this.simpleInfoPanelUnitDetail, 0);
this.smashAttack1IconWrapper.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail,
FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.030125f)));
FramePoint.TOPLEFT, 0, GameUI.convertY(this.uiViewport, -0.032f)));
this.smashAttack1IconWrapper.setWidth(GameUI.convertX(this.uiViewport, 0.1f));
this.smashAttack1IconWrapper.setHeight(GameUI.convertY(this.uiViewport, 0.030125f));
this.attack1Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.smashAttack1IconWrapper,
@ -528,7 +543,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.simpleInfoPanelUnitDetail, 0);
this.smashAttack2IconWrapper
.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0.1f), GameUI.convertY(this.uiViewport, -0.030125f)));
GameUI.convertX(this.uiViewport, 0.1f), GameUI.convertY(this.uiViewport, -0.03125f)));
this.smashAttack2IconWrapper.setWidth(GameUI.convertX(this.uiViewport, 0.1f));
this.smashAttack2IconWrapper.setHeight(GameUI.convertY(this.uiViewport, 0.030125f));
this.attack2Icon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconDamage", this.smashAttack2IconWrapper,
@ -540,7 +555,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.smashArmorIconWrapper = (SimpleFrame) this.rootFrame.createSimpleFrame("SmashSimpleInfoPanelIconArmor",
this.simpleInfoPanelUnitDetail, 0);
this.smashArmorIconWrapper.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail,
FramePoint.TOPLEFT, GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f)));
FramePoint.TOPLEFT, GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.0625f)));
this.smashArmorIconWrapper.setWidth(GameUI.convertX(this.uiViewport, 0.1f));
this.smashArmorIconWrapper.setHeight(GameUI.convertY(this.uiViewport, 0.030125f));
this.armorIcon = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconArmor", this.smashArmorIconWrapper, 0);
@ -548,6 +563,19 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.armorInfoPanelIconValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconValue", 0);
this.armorInfoPanelIconLevel = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconLevel", 0);
this.smashHeroInfoPanelWrapper = (SimpleFrame) this.rootFrame.createSimpleFrame("SmashSimpleInfoPanelIconHero",
this.simpleInfoPanelUnitDetail, 0);
this.smashHeroInfoPanelWrapper.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail,
FramePoint.TOPLEFT, GameUI.convertX(this.uiViewport, 0.1f), GameUI.convertY(this.uiViewport, -0.029f)));
this.smashHeroInfoPanelWrapper.setWidth(GameUI.convertX(this.uiViewport, 0.1f));
this.smashHeroInfoPanelWrapper.setHeight(GameUI.convertY(this.uiViewport, 0.0625f));
this.heroInfoPanel = this.rootFrame.createSimpleFrame("SimpleInfoPanelIconHero", this.smashHeroInfoPanelWrapper,
0);
this.primaryAttributeIcon = (TextureFrame) this.rootFrame.getFrameByName("InfoPanelIconHeroIcon", 0);
this.strengthValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconHeroStrengthValue", 0);
this.agilityValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconHeroAgilityValue", 0);
this.intelligenceValue = (StringFrame) this.rootFrame.getFrameByName("InfoPanelIconHeroIntellectValue", 0);
this.inventoryCover = this.rootFrame.createSimpleFrame("SmashConsoleInventoryCover", this.rootFrame, 0);
final Element fontHeights = this.war3MapViewer.miscData.get("FontHeights");
@ -676,7 +704,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
final FreeTypeFontParameter fontParam = new FreeTypeFontParameter();
fontParam.size = (int) GameUI.convertY(this.uiViewport, 0.012f);
this.textTagFont = this.fontGenerator.generateFont(fontParam);
this.textTagFont = this.rootFrame.getFontGenerator().generateFont(fontParam);
this.rootFrame.positionBounds(this.rootFrame, this.uiViewport);
@ -876,10 +904,16 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
}
public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
this.rootFrame.render(batch, font20, glyphLayout);
public void render(final SpriteBatch batch, final GlyphLayout glyphLayout) {
final BitmapFont font = this.rootFrame.getFont();
font.setColor(Color.YELLOW);
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
glyphLayout.setText(font, fpsString);
font.draw(batch, fpsString, (this.uiViewport.getMinWorldWidth() - glyphLayout.width) / 2,
1100 * this.heightRatioCorrection);
this.rootFrame.render(batch, this.rootFrame.getFont20(), glyphLayout);
if (this.selectedUnit != null) {
font20.setColor(Color.WHITE);
this.rootFrame.getFont20().setColor(Color.WHITE);
}
@ -891,7 +925,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
if (this.war3MapViewer.worldScene.camera.rect.contains(screenCoordsVector.x,
(Gdx.graphics.getHeight() - screenCoordsVector.y) + textTag.getScreenCoordsZHeight())) {
final Vector2 unprojected = this.uiViewport.unproject(screenCoordsVector);
this.textTagFont.setColor(textTag.getColor());
final float remainingLife = textTag.getRemainingLife();
final float alpha = (remainingLife > 1.0f ? 1.0f : remainingLife);
this.textTagFont.setColor(textTag.getColor().r, textTag.getColor().g, textTag.getColor().b,
textTag.getColor().a * alpha);
glyphLayout.setText(this.textTagFont, textTag.getText());
this.textTagFont.draw(batch, textTag.getText(), unprojected.x - (glyphLayout.width / 2),
(unprojected.y - (glyphLayout.height / 2)) + textTag.getScreenCoordsZHeight());
@ -917,8 +954,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
public Void accept(final CAbilityAttack ability) {
if (MeleeUI.this.activeCommandOrderId == OrderIds.attackground) {
float radius = 0;
for (final CUnitAttack attack : MeleeUI.this.activeCommandUnit.getSimulationUnit().getUnitType()
.getAttacks()) {
for (final CUnitAttack attack : MeleeUI.this.activeCommandUnit.getSimulationUnit().getAttacks()) {
if (attack.getWeaponType().isAttackGroundSupported()) {
if (attack instanceof CUnitAttackMissileSplash) {
final int areaOfEffectSmallDamage = ((CUnitAttackMissileSplash) attack)
@ -1020,6 +1056,12 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
return null;
}
@Override
public Void accept(final CAbilityHero ability) {
handleTargetCursor(ability);
return null;
}
private void handleTargetCursor(final CAbility ability) {
if (MeleeUI.this.cursorModelInstance != null) {
MeleeUI.this.cursorModelInstance.detach();
@ -1333,6 +1375,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.armorIcon.setVisible(false);
this.rootFrame.setText(this.armorInfoPanelIconLevel, "");
this.simpleBuildTimeIndicator.setVisible(false);
this.simpleHeroLevelBar.setVisible(false);
this.simpleBuildingBuildTimeIndicator.setVisible(false);
this.simpleInfoPanelBuildingDetail.setVisible(false);
this.simpleInfoPanelUnitDetail.setVisible(false);
@ -1340,6 +1383,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
queueIconFrame.setVisible(false);
}
this.selectWorkerInsideFrame.setVisible(false);
this.heroInfoPanel.setVisible(false);
this.rallyPointInstance.hide();
this.rallyPointInstance.detach();
repositionWaypointFlags(null);
@ -1491,6 +1535,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.simpleBuildingBuildTimeIndicator.setVisible(true);
this.simpleBuildTimeIndicator.setVisible(false);
this.simpleHeroLevelBar.setVisible(false);
if (simulationUnit.getBuildQueueTypes()[0] == QueueItemType.UNIT) {
this.rootFrame.setText(this.simpleBuildingBuildingActionLabel,
this.rootFrame.getTemplates().getDecoratedString("TRAINING"));
@ -1502,6 +1547,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.attack1Icon.setVisible(false);
this.attack2Icon.setVisible(false);
this.armorIcon.setVisible(false);
this.heroInfoPanel.setVisible(false);
this.selectWorkerInsideFrame.setVisible(false);
}
else {
@ -1510,41 +1556,35 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
this.simpleInfoPanelBuildingDetail.setVisible(false);
this.simpleInfoPanelUnitDetail.setVisible(true);
this.rootFrame.setText(this.simpleNameValue, simulationUnit.getUnitType().getName());
String classText = null;
for (final CUnitClassification classification : simulationUnit.getClassifications()) {
if ((classification == CUnitClassification.MECHANICAL) && simulationUnit.getUnitType().isBuilding()) {
// buildings dont display MECHANICAL
continue;
}
if (classification.getDisplayName() != null) {
classText = classification.getDisplayName();
}
}
if (classText != null) {
this.rootFrame.setText(this.simpleClassValue, classText);
}
else {
this.rootFrame.setText(this.simpleClassValue, "");
}
final String unitTypeName = simulationUnit.getUnitType().getName();
final boolean anyAttacks = simulationUnit.getUnitType().getAttacks().size() > 0;
final boolean anyAttacks = simulationUnit.getAttacks().size() > 0;
final boolean constructing = simulationUnit.isConstructing();
final UIFrame localArmorIcon = this.armorIcon;
final TextureFrame localArmorIconBackdrop = this.armorIconBackdrop;
final StringFrame localArmorInfoPanelIconValue = this.armorInfoPanelIconValue;
if (anyAttacks && !constructing) {
final CUnitAttack attackOne = simulationUnit.getUnitType().getAttacks().get(0);
final CUnitAttack attackOne = simulationUnit.getAttacks().get(0);
this.attack1Icon.setVisible(attackOne.isShowUI());
this.attack1IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackOne.getAttackType()));
this.rootFrame.setText(this.attack1InfoPanelIconValue,
attackOne.getMinDamage() + " - " + attackOne.getMaxDamage());
if (simulationUnit.getUnitType().getAttacks().size() > 1) {
final CUnitAttack attackTwo = simulationUnit.getUnitType().getAttacks().get(1);
String attackOneDmgText = attackOne.getMinDamageDisplay() + " - " + attackOne.getMaxDamageDisplay();
final int attackOneTemporaryDamageBonus = attackOne.getTemporaryDamageBonus();
if (attackOneTemporaryDamageBonus != 0) {
attackOneDmgText += (attackOneTemporaryDamageBonus > 0 ? "|cFF00FF00 (+" : "|cFFFF0000 (+")
+ attackOneTemporaryDamageBonus + ")";
}
this.rootFrame.setText(this.attack1InfoPanelIconValue, attackOneDmgText);
if (simulationUnit.getAttacks().size() > 1) {
final CUnitAttack attackTwo = simulationUnit.getAttacks().get(1);
this.attack2Icon.setVisible(attackTwo.isShowUI());
this.attack2IconBackdrop.setTexture(this.damageBackdrops.getTexture(attackTwo.getAttackType()));
this.rootFrame.setText(this.attack2InfoPanelIconValue,
attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage());
String attackTwoDmgText = attackTwo.getMinDamage() + " - " + attackTwo.getMaxDamage();
final int attackTwoTemporaryDamageBonus = attackTwo.getTemporaryDamageBonus();
if (attackTwoTemporaryDamageBonus != 0) {
attackTwoDmgText += (attackTwoTemporaryDamageBonus > 0 ? "|cFF00FF00 (+" : "|cFFFF0000 (+")
+ attackTwoTemporaryDamageBonus + ")";
}
this.rootFrame.setText(this.attack2InfoPanelIconValue, attackTwoDmgText);
}
else {
this.attack2Icon.setVisible(false);
@ -1552,7 +1592,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.smashArmorIconWrapper.addSetPoint(
new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.06025f)));
GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.0625f)));
this.smashArmorIconWrapper.positionBounds(this.rootFrame, this.uiViewport);
this.armorIcon.positionBounds(this.rootFrame, this.uiViewport);
}
@ -1562,11 +1602,67 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.smashArmorIconWrapper.addSetPoint(
new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.030125f)));
GameUI.convertX(this.uiViewport, 0f), GameUI.convertY(this.uiViewport, -0.032f)));
this.smashArmorIconWrapper.positionBounds(this.rootFrame, this.uiViewport);
this.armorIcon.positionBounds(this.rootFrame, this.uiViewport);
}
final CAbilityHero heroData = simulationUnit.getHeroData();
final boolean hero = heroData != null;
this.heroInfoPanel.setVisible(hero);
if (hero) {
final CPrimaryAttribute primaryAttribute = simulationUnit.getUnitType().getPrimaryAttribute();
String iconKey;
switch (primaryAttribute) {
case AGILITY:
iconKey = "InfoPanelIconHeroIconAGI";
break;
case INTELLIGENCE:
iconKey = "InfoPanelIconHeroIconINT";
break;
default:
case STRENGTH:
iconKey = "InfoPanelIconHeroIconSTR";
break;
}
this.primaryAttributeIcon.setTexture(iconKey, this.rootFrame);
this.rootFrame.setText(this.strengthValue, heroData.getStrength().getDisplayText());
this.rootFrame.setText(this.agilityValue, heroData.getAgility().getDisplayText());
this.rootFrame.setText(this.intelligenceValue, heroData.getIntelligence().getDisplayText());
final String infopanelLevelClass = this.rootFrame.getTemplates()
.getDecoratedString("INFOPANEL_LEVEL_CLASS").replace("%u", "%d"); // :(
final int heroLevel = heroData.getHeroLevel();
this.rootFrame.setText(this.simpleClassValue,
String.format(infopanelLevelClass, heroLevel, unitTypeName));
this.rootFrame.setText(this.simpleNameValue, heroData.getProperName());
this.simpleHeroLevelBar.setVisible(true);
final CGameplayConstants gameplayConstants = this.war3MapViewer.simulation.getGameplayConstants();
this.simpleHeroLevelBar.setValue((heroData.getXp() - gameplayConstants.getNeedHeroXPSum(heroLevel - 1))
/ (float) gameplayConstants.getNeedHeroXP(heroLevel));
}
else {
this.rootFrame.setText(this.simpleNameValue, unitTypeName);
String classText = null;
for (final CUnitClassification classification : simulationUnit.getClassifications()) {
if ((classification == CUnitClassification.MECHANICAL)
&& simulationUnit.getUnitType().isBuilding()) {
// buildings dont display MECHANICAL
continue;
}
if (classification.getDisplayName() != null) {
classText = classification.getDisplayName();
}
}
if (classText != null) {
this.rootFrame.setText(this.simpleClassValue, classText);
}
else {
this.rootFrame.setText(this.simpleClassValue, "");
}
this.simpleHeroLevelBar.setVisible(false);
}
localArmorIcon.setVisible(!constructing);
this.simpleBuildTimeIndicator.setVisible(constructing);
this.simpleBuildingBuildTimeIndicator.setVisible(false);
@ -1574,13 +1670,13 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.rootFrame.setText(this.simpleBuildingActionLabel,
this.rootFrame.getTemplates().getDecoratedString("CONSTRUCTING"));
this.queueIconFrames[0].setVisible(true);
this.queueIconFrames[0].setTexture(this.war3MapViewer.getAbilityDataUI()
.getUnitUI(this.selectedUnit.getSimulationUnit().getTypeId()).getIcon());
this.queueIconFrames[0].setTexture(
this.war3MapViewer.getAbilityDataUI().getUnitUI(simulationUnit.getTypeId()).getIcon());
if (this.selectedUnit.getSimulationUnit().getWorkerInside() != null) {
if (simulationUnit.getWorkerInside() != null) {
this.selectWorkerInsideFrame.setVisible(true);
this.selectWorkerInsideFrame.setTexture(this.war3MapViewer.getAbilityDataUI()
.getUnitUI(this.selectedUnit.getSimulationUnit().getWorkerInside().getTypeId()).getIcon());
.getUnitUI(simulationUnit.getWorkerInside().getTypeId()).getIcon());
}
else {
this.selectWorkerInsideFrame.setVisible(false);
@ -1596,7 +1692,18 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
throw new RuntimeException(simulationUnit.getUnitType().getDefenseType() + " can't find texture!");
}
localArmorIconBackdrop.setTexture(defenseTexture);
this.rootFrame.setText(localArmorInfoPanelIconValue, Integer.toString(simulationUnit.getDefense()));
String defenseDisplayString = Integer.toString(simulationUnit.getCurrentDefenseDisplay());
final int temporaryDefenseBonus = simulationUnit.getTemporaryDefenseBonus();
if (temporaryDefenseBonus != 0) {
if (temporaryDefenseBonus > 0) {
defenseDisplayString += "|cFF00FF00 (+" + temporaryDefenseBonus + ")";
}
else {
defenseDisplayString += "|cFFFF0000 (+" + temporaryDefenseBonus + ")";
}
}
this.rootFrame.setText(localArmorInfoPanelIconValue, defenseDisplayString);
}
clearAndRepopulateCommandCard();
}
@ -1753,6 +1860,11 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
}
@Override
public void heroStatsChanged() {
reloadSelectedUnitUI(this.selectedUnit);
}
@Override
public void queueChanged() {
reloadSelectedUnitUI(this.selectedUnit);
@ -2191,4 +2303,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.unitOrderListener.unitCancelTrainingItem(simulationUnit.getHandleId(), index);
}
}
public void dispose() {
if (this.rootFrame != null) {
this.rootFrame.dispose();
}
}
}

View File

@ -1,23 +1,37 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui;
import java.io.IOException;
import java.io.InputStream;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.etheller.warsmash.WarsmashGdxMapScreen;
import com.etheller.warsmash.WarsmashGdxMenuScreen;
import com.etheller.warsmash.WarsmashGdxMultiScreenGame;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.GlueButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.GlueTextButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.custom.WTS;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.util.WorldEditStrings;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSound;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.ClickableFrame;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.sound.KeyedSounds;
public class MenuUI {
private static final Vector2 screenCoordsVector = new Vector2();
@ -25,7 +39,6 @@ public class MenuUI {
private final DataSource dataSource;
private final Scene uiScene;
private final ExtendViewport uiViewport;
private final FreeTypeFontGenerator fontGenerator;
private final MdxViewer viewer;
private final RootFrameListener rootFrameListener;
private final float widthRatioCorrection;
@ -33,20 +46,61 @@ public class MenuUI {
private GameUI rootFrame;
private SpriteFrame cursorFrame;
private ClickableFrame mouseDownUIFrame;
private ClickableFrame mouseOverUIFrame;
private UIFrame mainMenuFrame;
private SpriteFrame glueSpriteLayerTopRight;
private SpriteFrame glueSpriteLayerTopLeft;
public MenuUI(final DataSource dataSource, final ExtendViewport uiViewport,
final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final MdxViewer viewer,
private WorldEditStrings worldEditStrings;
private DataTable uiSoundsTable;
private KeyedSounds uiSounds;
private GlueTextButtonFrame singlePlayerButton;
private GlueTextButtonFrame battleNetButton;
private GlueTextButtonFrame localAreaNetworkButton;
private GlueTextButtonFrame optionsButton;
private GlueTextButtonFrame creditsButton;
private GlueButtonFrame realmButton;
private GlueTextButtonFrame exitButton;
private final boolean quitting = false;
private MenuState menuState;
private UIFrame singlePlayerMenu;
private UIFrame profilePanel;
private GlueButtonFrame profileButton;
private GlueTextButtonFrame campaignButton;
private GlueTextButtonFrame loadSavedButton;
private GlueTextButtonFrame viewReplayButton;
private GlueTextButtonFrame customCampaignButton;
private GlueTextButtonFrame skirmishButton;
private GlueTextButtonFrame cancelButton;
private GlueButtonFrame editionButton;
private final WarsmashGdxMultiScreenGame screenManager;
private final DataTable warsmashIni;
private UnitSound glueScreenLoop;
public MenuUI(final DataSource dataSource, final ExtendViewport uiViewport, final Scene uiScene,
final MdxViewer viewer, final WarsmashGdxMultiScreenGame screenManager, final DataTable warsmashIni,
final RootFrameListener rootFrameListener) {
this.dataSource = dataSource;
this.uiViewport = uiViewport;
this.fontGenerator = fontGenerator;
this.uiScene = uiScene;
this.viewer = viewer;
this.screenManager = screenManager;
this.warsmashIni = warsmashIni;
this.rootFrameListener = rootFrameListener;
this.widthRatioCorrection = this.uiViewport.getMinWorldWidth() / 1600f;
@ -65,8 +119,9 @@ public class MenuUI {
// =================================
// Load skins and templates
// =================================
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, 1), this.uiViewport,
this.fontGenerator, this.uiScene, this.viewer, 0, WTS.DO_NOTHING);
this.rootFrame = new GameUI(this.dataSource, GameUI.loadSkin(this.dataSource, WarsmashConstants.GAME_VERSION),
this.uiViewport, this.uiScene, this.viewer, 0, WTS.DO_NOTHING);
this.rootFrameListener.onCreate(this.rootFrame);
try {
this.rootFrame.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
@ -80,23 +135,31 @@ public class MenuUI {
catch (final IOException exc) {
throw new IllegalStateException("Unable to load SmashFrameDef.toc", exc);
}
// Create main menu
this.mainMenuFrame = this.rootFrame.createFrame("MainMenuFrame", this.rootFrame, 0, 0);
this.mainMenuFrame.setVisible(false);
final SpriteFrame warcraftIIILogo = (SpriteFrame) this.rootFrame.getFrameByName("WarCraftIIILogo", 0);
this.rootFrame.setSpriteFrameModel(warcraftIIILogo, this.rootFrame.getSkinField("MainMenuLogo_V1"));
this.rootFrame.setSpriteFrameModel(warcraftIIILogo,
this.rootFrame.getSkinField("MainMenuLogo_V" + WarsmashConstants.GAME_VERSION));
warcraftIIILogo.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.mainMenuFrame, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0.13f), GameUI.convertY(this.uiViewport, -0.08f)));
this.rootFrame.getFrameByName("RealmSelect", 0).setVisible(false);
this.glueSpriteLayerTopRight = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
"SmashGlueSpriteLayerTopRight", this.rootFrame, "", 0);
this.glueSpriteLayerTopRight.setSetAllPoints(true);
final String topRightModel = this.rootFrame.getSkinField("GlueSpriteLayerTopRight_V1");
final String topRightModel = this.rootFrame
.getSkinField("GlueSpriteLayerTopRight_V" + WarsmashConstants.GAME_VERSION);
this.rootFrame.setSpriteFrameModel(this.glueSpriteLayerTopRight, topRightModel);
this.glueSpriteLayerTopRight.setSequence("MainMenu Birth");
this.glueSpriteLayerTopLeft = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
"SmashGlueSpriteLayerTopLeft", this.rootFrame, "", 0);
this.glueSpriteLayerTopLeft.setSetAllPoints(true);
final String topLeftModel = this.rootFrame.getSkinField("GlueSpriteLayerTopLeft_V1");
final String topLeftModel = this.rootFrame
.getSkinField("GlueSpriteLayerTopLeft_V" + WarsmashConstants.GAME_VERSION);
this.rootFrame.setSpriteFrameModel(this.glueSpriteLayerTopLeft, topLeftModel);
this.glueSpriteLayerTopLeft.setSequence("MainMenu Birth");
@ -107,15 +170,126 @@ public class MenuUI {
this.cursorFrame.setZDepth(-1.0f);
Gdx.input.setCursorCatched(true);
// Create single player
this.singlePlayerMenu = this.rootFrame.createFrame("SinglePlayerMenu", this.rootFrame, 0, 0);
this.singlePlayerMenu.setVisible(false);
this.profilePanel = this.rootFrame.getFrameByName("ProfilePanel", 0);
this.profilePanel.setVisible(false);
// position all
this.rootFrame.positionBounds(this.rootFrame, this.uiViewport);
// Main Menu
this.singlePlayerButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("SinglePlayerButton", 0);
this.battleNetButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("BattleNetButton", 0);
this.realmButton = (GlueButtonFrame) this.rootFrame.getFrameByName("RealmButton", 0);
this.localAreaNetworkButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("LocalAreaNetworkButton", 0);
this.optionsButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("OptionsButton", 0);
this.creditsButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CreditsButton", 0);
this.exitButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("ExitButton", 0);
this.editionButton = (GlueButtonFrame) this.rootFrame.getFrameByName("EditionButton", 0);
if (this.editionButton != null) {
this.editionButton.setOnClick(new Runnable() {
@Override
public void run() {
WarsmashConstants.GAME_VERSION = (WarsmashConstants.GAME_VERSION == 1 ? 0 : 1);
MenuUI.this.glueSpriteLayerTopLeft.setSequence("MainMenu Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("MainMenu Death");
MenuUI.this.mainMenuFrame.setVisible(false);
MenuUI.this.menuState = MenuState.RESTARTING;
}
});
}
this.battleNetButton.setEnabled(false);
this.realmButton.setEnabled(false);
this.localAreaNetworkButton.setEnabled(false);
this.optionsButton.setEnabled(false);
this.creditsButton.setEnabled(false);
this.exitButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("MainMenu Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("MainMenu Death");
MenuUI.this.mainMenuFrame.setVisible(false);
MenuUI.this.menuState = MenuState.QUITTING;
}
});
this.singlePlayerButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("MainMenu Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("MainMenu Death");
MenuUI.this.mainMenuFrame.setVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_SINGLE_PLAYER;
}
});
// Single Player
this.profileButton = (GlueButtonFrame) this.rootFrame.getFrameByName("ProfileButton", 0);
this.campaignButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CampaignButton", 0);
this.loadSavedButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("LoadSavedButton", 0);
this.viewReplayButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("ViewReplayButton", 0);
this.customCampaignButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CustomCampaignButton", 0);
this.skirmishButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("SkirmishButton", 0);
this.cancelButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CancelButton", 0);
final StringFrame profileNameText = (StringFrame) this.rootFrame.getFrameByName("ProfileNameText", 0);
this.rootFrame.setText(profileNameText, "WorldEdit");
this.profileButton.setEnabled(false);
this.loadSavedButton.setEnabled(false);
this.viewReplayButton.setEnabled(false);
this.customCampaignButton.setEnabled(false);
this.skirmishButton.setEnabled(false);
this.campaignButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("SinglePlayer Death");
MenuUI.this.singlePlayerMenu.setVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_CAMPAIGN;
}
});
this.cancelButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("SinglePlayer Death");
MenuUI.this.singlePlayerMenu.setVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_MAIN_MENU;
}
});
this.menuState = MenuState.MAIN_MENU;
loadSounds();
final String glueLoopField = this.rootFrame.getSkinField("GlueScreenLoop_V" + WarsmashConstants.GAME_VERSION);
this.glueScreenLoop = this.uiSounds.getSound(glueLoopField);
this.glueScreenLoop.play(this.uiScene.audioContext, 0f, 0f, 0f);
}
public void resize() {
}
public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
public void render(final SpriteBatch batch, final GlyphLayout glyphLayout) {
final BitmapFont font = this.rootFrame.getFont();
final BitmapFont font20 = this.rootFrame.getFont20();
font.setColor(Color.YELLOW);
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
glyphLayout.setText(font, fpsString);
font.draw(batch, fpsString, (this.uiViewport.getMinWorldWidth() - glyphLayout.width) / 2,
1100 * this.heightRatioCorrection);
this.rootFrame.render(batch, font20, glyphLayout);
}
@ -143,7 +317,140 @@ public class MenuUI {
this.cursorFrame.setSequence("Normal");
if (this.glueSpriteLayerTopRight.isSequenceEnded()) {
this.glueSpriteLayerTopRight.setSequence("MainMenu Stand");
switch (this.menuState) {
case GOING_TO_MAIN_MENU:
this.glueSpriteLayerTopLeft.setSequence("MainMenu Birth");
this.glueSpriteLayerTopRight.setSequence("MainMenu Birth");
this.menuState = MenuState.MAIN_MENU;
break;
case MAIN_MENU:
this.mainMenuFrame.setVisible(true);
this.glueSpriteLayerTopLeft.setSequence("MainMenu Stand");
this.glueSpriteLayerTopRight.setSequence("MainMenu Stand");
break;
case GOING_TO_SINGLE_PLAYER:
this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Birth");
this.glueSpriteLayerTopRight.setSequence("SinglePlayer Birth");
this.menuState = MenuState.SINGLE_PLAYER;
break;
case SINGLE_PLAYER:
this.singlePlayerMenu.setVisible(true);
this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Stand");
this.glueSpriteLayerTopRight.setSequence("SinglePlayer Stand");
break;
case GOING_TO_CAMPAIGN:
MenuUI.this.screenManager.setScreen(new WarsmashGdxMapScreen(MenuUI.this.warsmashIni,
this.warsmashIni.get("Map").getField("FilePath")));
break;
case QUITTING:
Gdx.app.exit();
break;
case RESTARTING:
MenuUI.this.screenManager
.setScreen(new WarsmashGdxMenuScreen(MenuUI.this.warsmashIni, this.screenManager));
break;
default:
break;
}
}
}
public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
final UIFrame clickedUIFrame = this.rootFrame.touchDown(screenCoordsVector.x, screenCoordsVector.y, button);
if (clickedUIFrame != null) {
if (clickedUIFrame instanceof ClickableFrame) {
this.mouseDownUIFrame = (ClickableFrame) clickedUIFrame;
this.mouseDownUIFrame.mouseDown(this.rootFrame, this.uiViewport);
}
}
return false;
}
public boolean touchUp(final int screenX, final int screenY, final float worldScreenY, final int button) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
final UIFrame clickedUIFrame = this.rootFrame.touchUp(screenCoordsVector.x, screenCoordsVector.y, button);
if (this.mouseDownUIFrame != null) {
if (clickedUIFrame == this.mouseDownUIFrame) {
this.mouseDownUIFrame.onClick(button);
this.uiSounds.getSound("GlueScreenClick").play(this.uiScene.audioContext, 0, 0, 0);
}
this.mouseDownUIFrame.mouseUp(this.rootFrame, this.uiViewport);
}
this.mouseDownUIFrame = null;
return false;
}
public boolean touchDragged(final int screenX, final int screenY, final float worldScreenY, final int pointer) {
mouseMoved(screenX, screenY, worldScreenY);
return false;
}
public boolean mouseMoved(final int screenX, final int screenY, final float worldScreenY) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
final UIFrame mousedUIFrame = this.rootFrame.getFrameChildUnderMouse(screenCoordsVector.x,
screenCoordsVector.y);
if (mousedUIFrame != this.mouseOverUIFrame) {
if (this.mouseOverUIFrame != null) {
this.mouseOverUIFrame.mouseExit(this.rootFrame, this.uiViewport);
}
if (mousedUIFrame instanceof ClickableFrame) {
this.mouseOverUIFrame = (ClickableFrame) mousedUIFrame;
if (this.mouseOverUIFrame != null) {
this.mouseOverUIFrame.mouseEnter(this.rootFrame, this.uiViewport);
}
}
else {
this.mouseOverUIFrame = null;
}
}
return false;
}
private void loadSounds() {
this.worldEditStrings = new WorldEditStrings(this.dataSource);
this.uiSoundsTable = new DataTable(this.worldEditStrings);
try {
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("UI\\SoundInfo\\UISounds.slk")) {
this.uiSoundsTable.readSLK(miscDataTxtStream);
}
try (InputStream miscDataTxtStream = this.dataSource
.getResourceAsStream("UI\\SoundInfo\\AmbienceSounds.slk")) {
this.uiSoundsTable.readSLK(miscDataTxtStream);
}
}
catch (final IOException e) {
e.printStackTrace();
}
this.uiSounds = new KeyedSounds(this.uiSoundsTable, this.dataSource);
}
public KeyedSounds getUiSounds() {
return this.uiSounds;
}
private static enum MenuState {
GOING_TO_MAIN_MENU,
MAIN_MENU,
GOING_TO_SINGLE_PLAYER,
SINGLE_PLAYER,
GOING_TO_CAMPAIGN,
CAMPAIGN,
QUITTING,
RESTARTING;
}
public void hide() {
this.glueScreenLoop.stop();
}
public void dispose() {
if (this.rootFrame != null) {
this.rootFrame.dispose();
}
}
}

View File

@ -97,6 +97,14 @@ public class QueueIcon extends AbstractRenderableFrame implements ClickableActio
positionBounds(gameUI, uiViewport);
}
@Override
public void mouseEnter(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public void mouseExit(final GameUI gameUI, final Viewport uiViewport) {
}
@Override
public UIFrame getFrameChildUnderMouse(final float screenX, final float screenY) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {

View File

@ -2,13 +2,15 @@ package com.etheller.warsmash.viewer5.handlers.w3x.ui.command;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
public interface ClickableActionFrame extends UIFrame {
public interface ClickableActionFrame extends ClickableFrame {
@Override
void mouseDown(final GameUI gameUI, final Viewport uiViewport);
@Override
void mouseUp(final GameUI gameUI, final Viewport uiViewport);
@Override
void onClick(int button);
String getToolTip();

View File

@ -0,0 +1,17 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui.command;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
public interface ClickableFrame extends UIFrame {
void mouseDown(final GameUI gameUI, final Viewport uiViewport);
void mouseUp(final GameUI gameUI, final Viewport uiViewport);
void mouseEnter(final GameUI gameUI, final Viewport uiViewport);
void mouseExit(final GameUI gameUI, final Viewport uiViewport);
void onClick(int button);
}

View File

@ -8,10 +8,10 @@ import com.hiveworkshop.rms.util.BinaryWriter;
public class MdlxTexture implements MdlxBlock {
public enum WrapMode {
REPEAT_BOTH(true, true),
REPEAT_BOTH(false, false),
WRAP_WIDTH(true, false),
WRAP_HEIGHT(false, true),
WRAP_BOTH(false, false);
WRAP_BOTH(true, true);
private final boolean wrapWidth;
private final boolean wrapHeight;

View File

@ -134,7 +134,13 @@ public class Flac {
}
// Start writing WAV output file
final int bytesPerSample = streamInfo.sampleDepth / 8;
int bytesPerSample = streamInfo.sampleDepth / 8;
final boolean needsDownscaleForLibgdx = bytesPerSample >= 3;
int downsampleBytes = 0;
if (needsDownscaleForLibgdx) {
downsampleBytes = bytesPerSample - 2;
bytesPerSample = 2;
}
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(baos))) {
// Header chunk
@ -151,14 +157,17 @@ public class Flac {
writeLittleInt32(out, streamInfo.sampleRate);
writeLittleInt32(out, streamInfo.sampleRate * streamInfo.numChannels * bytesPerSample);
writeLittleInt16(out, streamInfo.numChannels * bytesPerSample);
writeLittleInt16(out, streamInfo.sampleDepth);
writeLittleInt16(out, needsDownscaleForLibgdx ? 16 : streamInfo.sampleDepth);
// Audio data chunk ("data")
out.writeInt(0x64617461); // "data"
writeLittleInt32(out, sampleDataLen);
for (int i = 0; i < samples[0].length; i++) {
for (int j = 0; j < samples.length; j++) {
final int val = samples[j][i];
int val = samples[j][i];
for (int k = 0; k < downsampleBytes; k++) {
val = val >>> 8;
}
if (bytesPerSample == 1) {
out.write(val + 128); // Convert to unsigned, as per WAV PCM conventions
}

View File

@ -226,8 +226,8 @@ public class OpenALSound implements Sound {
}
public long play(final float volume, final float pitch, final float x, final float y, final float z,
final boolean is3DSound, final float maxDistance, final float refDistance) {
final long id = play();
final boolean is3DSound, final float maxDistance, final float refDistance, final boolean looping) {
final long id = looping ? loop() : play();
setPitch(id, pitch);
setVolume(id, volume);
setPosition(id, x, y, z, is3DSound, maxDistance, refDistance);

View File

@ -15,12 +15,15 @@ import org.lwjgl.opengl.GL31;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL33;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics.DisplayMode;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.backends.lwjgl.LwjglNativesLoader;
import com.etheller.warsmash.WarsmashGdxMapGame;
import com.etheller.warsmash.WarsmashGdxMapScreen;
import com.etheller.warsmash.WarsmashGdxMenuScreen;
import com.etheller.warsmash.WarsmashGdxMultiScreenGame;
import com.etheller.warsmash.audio.OpenALSound;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.util.StringBundle;
@ -40,21 +43,40 @@ public class DesktopLauncher {
config.gles30ContextMajorVersion = 3;
config.gles30ContextMinorVersion = 3;
// config.samples = 16;
// config.vSyncEnabled = false;
// config.foregroundFPS = 0;
// config.backgroundFPS = 0;
config.vSyncEnabled = false;
config.foregroundFPS = 0;
config.backgroundFPS = 0;
final DisplayMode desktopDisplayMode = LwjglApplicationConfiguration.getDesktopDisplayMode();
config.width = desktopDisplayMode.width;
config.height = desktopDisplayMode.height;
if ((arg.length > 0) && "-windowed".equals(arg[0])) {
config.fullscreen = false;
}
else {
config.fullscreen = true;
String fileToLoad = null;
config.fullscreen = true;
for (int argIndex = 0; argIndex < arg.length; argIndex++) {
if ("-windowed".equals(arg[argIndex])) {
config.fullscreen = false;
}
else if ((arg.length > (argIndex + 1)) && "-loadfile".equals(arg[argIndex])) {
argIndex++;
fileToLoad = arg[argIndex];
}
}
loadExtensions();
final DataTable warsmashIni = loadWarsmashIni();
new LwjglApplication(new WarsmashGdxMapGame(warsmashIni), config);
final WarsmashGdxMultiScreenGame warsmashGdxMultiScreenGame = new WarsmashGdxMultiScreenGame();
new LwjglApplication(warsmashGdxMultiScreenGame, config);
final String finalFileToLoad = fileToLoad;
Gdx.app.postRunnable(new Runnable() {
@Override
public void run() {
if (finalFileToLoad != null) {
warsmashGdxMultiScreenGame.setScreen(new WarsmashGdxMapScreen(warsmashIni, finalFileToLoad));
}
else {
warsmashGdxMultiScreenGame
.setScreen(new WarsmashGdxMenuScreen(warsmashIni, warsmashGdxMultiScreenGame));
}
}
});
}
public static DataTable loadWarsmashIni() {
@ -123,8 +145,9 @@ public class DesktopLauncher {
@Override
public void play(final Sound buffer, final float volume, final float pitch, final float x, final float y,
final float z, final boolean is3dSound, final float maxDistance, final float refDistance) {
((OpenALSound) buffer).play(volume, pitch, x, y, z, is3dSound, maxDistance, refDistance);
final float z, final boolean is3dSound, final float maxDistance, final float refDistance,
final boolean looping) {
((OpenALSound) buffer).play(volume, pitch, x, y, z, is3dSound, maxDistance, refDistance, looping);
}
@Override

View File

@ -6,7 +6,7 @@ import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
import com.etheller.warsmash.WarsmashGdxMapGame;
import com.etheller.warsmash.WarsmashGdxMapScreen;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.desktop.DesktopLauncher;
import com.etheller.warsmash.parsers.w3x.War3Map;
@ -16,7 +16,7 @@ import com.etheller.warsmash.units.DataTable;
public class TerrainView {
public static void main(final String[] args) {
final DataTable warsmashIni = DesktopLauncher.loadWarsmashIni();
final DataSource dataSources = WarsmashGdxMapGame.parseDataSources(warsmashIni);
final DataSource dataSources = WarsmashGdxMapScreen.parseDataSources(warsmashIni);
final War3Map war3Map = new War3Map(dataSources, warsmashIni.get("Map").getField("FilePath"));
try {
final War3MapW3e environmentFile = war3Map.readEnvironment();

View File

@ -135,16 +135,19 @@ public class FrameDefinitionFieldVisitor extends FDFBaseVisitor<Void> {
@Override
public Void visitFontElement(final FontElementContext ctx) {
this.frameDefinition.set(ctx.ID().getText(),
new FontFrameDefinitionField(new FontDefinition(ctx.STRING_LITERAL(0).getText(),
Float.parseFloat(ctx.FLOAT().getText()), ctx.STRING_LITERAL(1).getText())));
String text = ctx.STRING_LITERAL(0).getText();
text = text.substring(1, text.length() - 1);
this.frameDefinition.set(ctx.ID().getText(), new FontFrameDefinitionField(
new FontDefinition(text, Float.parseFloat(ctx.FLOAT().getText()), ctx.STRING_LITERAL(1).getText())));
return null;
}
@Override
public Void visitSimpleFontElement(final SimpleFontElementContext ctx) {
this.frameDefinition.set(ctx.ID().getText(), new FontFrameDefinitionField(
new FontDefinition(ctx.STRING_LITERAL().getText(), Float.parseFloat(ctx.FLOAT().getText()), null)));
String text = ctx.STRING_LITERAL().getText();
text = text.substring(1, text.length() - 1);
this.frameDefinition.set(ctx.ID().getText(),
new FontFrameDefinitionField(new FontDefinition(text, Float.parseFloat(ctx.FLOAT().getText()), null)));
return null;
}

View File

@ -1,7 +1,19 @@
package com.etheller.warsmash.parsers.fdf.datamodel;
import java.util.EnumSet;
public enum ControlStyle {
AUTOTRACK,
HIGHLIGHTONFOCUS,
HIGHLIGHTONMOUSEOVER;
public static EnumSet<ControlStyle> parseControlStyle(final String controlStyles) {
final EnumSet<ControlStyle> set = EnumSet.noneOf(ControlStyle.class);
for (final String flag : controlStyles.split("\\|")) {
if (!"".equals(flag)) {
set.add(ControlStyle.valueOf(flag));
}
}
return set;
}
}

View File

@ -1,447 +0,0 @@
// --- 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",
}
}