mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Bunch of updates to Jass VM, added a bunch more natives and features to support them
This commit is contained in:
parent
a26a2cc248
commit
fdc78a105e
@ -1,5 +1,5 @@
|
|||||||
[DataSources]
|
[DataSources]
|
||||||
Count=9
|
Count=8
|
||||||
Type00=MPQ
|
Type00=MPQ
|
||||||
Path00="D:\Games\Warcraft III Patch 1.22\war3.mpq"
|
Path00="D:\Games\Warcraft III Patch 1.22\war3.mpq"
|
||||||
Type01=MPQ
|
Type01=MPQ
|
||||||
@ -8,13 +8,11 @@ Type02=MPQ
|
|||||||
Path02="D:\Games\Warcraft III Patch 1.22\War3xlocal.mpq"
|
Path02="D:\Games\Warcraft III Patch 1.22\War3xlocal.mpq"
|
||||||
Type03=MPQ
|
Type03=MPQ
|
||||||
Path03="D:\Games\Warcraft III Patch 1.22\War3Patch.mpq"
|
Path03="D:\Games\Warcraft III Patch 1.22\War3Patch.mpq"
|
||||||
Type04=MPQ
|
Type04=Folder
|
||||||
Path04="D:\Games\Warcraft III Patch 1.22\Warsmash\War3Mod.mpq"
|
Path04="..\..\resources"
|
||||||
Type05=Folder
|
Type05=Folder
|
||||||
Path05="..\..\resources"
|
Path05="D:\Backups\Warsmash\Data"
|
||||||
Type06=Folder
|
Type06=Folder
|
||||||
Path06="D:\Backups\Warsmash\Data"
|
Path06="D:\Games\Warcraft III Patch 1.22\Maps"
|
||||||
Type07=Folder
|
Type07=Folder
|
||||||
Path07="D:\Games\Warcraft III Patch 1.22\Maps"
|
Path07="."
|
||||||
Type08=Folder
|
|
||||||
Path08="."
|
|
||||||
|
@ -30,12 +30,12 @@ import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
|||||||
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
||||||
import com.etheller.warsmash.datasources.MpqDataSourceDescriptor;
|
import com.etheller.warsmash.datasources.MpqDataSourceDescriptor;
|
||||||
import com.etheller.warsmash.parsers.fdf.GameUI;
|
import com.etheller.warsmash.parsers.fdf.GameUI;
|
||||||
|
import com.etheller.warsmash.parsers.jass.Jass2;
|
||||||
|
import com.etheller.warsmash.parsers.jass.Jass2.CommonEnvironment;
|
||||||
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
|
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
|
||||||
import com.etheller.warsmash.units.DataTable;
|
import com.etheller.warsmash.units.DataTable;
|
||||||
import com.etheller.warsmash.units.Element;
|
import com.etheller.warsmash.units.Element;
|
||||||
import com.etheller.warsmash.util.DataSourceFileHandle;
|
|
||||||
import com.etheller.warsmash.util.ImageUtils;
|
import com.etheller.warsmash.util.ImageUtils;
|
||||||
import com.etheller.warsmash.util.WarsmashConstants;
|
|
||||||
import com.etheller.warsmash.viewer5.Model;
|
import com.etheller.warsmash.viewer5.Model;
|
||||||
import com.etheller.warsmash.viewer5.ModelInstance;
|
import com.etheller.warsmash.viewer5.ModelInstance;
|
||||||
import com.etheller.warsmash.viewer5.ModelViewer;
|
import com.etheller.warsmash.viewer5.ModelViewer;
|
||||||
@ -53,7 +53,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
|
|||||||
|
|
||||||
public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
||||||
public static final boolean ENABLE_AUDIO = true;
|
public static final boolean ENABLE_AUDIO = true;
|
||||||
private static final boolean ENABLE_MUSIC = true;
|
|
||||||
private final War3MapViewer viewer;
|
private final War3MapViewer viewer;
|
||||||
private final Rectangle tempRect = new Rectangle();
|
private final Rectangle tempRect = new Rectangle();
|
||||||
|
|
||||||
@ -76,6 +75,7 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
|||||||
private final WarsmashGdxMultiScreenGame screenManager;
|
private final WarsmashGdxMultiScreenGame screenManager;
|
||||||
private final WarsmashGdxMenuScreen menuScreen;
|
private final WarsmashGdxMenuScreen menuScreen;
|
||||||
private final CPlayerUnitOrderListener uiOrderListener;
|
private final CPlayerUnitOrderListener uiOrderListener;
|
||||||
|
private CommonEnvironment commonEnv;
|
||||||
|
|
||||||
public WarsmashGdxMapScreen(final War3MapViewer mapViewer, final WarsmashGdxMultiScreenGame screenManager,
|
public WarsmashGdxMapScreen(final War3MapViewer mapViewer, final WarsmashGdxMultiScreenGame screenManager,
|
||||||
final WarsmashGdxMenuScreen menuScreen, final CPlayerUnitOrderListener uiOrderListener) {
|
final WarsmashGdxMenuScreen menuScreen, final CPlayerUnitOrderListener uiOrderListener) {
|
||||||
@ -150,7 +150,8 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
|||||||
if (width < ((height * 4) / 3)) {
|
if (width < ((height * 4) / 3)) {
|
||||||
aspect3By4Width = width;
|
aspect3By4Width = width;
|
||||||
aspect3By4Height = (width * 3) / 4;
|
aspect3By4Height = (width * 3) / 4;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
aspect3By4Width = (height * 4) / 3;
|
aspect3By4Width = (height * 4) / 3;
|
||||||
aspect3By4Height = height;
|
aspect3By4Height = height;
|
||||||
}
|
}
|
||||||
@ -171,13 +172,6 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
|||||||
|
|
||||||
this.shapeRenderer = new ShapeRenderer();
|
this.shapeRenderer = new ShapeRenderer();
|
||||||
|
|
||||||
// Jass2.loadJUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, this.viewer,
|
|
||||||
// new RootFrameListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onCreate(final GameUI rootFrame) {
|
|
||||||
// WarsmashGdxMapGame.this.gameUI = rootFrame;
|
|
||||||
// }
|
|
||||||
// }, "Scripts\\common.jui", "Scripts\\melee.jui");
|
|
||||||
final Element cameraRatesElement = this.viewer.miscData.get("CameraRates");
|
final Element cameraRatesElement = this.viewer.miscData.get("CameraRates");
|
||||||
final CameraRates cameraRates = new CameraRates(cameraRatesElement.getFieldFloatValue("AOA"),
|
final CameraRates cameraRates = new CameraRates(cameraRatesElement.getFieldFloatValue("AOA"),
|
||||||
cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"),
|
cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"),
|
||||||
@ -188,22 +182,6 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(final GameUI rootFrame) {
|
public void onCreate(final GameUI rootFrame) {
|
||||||
WarsmashGdxMapScreen.this.viewer.setGameUI(rootFrame);
|
WarsmashGdxMapScreen.this.viewer.setGameUI(rootFrame);
|
||||||
|
|
||||||
if (ENABLE_MUSIC) {
|
|
||||||
final String musicField = rootFrame
|
|
||||||
.getSkinField("Music_V" + WarsmashConstants.GAME_VERSION);
|
|
||||||
final String[] musics = musicField.split(";");
|
|
||||||
String musicPath = musics[(int) (Math.random() * musics.length)];
|
|
||||||
if (false) {
|
|
||||||
musicPath = "Sound\\Music\\mp3Music\\PH1.mp3";
|
|
||||||
}
|
|
||||||
final Music music = Gdx.audio.newMusic(
|
|
||||||
new DataSourceFileHandle(WarsmashGdxMapScreen.this.viewer.dataSource, musicPath));
|
|
||||||
music.setVolume(1.0f);
|
|
||||||
music.setLooping(true);
|
|
||||||
music.play();
|
|
||||||
WarsmashGdxMapScreen.this.currentMusic = music;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, this.uiOrderListener, new Runnable() {
|
}, this.uiOrderListener, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -224,9 +202,12 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.viewer.loadAfterUI();
|
this.viewer.loadAfterUI();
|
||||||
} catch (final IOException e) {
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
this.commonEnv = Jass2.loadCommon(this.viewer.mapMpq, this.uiViewport, this.uiScene, this.viewer, this.meleeUI,
|
||||||
|
"Scripts\\common.j", "Scripts\\Blizzard.j", "war3map.j");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSource parseDataSources(final DataTable warsmashIni) {
|
public static DataSource parseDataSources(final DataTable warsmashIni) {
|
||||||
@ -508,8 +489,6 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hide() {
|
public void hide() {
|
||||||
if (this.currentMusic != null) {
|
this.meleeUI.gameClosed();
|
||||||
this.currentMusic.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.MenuUI;
|
|||||||
|
|
||||||
public class WarsmashGdxMenuScreen implements InputProcessor, Screen, SingleModelScreen {
|
public class WarsmashGdxMenuScreen implements InputProcessor, Screen, SingleModelScreen {
|
||||||
private static final boolean ENABLE_AUDIO = true;
|
private static final boolean ENABLE_AUDIO = true;
|
||||||
private static final boolean ENABLE_MUSIC = true;
|
|
||||||
private DataSource codebase;
|
private DataSource codebase;
|
||||||
private MdxViewer viewer;
|
private MdxViewer viewer;
|
||||||
private MdxModel model;
|
private MdxModel model;
|
||||||
@ -185,7 +184,7 @@ public class WarsmashGdxMenuScreen implements InputProcessor, Screen, SingleMode
|
|||||||
public void onCreate(final GameUI rootFrame) {
|
public void onCreate(final GameUI rootFrame) {
|
||||||
// WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
|
// WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
|
||||||
|
|
||||||
if (ENABLE_MUSIC) {
|
if (WarsmashConstants.ENABLE_MUSIC) {
|
||||||
final String musicField = rootFrame
|
final String musicField = rootFrame
|
||||||
.getSkinField("GlueMusic_V" + WarsmashConstants.GAME_VERSION);
|
.getSkinField("GlueMusic_V" + WarsmashConstants.GAME_VERSION);
|
||||||
final String[] musics = musicField.split(";");
|
final String[] musics = musicField.split(";");
|
||||||
|
@ -14,6 +14,9 @@ public interface ClientToServerListener {
|
|||||||
void issueDropItemAtPointOrder(SocketAddress sourceAddress, int unitHandleId, int abilityHandleId, int orderId,
|
void issueDropItemAtPointOrder(SocketAddress sourceAddress, int unitHandleId, int abilityHandleId, int orderId,
|
||||||
int targetHandleId, float x, float y, final boolean queue);
|
int targetHandleId, float x, float y, final boolean queue);
|
||||||
|
|
||||||
|
void issueDropItemAtTargetOrder(SocketAddress sourceAddress, int unitHandleId, int abilityHandleId, int orderId,
|
||||||
|
int targetHandleId, int targetHeroHandleId, final boolean queue);
|
||||||
|
|
||||||
void issueImmediateOrder(SocketAddress sourceAddress, int unitHandleId, int abilityHandleId, int orderId,
|
void issueImmediateOrder(SocketAddress sourceAddress, int unitHandleId, int abilityHandleId, int orderId,
|
||||||
boolean queue);
|
boolean queue);
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ public class ClientToServerProtocol {
|
|||||||
public static final int ISSUE_TARGET_ORDER = 1;
|
public static final int ISSUE_TARGET_ORDER = 1;
|
||||||
public static final int ISSUE_POINT_ORDER = 2;
|
public static final int ISSUE_POINT_ORDER = 2;
|
||||||
public static final int ISSUE_DROP_ITEM_ORDER = 3;
|
public static final int ISSUE_DROP_ITEM_ORDER = 3;
|
||||||
|
public static final int ISSUE_DROP_ITEM_ON_TARGET_ORDER = 9;
|
||||||
public static final int ISSUE_IMMEDIATE_ORDER = 4;
|
public static final int ISSUE_IMMEDIATE_ORDER = 4;
|
||||||
public static final int UNIT_CANCEL_TRAINING = 5;
|
public static final int UNIT_CANCEL_TRAINING = 5;
|
||||||
public static final int FINISHED_TURN = 6;
|
public static final int FINISHED_TURN = 6;
|
||||||
|
@ -12,6 +12,9 @@ public interface ServerToClientListener {
|
|||||||
void issueDropItemAtPointOrder(int playerIndex, int unitHandleId, int abilityHandleId, int orderId,
|
void issueDropItemAtPointOrder(int playerIndex, int unitHandleId, int abilityHandleId, int orderId,
|
||||||
int targetHandleId, float x, float y, final boolean queue);
|
int targetHandleId, float x, float y, final boolean queue);
|
||||||
|
|
||||||
|
void issueDropItemAtTargetOrder(int playerIndex, int unitHandleId, int abilityHandleId, int orderId,
|
||||||
|
int targetHandleId, int targetHeroHandleId, final boolean queue);
|
||||||
|
|
||||||
void issueImmediateOrder(int playerIndex, int unitHandleId, int abilityHandleId, int orderId, boolean queue);
|
void issueImmediateOrder(int playerIndex, int unitHandleId, int abilityHandleId, int orderId, boolean queue);
|
||||||
|
|
||||||
void unitCancelTrainingItem(int playerIndex, int unitHandleId, int cancelIndex);
|
void unitCancelTrainingItem(int playerIndex, int unitHandleId, int cancelIndex);
|
||||||
|
@ -5,6 +5,7 @@ public class ServerToClientProtocol {
|
|||||||
public static final int ISSUE_TARGET_ORDER = 1;
|
public static final int ISSUE_TARGET_ORDER = 1;
|
||||||
public static final int ISSUE_POINT_ORDER = 2;
|
public static final int ISSUE_POINT_ORDER = 2;
|
||||||
public static final int ISSUE_DROP_ITEM_ORDER = 3;
|
public static final int ISSUE_DROP_ITEM_ORDER = 3;
|
||||||
|
public static final int ISSUE_DROP_ITEM_ON_TARGET_ORDER = 10;
|
||||||
public static final int ISSUE_IMMEDIATE_ORDER = 4;
|
public static final int ISSUE_IMMEDIATE_ORDER = 4;
|
||||||
public static final int UNIT_CANCEL_TRAINING = 5;
|
public static final int UNIT_CANCEL_TRAINING = 5;
|
||||||
public static final int FINISHED_TURN = 6;
|
public static final int FINISHED_TURN = 6;
|
||||||
|
@ -3,7 +3,10 @@ package com.etheller.warsmash.networking;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.*;
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.etheller.warsmash.networking.udp.OrderedUdpClient;
|
import com.etheller.warsmash.networking.udp.OrderedUdpClient;
|
||||||
@ -53,18 +56,21 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
Gdx.app.postRunnable(new Runnable() {
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
|
||||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
}
|
||||||
|
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
||||||
} else {
|
}
|
||||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
else {
|
||||||
|
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < "
|
||||||
|
+ WarsmashClient.this.latestLocallyRequestedTurn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -77,18 +83,22 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
Gdx.app.postRunnable(new Runnable() {
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
|
||||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
|
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
}
|
||||||
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);;
|
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
} else {
|
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
|
||||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < "
|
||||||
|
+ WarsmashClient.this.latestLocallyRequestedTurn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -102,18 +112,52 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
Gdx.app.postRunnable(new Runnable() {
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
|
||||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, x, y, queue);
|
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId,
|
||||||
|
x, y, queue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
}
|
||||||
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, x, y, queue);
|
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
} else {
|
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, x, y,
|
||||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
queue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < "
|
||||||
|
+ WarsmashClient.this.latestLocallyRequestedTurn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void issueDropItemAtTargetOrder(final int playerIndex, final int unitHandleId, final int abilityHandleId,
|
||||||
|
final int orderId, final int targetHandleId, final int targetHeroHandleId, final boolean queue) {
|
||||||
|
final CPlayerUnitOrderExecutor executor = getExecutor(playerIndex);
|
||||||
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
|
||||||
|
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
|
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
executor.issueDropItemAtTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId,
|
||||||
|
targetHeroHandleId, queue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
|
executor.issueDropItemAtTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId,
|
||||||
|
targetHeroHandleId, queue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < "
|
||||||
|
+ WarsmashClient.this.latestLocallyRequestedTurn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -126,18 +170,21 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
Gdx.app.postRunnable(new Runnable() {
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
|
||||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
}
|
||||||
|
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
||||||
} else {
|
}
|
||||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
else {
|
||||||
|
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < "
|
||||||
|
+ WarsmashClient.this.latestLocallyRequestedTurn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -149,18 +196,21 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
Gdx.app.postRunnable(new Runnable() {
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
|
||||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
}
|
||||||
|
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||||
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
||||||
} else {
|
}
|
||||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
else {
|
||||||
|
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < "
|
||||||
|
+ WarsmashClient.this.latestLocallyRequestedTurn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -168,7 +218,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishedTurn(final int gameTurnTick) {
|
public void finishedTurn(final int gameTurnTick) {
|
||||||
if(WarsmashConstants.VERBOSE_LOGGING) {
|
if (WarsmashConstants.VERBOSE_LOGGING) {
|
||||||
System.out.println("finishedTurn " + gameTurnTick);
|
System.out.println("finishedTurn " + gameTurnTick);
|
||||||
}
|
}
|
||||||
Gdx.app.postRunnable(new Runnable() {
|
Gdx.app.postRunnable(new Runnable() {
|
||||||
@ -183,9 +233,10 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
public void turnCompleted(final int gameTurnTick) {
|
public void turnCompleted(final int gameTurnTick) {
|
||||||
this.writer.finishedTurn(gameTurnTick);
|
this.writer.finishedTurn(gameTurnTick);
|
||||||
this.writer.send();
|
this.writer.send();
|
||||||
latestLocallyRequestedTurn = gameTurnTick;
|
this.latestLocallyRequestedTurn = gameTurnTick;
|
||||||
while(!queuedMessages.isEmpty() && queuedMessages.peek().messageTurnTick == latestLocallyRequestedTurn) {
|
while (!this.queuedMessages.isEmpty()
|
||||||
queuedMessages.poll().run();
|
&& (this.queuedMessages.peek().messageTurnTick == this.latestLocallyRequestedTurn)) {
|
||||||
|
this.queuedMessages.poll().run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,8 +258,10 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void heartbeat() {
|
public void heartbeat() {
|
||||||
// Not doing anything here at the moment. The act of the server sending us that packet
|
// Not doing anything here at the moment. The act of the server sending us that
|
||||||
// will let the middle layer UDP system know to re-request any lost packets based
|
// packet
|
||||||
|
// will let the middle layer UDP system know to re-request any lost packets
|
||||||
|
// based
|
||||||
// on the heartbeat seq no. But at app layer, here, we can ignore it.
|
// on the heartbeat seq no. But at app layer, here, we can ignore it.
|
||||||
System.out.println("got heartbeat() from server");
|
System.out.println("got heartbeat() from server");
|
||||||
}
|
}
|
||||||
@ -223,16 +276,17 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class QueuedMessage implements Runnable {
|
private static abstract class QueuedMessage implements Runnable {
|
||||||
private int messageTurnTick;
|
private final int messageTurnTick;
|
||||||
|
|
||||||
public QueuedMessage(int messageTurnTick) {
|
public QueuedMessage(final int messageTurnTick) {
|
||||||
this.messageTurnTick = messageTurnTick;
|
this.messageTurnTick = messageTurnTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int getMessageTurnTick() {
|
public final int getMessageTurnTick() {
|
||||||
return messageTurnTick;
|
return this.messageTurnTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public abstract void run();
|
public abstract void run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,14 @@ public class WarsmashClientSendingOrderListener implements CPlayerUnitOrderListe
|
|||||||
this.writer.send();
|
this.writer.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void issueDropItemAtTargetOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
||||||
|
final int targetItemHandleId, final int targetHeroHandleId, final boolean queue) {
|
||||||
|
this.writer.issueDropItemAtTargetOrder(unitHandleId, abilityHandleId, orderId, targetItemHandleId,
|
||||||
|
targetHeroHandleId, queue);
|
||||||
|
this.writer.send();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
public void issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
||||||
final boolean queue) {
|
final boolean queue) {
|
||||||
|
@ -53,6 +53,19 @@ public class WarsmashClientWriter {
|
|||||||
this.sendBuffer.put(queue ? (byte) 1 : (byte) 0);
|
this.sendBuffer.put(queue ? (byte) 1 : (byte) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void issueDropItemAtTargetOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
||||||
|
final int targetHandleId, final int targetHeroHandleId, final boolean queue) {
|
||||||
|
this.sendBuffer.clear();
|
||||||
|
this.sendBuffer.putInt(4 + 4 + 4 + 4 + 4 + 4 + 1);
|
||||||
|
this.sendBuffer.putInt(ClientToServerProtocol.ISSUE_DROP_ITEM_ON_TARGET_ORDER);
|
||||||
|
this.sendBuffer.putInt(unitHandleId);
|
||||||
|
this.sendBuffer.putInt(abilityHandleId);
|
||||||
|
this.sendBuffer.putInt(orderId);
|
||||||
|
this.sendBuffer.putInt(targetHandleId);
|
||||||
|
this.sendBuffer.putInt(targetHeroHandleId);
|
||||||
|
this.sendBuffer.put(queue ? (byte) 1 : (byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
public void issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
public void issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
||||||
final boolean queue) {
|
final boolean queue) {
|
||||||
this.sendBuffer.clear();
|
this.sendBuffer.clear();
|
||||||
|
@ -108,6 +108,22 @@ public class WarsmashServer implements ClientToServerListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void issueDropItemAtTargetOrder(final SocketAddress sourceAddress, final int unitHandleId,
|
||||||
|
final int abilityHandleId, final int orderId, final int targetHandleId, final int targetHeroHandleId,
|
||||||
|
final boolean queue) {
|
||||||
|
System.out.println("issueDropItemAtTargetOrder from " + sourceAddress);
|
||||||
|
final int playerIndex = getPlayerIndex(sourceAddress);
|
||||||
|
this.turnActions.add(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
WarsmashServer.this.writer.issueDropItemAtTargetOrder(playerIndex, unitHandleId, abilityHandleId,
|
||||||
|
orderId, targetHandleId, targetHeroHandleId, queue);
|
||||||
|
WarsmashServer.this.writer.send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void issueImmediateOrder(final SocketAddress sourceAddress, final int unitHandleId,
|
public void issueImmediateOrder(final SocketAddress sourceAddress, final int unitHandleId,
|
||||||
final int abilityHandleId, final int orderId, final boolean queue) {
|
final int abilityHandleId, final int orderId, final boolean queue) {
|
||||||
|
@ -60,6 +60,17 @@ public class WarsmashServerParser implements OrderedUdpServerListener {
|
|||||||
targetHandleId, x, y, queue);
|
targetHandleId, x, y, queue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ClientToServerProtocol.ISSUE_DROP_ITEM_ON_TARGET_ORDER: {
|
||||||
|
final int unitHandleId = buffer.getInt();
|
||||||
|
final int abilityHandleId = buffer.getInt();
|
||||||
|
final int orderId = buffer.getInt();
|
||||||
|
final int targetHandleId = buffer.getInt();
|
||||||
|
final int targetHeroHandleId = buffer.getInt();
|
||||||
|
final boolean queue = buffer.get() == 1;
|
||||||
|
this.listener.issueDropItemAtTargetOrder(sourceAddress, unitHandleId, abilityHandleId, orderId,
|
||||||
|
targetHandleId, targetHeroHandleId, queue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ClientToServerProtocol.ISSUE_IMMEDIATE_ORDER: {
|
case ClientToServerProtocol.ISSUE_IMMEDIATE_ORDER: {
|
||||||
final int unitHandleId = buffer.getInt();
|
final int unitHandleId = buffer.getInt();
|
||||||
final int abilityHandleId = buffer.getInt();
|
final int abilityHandleId = buffer.getInt();
|
||||||
|
@ -63,6 +63,21 @@ public class WarsmashServerWriter implements ServerToClientListener {
|
|||||||
this.sendBuffer.put(queue ? (byte) 1 : (byte) 0);
|
this.sendBuffer.put(queue ? (byte) 1 : (byte) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void issueDropItemAtTargetOrder(final int playerIndex, final int unitHandleId, final int abilityHandleId,
|
||||||
|
final int orderId, final int targetHandleId, final int targetHeroHandleId, final boolean queue) {
|
||||||
|
this.sendBuffer.clear();
|
||||||
|
this.sendBuffer.putInt(4 + 4 + 4 + 4 + 4 + 4 + 4 + 1);
|
||||||
|
this.sendBuffer.putInt(ServerToClientProtocol.ISSUE_DROP_ITEM_ON_TARGET_ORDER);
|
||||||
|
this.sendBuffer.putInt(playerIndex);
|
||||||
|
this.sendBuffer.putInt(unitHandleId);
|
||||||
|
this.sendBuffer.putInt(abilityHandleId);
|
||||||
|
this.sendBuffer.putInt(orderId);
|
||||||
|
this.sendBuffer.putInt(targetHandleId);
|
||||||
|
this.sendBuffer.putInt(targetHeroHandleId);
|
||||||
|
this.sendBuffer.put(queue ? (byte) 1 : (byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void issueImmediateOrder(final int playerIndex, final int unitHandleId, final int abilityHandleId,
|
public void issueImmediateOrder(final int playerIndex, final int unitHandleId, final int abilityHandleId,
|
||||||
final int orderId, final boolean queue) {
|
final int orderId, final boolean queue) {
|
||||||
|
@ -1054,7 +1054,11 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getErrorString(final String key) {
|
public String getErrorString(final String key) {
|
||||||
String errorString = this.errorStrings.getField(key, this.racialCommandIndex);
|
final String errorString = this.errorStrings.getField(key, this.racialCommandIndex);
|
||||||
|
return getTrigStr(errorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrigStr(String errorString) {
|
||||||
if (errorString.startsWith("TRIGSTR_")) {
|
if (errorString.startsWith("TRIGSTR_")) {
|
||||||
errorString = this.mapStrings.get(Integer.parseInt(errorString.substring(8)));
|
errorString = this.mapStrings.get(Integer.parseInt(errorString.substring(8)));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.etheller.warsmash.parsers.fdf.frames;
|
package com.etheller.warsmash.parsers.fdf.frames;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.GameUI;
|
||||||
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
|
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
|
||||||
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
|
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
|
||||||
|
|
||||||
@ -8,6 +10,7 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
|
|||||||
private final TextureFrame barFrame;
|
private final TextureFrame barFrame;
|
||||||
private final TextureFrame borderFrame;
|
private final TextureFrame borderFrame;
|
||||||
private final float barInset;
|
private final float barInset;
|
||||||
|
private float lastValue = Float.NaN;
|
||||||
|
|
||||||
public SimpleStatusBarFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
|
public SimpleStatusBarFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
|
||||||
final boolean borderBelow, final float barInset) {
|
final boolean borderBelow, final float barInset) {
|
||||||
@ -31,6 +34,14 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
|
||||||
|
if (!Float.isNaN(this.lastValue)) {
|
||||||
|
this.barFrame.setWidth(((this.renderBounds.width - (this.barInset * 2)) * this.lastValue));
|
||||||
|
}
|
||||||
|
super.innerPositionBounds(gameUI, viewport);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDecorateFileNames() {
|
public boolean isDecorateFileNames() {
|
||||||
return this.decorateFileNames;
|
return this.decorateFileNames;
|
||||||
}
|
}
|
||||||
@ -38,6 +49,7 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
|
|||||||
public void setValue(final float value) {
|
public void setValue(final float value) {
|
||||||
this.barFrame.setTexCoord(0, value, 0, 1);
|
this.barFrame.setTexCoord(0, value, 0, 1);
|
||||||
this.barFrame.setWidth(((this.renderBounds.width - (this.barInset * 2)) * value));
|
this.barFrame.setWidth(((this.renderBounds.width - (this.barInset * 2)) * value));
|
||||||
|
this.lastValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureFrame getBarFrame() {
|
public TextureFrame getBarFrame() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.etheller.warsmash.parsers.fdf.frames;
|
package com.etheller.warsmash.parsers.fdf.frames;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
@ -135,4 +136,10 @@ public class SpriteFrame extends AbstractUIFrame {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVertexColor(final Color color) {
|
||||||
|
if (this.instance != null) {
|
||||||
|
this.instance.setVertexColor(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ public class StringFrame extends AbstractRenderableFrame {
|
|||||||
private float alpha = 1.0f;
|
private float alpha = 1.0f;
|
||||||
private final SimpleFrame internalFramesContainer;
|
private final SimpleFrame internalFramesContainer;
|
||||||
private float predictedViewportHeight;
|
private float predictedViewportHeight;
|
||||||
|
private float predictedViewportWidth;
|
||||||
|
|
||||||
static ShapeRenderer shapeRenderer = new ShapeRenderer();
|
static ShapeRenderer shapeRenderer = new ShapeRenderer();
|
||||||
private final Color fontHighlightColor;
|
private final Color fontHighlightColor;
|
||||||
@ -425,6 +426,7 @@ public class StringFrame extends AbstractRenderableFrame {
|
|||||||
this.internalFramesContainer.setWidth(usedWidthMax);
|
this.internalFramesContainer.setWidth(usedWidthMax);
|
||||||
this.internalFramesContainer.setHeight(usedHeight);
|
this.internalFramesContainer.setHeight(usedHeight);
|
||||||
this.predictedViewportHeight = (usedHeight - this.frameFont.getCapHeight()) + this.frameFont.getLineHeight();
|
this.predictedViewportHeight = (usedHeight - this.frameFont.getCapHeight()) + this.frameFont.getLineHeight();
|
||||||
|
this.predictedViewportWidth = usedWidthMax;
|
||||||
|
|
||||||
this.internalFramesContainer.clearFramePointAssignments();
|
this.internalFramesContainer.clearFramePointAssignments();
|
||||||
switch (this.justifyH) {
|
switch (this.justifyH) {
|
||||||
@ -490,6 +492,10 @@ public class StringFrame extends AbstractRenderableFrame {
|
|||||||
return this.predictedViewportHeight;
|
return this.predictedViewportHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getPredictedViewportWidth() {
|
||||||
|
return this.predictedViewportWidth;
|
||||||
|
}
|
||||||
|
|
||||||
public BitmapFont getFrameFont() {
|
public BitmapFont getFrameFont() {
|
||||||
return this.frameFont;
|
return this.frameFont;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -64,13 +64,14 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
|
|||||||
private CDestructable orderTargetDestructable;
|
private CDestructable orderTargetDestructable;
|
||||||
private CItem orderTargetItem;
|
private CItem orderTargetItem;
|
||||||
private CUnit orderTargetUnit;
|
private CUnit orderTargetUnit;
|
||||||
|
private CWidget triggerWidget;
|
||||||
|
|
||||||
public CommonTriggerExecutionScope(final Trigger triggeringTrigger) {
|
public CommonTriggerExecutionScope(final Trigger triggeringTrigger) {
|
||||||
super(triggeringTrigger);
|
super(triggeringTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommonTriggerExecutionScope(final TriggerExecutionScope parentScope) {
|
public CommonTriggerExecutionScope(final Trigger triggeringTrigger, final TriggerExecutionScope parentScope) {
|
||||||
super(parentScope.getTriggeringTrigger());
|
super(triggeringTrigger);
|
||||||
if (parentScope instanceof CommonTriggerExecutionScope) {
|
if (parentScope instanceof CommonTriggerExecutionScope) {
|
||||||
copyFrom((CommonTriggerExecutionScope) parentScope);
|
copyFrom((CommonTriggerExecutionScope) parentScope);
|
||||||
}
|
}
|
||||||
@ -134,6 +135,7 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
|
|||||||
this.orderTargetDestructable = parentScope.orderTargetDestructable;
|
this.orderTargetDestructable = parentScope.orderTargetDestructable;
|
||||||
this.orderTargetItem = parentScope.orderTargetItem;
|
this.orderTargetItem = parentScope.orderTargetItem;
|
||||||
this.orderTargetUnit = parentScope.orderTargetUnit;
|
this.orderTargetUnit = parentScope.orderTargetUnit;
|
||||||
|
this.triggerWidget = parentScope.triggerWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CUnit getEnumUnit() {
|
public CUnit getEnumUnit() {
|
||||||
@ -144,6 +146,10 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
|
|||||||
return this.triggeringUnit;
|
return this.triggeringUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CWidget getTriggerWidget() {
|
||||||
|
return this.triggerWidget;
|
||||||
|
}
|
||||||
|
|
||||||
public CUnit getFilterUnit() {
|
public CUnit getFilterUnit() {
|
||||||
return this.filterUnit;
|
return this.filterUnit;
|
||||||
}
|
}
|
||||||
@ -350,63 +356,121 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
|
|||||||
|
|
||||||
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
|
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
|
||||||
final CUnit filterUnit) {
|
final CUnit filterUnit) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
scope.filterUnit = filterUnit;
|
scope.filterUnit = filterUnit;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope, final CUnit enumUnit) {
|
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope, final CUnit enumUnit) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
scope.enumUnit = enumUnit;
|
scope.enumUnit = enumUnit;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
|
||||||
|
final CItem filterItem) {
|
||||||
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
|
scope.filterItem = filterItem;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope, final CItem enumItem) {
|
||||||
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
|
scope.enumItem = enumItem;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
|
||||||
|
final CDestructable filterDestructable) {
|
||||||
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
|
scope.filterDestructable = filterDestructable;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope,
|
||||||
|
final CDestructable enumDestructable) {
|
||||||
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
|
scope.enumDestructable = enumDestructable;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
|
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
|
||||||
final CPlayerJass filterPlayer) {
|
final CPlayerJass filterPlayer) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
scope.filterPlayer = filterPlayer;
|
scope.filterPlayer = filterPlayer;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope,
|
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope,
|
||||||
final CPlayerJass enumPlayer) {
|
final CPlayerJass enumPlayer) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||||
|
parentScope);
|
||||||
scope.enumPlayer = enumPlayer;
|
scope.enumPlayer = enumPlayer;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope expiringTimer(final CTimerJass cTimerJass) {
|
public static CommonTriggerExecutionScope expiringTimer(final Trigger trigger, final CTimerJass cTimerJass) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(TriggerExecutionScope.EMPTY);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||||
scope.expiringTimer = cTimerJass;
|
scope.expiringTimer = cTimerJass;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope unitEnterRegionScope(final TriggerExecutionScope parentScope,
|
public static CommonTriggerExecutionScope unitEnterRegionScope(final Trigger trigger,
|
||||||
final CUnit enteringUnit, final CRegion triggeringRegion) {
|
final TriggerExecutionScope parentScope, final CUnit enteringUnit, final CRegion triggeringRegion) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, parentScope);
|
||||||
scope.enteringUnit = enteringUnit;
|
scope.enteringUnit = enteringUnit;
|
||||||
scope.triggeringRegion = triggeringRegion;
|
scope.triggeringRegion = triggeringRegion;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope unitLeaveRegionScope(final TriggerExecutionScope parentScope,
|
public static CommonTriggerExecutionScope unitLeaveRegionScope(final Trigger trigger,
|
||||||
final CUnit leavingUnit, final CRegion triggeringRegion) {
|
final TriggerExecutionScope parentScope, final CUnit leavingUnit, final CRegion triggeringRegion) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, parentScope);
|
||||||
scope.leavingUnit = leavingUnit;
|
scope.leavingUnit = leavingUnit;
|
||||||
scope.triggeringRegion = triggeringRegion;
|
scope.triggeringRegion = triggeringRegion;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope playerHeroLevelScope(final CUnit hero) {
|
public static CommonTriggerExecutionScope playerHeroLevelScope(final Trigger trigger, final CUnit hero) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(TriggerExecutionScope.EMPTY);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||||
scope.levelingUnit = hero;
|
scope.levelingUnit = hero;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommonTriggerExecutionScope playerHeroRevivableScope(final CUnit hero) {
|
public static CommonTriggerExecutionScope playerHeroRevivableScope(final Trigger trigger, final CUnit hero) {
|
||||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(TriggerExecutionScope.EMPTY);
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||||
scope.revivableUnit = hero;
|
scope.revivableUnit = hero;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CommonTriggerExecutionScope playerUnitDeathScope(final Trigger trigger, final CUnit dyingUnit,
|
||||||
|
final CUnit killingUnit) {
|
||||||
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||||
|
scope.dyingUnit = dyingUnit;
|
||||||
|
scope.triggerWidget = dyingUnit;
|
||||||
|
scope.triggeringUnit = dyingUnit;
|
||||||
|
scope.killingUnit = killingUnit;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommonTriggerExecutionScope widgetTriggerScope(final Trigger trigger, final CWidget triggerWidget) {
|
||||||
|
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||||
|
scope.triggerWidget = triggerWidget;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface UnitEventScopeBuilder {
|
||||||
|
CommonTriggerExecutionScope create(Trigger trigger, CUnit unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface WidgetEventScopeBuilder {
|
||||||
|
CommonTriggerExecutionScope create(Trigger trigger, CWidget unit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,22 @@ package com.etheller.warsmash.parsers.w3x.objectdata;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import com.etheller.warsmash.datasources.DataSource;
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
import com.etheller.warsmash.units.DataTable;
|
import com.etheller.warsmash.units.DataTable;
|
||||||
import com.etheller.warsmash.units.StandardObjectData;
|
import com.etheller.warsmash.units.StandardObjectData;
|
||||||
import com.etheller.warsmash.units.StandardObjectData.WarcraftData;
|
import com.etheller.warsmash.units.StandardObjectData.WarcraftData;
|
||||||
|
import com.etheller.warsmash.units.custom.ObjectDataChangeEntry;
|
||||||
import com.etheller.warsmash.units.custom.WTS;
|
import com.etheller.warsmash.units.custom.WTS;
|
||||||
import com.etheller.warsmash.units.custom.WTSFile;
|
import com.etheller.warsmash.units.custom.WTSFile;
|
||||||
import com.etheller.warsmash.units.custom.War3ObjectDataChangeset;
|
import com.etheller.warsmash.units.custom.War3ObjectDataChangeset;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData;
|
import com.etheller.warsmash.units.manager.MutableObjectData;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
||||||
|
import com.etheller.warsmash.util.War3ID;
|
||||||
import com.etheller.warsmash.util.WorldEditStrings;
|
import com.etheller.warsmash.util.WorldEditStrings;
|
||||||
import com.google.common.io.LittleEndianDataInputStream;
|
import com.google.common.io.LittleEndianDataInputStream;
|
||||||
|
|
||||||
@ -135,6 +139,27 @@ public final class Warcraft3MapObjectData {
|
|||||||
if (dataSource.has("war3map.w3u")) {
|
if (dataSource.has("war3map.w3u")) {
|
||||||
unitChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3u")), wts,
|
unitChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3u")), wts,
|
||||||
inlineWTS);
|
inlineWTS);
|
||||||
|
// push unit changes to items.... as a Reign of Chaos support...
|
||||||
|
Iterator<Entry<War3ID, ObjectDataChangeEntry>> entryIterator = unitChangeset.getOriginal().iterator();
|
||||||
|
while (entryIterator.hasNext()) {
|
||||||
|
final Entry<War3ID, ObjectDataChangeEntry> entry = entryIterator.next();
|
||||||
|
final String rawcodeString = entry.toString();
|
||||||
|
final String oldIdString = entry.getValue().getOldId().toString();
|
||||||
|
if ((standardUnits.get(oldIdString) == null) && (standardItems.get(oldIdString) != null)) {
|
||||||
|
itemChangeset.getOriginal().put(entry.getKey(), entry.getValue());
|
||||||
|
entryIterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entryIterator = unitChangeset.getCustom().iterator();
|
||||||
|
while (entryIterator.hasNext()) {
|
||||||
|
final Entry<War3ID, ObjectDataChangeEntry> entry = entryIterator.next();
|
||||||
|
final String rawcodeString = entry.toString();
|
||||||
|
final String oldIdString = entry.getValue().getOldId().toString();
|
||||||
|
if ((standardUnits.get(oldIdString) == null) && (standardItems.get(oldIdString) != null)) {
|
||||||
|
itemChangeset.getCustom().put(entry.getKey(), entry.getValue());
|
||||||
|
entryIterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (dataSource.has("war3map.w3t")) {
|
if (dataSource.has("war3map.w3t")) {
|
||||||
itemChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3t")), wts,
|
itemChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3t")), wts,
|
||||||
|
@ -107,6 +107,10 @@ public class Corner {
|
|||||||
return this.blight;
|
return this.blight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBlight(final boolean flag) {
|
||||||
|
this.blight = flag ? 0b00100000 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public int getWater() {
|
public int getWater() {
|
||||||
return this.water;
|
return this.water;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ public class WarsmashConstants {
|
|||||||
* With version, we use 0 for RoC, 1 for TFT emulation, and probably 2+ or
|
* With version, we use 0 for RoC, 1 for TFT emulation, and probably 2+ or
|
||||||
* whatever for custom mods and other stuff
|
* whatever for custom mods and other stuff
|
||||||
*/
|
*/
|
||||||
public static int GAME_VERSION = 0;
|
public static int GAME_VERSION = 1;
|
||||||
public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
|
public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
|
||||||
public static final float SIMULATION_STEP_TIME = 1 / 20f;
|
public static final float SIMULATION_STEP_TIME = 1 / 20f;
|
||||||
public static final int PORT_NUMBER = 6115;
|
public static final int PORT_NUMBER = 6115;
|
||||||
@ -36,4 +36,7 @@ public class WarsmashConstants {
|
|||||||
// workaround to fix it if you need the local files
|
// workaround to fix it if you need the local files
|
||||||
// to take priority over built-ins for tilesets.
|
// to take priority over built-ins for tilesets.
|
||||||
public static final boolean FIX_FLAT_FILES_TILESET_LOADING = false;
|
public static final boolean FIX_FLAT_FILES_TILESET_LOADING = false;
|
||||||
|
public static final boolean ENABLE_MUSIC = false;
|
||||||
|
public static final boolean LOAD_UNITS_FROM_WORLDEDIT_DATA = false;
|
||||||
|
public static final boolean LOCAL_TEMP_TEST_ALL_PLAYERS_PLAYING = true;
|
||||||
}
|
}
|
||||||
|
@ -78,11 +78,29 @@ public class AudioContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public AudioPanner createPanner() {
|
public AudioPanner createPanner() {
|
||||||
return new AudioPanner(this.listener) {
|
return createPanner(true);
|
||||||
@Override
|
}
|
||||||
public void connect(final AudioDestination destination) {
|
|
||||||
}
|
public AudioPanner createPanner(final boolean stopWhenOutOfRange) {
|
||||||
};
|
if (!stopWhenOutOfRange) {
|
||||||
|
return new AudioPanner(this.listener) {
|
||||||
|
@Override
|
||||||
|
public void connect(final AudioDestination destination) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWithinListenerDistance() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new AudioPanner(this.listener) {
|
||||||
|
@Override
|
||||||
|
public void connect(final AudioDestination destination) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AudioBufferSource createBufferSource() {
|
public AudioBufferSource createBufferSource() {
|
||||||
|
@ -7,6 +7,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.math.Matrix4;
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
import com.badlogic.gdx.math.Quaternion;
|
import com.badlogic.gdx.math.Quaternion;
|
||||||
@ -73,6 +74,7 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
private float blendTime;
|
private float blendTime;
|
||||||
private float blendTimeRemaining;
|
private float blendTimeRemaining;
|
||||||
public boolean additiveOverrideMeshMode = false;
|
public boolean additiveOverrideMeshMode = false;
|
||||||
|
private boolean hasAnyUnselectableMesh = false;
|
||||||
|
|
||||||
public MdxComplexInstance(final MdxModel model) {
|
public MdxComplexInstance(final MdxModel model) {
|
||||||
super(model);
|
super(model);
|
||||||
@ -85,6 +87,9 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
this.geosetColors = new float[model.geosets.size()][];
|
this.geosetColors = new float[model.geosets.size()][];
|
||||||
for (int i = 0, l = model.geosets.size(); i < l; i++) {
|
for (int i = 0, l = model.geosets.size(); i < l; i++) {
|
||||||
this.geosetColors[i] = new float[4];
|
this.geosetColors[i] = new float[4];
|
||||||
|
if (model.geosets.get(i).unselectable) {
|
||||||
|
this.hasAnyUnselectableMesh = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.layerAlphas = new float[model.layers.size()];
|
this.layerAlphas = new float[model.layers.size()];
|
||||||
@ -677,6 +682,17 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the vertex color of this instance.
|
||||||
|
*/
|
||||||
|
public MdxComplexInstance setVertexColor(final Color color) {
|
||||||
|
this.vertexColor[0] = color.r;
|
||||||
|
this.vertexColor[1] = color.g;
|
||||||
|
this.vertexColor[2] = color.b;
|
||||||
|
this.vertexColor[3] = color.a;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public MdxComplexInstance setVertexAlpha(final float alpha) {
|
public MdxComplexInstance setVertexAlpha(final float alpha) {
|
||||||
this.vertexColor[3] = alpha;
|
this.vertexColor[3] = alpha;
|
||||||
|
|
||||||
@ -808,7 +824,7 @@ public class MdxComplexInstance extends ModelInstance {
|
|||||||
intersected = true;
|
intersected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return intersected || intersectRayBounds(ray, intersection);
|
return intersected || (!this.hasAnyUnselectableMesh && intersectRayBounds(ray, intersection));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.etheller.warsmash.viewer5.handlers.mdx;
|
package com.etheller.warsmash.viewer5.handlers.mdx;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.util.WarsmashConstants;
|
||||||
|
|
||||||
public class RibbonEmitter extends MdxEmitter<MdxComplexInstance, RibbonEmitterObject, Ribbon> {
|
public class RibbonEmitter extends MdxEmitter<MdxComplexInstance, RibbonEmitterObject, Ribbon> {
|
||||||
public Ribbon first;
|
public Ribbon first;
|
||||||
public Ribbon last;
|
public Ribbon last;
|
||||||
@ -16,7 +18,8 @@ public class RibbonEmitter extends MdxEmitter<MdxComplexInstance, RibbonEmitterO
|
|||||||
final RibbonEmitterObject emitterObject = this.emitterObject;
|
final RibbonEmitterObject emitterObject = this.emitterObject;
|
||||||
|
|
||||||
// It doesn't make sense to emit more than 1 ribbon at the same time.
|
// It doesn't make sense to emit more than 1 ribbon at the same time.
|
||||||
this.currentEmission = Math.min(this.currentEmission + (emitterObject.emissionRate * dt), 1);
|
this.currentEmission = Math.min(this.currentEmission
|
||||||
|
+ (emitterObject.emissionRate * dt * WarsmashConstants.MODEL_DETAIL_PARTICLE_FACTOR), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,23 +60,32 @@ public final class UnitSound {
|
|||||||
final UnitSound sound = new UnitSound(volume, pitch, pitchVariance, minDistance, maxDistance, distanceCutoff,
|
final UnitSound sound = new UnitSound(volume, pitch, pitchVariance, minDistance, maxDistance, distanceCutoff,
|
||||||
looping);
|
looping);
|
||||||
for (final String fileName : fileNames.split(",")) {
|
for (final String fileName : fileNames.split(",")) {
|
||||||
String filePath = directoryBase + fileName;
|
final String filePath = directoryBase + fileName;
|
||||||
final int lastDotIndex = filePath.lastIndexOf('.');
|
final Sound newSound = createSound(dataSource, filePath);
|
||||||
if (lastDotIndex != -1) {
|
if (newSound != null) {
|
||||||
filePath = filePath.substring(0, lastDotIndex);
|
sound.sounds.add(newSound);
|
||||||
}
|
|
||||||
if (dataSource.has(filePath + ".wav") || dataSource.has(filePath + ".flac")) {
|
|
||||||
try {
|
|
||||||
sound.sounds.add(Gdx.audio.newSound(new DataSourceFileHandle(dataSource, filePath + ".wav")));
|
|
||||||
}
|
|
||||||
catch (final Exception exc) {
|
|
||||||
exc.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Sound createSound(final DataSource dataSource, String filePath) {
|
||||||
|
final int lastDotIndex = filePath.lastIndexOf('.');
|
||||||
|
if (lastDotIndex != -1) {
|
||||||
|
filePath = filePath.substring(0, lastDotIndex);
|
||||||
|
}
|
||||||
|
Sound newSound = null;
|
||||||
|
if (dataSource.has(filePath + ".wav") || dataSource.has(filePath + ".flac")) {
|
||||||
|
try {
|
||||||
|
newSound = Gdx.audio.newSound(new DataSourceFileHandle(dataSource, filePath + ".wav"));
|
||||||
|
}
|
||||||
|
catch (final Exception exc) {
|
||||||
|
exc.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newSound;
|
||||||
|
}
|
||||||
|
|
||||||
public UnitSound(final float volume, final float pitch, final float pitchVariation, final float minDistance,
|
public UnitSound(final float volume, final float pitch, final float pitchVariation, final float minDistance,
|
||||||
final float maxDistance, final float distanceCutoff, final boolean looping) {
|
final float maxDistance, final float distanceCutoff, final boolean looping) {
|
||||||
this.volume = volume;
|
this.volume = volume;
|
||||||
|
@ -91,6 +91,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderDestructable;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderDoodad;
|
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderDoodad;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderEffect;
|
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderEffect;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderItem;
|
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderItem;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderSpellEffect;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
|
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.RenderUnitTypeData;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderWidget;
|
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderWidget;
|
||||||
@ -701,10 +702,36 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
@Override
|
@Override
|
||||||
public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex,
|
public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex,
|
||||||
final float x, final float y, final float facing) {
|
final float x, final float y, final float facing) {
|
||||||
return createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y, 0f, playerIndex,
|
return (CUnit) createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y, 0f, playerIndex,
|
||||||
playerIndex, (float) Math.toRadians(facing));
|
playerIndex, (float) Math.toRadians(facing));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CDestructable createDestructable(final War3ID typeId, final float x, final float y,
|
||||||
|
final float facing, final float scale, final int variation) {
|
||||||
|
return createDestructableZ(typeId, x, y, Math.max(getWalkableRenderHeight(x, y),
|
||||||
|
War3MapViewer.this.terrain.getGroundHeight(x, y)), facing, scale, variation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CDestructable createDestructableZ(final War3ID typeId, final float x, final float y,
|
||||||
|
final float z, final float facing, final float scale, final int variation) {
|
||||||
|
final MutableGameObject row = War3MapViewer.this.allObjectData.getDestructibles().get(typeId);
|
||||||
|
final float[] location3d = { x, y, z };
|
||||||
|
final float[] scale3d = { scale, scale, scale };
|
||||||
|
final RenderDestructable newDestructable = createNewDestructable(typeId, row, variation,
|
||||||
|
location3d, (float) Math.toRadians(facing), (short) 100, scale3d);
|
||||||
|
return newDestructable.getSimulationDestructable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CItem createItem(final CSimulation simulation, final War3ID typeId, final float x,
|
||||||
|
final float y) {
|
||||||
|
return (CItem) createNewUnit(War3MapViewer.this.allObjectData, typeId, x, y, 0f, -1, -1,
|
||||||
|
(float) Math.toRadians(
|
||||||
|
War3MapViewer.this.simulation.getGameplayConstants().getBuildingAngle()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnBuildingDeathEffect(final CUnit source) {
|
public void spawnBuildingDeathEffect(final CUnit source) {
|
||||||
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
|
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
|
||||||
@ -777,10 +804,11 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
modelInstance.setTeamColor(unit.getPlayerIndex());
|
modelInstance.setTeamColor(unit.getPlayerIndex());
|
||||||
modelInstance.setLocation(renderUnit.location);
|
modelInstance.setLocation(renderUnit.location);
|
||||||
modelInstance.setScene(War3MapViewer.this.worldScene);
|
modelInstance.setScene(War3MapViewer.this.worldScene);
|
||||||
SequenceUtils.randomBirthSequence(modelInstance);
|
final RenderSpellEffect renderAttackInstant = new RenderSpellEffect(modelInstance,
|
||||||
War3MapViewer.this.projectiles
|
War3MapViewer.this,
|
||||||
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this,
|
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing()),
|
||||||
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing())));
|
RenderSpellEffect.DEFAULT_ANIMATION_QUEUE);
|
||||||
|
War3MapViewer.this.projectiles.add(renderAttackInstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -873,8 +901,6 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
loadSounds();
|
loadSounds();
|
||||||
|
|
||||||
this.terrain.createWaves();
|
this.terrain.createWaves();
|
||||||
|
|
||||||
loadLightsAndShading(tileset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnFxOnOrigin(final RenderUnit renderUnit, final String heroLevelUpArt) {
|
public void spawnFxOnOrigin(final RenderUnit renderUnit, final String heroLevelUpArt) {
|
||||||
@ -941,16 +967,6 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
this.terrain.initShadows();
|
this.terrain.initShadows();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadLightsAndShading(final char tileset) {
|
|
||||||
// TODO this should be set by the war3map.j actually, not by the tileset, so the
|
|
||||||
// call to set day night models is just for testing to make the test look pretty
|
|
||||||
final Element defaultTerrainLights = this.worldEditData.get("TerrainLights");
|
|
||||||
final Element defaultUnitLights = this.worldEditData.get("UnitLights");
|
|
||||||
setDayNightModels(defaultTerrainLights.getField(Character.toString(tileset)),
|
|
||||||
defaultUnitLights.getField(Character.toString(tileset)));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadDoodadsAndDestructibles(final Warcraft3MapObjectData modifications) throws IOException {
|
private void loadDoodadsAndDestructibles(final Warcraft3MapObjectData modifications) throws IOException {
|
||||||
this.applyModificationFile(this.doodadsData, this.doodadMetaData, modifications.getDoodads(),
|
this.applyModificationFile(this.doodadsData, this.doodadMetaData, modifications.getDoodads(),
|
||||||
WorldEditorDataType.DOODADS);
|
WorldEditorDataType.DOODADS);
|
||||||
@ -960,105 +976,17 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
final War3MapDoo doo = this.mapMpq.readDoodads();
|
final War3MapDoo doo = this.mapMpq.readDoodads();
|
||||||
|
|
||||||
for (final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad : doo.getDoodads()) {
|
for (final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad : doo.getDoodads()) {
|
||||||
WorldEditorDataType type = WorldEditorDataType.DOODADS;
|
if ((doodad.getFlags() & 0x2) == 0) {
|
||||||
MutableGameObject row = modifications.getDoodads().get(doodad.getId());
|
continue;
|
||||||
if (row == null) {
|
|
||||||
row = modifications.getDestructibles().get(doodad.getId());
|
|
||||||
type = WorldEditorDataType.DESTRUCTIBLES;
|
|
||||||
}
|
|
||||||
if (row != null) {
|
|
||||||
BuildingShadow destructableShadow = null;
|
|
||||||
RemovablePathingMapInstance destructablePathing = null;
|
|
||||||
RemovablePathingMapInstance destructablePathingDeath = null;
|
|
||||||
String file = row.readSLKTag("file");
|
|
||||||
final int numVar = row.readSLKTagInt("numVar");
|
|
||||||
|
|
||||||
if (file.endsWith(".mdx") || file.endsWith(".mdl")) {
|
|
||||||
file = file.substring(0, file.length() - 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
String fileVar = file;
|
|
||||||
|
|
||||||
file += ".mdx";
|
|
||||||
|
|
||||||
if (numVar > 1) {
|
|
||||||
fileVar += Math.min(doodad.getVariation(), numVar - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileVar += ".mdx";
|
|
||||||
|
|
||||||
final float maxPitch = row.readSLKTagFloat("maxPitch");
|
|
||||||
final float maxRoll = row.readSLKTagFloat("maxRoll");
|
|
||||||
if (type == WorldEditorDataType.DESTRUCTIBLES) {
|
|
||||||
final String shadowString = row.readSLKTag("shadow");
|
|
||||||
if ((shadowString != null) && (shadowString.length() > 0) && !"_".equals(shadowString)) {
|
|
||||||
destructableShadow = this.terrain.addShadow(shadowString, doodad.getLocation()[0],
|
|
||||||
doodad.getLocation()[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
final BufferedImage destructablePathingPixelMap = getDestructablePathingPixelMap(row);
|
|
||||||
if (destructablePathingPixelMap != null) {
|
|
||||||
destructablePathing = this.terrain.pathingGrid.createRemovablePathingOverlayTexture(
|
|
||||||
doodad.getLocation()[0], doodad.getLocation()[1],
|
|
||||||
(int) Math.toDegrees(doodad.getAngle()), destructablePathingPixelMap);
|
|
||||||
if (doodad.getLife() > 0) {
|
|
||||||
destructablePathing.add();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final BufferedImage destructablePathingDeathPixelMap = getDestructablePathingDeathPixelMap(row);
|
|
||||||
if (destructablePathingDeathPixelMap != null) {
|
|
||||||
destructablePathingDeath = this.terrain.pathingGrid.createRemovablePathingOverlayTexture(
|
|
||||||
doodad.getLocation()[0], doodad.getLocation()[1],
|
|
||||||
(int) Math.toDegrees(doodad.getAngle()), destructablePathingDeathPixelMap);
|
|
||||||
if (doodad.getLife() <= 0) {
|
|
||||||
destructablePathingDeath.add();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// First see if the model is local.
|
|
||||||
// Doodads referring to local models may have invalid variations, so if the
|
|
||||||
// variation doesn't exist, try without a variation.
|
|
||||||
|
|
||||||
String path;
|
|
||||||
if (this.mapMpq.has(fileVar)) {
|
|
||||||
path = fileVar;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
path = file;
|
|
||||||
}
|
|
||||||
MdxModel model;
|
|
||||||
if (this.mapMpq.has(path)) {
|
|
||||||
model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == WorldEditorDataType.DESTRUCTIBLES) {
|
|
||||||
final float x = doodad.getLocation()[0];
|
|
||||||
final float y = doodad.getLocation()[1];
|
|
||||||
final CDestructable simulationDestructable = this.simulation.createDestructable(row.getAlias(), x,
|
|
||||||
y, destructablePathing, destructablePathingDeath);
|
|
||||||
simulationDestructable.setLife(this.simulation,
|
|
||||||
simulationDestructable.getLife() * (doodad.getLife() / 100f));
|
|
||||||
final RenderDestructable renderDestructable = new RenderDestructable(this, model, row, doodad, type,
|
|
||||||
maxPitch, maxRoll, doodad.getLife(), destructableShadow, simulationDestructable);
|
|
||||||
if (row.readSLKTagBoolean("walkable")) {
|
|
||||||
final float angle = doodad.getAngle();
|
|
||||||
final BoundingBox boundingBox = model.bounds.getBoundingBox();
|
|
||||||
final Rectangle renderDestructableBounds = getRotatedBoundingBox(x, y, angle, boundingBox);
|
|
||||||
System.out.println("ROTATED BOUNDS TO: " + renderDestructableBounds);
|
|
||||||
this.walkableObjectsTree.add((MdxComplexInstance) renderDestructable.instance,
|
|
||||||
renderDestructableBounds);
|
|
||||||
renderDestructable.walkableBounds = renderDestructableBounds;
|
|
||||||
}
|
|
||||||
this.widgets.add(renderDestructable);
|
|
||||||
this.destructableToRenderPeer.put(simulationDestructable, renderDestructable);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.doodads.add(new RenderDoodad(this, model, row, doodad, type, maxPitch, maxRoll));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
final War3ID doodadId = doodad.getId();
|
||||||
|
final int doodadVariation = doodad.getVariation();
|
||||||
|
final float[] location = doodad.getLocation();
|
||||||
|
final float facingRadians = doodad.getAngle();
|
||||||
|
final short lifePercent = doodad.getLife();
|
||||||
|
final float[] scale = doodad.getScale();
|
||||||
|
createDestructableOrDoodad(doodadId, modifications, doodadVariation, location, facingRadians, lifePercent,
|
||||||
|
scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cliff/Terrain doodads.
|
// Cliff/Terrain doodads.
|
||||||
@ -1124,6 +1052,125 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
this.anyReady = true;
|
this.anyReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createDoodad(final MutableGameObject row, final int doodadVariation, final float[] location,
|
||||||
|
final float facingRadians, final float[] scale) {
|
||||||
|
final MdxModel model = getDoodadModel(doodadVariation, row);
|
||||||
|
final float maxPitch = row.readSLKTagFloat("maxPitch");
|
||||||
|
final float maxRoll = row.readSLKTagFloat("maxRoll");
|
||||||
|
final float defScale = row.readSLKTagFloat("defScale");
|
||||||
|
final RenderDoodad renderDoodad = new RenderDoodad(this, model, row, location, scale, facingRadians, maxPitch,
|
||||||
|
maxRoll, defScale);
|
||||||
|
renderDoodad.instance.uniformScale(defScale);
|
||||||
|
this.doodads.add(renderDoodad);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RenderDestructable createNewDestructable(final War3ID doodadId, final MutableGameObject row,
|
||||||
|
final int doodadVariation, final float[] location, final float facingRadians, final short lifePercent,
|
||||||
|
final float[] scale) {
|
||||||
|
BuildingShadow destructableShadow = null;
|
||||||
|
RemovablePathingMapInstance destructablePathing = null;
|
||||||
|
RemovablePathingMapInstance destructablePathingDeath = null;
|
||||||
|
final MdxModel model = getDoodadModel(doodadVariation, row);
|
||||||
|
|
||||||
|
final float maxPitch = row.readSLKTagFloat("maxPitch");
|
||||||
|
final float maxRoll = row.readSLKTagFloat("maxRoll");
|
||||||
|
final String shadowString = row.readSLKTag("shadow");
|
||||||
|
if ((shadowString != null) && (shadowString.length() > 0) && !"_".equals(shadowString)) {
|
||||||
|
destructableShadow = this.terrain.addShadow(shadowString, location[0], location[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
final BufferedImage destructablePathingPixelMap = getDestructablePathingPixelMap(row);
|
||||||
|
if (destructablePathingPixelMap != null) {
|
||||||
|
destructablePathing = this.terrain.pathingGrid.createRemovablePathingOverlayTexture(location[0],
|
||||||
|
location[1], (int) Math.toDegrees(facingRadians), destructablePathingPixelMap);
|
||||||
|
if (lifePercent > 0) {
|
||||||
|
destructablePathing.add();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final BufferedImage destructablePathingDeathPixelMap = getDestructablePathingDeathPixelMap(row);
|
||||||
|
if (destructablePathingDeathPixelMap != null) {
|
||||||
|
destructablePathingDeath = this.terrain.pathingGrid.createRemovablePathingOverlayTexture(location[0],
|
||||||
|
location[1], (int) Math.toDegrees(facingRadians), destructablePathingDeathPixelMap);
|
||||||
|
if (lifePercent <= 0) {
|
||||||
|
destructablePathingDeath.add();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final float x = location[0];
|
||||||
|
final float y = location[1];
|
||||||
|
final CDestructable simulationDestructable = this.simulation.internalCreateDestructable(row.getAlias(), x, y,
|
||||||
|
destructablePathing, destructablePathingDeath);
|
||||||
|
// Used to be this, but why: (float) Math.sqrt((scale[0]) * (scale[1]) *
|
||||||
|
// (scale[2]));
|
||||||
|
final float selectionScale = 1.0f;
|
||||||
|
simulationDestructable.setLife(this.simulation, simulationDestructable.getLife() * (lifePercent / 100f));
|
||||||
|
final RenderDestructable renderDestructable = new RenderDestructable(this, model, row, location, scale,
|
||||||
|
facingRadians, selectionScale, maxPitch, maxRoll, lifePercent, destructableShadow,
|
||||||
|
simulationDestructable);
|
||||||
|
if (row.readSLKTagBoolean("walkable")) {
|
||||||
|
final float angle = facingRadians;
|
||||||
|
final BoundingBox boundingBox = model.bounds.getBoundingBox();
|
||||||
|
final Rectangle renderDestructableBounds = getRotatedBoundingBox(x, y, angle, boundingBox);
|
||||||
|
this.walkableObjectsTree.add((MdxComplexInstance) renderDestructable.instance, renderDestructableBounds);
|
||||||
|
renderDestructable.walkableBounds = renderDestructableBounds;
|
||||||
|
}
|
||||||
|
this.widgets.add(renderDestructable);
|
||||||
|
this.destructableToRenderPeer.put(simulationDestructable, renderDestructable);
|
||||||
|
return renderDestructable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDestructableOrDoodad(final War3ID doodadId, final Warcraft3MapObjectData modifications,
|
||||||
|
final int doodadVariation, final float[] location, final float facingRadians, final short lifePercent,
|
||||||
|
final float[] scale) {
|
||||||
|
MutableGameObject row = modifications.getDoodads().get(doodadId);
|
||||||
|
if (row == null) {
|
||||||
|
row = modifications.getDestructibles().get(doodadId);
|
||||||
|
if (row != null) {
|
||||||
|
createNewDestructable(doodadId, row, doodadVariation, location, facingRadians, lifePercent, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createDoodad(row, doodadVariation, location, facingRadians, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MdxModel getDoodadModel(final int doodadVariation, final MutableGameObject row) {
|
||||||
|
String file = row.readSLKTag("file");
|
||||||
|
final int numVar = row.readSLKTagInt("numVar");
|
||||||
|
|
||||||
|
if (file.endsWith(".mdx") || file.endsWith(".mdl")) {
|
||||||
|
file = file.substring(0, file.length() - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileVar = file;
|
||||||
|
|
||||||
|
file += ".mdx";
|
||||||
|
|
||||||
|
if (numVar > 1) {
|
||||||
|
fileVar += Math.min(doodadVariation, numVar - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileVar += ".mdx";
|
||||||
|
// First see if the model is local.
|
||||||
|
// Doodads referring to local models may have invalid variations, so if the
|
||||||
|
// variation doesn't exist, try without a variation.
|
||||||
|
|
||||||
|
String path;
|
||||||
|
if (this.mapMpq.has(fileVar)) {
|
||||||
|
path = fileVar;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
path = file;
|
||||||
|
}
|
||||||
|
MdxModel model;
|
||||||
|
if (this.mapMpq.has(path)) {
|
||||||
|
model = (MdxModel) this.load(path, this.mapPathSolver, this.solverParams);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
model = (MdxModel) this.load(fileVar, this.mapPathSolver, this.solverParams);
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
private Rectangle getRotatedBoundingBox(final float x, final float y, final float angle,
|
private Rectangle getRotatedBoundingBox(final float x, final float y, final float angle,
|
||||||
final BoundingBox boundingBox) {
|
final BoundingBox boundingBox) {
|
||||||
final float x1 = boundingBox.min.x;
|
final float x1 = boundingBox.min.x;
|
||||||
@ -1170,7 +1217,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
|
|
||||||
this.soundsetNameToSoundset = new HashMap<>();
|
this.soundsetNameToSoundset = new HashMap<>();
|
||||||
|
|
||||||
if (this.dataSource.has("war3mapUnits.doo")) {
|
if (this.dataSource.has("war3mapUnits.doo") && WarsmashConstants.LOAD_UNITS_FROM_WORLDEDIT_DATA) {
|
||||||
final War3MapUnitsDoo dooFile = mpq.readUnits();
|
final War3MapUnitsDoo dooFile = mpq.readUnits();
|
||||||
|
|
||||||
// Collect the units and items data.
|
// Collect the units and items data.
|
||||||
@ -1184,9 +1231,10 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
final float unitAngle = unit.getAngle();
|
final float unitAngle = unit.getAngle();
|
||||||
final int editorConfigHitPointPercent = unit.getHitpoints();
|
final int editorConfigHitPointPercent = unit.getHitpoints();
|
||||||
|
|
||||||
final CUnit unitCreated = createNewUnit(modifications, unitId, unitX, unitY, unitZ, playerIndex,
|
final CWidget widgetCreated = createNewUnit(modifications, unitId, unitX, unitY, unitZ, playerIndex,
|
||||||
customTeamColor, unitAngle);
|
customTeamColor, unitAngle);
|
||||||
if (unitCreated != null) {
|
if (widgetCreated instanceof CUnit) {
|
||||||
|
final CUnit unitCreated = (CUnit) widgetCreated;
|
||||||
if (editorConfigHitPointPercent > 0) {
|
if (editorConfigHitPointPercent > 0) {
|
||||||
unitCreated.setLife(this.simulation,
|
unitCreated.setLife(this.simulation,
|
||||||
unitCreated.getMaximumLife() * (editorConfigHitPointPercent / 100f));
|
unitCreated.getMaximumLife() * (editorConfigHitPointPercent / 100f));
|
||||||
@ -1205,7 +1253,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
this.anyReady = true;
|
this.anyReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CUnit createNewUnit(final Warcraft3MapObjectData modifications, final War3ID unitId, float unitX,
|
private CWidget createNewUnit(final Warcraft3MapObjectData modifications, final War3ID unitId, float unitX,
|
||||||
float unitY, final float unitZ, final int playerIndex, int customTeamColor, final float unitAngle) {
|
float unitY, final float unitZ, final int playerIndex, int customTeamColor, final float unitAngle) {
|
||||||
UnitSoundset soundset = null;
|
UnitSoundset soundset = null;
|
||||||
MutableGameObject row = null;
|
MutableGameObject row = null;
|
||||||
@ -1215,7 +1263,6 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
Splat buildingUberSplat = null;
|
Splat buildingUberSplat = null;
|
||||||
SplatMover buildingUberSplatDynamicIngame = null;
|
SplatMover buildingUberSplatDynamicIngame = null;
|
||||||
BufferedImage buildingPathingPixelMap = null;
|
BufferedImage buildingPathingPixelMap = null;
|
||||||
final float unitVertexScale = 1.0f;
|
|
||||||
RemovablePathingMapInstance pathingInstance = null;
|
RemovablePathingMapInstance pathingInstance = null;
|
||||||
BuildingShadow buildingShadowInstance = null;
|
BuildingShadow buildingShadowInstance = null;
|
||||||
|
|
||||||
@ -1421,7 +1468,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
final CItem simulationItem = this.simulation.createItem(row.getAlias(), unitX, unitY);
|
final CItem simulationItem = this.simulation.internalCreateItem(row.getAlias(), unitX, unitY);
|
||||||
final RenderItem renderItem = new RenderItem(this, model, row, unitX, unitY, unitZ, unitAngle, soundset,
|
final RenderItem renderItem = new RenderItem(this, model, row, unitX, unitY, unitZ, unitAngle, soundset,
|
||||||
portraitModel, simulationItem);
|
portraitModel, simulationItem);
|
||||||
this.widgets.add(renderItem);
|
this.widgets.add(renderItem);
|
||||||
@ -1438,6 +1485,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
if (unitShadowSplatDynamicIngame != null) {
|
if (unitShadowSplatDynamicIngame != null) {
|
||||||
renderItem.shadow = unitShadowSplatDynamicIngame;
|
renderItem.shadow = unitShadowSplatDynamicIngame;
|
||||||
}
|
}
|
||||||
|
return simulationItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1671,7 +1719,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
if (!localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.PASSIVE)) {
|
if (!localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.PASSIVE)) {
|
||||||
allyKey = "e:";
|
allyKey = "e:";
|
||||||
}
|
}
|
||||||
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.HELP_REQUEST)) {
|
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.SHARED_CONTROL)) {
|
||||||
allyKey = "f:";
|
allyKey = "f:";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1780,7 +1828,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
if (!localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.PASSIVE)) {
|
if (!localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.PASSIVE)) {
|
||||||
allyKey = "e:";
|
allyKey = "e:";
|
||||||
}
|
}
|
||||||
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.HELP_REQUEST)) {
|
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.SHARED_CONTROL)) {
|
||||||
allyKey = "f:";
|
allyKey = "f:";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2246,4 +2294,32 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
|||||||
public void setGameTurnManager(final GameTurnManager gameTurnManager) {
|
public void setGameTurnManager(final GameTurnManager gameTurnManager) {
|
||||||
this.gameTurnManager = gameTurnManager;
|
this.gameTurnManager = gameTurnManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RenderEffect addSpecialEffectTarget(final String modelName, final CWidget targetWidget,
|
||||||
|
final String attachPointName) {
|
||||||
|
if (targetWidget instanceof CUnit) {
|
||||||
|
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(targetWidget);
|
||||||
|
final MdxModel spawnedEffectModel = (MdxModel) load(mdx(modelName), PathSolver.DEFAULT, null);
|
||||||
|
if (spawnedEffectModel != null) {
|
||||||
|
final MdxComplexInstance modelInstance = (MdxComplexInstance) spawnedEffectModel.addInstance();
|
||||||
|
modelInstance.setTeamColor(renderUnit.playerIndex);
|
||||||
|
modelInstance.setLocation(renderUnit.location);
|
||||||
|
modelInstance.setScene(War3MapViewer.this.worldScene);
|
||||||
|
final RenderSpellEffect renderAttackInstant = new RenderSpellEffect(modelInstance, War3MapViewer.this,
|
||||||
|
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing()),
|
||||||
|
RenderSpellEffect.DEFAULT_ANIMATION_QUEUE);
|
||||||
|
War3MapViewer.this.projectiles.add(renderAttackInstant);
|
||||||
|
return renderAttackInstant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (targetWidget instanceof CItem) {
|
||||||
|
// TODO this is stupid api, who would do this?
|
||||||
|
throw new UnsupportedOperationException("API for addSpecialEffectTarget() on item is NYI");
|
||||||
|
}
|
||||||
|
else if (targetWidget instanceof CDestructable) {
|
||||||
|
// TODO this is stupid api, who would do this?
|
||||||
|
throw new UnsupportedOperationException("API for addSpecialEffectTarget() on destructable is NYI");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.camera;
|
|||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.Input;
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
|
||||||
|
|
||||||
public final class GameCameraManager extends CameraManager {
|
public final class GameCameraManager extends CameraManager {
|
||||||
private static final CameraRates INFINITE_CAMERA_RATES = new CameraRates(Float.POSITIVE_INFINITY,
|
private static final CameraRates INFINITE_CAMERA_RATES = new CameraRates(Float.POSITIVE_INFINITY,
|
||||||
@ -11,8 +12,13 @@ public final class GameCameraManager extends CameraManager {
|
|||||||
private final CameraPreset[] presets;
|
private final CameraPreset[] presets;
|
||||||
private final CameraRates cameraRates;
|
private final CameraRates cameraRates;
|
||||||
public final CameraPanControls cameraPanControls;
|
public final CameraPanControls cameraPanControls;
|
||||||
|
private Rectangle cameraBounds;
|
||||||
private int currentPreset = 0;
|
private int currentPreset = 0;
|
||||||
private float fov;
|
private float fov;
|
||||||
|
private RenderUnit targetControllerUnit;
|
||||||
|
private float targetControllerXOffset;
|
||||||
|
private float targetControllerYOffset;
|
||||||
|
private boolean targetControllerInheritOrientation;
|
||||||
|
|
||||||
public GameCameraManager(final CameraPreset[] presets, final CameraRates cameraRates) {
|
public GameCameraManager(final CameraPreset[] presets, final CameraRates cameraRates) {
|
||||||
this.presets = presets;
|
this.presets = presets;
|
||||||
@ -20,6 +26,10 @@ public final class GameCameraManager extends CameraManager {
|
|||||||
this.cameraPanControls = new CameraPanControls();
|
this.cameraPanControls = new CameraPanControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCameraBounds(final Rectangle cameraBounds) {
|
||||||
|
this.cameraBounds = cameraBounds;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateCamera() {
|
public void updateCamera() {
|
||||||
final CameraPreset cameraPreset = this.presets[this.currentPreset];
|
final CameraPreset cameraPreset = this.presets[this.currentPreset];
|
||||||
@ -30,8 +40,16 @@ public final class GameCameraManager extends CameraManager {
|
|||||||
private void updateCamera(final CameraPreset cameraPreset, final CameraRates cameraRate) {
|
private void updateCamera(final CameraPreset cameraPreset, final CameraRates cameraRate) {
|
||||||
this.quatHeap2.idt();
|
this.quatHeap2.idt();
|
||||||
this.quatHeap.idt();
|
this.quatHeap.idt();
|
||||||
this.horizontalAngle = applyAtRate(this.horizontalAngle, (float) Math.toRadians(
|
final float newHorizontalAngle;
|
||||||
cameraPreset.getRotation(this.cameraPanControls.insertDown, this.cameraPanControls.deleteDown) - 90),
|
if (this.targetControllerInheritOrientation && (this.targetControllerUnit != null)) {
|
||||||
|
newHorizontalAngle = this.targetControllerUnit.getFacing();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newHorizontalAngle = (float) Math.toRadians(
|
||||||
|
cameraPreset.getRotation(this.cameraPanControls.insertDown, this.cameraPanControls.deleteDown)
|
||||||
|
- 90);
|
||||||
|
}
|
||||||
|
this.horizontalAngle = applyAtRate(this.horizontalAngle, newHorizontalAngle,
|
||||||
(float) Math.toRadians(cameraRate.rotation * 3));
|
(float) Math.toRadians(cameraRate.rotation * 3));
|
||||||
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
|
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
|
||||||
this.distance = applyAtRate(this.distance, Math.max(1200, cameraPreset.getDistance()), cameraRate.distance);
|
this.distance = applyAtRate(this.distance, Math.max(1200, cameraPreset.getDistance()), cameraRate.distance);
|
||||||
@ -69,41 +87,61 @@ public final class GameCameraManager extends CameraManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void applyVelocity(final float deltaTime, boolean up, boolean down, boolean left, boolean right) {
|
public void applyVelocity(final float deltaTime, boolean up, boolean down, boolean left, boolean right) {
|
||||||
final float velocityX;
|
if (this.targetControllerUnit != null) {
|
||||||
final float velocityY;
|
this.target.x = this.targetControllerUnit.getX() + this.targetControllerXOffset;
|
||||||
up |= this.cameraPanControls.up;
|
this.target.y = this.targetControllerUnit.getY() + this.targetControllerYOffset;
|
||||||
down |= this.cameraPanControls.down;
|
}
|
||||||
left |= this.cameraPanControls.left;
|
else {
|
||||||
right |= this.cameraPanControls.right;
|
final float velocityX;
|
||||||
if (up) {
|
final float velocityY;
|
||||||
if (down) {
|
up |= this.cameraPanControls.up;
|
||||||
|
down |= this.cameraPanControls.down;
|
||||||
|
left |= this.cameraPanControls.left;
|
||||||
|
right |= this.cameraPanControls.right;
|
||||||
|
if (up) {
|
||||||
|
if (down) {
|
||||||
|
velocityY = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
velocityY = this.cameraRates.forward;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (down) {
|
||||||
|
velocityY = -this.cameraRates.forward;
|
||||||
|
}
|
||||||
|
else {
|
||||||
velocityY = 0;
|
velocityY = 0;
|
||||||
}
|
}
|
||||||
else {
|
if (right) {
|
||||||
velocityY = this.cameraRates.forward;
|
if (left) {
|
||||||
|
velocityX = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
velocityX = this.cameraRates.strafe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (left) {
|
||||||
else if (down) {
|
velocityX = -this.cameraRates.strafe;
|
||||||
velocityY = -this.cameraRates.forward;
|
}
|
||||||
}
|
else {
|
||||||
else {
|
|
||||||
velocityY = 0;
|
|
||||||
}
|
|
||||||
if (right) {
|
|
||||||
if (left) {
|
|
||||||
velocityX = 0;
|
velocityX = 0;
|
||||||
}
|
}
|
||||||
else {
|
this.target.add(velocityX * deltaTime, velocityY * deltaTime, 0);
|
||||||
velocityX = this.cameraRates.strafe;
|
}
|
||||||
|
if (this.cameraBounds != null) {
|
||||||
|
if (this.target.x < this.cameraBounds.x) {
|
||||||
|
this.target.x = this.cameraBounds.x;
|
||||||
|
}
|
||||||
|
if (this.target.y < this.cameraBounds.y) {
|
||||||
|
this.target.y = this.cameraBounds.y;
|
||||||
|
}
|
||||||
|
if (this.target.x > (this.cameraBounds.x + this.cameraBounds.width)) {
|
||||||
|
this.target.x = this.cameraBounds.x + this.cameraBounds.width;
|
||||||
|
}
|
||||||
|
if (this.target.y > (this.cameraBounds.y + this.cameraBounds.height)) {
|
||||||
|
this.target.y = this.cameraBounds.y + this.cameraBounds.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (left) {
|
|
||||||
velocityX = -this.cameraRates.strafe;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
velocityX = 0;
|
|
||||||
}
|
|
||||||
this.target.add(velocityX * deltaTime, velocityY * deltaTime, 0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,4 +214,17 @@ public final class GameCameraManager extends CameraManager {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rectangle getCameraBounds() {
|
||||||
|
return this.cameraBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetController(final RenderUnit targetControllerUnit, final float xoffset, final float yoffset,
|
||||||
|
final boolean inheritOrientation) {
|
||||||
|
this.targetControllerUnit = targetControllerUnit;
|
||||||
|
this.targetControllerXOffset = xoffset;
|
||||||
|
this.targetControllerYOffset = yoffset;
|
||||||
|
this.targetControllerInheritOrientation = inheritOrientation;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -252,6 +252,24 @@ public class PathingGrid {
|
|||||||
return (short) (this.pathingGrid[index] | this.dynamicPathingOverlay[index]);
|
return (short) (this.pathingGrid[index] | this.dynamicPathingOverlay[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCellPathing(final int cellX, final int cellY, final short pathingValue) {
|
||||||
|
final int index = (cellY * this.pathingGridSizes[0]) + cellX;
|
||||||
|
this.pathingGrid[index] = pathingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCellBlighted(final int cellX, final int cellY, final boolean blighted) {
|
||||||
|
if (blighted) {
|
||||||
|
setCellPathing(cellX, cellY, (short) (getCellPathing(cellX, cellY) | (short) PathingFlags.BLIGHTED));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setCellPathing(cellX, cellY, (short) (getCellPathing(cellX, cellY) & (short) ~PathingFlags.BLIGHTED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlighted(final float x, final float y, final boolean blighted) {
|
||||||
|
setCellBlighted(getCellX(x), getCellY(y), blighted);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPathable(final float x, final float y, final PathingType pathingType) {
|
public boolean isPathable(final float x, final float y, final PathingType pathingType) {
|
||||||
return !PathingFlags.isPathingFlag(getPathing(x, y), pathingType.preventionFlag);
|
return !PathingFlags.isPathingFlag(getPathing(x, y), pathingType.preventionFlag);
|
||||||
}
|
}
|
||||||
|
@ -406,6 +406,7 @@ public class Terrain {
|
|||||||
this.centerOffset = w3eFile.getCenterOffset();
|
this.centerOffset = w3eFile.getCenterOffset();
|
||||||
this.uberSplatModels = new LinkedHashMap<>();
|
this.uberSplatModels = new LinkedHashMap<>();
|
||||||
this.uberSplatModelsList = new ArrayList<>();
|
this.uberSplatModelsList = new ArrayList<>();
|
||||||
|
this.defaultCameraBounds = w3iFile.getCameraBounds();
|
||||||
this.mapBounds = w3iFile.getCameraBoundsComplements();
|
this.mapBounds = w3iFile.getCameraBoundsComplements();
|
||||||
this.shaderMapBounds = new float[] { (this.mapBounds[0] * 128.0f) + this.centerOffset[0],
|
this.shaderMapBounds = new float[] { (this.mapBounds[0] * 128.0f) + this.centerOffset[0],
|
||||||
(this.mapBounds[2] * 128.0f) + this.centerOffset[1],
|
(this.mapBounds[2] * 128.0f) + this.centerOffset[1],
|
||||||
@ -724,7 +725,7 @@ public class Terrain {
|
|||||||
System.out.println("cliff: " + this.corners[x][y].cliff);
|
System.out.println("cliff: " + this.corners[x][y].cliff);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateGroundTextures(final Rectangle area) {
|
public void updateGroundTextures(final Rectangle area) {
|
||||||
final Rectangle adjusted = new Rectangle(area.x - 1, area.y - 1, area.width + 2, area.height + 2);
|
final Rectangle adjusted = new Rectangle(area.x - 1, area.y - 1, area.width + 2, area.height + 2);
|
||||||
final Rectangle updateArea = new Rectangle();
|
final Rectangle updateArea = new Rectangle();
|
||||||
Intersector.intersectRectangles(new Rectangle(0, 0, this.columns - 1, this.rows - 1), adjusted, updateArea);
|
Intersector.intersectRectangles(new Rectangle(0, 0, this.columns - 1, this.rows - 1), adjusted, updateArea);
|
||||||
@ -1343,6 +1344,7 @@ public class Terrain {
|
|||||||
public PathingGrid pathingGrid;
|
public PathingGrid pathingGrid;
|
||||||
private final Rectangle shaderMapBoundsRectangle;
|
private final Rectangle shaderMapBoundsRectangle;
|
||||||
private final Rectangle entireMapRectangle;
|
private final Rectangle entireMapRectangle;
|
||||||
|
private final float[] defaultCameraBounds;
|
||||||
|
|
||||||
private static final class UnloadedTexture {
|
private static final class UnloadedTexture {
|
||||||
private final int width;
|
private final int width;
|
||||||
@ -1390,6 +1392,19 @@ public class Terrain {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RenderCorner getCorner(final float x, final float y) {
|
||||||
|
final float userCellSpaceX = (x - this.centerOffset[0]) / 128.0f;
|
||||||
|
final float userCellSpaceY = (y - this.centerOffset[1]) / 128.0f;
|
||||||
|
final int cellX = (int) userCellSpaceX;
|
||||||
|
final int cellY = (int) userCellSpaceY;
|
||||||
|
|
||||||
|
if ((cellX >= 0) && (cellX < (this.mapSize[0] - 1)) && (cellY >= 0) && (cellY < (this.mapSize[1] - 1))) {
|
||||||
|
return this.corners[cellX][cellY];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public float getWaterHeight(final float x, final float y) {
|
public float getWaterHeight(final float x, final float y) {
|
||||||
final float userCellSpaceX = (x - this.centerOffset[0]) / 128.0f;
|
final float userCellSpaceX = (x - this.centerOffset[0]) / 128.0f;
|
||||||
final float userCellSpaceY = (y - this.centerOffset[1]) / 128.0f;
|
final float userCellSpaceY = (y - this.centerOffset[1]) / 128.0f;
|
||||||
@ -1564,4 +1579,8 @@ public class Terrain {
|
|||||||
return (char) ('A' + layerHeightOffset);
|
return (char) ('A' + layerHeightOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float[] getDefaultCameraBounds() {
|
||||||
|
return this.defaultCameraBounds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
|
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
|
||||||
import com.etheller.warsmash.util.War3ID;
|
import com.etheller.warsmash.util.War3ID;
|
||||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
|
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
|
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
|
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
|
||||||
@ -34,10 +36,10 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
|
|||||||
private String replaceableTextureFile;
|
private String replaceableTextureFile;
|
||||||
|
|
||||||
public RenderDestructable(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
public RenderDestructable(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||||
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
|
final float[] location3D, final float[] scale3D, final float facingRadians, final float selectionScale,
|
||||||
final float maxPitch, final float maxRoll, final float life, final BuildingShadow destructableShadow,
|
final float maxPitch, final float maxRoll, final float life, final BuildingShadow destructableShadow,
|
||||||
final CDestructable simulationDestructable) {
|
final CDestructable simulationDestructable) {
|
||||||
super(map, model, row, doodad, type, maxPitch, maxRoll);
|
super(map, model, row, location3D, scale3D, facingRadians, maxPitch, maxRoll, selectionScale);
|
||||||
this.life = simulationDestructable.getLife();
|
this.life = simulationDestructable.getLife();
|
||||||
this.destructableShadow = destructableShadow;
|
this.destructableShadow = destructableShadow;
|
||||||
this.simulationDestructable = simulationDestructable;
|
this.simulationDestructable = simulationDestructable;
|
||||||
@ -187,4 +189,44 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
|
|||||||
public SplatMover getSelectionCircle() {
|
public SplatMover getSelectionCircle() {
|
||||||
return this.selectionCircle;
|
return this.selectionCircle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CDestructable getSimulationDestructable() {
|
||||||
|
return this.simulationDestructable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitAnimationListenerImpl getUnitAnimationListenerImpl() {
|
||||||
|
return this.unitAnimationListenerImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnimation(final String sequence) {
|
||||||
|
final EnumSet<PrimaryTag> primaryTags = EnumSet.noneOf(PrimaryTag.class);
|
||||||
|
PrimaryTag bestPrimaryTag = null;
|
||||||
|
final EnumSet<SecondaryTag> secondaryTags = EnumSet.noneOf(SecondaryTag.class);
|
||||||
|
TokenLoop: for (final String token : sequence.split("\\s+")) {
|
||||||
|
final String upperCaseToken = token.toUpperCase();
|
||||||
|
for (final PrimaryTag primaryTag : PrimaryTag.values()) {
|
||||||
|
if (upperCaseToken.equals(primaryTag.name())) {
|
||||||
|
primaryTags.add(primaryTag);
|
||||||
|
bestPrimaryTag = primaryTag;
|
||||||
|
continue TokenLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final SecondaryTag secondaryTag : SecondaryTag.values()) {
|
||||||
|
if (upperCaseToken.equals(secondaryTag.name())) {
|
||||||
|
secondaryTags.add(secondaryTag);
|
||||||
|
continue TokenLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.dead = this.simulationDestructable.isDead();
|
||||||
|
this.life = this.simulationDestructable.getLife();
|
||||||
|
this.unitAnimationListenerImpl.playAnimation(true, bestPrimaryTag, secondaryTags, 1.0f, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyLifeRestored() {
|
||||||
|
this.dead = this.simulationDestructable.isDead();
|
||||||
|
this.life = this.simulationDestructable.getLife();
|
||||||
|
this.unitAnimationListenerImpl.playAnimation(true, getAnimation(), SequenceUtils.EMPTY, 1.0f, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
|
|||||||
|
|
||||||
import com.badlogic.gdx.math.Quaternion;
|
import com.badlogic.gdx.math.Quaternion;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
|
||||||
import com.etheller.warsmash.util.RenderMathUtils;
|
import com.etheller.warsmash.util.RenderMathUtils;
|
||||||
import com.etheller.warsmash.viewer5.ModelInstance;
|
import com.etheller.warsmash.viewer5.ModelInstance;
|
||||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||||
@ -23,8 +22,8 @@ public class RenderDoodad {
|
|||||||
protected float selectionScale;
|
protected float selectionScale;
|
||||||
|
|
||||||
public RenderDoodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
public RenderDoodad(final War3MapViewer map, final MdxModel model, final MutableGameObject row,
|
||||||
final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad, final WorldEditorDataType type,
|
final float[] location3D, final float[] scale3D, final float facingRadians, final float maxPitch,
|
||||||
final float maxPitch, final float maxRoll) {
|
final float maxRoll, final float selectionScale) {
|
||||||
this.maxPitch = maxPitch;
|
this.maxPitch = maxPitch;
|
||||||
this.maxRoll = maxRoll;
|
this.maxRoll = maxRoll;
|
||||||
final boolean isSimple = row.readSLKTagBoolean("lightweight");
|
final boolean isSimple = row.readSLKTagBoolean("lightweight");
|
||||||
@ -38,7 +37,7 @@ public class RenderDoodad {
|
|||||||
((MdxComplexInstance) instance).setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
|
((MdxComplexInstance) instance).setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.move(doodad.getLocation());
|
instance.move(location3D);
|
||||||
// TODO: the following pitch/roll system is a heuristic, and we probably want to
|
// TODO: the following pitch/roll system is a heuristic, and we probably want to
|
||||||
// revisit it later.
|
// revisit it later.
|
||||||
// Specifically, I was pretty convinced that whichever is applied first
|
// Specifically, I was pretty convinced that whichever is applied first
|
||||||
@ -46,10 +45,9 @@ public class RenderDoodad {
|
|||||||
// to find the angle used for the other of the two
|
// to find the angle used for the other of the two
|
||||||
// (instead of measuring down from an imaginary flat ground plane, as we do
|
// (instead of measuring down from an imaginary flat ground plane, as we do
|
||||||
// currently).
|
// currently).
|
||||||
final float facingRadians = doodad.getAngle();
|
|
||||||
float pitch, roll;
|
float pitch, roll;
|
||||||
this.x = doodad.getLocation()[0];
|
this.x = location3D[0];
|
||||||
this.y = doodad.getLocation()[1];
|
this.y = location3D[1];
|
||||||
{
|
{
|
||||||
if (!map.terrain.inPlayableArea(this.x, this.y)) {
|
if (!map.terrain.inPlayableArea(this.x, this.y)) {
|
||||||
((MdxComplexInstance) instance).setVertexColor(VERTEX_COLOR_BLACK);
|
((MdxComplexInstance) instance).setVertexColor(VERTEX_COLOR_BLACK);
|
||||||
@ -76,16 +74,8 @@ public class RenderDoodad {
|
|||||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Y, -pitch));
|
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_Y, -pitch));
|
||||||
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_X, roll));
|
instance.rotate(new Quaternion().setFromAxisRad(RenderMathUtils.VEC3_UNIT_X, roll));
|
||||||
// instance.rotate(new Quaternion().setEulerAnglesRad(facingRadians, 0, 0));
|
// instance.rotate(new Quaternion().setEulerAnglesRad(facingRadians, 0, 0));
|
||||||
final float[] scale = doodad.getScale();
|
instance.scale(scale3D);
|
||||||
instance.scale(scale);
|
this.selectionScale = selectionScale;
|
||||||
if (type == WorldEditorDataType.DOODADS) {
|
|
||||||
final float defScale = row.readSLKTagFloat("defScale");
|
|
||||||
instance.uniformScale(defScale);
|
|
||||||
this.selectionScale = defScale;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.selectionScale = (float) Math.sqrt((scale[0]) * (scale[1]) * (scale[2]));
|
|
||||||
}
|
|
||||||
instance.setScene(map.worldScene);
|
instance.setScene(map.worldScene);
|
||||||
|
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
|
@ -92,6 +92,7 @@ public class RenderItem implements RenderWidget {
|
|||||||
this.instance.show();
|
this.instance.show();
|
||||||
if (this.shadow != null) {
|
if (this.shadow != null) {
|
||||||
this.shadow.show(map.terrain.centerOffset);
|
this.shadow.show(map.terrain.centerOffset);
|
||||||
|
this.shadow.setLocation(this.location[0], this.location[1], map.terrain.centerOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,12 +112,10 @@ public class RenderItem implements RenderWidget {
|
|||||||
final float prevY = this.location[1];
|
final float prevY = this.location[1];
|
||||||
final float simulationX = this.simulationItem.getX();
|
final float simulationX = this.simulationItem.getX();
|
||||||
final float simulationY = this.simulationItem.getY();
|
final float simulationY = this.simulationItem.getY();
|
||||||
final float simDx = simulationX - this.location[0];
|
final float dx = simulationX - prevX;
|
||||||
final float simDy = simulationY - this.location[1];
|
final float dy = simulationY - prevY;
|
||||||
this.location[0] = simulationX;
|
this.location[0] = simulationX;
|
||||||
this.location[1] = simulationY;
|
this.location[1] = simulationY;
|
||||||
final float dx = this.location[0] - prevX;
|
|
||||||
final float dy = this.location[1] - prevY;
|
|
||||||
final float groundHeight;
|
final float groundHeight;
|
||||||
// land units will have their feet pass under the surface of the water, so items
|
// land units will have their feet pass under the surface of the water, so items
|
||||||
// here are in the same place
|
// here are in the same place
|
||||||
@ -150,7 +149,7 @@ public class RenderItem implements RenderWidget {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getSelectionScale() {
|
public float getSelectionScale() {
|
||||||
return 1.0f;
|
return 64.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -202,4 +201,8 @@ public class RenderItem implements RenderWidget {
|
|||||||
public SplatMover getSelectionCircle() {
|
public SplatMover getSelectionCircle() {
|
||||||
return this.selectionCircle;
|
return this.selectionCircle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CItem getSimulationItem() {
|
||||||
|
return this.simulationItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.mdx.Sequence;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.IndexedSequence;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
|
||||||
|
|
||||||
|
public class RenderSpellEffect implements RenderEffect {
|
||||||
|
public static final PrimaryTag[] DEFAULT_ANIMATION_QUEUE = { PrimaryTag.BIRTH, PrimaryTag.STAND, PrimaryTag.DEATH };
|
||||||
|
private final MdxComplexInstance modelInstance;
|
||||||
|
private final PrimaryTag[] animationQueue;
|
||||||
|
private int animationQueueIndex;
|
||||||
|
private final List<Sequence> sequences;
|
||||||
|
|
||||||
|
public RenderSpellEffect(final MdxComplexInstance modelInstance, final War3MapViewer war3MapViewer, final float yaw,
|
||||||
|
final PrimaryTag[] animationQueue) {
|
||||||
|
this.modelInstance = modelInstance;
|
||||||
|
this.animationQueue = animationQueue;
|
||||||
|
final MdxModel model = (MdxModel) this.modelInstance.model;
|
||||||
|
this.sequences = model.getSequences();
|
||||||
|
this.modelInstance.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
|
||||||
|
this.modelInstance.localRotation.setFromAxisRad(0, 0, 1, yaw);
|
||||||
|
this.modelInstance.sequenceEnded = true;
|
||||||
|
playNextAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateAnimations(final War3MapViewer war3MapViewer, final float deltaTime) {
|
||||||
|
playNextAnimation();
|
||||||
|
final boolean everythingDone = this.animationQueueIndex >= this.animationQueue.length;
|
||||||
|
if (everythingDone) {
|
||||||
|
war3MapViewer.worldScene.removeInstance(this.modelInstance);
|
||||||
|
}
|
||||||
|
return everythingDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playNextAnimation() {
|
||||||
|
while (this.modelInstance.sequenceEnded && (this.animationQueueIndex < this.animationQueue.length)) {
|
||||||
|
final IndexedSequence sequence = SequenceUtils.selectSequence(this.animationQueue[this.animationQueueIndex],
|
||||||
|
SequenceUtils.EMPTY, this.sequences, true);
|
||||||
|
if ((sequence != null) && (sequence.index != -1)) {
|
||||||
|
this.modelInstance.setSequence(sequence.index);
|
||||||
|
}
|
||||||
|
this.animationQueueIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -563,4 +563,17 @@ public class RenderUnit implements RenderWidget {
|
|||||||
return this.selectionCircle;
|
return this.selectionCircle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean groupsWith(final RenderUnit selectedUnit) {
|
||||||
|
return this.simulationUnit.getUnitType() == selectedUnit.getSimulationUnit().getUnitType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlayerColor(final int ordinal) {
|
||||||
|
this.playerIndex = ordinal;
|
||||||
|
getInstance().setTeamColor(ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFacing() {
|
||||||
|
return this.facing;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbi
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
|
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.queue.CAbilityRally;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.upgrade.CAbilityUpgrade;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
|
||||||
@ -238,23 +239,25 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
|||||||
final int autoCastOrderId, final boolean autoCastActive, final boolean menuButton, int goldCost,
|
final int autoCastOrderId, final boolean autoCastActive, final boolean menuButton, int goldCost,
|
||||||
int lumberCost, int foodCost) {
|
int lumberCost, int foodCost) {
|
||||||
ability.checkCanUse(this.game, this.unit, orderId, this.previewCallback.reset());
|
ability.checkCanUse(this.game, this.unit, orderId, this.previewCallback.reset());
|
||||||
final boolean active = ((this.unit.getCurrentBehavior() != null)
|
if (!this.previewCallback.techtreeMaxReached) {
|
||||||
&& (orderId == this.unit.getCurrentBehavior().getHighlightOrderId()));
|
final boolean active = ((this.unit.getCurrentBehavior() != null)
|
||||||
final boolean disabled = ((ability != null) && ability.isDisabled()) || this.previewCallback.disabled;
|
&& (orderId == this.unit.getCurrentBehavior().getHighlightOrderId()));
|
||||||
String uberTip = iconUI.getUberTip();
|
final boolean disabled = ((ability != null) && ability.isDisabled()) || this.previewCallback.disabled;
|
||||||
if (disabled) {
|
String uberTip = iconUI.getUberTip();
|
||||||
// dont show these on disabled
|
if (disabled) {
|
||||||
goldCost = 0;
|
// dont show these on disabled
|
||||||
lumberCost = 0;
|
goldCost = 0;
|
||||||
foodCost = 0;
|
lumberCost = 0;
|
||||||
|
foodCost = 0;
|
||||||
|
}
|
||||||
|
if (this.previewCallback.isShowingRequirements()) {
|
||||||
|
uberTip = this.previewCallback.getRequirementsText() + "|r" + uberTip;
|
||||||
|
}
|
||||||
|
this.commandButtonListener.commandButton(buttonPosX, buttonPosY,
|
||||||
|
disabled ? iconUI.getIconDisabled() : iconUI.getIcon(), handleId, disabled ? 0 : orderId,
|
||||||
|
autoCastOrderId, active, autoCastActive, menuButton, toolTip, uberTip, iconUI.getHotkey(), goldCost,
|
||||||
|
lumberCost, foodCost);
|
||||||
}
|
}
|
||||||
if (this.previewCallback.isShowingRequirements()) {
|
|
||||||
uberTip = this.previewCallback.getRequirementsText() + "|r" + uberTip;
|
|
||||||
}
|
|
||||||
this.commandButtonListener.commandButton(buttonPosX, buttonPosY,
|
|
||||||
disabled ? iconUI.getIconDisabled() : iconUI.getIcon(), handleId, disabled ? 0 : orderId,
|
|
||||||
autoCastOrderId, active, autoCastActive, menuButton, toolTip, uberTip, iconUI.getHotkey(), goldCost,
|
|
||||||
lumberCost, foodCost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -332,12 +335,37 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void accept(final CAbilityUpgrade ability) {
|
||||||
|
if ((this.menuBaseOrderId == 0) && ability.isIconShowing()) {
|
||||||
|
for (final War3ID unitType : ability.getUpgradesTo()) {
|
||||||
|
final IconUI unitUI = this.abilityDataUI.getUnitUI(unitType);
|
||||||
|
if (unitUI != null) {
|
||||||
|
final CUnitType simulationUnitType = this.game.getUnitData().getUnitType(unitType);
|
||||||
|
addCommandButton(ability, unitUI, ability.getHandleId(), unitType.getValue(), 0, false, false,
|
||||||
|
simulationUnitType.getGoldCost(), simulationUnitType.getLumberCost(),
|
||||||
|
simulationUnitType.getFoodUsed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.unit.getBuildQueueTypes()[0] != null) {
|
||||||
|
if (!this.hasCancel) {
|
||||||
|
this.hasCancel = true;
|
||||||
|
addCommandButton(ability, this.abilityDataUI.getCancelTrainUI(), ability.getHandleId(),
|
||||||
|
OrderIds.cancel, 0, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private final class CommandCardActivationReceiverPreviewCallback implements AbilityActivationReceiver {
|
private final class CommandCardActivationReceiverPreviewCallback implements AbilityActivationReceiver {
|
||||||
private boolean disabled;
|
private boolean disabled;
|
||||||
|
private boolean techtreeMaxReached;
|
||||||
private final StringBuilder requirementsTextBuilder = new StringBuilder();
|
private final StringBuilder requirementsTextBuilder = new StringBuilder();
|
||||||
|
|
||||||
public CommandCardActivationReceiverPreviewCallback reset() {
|
public CommandCardActivationReceiverPreviewCallback reset() {
|
||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
|
this.techtreeMaxReached = false;
|
||||||
this.requirementsTextBuilder.setLength(0);
|
this.requirementsTextBuilder.setLength(0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -374,6 +402,11 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
|||||||
this.requirementsTextBuilder.append("|n");
|
this.requirementsTextBuilder.append("|n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void techtreeMaximumReached() {
|
||||||
|
this.techtreeMaxReached = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void casterMovementDisabled() {
|
public void casterMovementDisabled() {
|
||||||
|
|
||||||
|
@ -61,17 +61,34 @@ public class CDestructable extends CWidget {
|
|||||||
@Override
|
@Override
|
||||||
public void damage(final CSimulation simulation, final CUnit source, final CAttackType attackType,
|
public void damage(final CSimulation simulation, final CUnit source, final CAttackType attackType,
|
||||||
final String weaponType, final float damage) {
|
final String weaponType, final float damage) {
|
||||||
|
if (isInvulnerable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final boolean wasDead = isDead();
|
final boolean wasDead = isDead();
|
||||||
this.life -= damage;
|
this.life -= damage;
|
||||||
if (!wasDead && isDead()) {
|
|
||||||
if (this.pathingInstance != null) {
|
|
||||||
this.pathingInstance.remove();
|
|
||||||
}
|
|
||||||
if (this.pathingInstanceDeath != null) {
|
|
||||||
this.pathingInstanceDeath.add();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
simulation.destructableDamageEvent(this, weaponType, this.destType.getArmorType());
|
simulation.destructableDamageEvent(this, weaponType, this.destType.getArmorType());
|
||||||
|
if (!wasDead && isDead()) {
|
||||||
|
kill(simulation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void kill(final CSimulation simulation) {
|
||||||
|
if (this.pathingInstance != null) {
|
||||||
|
this.pathingInstance.remove();
|
||||||
|
}
|
||||||
|
if (this.pathingInstanceDeath != null) {
|
||||||
|
this.pathingInstanceDeath.add();
|
||||||
|
}
|
||||||
|
fireDeathEvents(simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLife(final CSimulation simulation, final float life) {
|
||||||
|
final boolean wasDead = isDead();
|
||||||
|
super.setLife(simulation, life);
|
||||||
|
if (isDead() && !wasDead) {
|
||||||
|
kill(simulation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -80,10 +97,12 @@ public class CDestructable extends CWidget {
|
|||||||
if (targetsAllowed.containsAll(this.destType.getTargetedAs())) {
|
if (targetsAllowed.containsAll(this.destType.getTargetedAs())) {
|
||||||
if (isDead()) {
|
if (isDead()) {
|
||||||
return targetsAllowed.contains(CTargetType.DEAD);
|
return targetsAllowed.contains(CTargetType.DEAD);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return !targetsAllowed.contains(CTargetType.DEAD) || targetsAllowed.contains(CTargetType.ALIVE);
|
return !targetsAllowed.contains(CTargetType.DEAD) || targetsAllowed.contains(CTargetType.ALIVE);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
System.err.println("Not targeting because " + targetsAllowed + " does not contain all of "
|
System.err.println("Not targeting because " + targetsAllowed + " does not contain all of "
|
||||||
+ this.destType.getTargetedAs());
|
+ this.destType.getTargetedAs());
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ public class CItem extends CWidget {
|
|||||||
private final War3ID typeId;
|
private final War3ID typeId;
|
||||||
private final CItemType itemType;
|
private final CItemType itemType;
|
||||||
private boolean hidden;
|
private boolean hidden;
|
||||||
|
private boolean invulnerable;
|
||||||
|
|
||||||
public CItem(final int handleId, final float x, final float y, final float life, final War3ID typeId,
|
public CItem(final int handleId, final float x, final float y, final float life, final War3ID typeId,
|
||||||
final CItemType itemTypeInstance) {
|
final CItemType itemTypeInstance) {
|
||||||
@ -34,8 +35,15 @@ public class CItem extends CWidget {
|
|||||||
@Override
|
@Override
|
||||||
public void damage(final CSimulation simulation, final CUnit source, final CAttackType attackType,
|
public void damage(final CSimulation simulation, final CUnit source, final CAttackType attackType,
|
||||||
final String weaponType, final float damage) {
|
final String weaponType, final float damage) {
|
||||||
|
if (this.invulnerable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final boolean wasDead = isDead();
|
||||||
this.life -= damage;
|
this.life -= damage;
|
||||||
simulation.itemDamageEvent(this, weaponType, this.itemType.getArmorType());
|
simulation.itemDamageEvent(this, weaponType, this.itemType.getArmorType());
|
||||||
|
if (isDead() && !wasDead) {
|
||||||
|
fireDeathEvents(simulation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -75,7 +83,7 @@ public class CItem extends CWidget {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getMaxLife() {
|
public float getMaxLife() {
|
||||||
return itemType.getMaxLife();
|
return this.itemType.getMaxLife();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPointAndCheckUnstuck(final float newX, final float newY, final CSimulation game) {
|
public void setPointAndCheckUnstuck(final float newX, final float newY, final CSimulation game) {
|
||||||
@ -107,7 +115,11 @@ public class CItem extends CWidget {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInvulnerable() {
|
public boolean isInvulnerable() {
|
||||||
return false;
|
return this.invulnerable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInvulernable(final boolean invulnerable) {
|
||||||
|
this.invulnerable = invulnerable;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,11 @@ public interface CPlayerStateListener {
|
|||||||
|
|
||||||
void upkeepChanged();
|
void upkeepChanged();
|
||||||
|
|
||||||
void heroDeath();
|
void heroDeath();
|
||||||
|
|
||||||
public static final class CPlayerStateNotifier extends SubscriberSetNotifier<CPlayerStateListener>
|
void heroTokensChanged();
|
||||||
|
|
||||||
|
public static final class CPlayerStateNotifier extends SubscriberSetNotifier<CPlayerStateListener>
|
||||||
implements CPlayerStateListener {
|
implements CPlayerStateListener {
|
||||||
@Override
|
@Override
|
||||||
public void goldChanged() {
|
public void goldChanged() {
|
||||||
@ -49,5 +51,12 @@ public interface CPlayerStateListener {
|
|||||||
listener.heroDeath();
|
listener.heroDeath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void heroTokensChanged() {
|
||||||
|
for (final CPlayerStateListener listener : set) {
|
||||||
|
listener.heroTokensChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayerJass
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CRace;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CRace;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegionManager;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegionManager;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.timers.CTimer;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.timers.CTimer;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.enumtypes.CPlayerSlotState;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
|
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
|
||||||
@ -79,6 +81,7 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
private transient CommandErrorListener commandErrorListener;
|
private transient CommandErrorListener commandErrorListener;
|
||||||
private final CRegionManager regionManager;
|
private final CRegionManager regionManager;
|
||||||
private final List<TimeOfDayVariableEvent> timeOfDayVariableEvents = new ArrayList<>();
|
private final List<TimeOfDayVariableEvent> timeOfDayVariableEvents = new ArrayList<>();
|
||||||
|
private boolean timeOfDaySuspended;
|
||||||
|
|
||||||
public CSimulation(final War3MapConfig config, final DataTable miscData, final MutableObjectData parsedUnitData,
|
public CSimulation(final War3MapConfig config, final DataTable miscData, final MutableObjectData parsedUnitData,
|
||||||
final MutableObjectData parsedItemData, final MutableObjectData parsedDestructableData,
|
final MutableObjectData parsedItemData, final MutableObjectData parsedDestructableData,
|
||||||
@ -115,6 +118,9 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
final CRace defaultRace = CRace.UNDEAD;
|
final CRace defaultRace = CRace.UNDEAD;
|
||||||
final CPlayer newPlayer = new CPlayer(defaultRace, new float[] { startLoc.getX(), startLoc.getY() },
|
final CPlayer newPlayer = new CPlayer(defaultRace, new float[] { startLoc.getX(), startLoc.getY() },
|
||||||
configPlayer);
|
configPlayer);
|
||||||
|
if (WarsmashConstants.LOCAL_TEMP_TEST_ALL_PLAYERS_PLAYING) {
|
||||||
|
newPlayer.setSlotState(CPlayerSlotState.PLAYING);
|
||||||
|
}
|
||||||
this.players.add(newPlayer);
|
this.players.add(newPlayer);
|
||||||
}
|
}
|
||||||
this.players.get(this.players.size() - 4).setName(miscData.getLocalizedString("WESTRING_PLAYER_NA"));
|
this.players.get(this.players.size() - 4).setName(miscData.getLocalizedString("WESTRING_PLAYER_NA"));
|
||||||
@ -164,6 +170,7 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
if (nextTimer.getEngineFireTick() > timer.getEngineFireTick()) {
|
if (nextTimer.getEngineFireTick() > timer.getEngineFireTick()) {
|
||||||
listIterator.previous();
|
listIterator.previous();
|
||||||
listIterator.add(timer);
|
listIterator.add(timer);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.activeTimers.add(timer);
|
this.activeTimers.add(timer);
|
||||||
@ -187,7 +194,7 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
return unit;
|
return unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CDestructable createDestructable(final War3ID typeId, final float x, final float y,
|
public CDestructable internalCreateDestructable(final War3ID typeId, final float x, final float y,
|
||||||
final RemovablePathingMapInstance pathingInstance, final RemovablePathingMapInstance pathingInstanceDeath) {
|
final RemovablePathingMapInstance pathingInstance, final RemovablePathingMapInstance pathingInstanceDeath) {
|
||||||
final CDestructable dest = this.destructableData.create(this, typeId, x, y, this.handleIdAllocator,
|
final CDestructable dest = this.destructableData.create(this, typeId, x, y, this.handleIdAllocator,
|
||||||
pathingInstance, pathingInstanceDeath);
|
pathingInstance, pathingInstanceDeath);
|
||||||
@ -198,18 +205,32 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CItem createItem(final War3ID alias, final float unitX, final float unitY) {
|
public CItem internalCreateItem(final War3ID alias, final float unitX, final float unitY) {
|
||||||
final CItem item = this.itemData.create(this, alias, unitX, unitY, this.handleIdAllocator.createId());
|
final CItem item = this.itemData.create(this, alias, unitX, unitY, this.handleIdAllocator.createId());
|
||||||
this.handleIdToItem.put(item.getHandleId(), item);
|
this.handleIdToItem.put(item.getHandleId(), item);
|
||||||
this.items.add(item);
|
this.items.add(item);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CItem createItem(final War3ID alias, final float unitX, final float unitY) {
|
||||||
|
return this.simulationRenderController.createItem(this, alias, unitX, unitY);
|
||||||
|
}
|
||||||
|
|
||||||
public CUnit createUnit(final War3ID typeId, final int playerIndex, final float x, final float y,
|
public CUnit createUnit(final War3ID typeId, final int playerIndex, final float x, final float y,
|
||||||
final float facing) {
|
final float facing) {
|
||||||
return this.simulationRenderController.createUnit(this, typeId, playerIndex, x, y, facing);
|
return this.simulationRenderController.createUnit(this, typeId, playerIndex, x, y, facing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CDestructable createDestructable(final War3ID typeId, final float x, final float y, final float facing,
|
||||||
|
final float scale, final int variation) {
|
||||||
|
return this.simulationRenderController.createDestructable(typeId, x, y, facing, scale, variation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CDestructable createDestructableZ(final War3ID typeId, final float x, final float y, final float z,
|
||||||
|
final float facing, final float scale, final int variation) {
|
||||||
|
return this.simulationRenderController.createDestructableZ(typeId, x, y, z, facing, scale, variation);
|
||||||
|
}
|
||||||
|
|
||||||
public CUnit getUnit(final int handleId) {
|
public CUnit getUnit(final int handleId) {
|
||||||
return this.handleIdToUnit.get(handleId);
|
return this.handleIdToUnit.get(handleId);
|
||||||
}
|
}
|
||||||
@ -288,8 +309,10 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
}
|
}
|
||||||
this.gameTurnTick++;
|
this.gameTurnTick++;
|
||||||
final float timeOfDayBefore = this.getGameTimeOfDay();
|
final float timeOfDayBefore = this.getGameTimeOfDay();
|
||||||
this.currentGameDayTimeElapsed = (this.currentGameDayTimeElapsed + WarsmashConstants.SIMULATION_STEP_TIME)
|
if (!this.timeOfDaySuspended) {
|
||||||
% this.gameplayConstants.getGameDayLength();
|
this.currentGameDayTimeElapsed = (this.currentGameDayTimeElapsed + WarsmashConstants.SIMULATION_STEP_TIME)
|
||||||
|
% this.gameplayConstants.getGameDayLength();
|
||||||
|
}
|
||||||
final float timeOfDayAfter = this.getGameTimeOfDay();
|
final float timeOfDayAfter = this.getGameTimeOfDay();
|
||||||
while (!this.activeTimers.isEmpty() && (this.activeTimers.peek().getEngineFireTick() <= this.gameTurnTick)) {
|
while (!this.activeTimers.isEmpty() && (this.activeTimers.peek().getEngineFireTick() <= this.gameTurnTick)) {
|
||||||
this.activeTimers.pop().fire(this);
|
this.activeTimers.pop().fire(this);
|
||||||
@ -327,6 +350,11 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
* this.gameplayConstants.getGameDayHours();
|
* this.gameplayConstants.getGameDayHours();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setGameTimeOfDay(final float value) {
|
||||||
|
final float elapsed = value / this.gameplayConstants.getGameDayHours();
|
||||||
|
this.currentGameDayTimeElapsed = elapsed * this.gameplayConstants.getGameDayLength();
|
||||||
|
}
|
||||||
|
|
||||||
public int getGameTurnTick() {
|
public int getGameTurnTick() {
|
||||||
return this.gameTurnTick;
|
return this.gameTurnTick;
|
||||||
}
|
}
|
||||||
@ -482,6 +510,16 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RemovableTriggerEvent registerGameEvent(final GlobalScope globalScope, final Trigger trigger,
|
||||||
|
final JassGameEventsWar3 gameEvent) {
|
||||||
|
System.err.println("Game event not yet implemented: " + gameEvent);
|
||||||
|
return new RemovableTriggerEvent() {
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public void heroDeathEvent(final CUnit cUnit) {
|
public void heroDeathEvent(final CUnit cUnit) {
|
||||||
this.simulationRenderController.heroDeathEvent(cUnit);
|
this.simulationRenderController.heroDeathEvent(cUnit);
|
||||||
}
|
}
|
||||||
@ -524,4 +562,19 @@ public class CSimulation implements CPlayerAPI {
|
|||||||
}
|
}
|
||||||
return RemovableTriggerEvent.DO_NOTHING;
|
return RemovableTriggerEvent.DO_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAllItemTypeSlots(final int slots) {
|
||||||
|
System.err.println(
|
||||||
|
"Ignoring call to set all item type slots to: " + slots + " (marketplace is not yet implemented)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllUnitTypeSlots(final int slots) {
|
||||||
|
System.err.println(
|
||||||
|
"Ignoring call to set all unit type slots to: " + slots + " (marketplace is not yet implemented)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeOfDaySuspended(final boolean flag) {
|
||||||
|
this.timeOfDaySuspended = flag;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorStop;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorStop;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CWeaponType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrder;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrder;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderNoTarget;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderNoTarget;
|
||||||
@ -49,6 +50,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegion;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegion;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegionEnumFunction;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegionEnumFunction;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegionManager;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegionManager;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.state.CUnitState;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.unit.CUnitTypeJass;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityTargetCheckReceiver;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityTargetCheckReceiver;
|
||||||
|
|
||||||
@ -263,6 +266,7 @@ public class CUnit extends CWidget {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.stateListenersUpdates.clear();
|
||||||
if (isDead()) {
|
if (isDead()) {
|
||||||
if (this.collisionRectangle != null) {
|
if (this.collisionRectangle != null) {
|
||||||
// Moved this here because doing it on "kill" was able to happen in some cases
|
// Moved this here because doing it on "kill" was able to happen in some cases
|
||||||
@ -988,6 +992,8 @@ public class CUnit extends CWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fireDeathEvents(simulation);
|
||||||
|
simulation.getPlayer(this.playerIndex).fireUnitDeathEvents(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canReach(final AbilityTarget target, final float range) {
|
public boolean canReach(final AbilityTarget target, final float range) {
|
||||||
@ -1610,6 +1616,15 @@ public class CUnit extends CWidget {
|
|||||||
this.defaultBehavior = defaultBehavior;
|
this.defaultBehavior = defaultBehavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CAbilityGoldMine getGoldMineData() {
|
||||||
|
for (final CAbility ability : this.abilities) {
|
||||||
|
if (ability instanceof CAbilityGoldMine) {
|
||||||
|
return ((CAbilityGoldMine) ability);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public int getGold() {
|
public int getGold() {
|
||||||
for (final CAbility ability : this.abilities) {
|
for (final CAbility ability : this.abilities) {
|
||||||
if (ability instanceof CAbilityGoldMine) {
|
if (ability instanceof CAbilityGoldMine) {
|
||||||
@ -1744,4 +1759,141 @@ public class CUnit extends CWidget {
|
|||||||
return this.updateType;
|
return this.updateType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void cancelUpgrade(final CSimulation game) {
|
||||||
|
throw new RuntimeException("NYI");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beginUpgrade(final CSimulation game, final War3ID rawcode) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnitState(final CSimulation game, final CUnitState whichUnitState, final float value) {
|
||||||
|
switch (whichUnitState) {
|
||||||
|
case LIFE:
|
||||||
|
setLife(game, value);
|
||||||
|
break;
|
||||||
|
case MANA:
|
||||||
|
setMana(value);
|
||||||
|
break;
|
||||||
|
case MAX_LIFE:
|
||||||
|
setMaximumLife((int) value);
|
||||||
|
break;
|
||||||
|
case MAX_MANA:
|
||||||
|
setMaximumMana((int) value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getUnitState(final CSimulation game, final CUnitState whichUnitState) {
|
||||||
|
switch (whichUnitState) {
|
||||||
|
case LIFE:
|
||||||
|
return getLife();
|
||||||
|
case MANA:
|
||||||
|
return getMana();
|
||||||
|
case MAX_LIFE:
|
||||||
|
return getMaximumLife();
|
||||||
|
case MAX_MANA:
|
||||||
|
return getMaximumMana();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUnitType(final CUnitTypeJass whichUnitType) {
|
||||||
|
switch (whichUnitType) {
|
||||||
|
case HERO:
|
||||||
|
return getHeroData() != null;
|
||||||
|
case DEAD:
|
||||||
|
return isDead();
|
||||||
|
case STRUCTURE:
|
||||||
|
return isBuilding();
|
||||||
|
|
||||||
|
case FLYING:
|
||||||
|
return getUnitType().getTargetedAs().contains(CTargetType.AIR);
|
||||||
|
case GROUND:
|
||||||
|
return getUnitType().getTargetedAs().contains(CTargetType.GROUND);
|
||||||
|
|
||||||
|
case ATTACKS_FLYING:
|
||||||
|
for (final CUnitAttack attack : getAttacks()) {
|
||||||
|
if (attack.getTargetsAllowed().contains(CTargetType.AIR)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case ATTACKS_GROUND:
|
||||||
|
for (final CUnitAttack attack : getAttacks()) {
|
||||||
|
if (attack.getTargetsAllowed().contains(CTargetType.GROUND)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case MELEE_ATTACKER:
|
||||||
|
boolean hasAttacks = false;
|
||||||
|
for (final CUnitAttack attack : getAttacks()) {
|
||||||
|
if (attack.getWeaponType() != CWeaponType.NORMAL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
hasAttacks = true;
|
||||||
|
}
|
||||||
|
return hasAttacks;
|
||||||
|
|
||||||
|
case RANGED_ATTACKER:
|
||||||
|
for (final CUnitAttack attack : getAttacks()) {
|
||||||
|
if (attack.getWeaponType() != CWeaponType.NORMAL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case GIANT:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.GIANT);
|
||||||
|
case SUMMONED:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.SUMMONED);
|
||||||
|
case STUNNED:
|
||||||
|
return getCurrentBehavior().getHighlightOrderId() == OrderIds.stunned;
|
||||||
|
case PLAGUED:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is plagued: plague is not yet implemented");
|
||||||
|
case SNARED:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is snared: snare is not yet implemented");
|
||||||
|
|
||||||
|
case UNDEAD:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.UNDEAD);
|
||||||
|
case MECHANICAL:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.MECHANICAL);
|
||||||
|
case PEON:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.PEON);
|
||||||
|
case SAPPER:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.SAPPER);
|
||||||
|
case TOWNHALL:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.TOWNHALL);
|
||||||
|
case ANCIENT:
|
||||||
|
return this.unitType.getClassifications().contains(CUnitClassification.ANCIENT);
|
||||||
|
|
||||||
|
case TAUREN:
|
||||||
|
return getUnitType().getClassifications().contains(CUnitClassification.TAUREN);
|
||||||
|
case POISONED:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is poisoned: poison is not yet implemented");
|
||||||
|
case POLYMORPHED:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is POLYMORPHED: POLYMORPHED is not yet implemented");
|
||||||
|
case SLEEPING:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is SLEEPING: SLEEPING is not yet implemented");
|
||||||
|
case RESISTANT:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is RESISTANT: RESISTANT is not yet implemented");
|
||||||
|
case ETHEREAL:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is ETHEREAL: ETHEREAL is not yet implemented");
|
||||||
|
case MAGIC_IMMUNE:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"cannot ask engine if unit is MAGIC_IMMUNE: MAGIC_IMMUNE is not yet implemented");
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ public class CUnitType {
|
|||||||
private final List<War3ID> structuresBuilt;
|
private final List<War3ID> structuresBuilt;
|
||||||
private final List<War3ID> unitsTrained;
|
private final List<War3ID> unitsTrained;
|
||||||
private final List<War3ID> researchesAvailable;
|
private final List<War3ID> researchesAvailable;
|
||||||
|
private final List<War3ID> upgradesTo;
|
||||||
private final CUnitRace unitRace;
|
private final CUnitRace unitRace;
|
||||||
private final int goldCost;
|
private final int goldCost;
|
||||||
private final int lumberCost;
|
private final int lumberCost;
|
||||||
@ -85,8 +86,8 @@ public class CUnitType {
|
|||||||
final CDefenseType defenseType, final float impactZ, final BufferedImage buildingPathingPixelMap,
|
final CDefenseType defenseType, final float impactZ, final BufferedImage buildingPathingPixelMap,
|
||||||
final float deathTime, final EnumSet<CTargetType> targetedAs, final float defaultAcquisitionRange,
|
final float deathTime, final EnumSet<CTargetType> targetedAs, final float defaultAcquisitionRange,
|
||||||
final float minimumAttackRange, final List<War3ID> structuresBuilt, final List<War3ID> unitsTrained,
|
final float minimumAttackRange, final List<War3ID> structuresBuilt, final List<War3ID> unitsTrained,
|
||||||
final List<War3ID> researchesAvailable, final CUnitRace unitRace, final int goldCost, final int lumberCost,
|
final List<War3ID> researchesAvailable, final List<War3ID> upgradesTo, final CUnitRace unitRace,
|
||||||
final int foodUsed, final int foodMade, final int buildTime,
|
final int goldCost, final int lumberCost, final int foodUsed, final int foodMade, final int buildTime,
|
||||||
final EnumSet<CBuildingPathingType> preventedPathingTypes,
|
final EnumSet<CBuildingPathingType> preventedPathingTypes,
|
||||||
final EnumSet<CBuildingPathingType> requiredPathingTypes, final float propWindow, final float turnRate,
|
final EnumSet<CBuildingPathingType> requiredPathingTypes, final float propWindow, final float turnRate,
|
||||||
final List<CUnitTypeRequirement> requirements, final int level, final boolean hero, final int strength,
|
final List<CUnitTypeRequirement> requirements, final int level, final boolean hero, final int strength,
|
||||||
@ -122,6 +123,7 @@ public class CUnitType {
|
|||||||
this.structuresBuilt = structuresBuilt;
|
this.structuresBuilt = structuresBuilt;
|
||||||
this.unitsTrained = unitsTrained;
|
this.unitsTrained = unitsTrained;
|
||||||
this.researchesAvailable = researchesAvailable;
|
this.researchesAvailable = researchesAvailable;
|
||||||
|
this.upgradesTo = upgradesTo;
|
||||||
this.unitRace = unitRace;
|
this.unitRace = unitRace;
|
||||||
this.goldCost = goldCost;
|
this.goldCost = goldCost;
|
||||||
this.lumberCost = lumberCost;
|
this.lumberCost = lumberCost;
|
||||||
@ -262,6 +264,10 @@ public class CUnitType {
|
|||||||
return this.researchesAvailable;
|
return this.researchesAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<War3ID> getUpgradesTo() {
|
||||||
|
return this.upgradesTo;
|
||||||
|
}
|
||||||
|
|
||||||
public CUnitRace getRace() {
|
public CUnitRace getRace() {
|
||||||
return this.unitRace;
|
return this.unitRace;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.trigger.RemovableTriggerEvent;
|
||||||
|
import com.etheller.interpreter.ast.scope.trigger.Trigger;
|
||||||
|
import com.etheller.warsmash.parsers.jass.scope.CommonTriggerExecutionScope;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTarget;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTarget;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.unit.CWidgetEvent;
|
||||||
|
|
||||||
public abstract class CWidget implements AbilityTarget {
|
public abstract class CWidget implements AbilityTarget {
|
||||||
protected static final Rectangle tempRect = new Rectangle();
|
protected static final Rectangle tempRect = new Rectangle();
|
||||||
@ -13,6 +22,8 @@ public abstract class CWidget implements AbilityTarget {
|
|||||||
private float x;
|
private float x;
|
||||||
private float y;
|
private float y;
|
||||||
protected float life;
|
protected float life;
|
||||||
|
private final EnumMap<JassGameEventsWar3, List<CWidgetEvent>> eventTypeToEvents = new EnumMap<>(
|
||||||
|
JassGameEventsWar3.class);
|
||||||
|
|
||||||
public CWidget(final int handleId, final float x, final float y, final float life) {
|
public CWidget(final int handleId, final float x, final float y, final float life) {
|
||||||
this.handleId = handleId;
|
this.handleId = handleId;
|
||||||
@ -78,4 +89,49 @@ public abstract class CWidget implements AbilityTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean isInvulnerable();
|
public abstract boolean isInvulnerable();
|
||||||
|
|
||||||
|
public void fireDeathEvents(final CSimulation simulation) {
|
||||||
|
fireEvents(CommonTriggerExecutionScope::widgetTriggerScope, JassGameEventsWar3.EVENT_WIDGET_DEATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CWidgetEvent> getOrCreateEventList(final JassGameEventsWar3 eventType) {
|
||||||
|
List<CWidgetEvent> playerEvents = this.eventTypeToEvents.get(eventType);
|
||||||
|
if (playerEvents == null) {
|
||||||
|
playerEvents = new ArrayList<>();
|
||||||
|
this.eventTypeToEvents.put(eventType, playerEvents);
|
||||||
|
}
|
||||||
|
return playerEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CWidgetEvent> getEventList(final JassGameEventsWar3 eventType) {
|
||||||
|
return this.eventTypeToEvents.get(eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemovableTriggerEvent addEvent(final GlobalScope globalScope, final Trigger whichTrigger,
|
||||||
|
final JassGameEventsWar3 eventType) {
|
||||||
|
final CWidgetEvent playerEvent = new CWidgetEvent(globalScope, this, whichTrigger, eventType, null);
|
||||||
|
getOrCreateEventList(eventType).add(playerEvent);
|
||||||
|
return playerEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEvent(final CWidgetEvent playerEvent) {
|
||||||
|
final List<CWidgetEvent> eventList = getEventList(playerEvent.getEventType());
|
||||||
|
if (eventList != null) {
|
||||||
|
eventList.remove(playerEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fireEvents(final CommonTriggerExecutionScope.WidgetEventScopeBuilder eventScopeBuilder,
|
||||||
|
final JassGameEventsWar3 eventType) {
|
||||||
|
final List<CWidgetEvent> eventList = getEventList(eventType);
|
||||||
|
if (eventList != null) {
|
||||||
|
for (final CWidgetEvent event : eventList) {
|
||||||
|
event.fire(this, eventScopeBuilder.create(event.getTrigger(), this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemovableTriggerEvent addDeathEvent(final GlobalScope globalScope, final Trigger whichTrigger) {
|
||||||
|
return addEvent(globalScope, whichTrigger, JassGameEventsWar3.EVENT_WIDGET_DEATH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
|
||||||
|
|
||||||
|
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.CSimulation;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
||||||
@ -43,6 +44,9 @@ public class CAbilityAttack extends AbstractCAbility {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (target instanceof CDestructable) {
|
||||||
|
// fall thru to below
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
receiver.orderIdNotAccepted();
|
receiver.orderIdNotAccepted();
|
||||||
return;
|
return;
|
||||||
|
@ -14,6 +14,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbi
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
|
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.queue.CAbilityRally;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.upgrade.CAbilityUpgrade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A visitor for the lowest level inherent types of an ability. It's a bit of a
|
* A visitor for the lowest level inherent types of an ability. It's a bit of a
|
||||||
@ -48,6 +49,8 @@ public interface CAbilityVisitor<T> {
|
|||||||
|
|
||||||
T accept(CAbilityQueue ability);
|
T accept(CAbilityQueue ability);
|
||||||
|
|
||||||
|
T accept(CAbilityUpgrade ability);
|
||||||
|
|
||||||
T accept(CAbilityReviveHero ability);
|
T accept(CAbilityReviveHero ability);
|
||||||
|
|
||||||
T accept(GenericSingleIconActiveAbility ability);
|
T accept(GenericSingleIconActiveAbility ability);
|
||||||
|
@ -42,7 +42,8 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements
|
|||||||
if (unitType != null) {
|
if (unitType != null) {
|
||||||
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||||
final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
|
final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
|
||||||
boolean requirementsMet = true;
|
final boolean techtreeAllowedByMax = player.isTechtreeAllowedByMax(orderIdAsRawtype);
|
||||||
|
boolean requirementsMet = techtreeAllowedByMax;
|
||||||
for (final CUnitTypeRequirement requirement : requirements) {
|
for (final CUnitTypeRequirement requirement : requirements) {
|
||||||
if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
|
if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
|
||||||
requirementsMet = false;
|
requirementsMet = false;
|
||||||
@ -69,8 +70,13 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (final CUnitTypeRequirement requirement : requirements) {
|
if (techtreeAllowedByMax) {
|
||||||
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
|
for (final CUnitTypeRequirement requirement : requirements) {
|
||||||
|
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.techtreeMaximumReached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,7 +114,8 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId, AbilityTarget target) {
|
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId,
|
||||||
|
final AbilityTarget target) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ public class CAbilityHero extends AbstractCAbility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addXp(final CSimulation simulation, final CUnit unit, final int xp) {
|
public void addXp(final CSimulation simulation, final CUnit unit, final int xp) {
|
||||||
this.xp += xp;
|
this.xp += xp * simulation.getPlayer(unit.getPlayerIndex()).getHandicapXP();
|
||||||
final CGameplayConstants gameplayConstants = simulation.getGameplayConstants();
|
final CGameplayConstants gameplayConstants = simulation.getGameplayConstants();
|
||||||
while ((this.heroLevel < gameplayConstants.getMaxHeroLevel())
|
while ((this.heroLevel < gameplayConstants.getMaxHeroLevel())
|
||||||
&& (this.xp >= gameplayConstants.getNeedHeroXPSum(this.heroLevel))) {
|
&& (this.xp >= gameplayConstants.getNeedHeroXPSum(this.heroLevel))) {
|
||||||
|
@ -18,7 +18,9 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAb
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.inventory.CBehaviorDropItem;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.inventory.CBehaviorDropItem;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.inventory.CBehaviorGetItem;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.inventory.CBehaviorGetItem;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.inventory.CBehaviorGiveItemToHero;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CAllianceType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
|||||||
private final List<CAbility>[] itemsHeldAbilities;
|
private final List<CAbility>[] itemsHeldAbilities;
|
||||||
private CBehaviorGetItem behaviorGetItem;
|
private CBehaviorGetItem behaviorGetItem;
|
||||||
private CBehaviorDropItem behaviorDropItem;
|
private CBehaviorDropItem behaviorDropItem;
|
||||||
|
private CBehaviorGiveItemToHero behaviorGiveItem;
|
||||||
|
|
||||||
public CAbilityInventory(final int handleId, final War3ID alias, final boolean canDropItems,
|
public CAbilityInventory(final int handleId, final War3ID alias, final boolean canDropItems,
|
||||||
final boolean canGetItems, final boolean canUseItems, final boolean dropItemsOnDeath,
|
final boolean canGetItems, final boolean canUseItems, final boolean dropItemsOnDeath,
|
||||||
@ -51,6 +54,7 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
|||||||
public void onAdd(final CSimulation game, final CUnit unit) {
|
public void onAdd(final CSimulation game, final CUnit unit) {
|
||||||
this.behaviorGetItem = new CBehaviorGetItem(unit, this);
|
this.behaviorGetItem = new CBehaviorGetItem(unit, this);
|
||||||
this.behaviorDropItem = new CBehaviorDropItem(unit, this);
|
this.behaviorDropItem = new CBehaviorDropItem(unit, this);
|
||||||
|
this.behaviorGiveItem = new CBehaviorGiveItemToHero(unit, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -81,16 +85,37 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((orderId >= OrderIds.itemuse00) && (orderId <= OrderIds.itemuse05)) {
|
else if ((orderId >= OrderIds.itemuse00) && (orderId <= OrderIds.itemuse05)) {
|
||||||
final CAbility cAbility = this.itemsHeldAbilities[orderId - OrderIds.itemuse00].get(0);
|
final int slot = orderId - OrderIds.itemuse00;
|
||||||
|
final CAbility cAbility = this.itemsHeldAbilities[slot].get(0);
|
||||||
int forwardedOrderId = orderId;
|
int forwardedOrderId = orderId;
|
||||||
if (cAbility instanceof GenericSingleIconActiveAbility) {
|
if (cAbility instanceof GenericSingleIconActiveAbility) {
|
||||||
forwardedOrderId = ((GenericSingleIconActiveAbility) cAbility).getBaseOrderId();
|
forwardedOrderId = ((GenericSingleIconActiveAbility) cAbility).getBaseOrderId();
|
||||||
}
|
}
|
||||||
cAbility.checkBeforeQueue(game, caster, forwardedOrderId, target);
|
final boolean checkResult = cAbility.checkBeforeQueue(game, caster, forwardedOrderId, target);
|
||||||
|
if (!checkResult) {
|
||||||
|
// we will never call begin, so we need to consume a charge of perishables here
|
||||||
|
// assuming this is a no-queue instant use perishable... later if we have some
|
||||||
|
// other weird case where "check before queue" false is supposed to mean you
|
||||||
|
// can't use the skill, then this would consume charges without using it, and
|
||||||
|
// that would be stupid but I don't think we will do that since checkCanUse
|
||||||
|
// should be failing at that point. So then we should have never called
|
||||||
|
// checkBeforeQueue.
|
||||||
|
final CItem cItem = this.itemsHeld[slot];
|
||||||
|
consumePerishableCharge(game, caster, slot, cItem);
|
||||||
|
}
|
||||||
|
return checkResult;
|
||||||
}
|
}
|
||||||
return super.checkBeforeQueue(game, caster, orderId, target);
|
return super.checkBeforeQueue(game, caster, orderId, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void consumePerishableCharge(final CSimulation game, final CUnit caster, final int slot,
|
||||||
|
final CItem cItem) {
|
||||||
|
if (cItem.getItemType().isPerishable()) {
|
||||||
|
dropItem(game, caster, slot, caster.getX(), caster.getY(), false);
|
||||||
|
game.removeItem(cItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancelFromQueue(final CSimulation game, final CUnit unit, final int orderId) {
|
public void onCancelFromQueue(final CSimulation game, final CUnit unit, final int orderId) {
|
||||||
|
|
||||||
@ -121,6 +146,11 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
|||||||
return this.behaviorDropItem.reset(itemToDrop, target);
|
return this.behaviorDropItem.reset(itemToDrop, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CBehavior beginDropItem(final CSimulation game, final CUnit caster, final int orderId,
|
||||||
|
final CItem itemToDrop, final CUnit targetHero) {
|
||||||
|
return this.behaviorGiveItem.reset(itemToDrop, targetHero);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId,
|
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId,
|
||||||
final AbilityPointTarget point) {
|
final AbilityPointTarget point) {
|
||||||
@ -133,10 +163,7 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
|||||||
final int slot = orderId - OrderIds.itemuse00;
|
final int slot = orderId - OrderIds.itemuse00;
|
||||||
final CBehavior behavior = this.itemsHeldAbilities[slot].get(0).beginNoTarget(game, caster, orderId);
|
final CBehavior behavior = this.itemsHeldAbilities[slot].get(0).beginNoTarget(game, caster, orderId);
|
||||||
final CItem cItem = this.itemsHeld[slot];
|
final CItem cItem = this.itemsHeld[slot];
|
||||||
if (cItem.getItemType().isPerishable()) {
|
consumePerishableCharge(game, caster, slot, cItem);
|
||||||
dropItem(game, caster, slot, caster.getX(), caster.getY(), false);
|
|
||||||
game.removeItem(cItem);
|
|
||||||
}
|
|
||||||
return behavior;
|
return behavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +199,24 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
|||||||
receiver.orderIdNotAccepted();
|
receiver.orderIdNotAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
receiver.orderIdNotAccepted();
|
else if (orderId == OrderIds.dropitem) {
|
||||||
|
if (target instanceof CUnit) {
|
||||||
|
final CUnit hero = (CUnit) target;
|
||||||
|
if ((hero.getInventoryData() != null) && game.getPlayer(hero.getPlayerIndex())
|
||||||
|
.hasAlliance(unit.getPlayerIndex(), CAllianceType.PASSIVE)) {
|
||||||
|
receiver.targetOk(target);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.orderIdNotAccepted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.orderIdNotAccepted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.orderIdNotAccepted();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,9 +233,12 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
|||||||
@Override
|
@Override
|
||||||
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId,
|
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId,
|
||||||
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
|
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
|
||||||
if (orderId == OrderIds.dropitem) {
|
if (orderId != OrderIds.dropitem) {
|
||||||
receiver.orderIdNotAccepted();
|
receiver.orderIdNotAccepted();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
receiver.targetOk(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,7 +48,8 @@ public final class CAbilityQueue extends AbstractCAbility {
|
|||||||
if (unitType != null) {
|
if (unitType != null) {
|
||||||
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||||
final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
|
final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
|
||||||
boolean requirementsMet = true;
|
final boolean techtreeAllowedByMax = player.isTechtreeAllowedByMax(orderIdAsRawtype);
|
||||||
|
boolean requirementsMet = techtreeAllowedByMax;
|
||||||
for (final CUnitTypeRequirement requirement : requirements) {
|
for (final CUnitTypeRequirement requirement : requirements) {
|
||||||
if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
|
if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
|
||||||
requirementsMet = false;
|
requirementsMet = false;
|
||||||
@ -74,8 +75,13 @@ public final class CAbilityQueue extends AbstractCAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (final CUnitTypeRequirement requirement : requirements) {
|
if (techtreeAllowedByMax) {
|
||||||
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
|
for (final CUnitTypeRequirement requirement : requirements) {
|
||||||
|
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.techtreeMaximumReached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +122,8 @@ public final class CAbilityQueue extends AbstractCAbility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId, AbilityTarget target) {
|
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId,
|
||||||
|
final AbilityTarget target) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,171 @@
|
|||||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.upgrade;
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.upgrade;
|
||||||
|
|
||||||
public class CAbilityUpgrade {
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.util.War3ID;
|
||||||
|
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.CUnitTypeRequirement;
|
||||||
|
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.abilities.targeting.AbilityTarget;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
|
||||||
|
|
||||||
|
public final class CAbilityUpgrade extends AbstractCAbility {
|
||||||
|
private final Set<War3ID> upgradesTo;
|
||||||
|
|
||||||
|
public CAbilityUpgrade(final int handleId, final List<War3ID> upgradesTo) {
|
||||||
|
super(handleId);
|
||||||
|
this.upgradesTo = new LinkedHashSet<>(upgradesTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<War3ID> getUpgradesTo() {
|
||||||
|
return this.upgradesTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerCheckCanUse(final CSimulation game, final CUnit unit, final int orderId,
|
||||||
|
final AbilityActivationReceiver receiver) {
|
||||||
|
final War3ID orderIdAsRawtype = new War3ID(orderId);
|
||||||
|
if (this.upgradesTo.contains(orderIdAsRawtype) && (unit.getBuildQueue()[0] == null)) {
|
||||||
|
final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype);
|
||||||
|
if (unitType != null) {
|
||||||
|
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||||
|
final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
|
||||||
|
final boolean techtreeAllowedByMax = player.isTechtreeAllowedByMax(orderIdAsRawtype);
|
||||||
|
boolean requirementsMet = techtreeAllowedByMax;
|
||||||
|
for (final CUnitTypeRequirement requirement : requirements) {
|
||||||
|
if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
|
||||||
|
requirementsMet = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requirementsMet) {
|
||||||
|
if (player.getGold() >= unitType.getGoldCost()) {
|
||||||
|
if (player.getLumber() >= unitType.getLumberCost()) {
|
||||||
|
if ((unitType.getFoodUsed() == 0)
|
||||||
|
|| ((player.getFoodUsed() + unitType.getFoodUsed()) <= player.getFoodCap())) {
|
||||||
|
receiver.useOk();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.notEnoughResources(ResourceType.FOOD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.notEnoughResources(ResourceType.LUMBER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.notEnoughResources(ResourceType.GOLD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (techtreeAllowedByMax) {
|
||||||
|
for (final CUnitTypeRequirement requirement : requirements) {
|
||||||
|
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.techtreeMaximumReached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.useOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/// ???
|
||||||
|
receiver.useOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
|
||||||
|
final AbilityTargetCheckReceiver<CWidget> receiver) {
|
||||||
|
receiver.orderIdNotAccepted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId,
|
||||||
|
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
|
||||||
|
receiver.orderIdNotAccepted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
|
||||||
|
final AbilityTargetCheckReceiver<Void> receiver) {
|
||||||
|
if (this.upgradesTo.contains(new War3ID(orderId))) {
|
||||||
|
receiver.targetOk(null);
|
||||||
|
}
|
||||||
|
else if (orderId == OrderIds.cancel) {
|
||||||
|
receiver.targetOk(null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.orderIdNotAccepted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId,
|
||||||
|
final AbilityTarget target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAdd(final CSimulation game, final CUnit unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(final CSimulation game, final CUnit unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTick(final CSimulation game, final CUnit unit) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
|
||||||
|
return 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) {
|
||||||
|
if (orderId == OrderIds.cancel) {
|
||||||
|
caster.cancelUpgrade(game);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final War3ID rawcode = new War3ID(orderId);
|
||||||
|
if (this.upgradesTo.contains(rawcode)) {
|
||||||
|
caster.beginUpgrade(game, rawcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T visit(final CAbilityVisitor<T> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancelFromQueue(final CSimulation game, final CUnit unit, final int orderId) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CAbi
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
|
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.queue.CAbilityRally;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.upgrade.CAbilityUpgrade;
|
||||||
|
|
||||||
public class AbilityDisableWhileUnderConstructionVisitor implements CAbilityVisitor<Void> {
|
public class AbilityDisableWhileUnderConstructionVisitor implements CAbilityVisitor<Void> {
|
||||||
public static final AbilityDisableWhileUnderConstructionVisitor INSTANCE = new AbilityDisableWhileUnderConstructionVisitor();
|
public static final AbilityDisableWhileUnderConstructionVisitor INSTANCE = new AbilityDisableWhileUnderConstructionVisitor();
|
||||||
@ -107,7 +108,14 @@ public class AbilityDisableWhileUnderConstructionVisitor implements CAbilityVisi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void accept(CAbilityReviveHero ability) {
|
public Void accept(final CAbilityUpgrade ability) {
|
||||||
|
ability.setDisabled(true);
|
||||||
|
ability.setIconShowing(false);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void accept(final CAbilityReviveHero ability) {
|
||||||
ability.setDisabled(true);
|
ability.setDisabled(true);
|
||||||
ability.setIconShowing(false);
|
ability.setIconShowing(false);
|
||||||
return null;
|
return null;
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.inventory;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CItem;
|
||||||
|
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.abilities.inventory.CAbilityInventory;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetStillAliveVisitor;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedBehavior;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
|
||||||
|
|
||||||
|
public class CBehaviorGiveItemToHero extends CAbstractRangedBehavior {
|
||||||
|
private final CAbilityInventory inventory;
|
||||||
|
private CItem targetItem;
|
||||||
|
private CUnit targetHero;
|
||||||
|
|
||||||
|
public CBehaviorGiveItemToHero(final CUnit unit, final CAbilityInventory inventory) {
|
||||||
|
super(unit);
|
||||||
|
this.inventory = inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CBehaviorGiveItemToHero reset(final CItem targetItem, final CUnit targetHero) {
|
||||||
|
innerReset(targetHero);
|
||||||
|
this.targetItem = targetItem;
|
||||||
|
this.targetHero = targetHero;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWithinRange(final CSimulation simulation) {
|
||||||
|
return this.unit.canReach(this.target, simulation.getGameplayConstants().getGiveItemRange());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endMove(final CSimulation game, final boolean interrupted) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(final CSimulation game) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end(final CSimulation game, final boolean interrupted) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHighlightOrderId() {
|
||||||
|
return OrderIds.dropitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CBehavior update(final CSimulation simulation, final boolean withinFacingWindow) {
|
||||||
|
this.inventory.dropItem(simulation, this.unit, this.targetItem, this.target.getX(), this.target.getY(), true);
|
||||||
|
if (this.targetHero.getInventoryData() != null) {
|
||||||
|
this.targetHero.getInventoryData().giveItem(simulation, this.targetHero, this.targetItem, false);
|
||||||
|
}
|
||||||
|
return this.unit.pollNextOrderBehavior(simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CBehavior updateOnInvalidTarget(final CSimulation simulation) {
|
||||||
|
return this.unit.pollNextOrderBehavior(simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean checkTargetStillValid(final CSimulation simulation) {
|
||||||
|
return this.target.visit(AbilityTargetStillAliveVisitor.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void resetBeforeMoving(final CSimulation simulation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -28,6 +28,9 @@ public enum CDefenseType implements CodeKeyType {
|
|||||||
if (upperCaseTypeString.equals("HEAVY")) {
|
if (upperCaseTypeString.equals("HEAVY")) {
|
||||||
return LARGE;
|
return LARGE;
|
||||||
}
|
}
|
||||||
|
if (upperCaseTypeString.trim().isEmpty()) {
|
||||||
|
System.err.println("bad");
|
||||||
|
}
|
||||||
return valueOf(upperCaseTypeString);
|
return valueOf(upperCaseTypeString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,6 +176,10 @@ public abstract class CBasePlayer implements CPlayerJass {
|
|||||||
return this.slotState;
|
return this.slotState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSlotState(final CPlayerSlotState slotState) {
|
||||||
|
this.slotState = slotState;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTaxRate(final int otherPlayerIndex, final CPlayerState whichResource) {
|
public int getTaxRate(final int otherPlayerIndex, final CPlayerState whichResource) {
|
||||||
final Integer taxRate = this.taxRates[otherPlayerIndex].get(whichResource);
|
final Integer taxRate = this.taxRates[otherPlayerIndex].get(whichResource);
|
||||||
|
@ -34,6 +34,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CPri
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue;
|
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.queue.CAbilityRally;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.upgrade.CAbilityUpgrade;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
|
||||||
@ -144,6 +145,7 @@ public class CUnitData {
|
|||||||
private static final War3ID STRUCTURES_BUILT = War3ID.fromString("ubui");
|
private static final War3ID STRUCTURES_BUILT = War3ID.fromString("ubui");
|
||||||
private static final War3ID UNITS_TRAINED = War3ID.fromString("utra");
|
private static final War3ID UNITS_TRAINED = War3ID.fromString("utra");
|
||||||
private static final War3ID RESEARCHES_AVAILABLE = War3ID.fromString("ures");
|
private static final War3ID RESEARCHES_AVAILABLE = War3ID.fromString("ures");
|
||||||
|
private static final War3ID UPGRADES_TO = War3ID.fromString("uupt");
|
||||||
private static final War3ID REVIVES_HEROES = War3ID.fromString("urev");
|
private static final War3ID REVIVES_HEROES = War3ID.fromString("urev");
|
||||||
private static final War3ID UNIT_RACE = War3ID.fromString("urac");
|
private static final War3ID UNIT_RACE = War3ID.fromString("urac");
|
||||||
|
|
||||||
@ -242,9 +244,13 @@ public class CUnitData {
|
|||||||
}
|
}
|
||||||
final List<War3ID> unitsTrained = unitTypeInstance.getUnitsTrained();
|
final List<War3ID> unitsTrained = unitTypeInstance.getUnitsTrained();
|
||||||
final List<War3ID> researchesAvailable = unitTypeInstance.getResearchesAvailable();
|
final List<War3ID> researchesAvailable = unitTypeInstance.getResearchesAvailable();
|
||||||
|
final List<War3ID> upgradesTo = unitTypeInstance.getUpgradesTo();
|
||||||
if (!unitsTrained.isEmpty() || !researchesAvailable.isEmpty()) {
|
if (!unitsTrained.isEmpty() || !researchesAvailable.isEmpty()) {
|
||||||
unit.add(simulation, new CAbilityQueue(handleIdAllocator.createId(), unitsTrained, researchesAvailable));
|
unit.add(simulation, new CAbilityQueue(handleIdAllocator.createId(), unitsTrained, researchesAvailable));
|
||||||
}
|
}
|
||||||
|
if (!upgradesTo.isEmpty()) {
|
||||||
|
unit.add(simulation, new CAbilityUpgrade(handleIdAllocator.createId(), upgradesTo));
|
||||||
|
}
|
||||||
if (unitTypeInstance.isRevivesHeroes()) {
|
if (unitTypeInstance.isRevivesHeroes()) {
|
||||||
unit.add(simulation, new CAbilityReviveHero(handleIdAllocator.createId()));
|
unit.add(simulation, new CAbilityReviveHero(handleIdAllocator.createId()));
|
||||||
}
|
}
|
||||||
@ -466,6 +472,15 @@ public class CUnitData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String upgradesToString = unitType.getFieldAsString(UPGRADES_TO, 0);
|
||||||
|
final String[] upgradesToStringItems = upgradesToString.trim().split(",");
|
||||||
|
final List<War3ID> upgradesTo = new ArrayList<>();
|
||||||
|
for (final String upgradesToStringItem : upgradesToStringItems) {
|
||||||
|
if (upgradesToStringItem.length() == 4) {
|
||||||
|
upgradesTo.add(War3ID.fromString(upgradesToStringItem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final String researchesAvailableString = unitType.getFieldAsString(RESEARCHES_AVAILABLE, 0);
|
final String researchesAvailableString = unitType.getFieldAsString(RESEARCHES_AVAILABLE, 0);
|
||||||
final String[] researchesAvailableStringItems = researchesAvailableString.trim().split(",");
|
final String[] researchesAvailableStringItems = researchesAvailableString.trim().split(",");
|
||||||
final List<War3ID> researchesAvailable = new ArrayList<>();
|
final List<War3ID> researchesAvailable = new ArrayList<>();
|
||||||
@ -541,11 +556,11 @@ public class CUnitData {
|
|||||||
unitTypeInstance = new CUnitType(unitName, legacyName, typeId, life, manaInitial, manaMaximum, speed,
|
unitTypeInstance = new CUnitType(unitName, legacyName, typeId, life, manaInitial, manaMaximum, speed,
|
||||||
defense, abilityList, isBldg, movementType, moveHeight, collisionSize, classifications, attacks,
|
defense, abilityList, isBldg, movementType, moveHeight, collisionSize, classifications, attacks,
|
||||||
armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs,
|
armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs,
|
||||||
acquisitionRange, minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable, unitRace,
|
acquisitionRange, minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable,
|
||||||
goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes,
|
upgradesTo, unitRace, goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes,
|
||||||
propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus,
|
requiredPathingTypes, propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus,
|
||||||
intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames, properNamesCount,
|
agility, agiPlus, intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames,
|
||||||
canFlee, priority, revivesHeroes);
|
properNamesCount, canFlee, priority, revivesHeroes);
|
||||||
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
||||||
this.jassLegacyNameToUnitId.put(legacyName, typeId);
|
this.jassLegacyNameToUnitId.put(legacyName, typeId);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CItem;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.inventory.CAbilityInventory;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
|
||||||
|
|
||||||
|
public class COrderDropItemAtTargetWidget implements COrder {
|
||||||
|
private final int abilityHandleId;
|
||||||
|
private final int orderId;
|
||||||
|
private final int itemHandleId;
|
||||||
|
private final int targetHeroHandleId;
|
||||||
|
private final boolean queued;
|
||||||
|
|
||||||
|
public COrderDropItemAtTargetWidget(final int abilityHandleId, final int orderId, final int itemHandleId,
|
||||||
|
final int targetHeroHandleId, final boolean queued) {
|
||||||
|
this.abilityHandleId = abilityHandleId;
|
||||||
|
this.orderId = orderId;
|
||||||
|
this.itemHandleId = itemHandleId;
|
||||||
|
this.targetHeroHandleId = targetHeroHandleId;
|
||||||
|
this.queued = queued;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAbilityHandleId() {
|
||||||
|
return this.abilityHandleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrderId() {
|
||||||
|
return this.orderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CWidget getTarget(final CSimulation game) {
|
||||||
|
final CWidget target = game.getWidget(this.targetHeroHandleId);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isQueued() {
|
||||||
|
return this.queued;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CBehavior begin(final CSimulation game, final CUnit caster) {
|
||||||
|
final CAbilityInventory ability = (CAbilityInventory) game.getAbility(this.abilityHandleId);
|
||||||
|
ability.checkCanUse(game, caster, this.orderId, this.abilityActivationReceiver.reset());
|
||||||
|
if (this.abilityActivationReceiver.isUseOk()) {
|
||||||
|
final CItem itemToDrop = (CItem) game.getWidget(this.itemHandleId);
|
||||||
|
final CUnit targetHero = (CUnit) game.getWidget(this.targetHeroHandleId);
|
||||||
|
return ability.beginDropItem(game, caster, this.orderId, itemToDrop, targetHero);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
game.getCommandErrorListener(caster.getPlayerIndex())
|
||||||
|
.showCommandError(this.abilityActivationReceiver.getMessage());
|
||||||
|
return caster.pollNextOrderBehavior(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = (prime * result) + this.abilityHandleId;
|
||||||
|
result = (prime * result) + this.itemHandleId;
|
||||||
|
result = (prime * result) + this.orderId;
|
||||||
|
result = (prime * result) + (this.queued ? 1231 : 1237);
|
||||||
|
result = (prime * result) + this.targetHeroHandleId;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final COrderDropItemAtTargetWidget other = (COrderDropItemAtTargetWidget) obj;
|
||||||
|
if (this.abilityHandleId != other.abilityHandleId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.itemHandleId != other.itemHandleId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.orderId != other.orderId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.queued != other.queued) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.targetHeroHandleId != other.targetHeroHandleId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -50,7 +50,7 @@ public class COrderTargetWidget implements COrder {
|
|||||||
if (abilityActivationReceiver.isUseOk()) {
|
if (abilityActivationReceiver.isUseOk()) {
|
||||||
final CWidget target = game.getWidget(this.targetHandleId);
|
final CWidget target = game.getWidget(this.targetHandleId);
|
||||||
final StringMsgTargetCheckReceiver<CWidget> targetReceiver = (StringMsgTargetCheckReceiver<CWidget>) targetCheckReceiver;
|
final StringMsgTargetCheckReceiver<CWidget> targetReceiver = (StringMsgTargetCheckReceiver<CWidget>) targetCheckReceiver;
|
||||||
ability.checkCanTarget(game, caster, this.orderId, target, targetReceiver);
|
ability.checkCanTarget(game, caster, this.orderId, target, targetReceiver.reset());
|
||||||
if (targetReceiver.getTarget() != null) {
|
if (targetReceiver.getTarget() != null) {
|
||||||
return ability.begin(game, caster, this.orderId, targetReceiver.getTarget());
|
return ability.begin(game, caster, this.orderId, targetReceiver.getTarget());
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,12 @@ import java.util.Map;
|
|||||||
import com.etheller.interpreter.ast.scope.GlobalScope;
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
import com.etheller.interpreter.ast.scope.trigger.RemovableTriggerEvent;
|
import com.etheller.interpreter.ast.scope.trigger.RemovableTriggerEvent;
|
||||||
import com.etheller.interpreter.ast.scope.trigger.Trigger;
|
import com.etheller.interpreter.ast.scope.trigger.Trigger;
|
||||||
|
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
|
||||||
import com.etheller.warsmash.parsers.jass.scope.CommonTriggerExecutionScope;
|
import com.etheller.warsmash.parsers.jass.scope.CommonTriggerExecutionScope;
|
||||||
import com.etheller.warsmash.util.War3ID;
|
import com.etheller.warsmash.util.War3ID;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CPlayerStateListener;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CPlayerStateListener;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CPlayerStateListener.CPlayerStateNotifier;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CPlayerStateListener.CPlayerStateNotifier;
|
||||||
|
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.CUnit;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.config.CBasePlayer;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.config.CBasePlayer;
|
||||||
@ -21,19 +23,37 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEve
|
|||||||
public class CPlayer extends CBasePlayer {
|
public class CPlayer extends CBasePlayer {
|
||||||
private final CRace race;
|
private final CRace race;
|
||||||
private final float[] startLocation;
|
private final float[] startLocation;
|
||||||
private int gold = 500;
|
private int gold;
|
||||||
private int lumber = 150;
|
private int lumber;
|
||||||
|
private int heroTokens;
|
||||||
private int foodCap;
|
private int foodCap;
|
||||||
private int foodUsed;
|
private int foodUsed;
|
||||||
|
private int foodCapCeiling = 101; // TODO should not have a default, I put 101 to make it stand out
|
||||||
private final Map<War3ID, Integer> rawcodeToTechtreeUnlocked = new HashMap<>();
|
private final Map<War3ID, Integer> rawcodeToTechtreeUnlocked = new HashMap<>();
|
||||||
|
private final Map<War3ID, Integer> rawcodeToTechtreeMaxAllowed = new HashMap<>();
|
||||||
private final List<CUnit> heroes = new ArrayList<>();
|
private final List<CUnit> heroes = new ArrayList<>();
|
||||||
private final EnumMap<JassGameEventsWar3, List<CPlayerEvent>> eventTypeToEvents = new EnumMap<>(
|
private final EnumMap<JassGameEventsWar3, List<CPlayerEvent>> eventTypeToEvents = new EnumMap<>(
|
||||||
JassGameEventsWar3.class);
|
JassGameEventsWar3.class);
|
||||||
|
|
||||||
|
// Player state data
|
||||||
|
private boolean givesBounty = false;
|
||||||
|
private boolean alliedVictory = false;
|
||||||
|
private int gameResult;
|
||||||
|
private int placed;
|
||||||
|
private boolean observerOnDeath;
|
||||||
|
private boolean observer;
|
||||||
|
private boolean unfollowable;
|
||||||
|
private int goldUpkeepRate;
|
||||||
|
private int lumberUpkeepRate;
|
||||||
|
private int goldGathered;
|
||||||
|
private int lumberGathered;
|
||||||
|
private boolean noCreepSleep;
|
||||||
|
|
||||||
// if you use triggers for this then the transient tag here becomes really
|
// if you use triggers for this then the transient tag here becomes really
|
||||||
// questionable -- it already was -- but I meant for those to inform us
|
// questionable -- it already was -- but I meant for those to inform us
|
||||||
// which fields shouldn't be persisted if we do game state save later
|
// which fields shouldn't be persisted if we do game state save later
|
||||||
private transient CPlayerStateNotifier stateNotifier = new CPlayerStateNotifier();
|
private transient CPlayerStateNotifier stateNotifier = new CPlayerStateNotifier();
|
||||||
|
private float handicapXP;
|
||||||
|
|
||||||
public CPlayer(final CRace race, final float[] startLocation, final CBasePlayer configPlayer) {
|
public CPlayer(final CRace race, final float[] startLocation, final CBasePlayer configPlayer) {
|
||||||
super(configPlayer);
|
super(configPlayer);
|
||||||
@ -57,6 +77,10 @@ public class CPlayer extends CBasePlayer {
|
|||||||
return this.lumber;
|
return this.lumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getHeroTokens() {
|
||||||
|
return this.heroTokens;
|
||||||
|
}
|
||||||
|
|
||||||
public int getFoodCap() {
|
public int getFoodCap() {
|
||||||
return this.foodCap;
|
return this.foodCap;
|
||||||
}
|
}
|
||||||
@ -65,6 +89,10 @@ public class CPlayer extends CBasePlayer {
|
|||||||
return this.foodUsed;
|
return this.foodUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getFoodCapCeiling() {
|
||||||
|
return this.foodCapCeiling;
|
||||||
|
}
|
||||||
|
|
||||||
public float[] getStartLocation() {
|
public float[] getStartLocation() {
|
||||||
return this.startLocation;
|
return this.startLocation;
|
||||||
}
|
}
|
||||||
@ -79,11 +107,21 @@ public class CPlayer extends CBasePlayer {
|
|||||||
this.stateNotifier.lumberChanged();
|
this.stateNotifier.lumberChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHeroTokens(final int heroTokens) {
|
||||||
|
this.heroTokens = heroTokens;
|
||||||
|
this.stateNotifier.heroTokensChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public void setFoodCap(final int foodCap) {
|
public void setFoodCap(final int foodCap) {
|
||||||
this.foodCap = foodCap;
|
this.foodCap = foodCap;
|
||||||
this.stateNotifier.foodChanged();
|
this.stateNotifier.foodChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFoodCapCeiling(final int foodCapCeiling) {
|
||||||
|
this.foodCapCeiling = foodCapCeiling;
|
||||||
|
this.stateNotifier.foodChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public void setFoodUsed(final int foodUsed) {
|
public void setFoodUsed(final int foodUsed) {
|
||||||
this.foodUsed = foodUsed;
|
this.foodUsed = foodUsed;
|
||||||
this.stateNotifier.foodChanged();
|
this.stateNotifier.foodChanged();
|
||||||
@ -117,6 +155,18 @@ public class CPlayer extends CBasePlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTechtreeMaxAllowed(final War3ID war3id, final int maximum) {
|
||||||
|
this.rawcodeToTechtreeMaxAllowed.put(war3id, maximum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTechtreeMaxAllowed(final War3ID war3id) {
|
||||||
|
final Integer maxAllowed = this.rawcodeToTechtreeMaxAllowed.get(war3id);
|
||||||
|
if (maxAllowed != null) {
|
||||||
|
return maxAllowed;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
public void addStateListener(final CPlayerStateListener listener) {
|
public void addStateListener(final CPlayerStateListener listener) {
|
||||||
this.stateNotifier.subscribe(listener);
|
this.stateNotifier.subscribe(listener);
|
||||||
}
|
}
|
||||||
@ -169,16 +219,17 @@ public class CPlayer extends CBasePlayer {
|
|||||||
|
|
||||||
public void onHeroDeath(final CUnit hero) {
|
public void onHeroDeath(final CUnit hero) {
|
||||||
this.stateNotifier.heroDeath();
|
this.stateNotifier.heroDeath();
|
||||||
firePlayerUnitEvents(hero, CommonTriggerExecutionScope.playerHeroRevivableScope(hero),
|
firePlayerUnitEvents(hero, CommonTriggerExecutionScope::playerHeroRevivableScope,
|
||||||
JassGameEventsWar3.EVENT_PLAYER_HERO_REVIVABLE);
|
JassGameEventsWar3.EVENT_PLAYER_HERO_REVIVABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void firePlayerUnitEvents(final CUnit hero, final CommonTriggerExecutionScope eventScope,
|
private void firePlayerUnitEvents(final CUnit hero,
|
||||||
|
final CommonTriggerExecutionScope.UnitEventScopeBuilder eventScopeBuilder,
|
||||||
final JassGameEventsWar3 eventType) {
|
final JassGameEventsWar3 eventType) {
|
||||||
final List<CPlayerEvent> eventList = getEventList(eventType);
|
final List<CPlayerEvent> eventList = getEventList(eventType);
|
||||||
if (eventList != null) {
|
if (eventList != null) {
|
||||||
for (final CPlayerEvent event : eventList) {
|
for (final CPlayerEvent event : eventList) {
|
||||||
event.fire(hero, eventScope);
|
event.fire(hero, eventScopeBuilder.create(event.getTrigger(), hero));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,10 +239,20 @@ public class CPlayer extends CBasePlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void fireHeroLevelEvents(final CUnit hero) {
|
public void fireHeroLevelEvents(final CUnit hero) {
|
||||||
firePlayerUnitEvents(hero, CommonTriggerExecutionScope.playerHeroRevivableScope(hero),
|
firePlayerUnitEvents(hero, CommonTriggerExecutionScope::playerHeroRevivableScope,
|
||||||
JassGameEventsWar3.EVENT_PLAYER_HERO_LEVEL);
|
JassGameEventsWar3.EVENT_PLAYER_HERO_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fireUnitDeathEvents(final CUnit dyingUnit, final CUnit killingUnit) {
|
||||||
|
final List<CPlayerEvent> eventList = getEventList(JassGameEventsWar3.EVENT_PLAYER_UNIT_DEATH);
|
||||||
|
if (eventList != null) {
|
||||||
|
for (final CPlayerEvent event : eventList) {
|
||||||
|
event.fire(dyingUnit,
|
||||||
|
CommonTriggerExecutionScope.playerUnitDeathScope(event.getTrigger(), dyingUnit, killingUnit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<CPlayerEvent> getOrCreateEventList(final JassGameEventsWar3 eventType) {
|
private List<CPlayerEvent> getOrCreateEventList(final JassGameEventsWar3 eventType) {
|
||||||
List<CPlayerEvent> playerEvents = this.eventTypeToEvents.get(eventType);
|
List<CPlayerEvent> playerEvents = this.eventTypeToEvents.get(eventType);
|
||||||
if (playerEvents == null) {
|
if (playerEvents == null) {
|
||||||
@ -208,7 +269,14 @@ public class CPlayer extends CBasePlayer {
|
|||||||
@Override
|
@Override
|
||||||
public RemovableTriggerEvent addEvent(final GlobalScope globalScope, final Trigger whichTrigger,
|
public RemovableTriggerEvent addEvent(final GlobalScope globalScope, final Trigger whichTrigger,
|
||||||
final JassGameEventsWar3 eventType) {
|
final JassGameEventsWar3 eventType) {
|
||||||
final CPlayerEvent playerEvent = new CPlayerEvent(globalScope, this, whichTrigger, eventType);
|
final CPlayerEvent playerEvent = new CPlayerEvent(globalScope, this, whichTrigger, eventType, null);
|
||||||
|
getOrCreateEventList(eventType).add(playerEvent);
|
||||||
|
return playerEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemovableTriggerEvent addUnitEvent(final GlobalScope globalScope, final Trigger whichTrigger,
|
||||||
|
final JassGameEventsWar3 eventType, final TriggerBooleanExpression filter) {
|
||||||
|
final CPlayerEvent playerEvent = new CPlayerEvent(globalScope, this, whichTrigger, eventType, filter);
|
||||||
getOrCreateEventList(eventType).add(playerEvent);
|
getOrCreateEventList(eventType).add(playerEvent);
|
||||||
return playerEvent;
|
return playerEvent;
|
||||||
}
|
}
|
||||||
@ -220,4 +288,126 @@ public class CPlayer extends CBasePlayer {
|
|||||||
eventList.remove(playerEvent);
|
eventList.remove(playerEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPlayerState(final CSimulation simulation, final CPlayerState whichPlayerState, final int value) {
|
||||||
|
switch (whichPlayerState) {
|
||||||
|
case GAME_RESULT:
|
||||||
|
this.gameResult = value;
|
||||||
|
break;
|
||||||
|
case RESOURCE_GOLD:
|
||||||
|
setGold(value);
|
||||||
|
break;
|
||||||
|
case RESOURCE_LUMBER:
|
||||||
|
setLumber(value);
|
||||||
|
break;
|
||||||
|
case RESOURCE_HERO_TOKENS:
|
||||||
|
setHeroTokens(value);
|
||||||
|
break;
|
||||||
|
case RESOURCE_FOOD_CAP:
|
||||||
|
setFoodCap(value);
|
||||||
|
break;
|
||||||
|
case RESOURCE_FOOD_USED:
|
||||||
|
setFoodUsed(value);
|
||||||
|
break;
|
||||||
|
case FOOD_CAP_CEILING:
|
||||||
|
setFoodCapCeiling(value);
|
||||||
|
break;
|
||||||
|
case ALLIED_VICTORY:
|
||||||
|
this.alliedVictory = (value != 0);
|
||||||
|
break;
|
||||||
|
case GIVES_BOUNTY:
|
||||||
|
this.givesBounty = (value != 0);
|
||||||
|
break;
|
||||||
|
case PLACED:
|
||||||
|
this.placed = value;
|
||||||
|
case OBSERVER_ON_DEATH:
|
||||||
|
this.observerOnDeath = (value != 0);
|
||||||
|
case OBSERVER:
|
||||||
|
this.observer = (value != 0);
|
||||||
|
case UNFOLLOWABLE:
|
||||||
|
this.unfollowable = (value != 0);
|
||||||
|
case GOLD_UPKEEP_RATE:
|
||||||
|
this.goldUpkeepRate = value;
|
||||||
|
break;
|
||||||
|
case LUMBER_UPKEEP_RATE:
|
||||||
|
this.lumberUpkeepRate = value;
|
||||||
|
break;
|
||||||
|
case GOLD_GATHERED:
|
||||||
|
this.goldGathered = value;
|
||||||
|
break;
|
||||||
|
case LUMBER_GATHERED:
|
||||||
|
this.goldGathered = value;
|
||||||
|
break;
|
||||||
|
case NO_CREEP_SLEEP:
|
||||||
|
this.noCreepSleep = (value != 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPlayerState(final CSimulation simulation, final CPlayerState whichPlayerState) {
|
||||||
|
switch (whichPlayerState) {
|
||||||
|
case GAME_RESULT:
|
||||||
|
return this.gameResult;
|
||||||
|
case RESOURCE_GOLD:
|
||||||
|
return getGold();
|
||||||
|
case RESOURCE_LUMBER:
|
||||||
|
return getLumber();
|
||||||
|
case RESOURCE_HERO_TOKENS:
|
||||||
|
return getHeroTokens();
|
||||||
|
case RESOURCE_FOOD_CAP:
|
||||||
|
return getFoodCap();
|
||||||
|
case RESOURCE_FOOD_USED:
|
||||||
|
return getFoodUsed();
|
||||||
|
case FOOD_CAP_CEILING:
|
||||||
|
return getFoodCapCeiling();
|
||||||
|
case ALLIED_VICTORY:
|
||||||
|
return this.alliedVictory ? 1 : 0;
|
||||||
|
case GIVES_BOUNTY:
|
||||||
|
return this.givesBounty ? 1 : 0;
|
||||||
|
case PLACED:
|
||||||
|
return this.placed;
|
||||||
|
case OBSERVER_ON_DEATH:
|
||||||
|
return this.observerOnDeath ? 1 : 0;
|
||||||
|
case OBSERVER:
|
||||||
|
return this.observer ? 1 : 0;
|
||||||
|
case UNFOLLOWABLE:
|
||||||
|
return this.unfollowable ? 1 : 0;
|
||||||
|
case GOLD_UPKEEP_RATE:
|
||||||
|
return this.goldUpkeepRate;
|
||||||
|
case LUMBER_UPKEEP_RATE:
|
||||||
|
return this.lumberUpkeepRate;
|
||||||
|
case GOLD_GATHERED:
|
||||||
|
return this.goldGathered;
|
||||||
|
case LUMBER_GATHERED:
|
||||||
|
return this.lumberGathered;
|
||||||
|
case NO_CREEP_SLEEP:
|
||||||
|
return this.noCreepSleep ? 1 : 0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isObserver() {
|
||||||
|
return this.observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTechtreeAllowedByMax(final War3ID techtree) {
|
||||||
|
final int techtreeMaxAllowed = getTechtreeMaxAllowed(techtree);
|
||||||
|
if (techtreeMaxAllowed > 0) {
|
||||||
|
if (getTechtreeUnlocked(techtree) >= techtreeMaxAllowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHandicapXP(final float handicapXP) {
|
||||||
|
this.handicapXP = handicapXP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getHandicapXP() {
|
||||||
|
return this.handicapXP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import com.etheller.interpreter.ast.scope.GlobalScope;
|
|||||||
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
import com.etheller.interpreter.ast.scope.trigger.RemovableTriggerEvent;
|
import com.etheller.interpreter.ast.scope.trigger.RemovableTriggerEvent;
|
||||||
import com.etheller.interpreter.ast.scope.trigger.Trigger;
|
import com.etheller.interpreter.ast.scope.trigger.Trigger;
|
||||||
|
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
|
||||||
|
import com.etheller.warsmash.parsers.jass.scope.CommonTriggerExecutionScope;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
|
||||||
|
|
||||||
@ -12,13 +14,15 @@ public class CPlayerEvent implements RemovableTriggerEvent {
|
|||||||
private final CPlayerJass player;
|
private final CPlayerJass player;
|
||||||
private final Trigger trigger;
|
private final Trigger trigger;
|
||||||
private final JassGameEventsWar3 eventType;
|
private final JassGameEventsWar3 eventType;
|
||||||
|
private final TriggerBooleanExpression filter;
|
||||||
|
|
||||||
public CPlayerEvent(final GlobalScope globalScope, final CPlayerJass player, final Trigger trigger,
|
public CPlayerEvent(final GlobalScope globalScope, final CPlayerJass player, final Trigger trigger,
|
||||||
final JassGameEventsWar3 eventType) {
|
final JassGameEventsWar3 eventType, final TriggerBooleanExpression filter) {
|
||||||
this.globalScope = globalScope;
|
this.globalScope = globalScope;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.trigger = trigger;
|
this.trigger = trigger;
|
||||||
this.eventType = eventType;
|
this.eventType = eventType;
|
||||||
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Trigger getTrigger() {
|
public Trigger getTrigger() {
|
||||||
@ -35,6 +39,13 @@ public class CPlayerEvent implements RemovableTriggerEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void fire(final CUnit hero, final TriggerExecutionScope scope) {
|
public void fire(final CUnit hero, final TriggerExecutionScope scope) {
|
||||||
this.trigger.evaluate(this.globalScope, scope);
|
if (this.filter != null) {
|
||||||
|
if (!this.filter.evaluate(this.globalScope, CommonTriggerExecutionScope.filterScope(scope, hero))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.trigger.evaluate(this.globalScope, scope)) {
|
||||||
|
this.trigger.execute(this.globalScope, scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players;
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players;
|
||||||
|
|
||||||
public enum CPlayerState {
|
public enum CPlayerState {
|
||||||
|
GAME_RESULT,
|
||||||
// current resource levels
|
// current resource levels
|
||||||
//
|
//
|
||||||
RESOURCE_GOLD,
|
RESOURCE_GOLD,
|
||||||
|
@ -5,6 +5,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
|||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorHoldPosition;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorHoldPosition;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderDropItemAtPoint;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderDropItemAtPoint;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderDropItemAtTargetWidget;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderNoTarget;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderNoTarget;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderTargetPoint;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderTargetPoint;
|
||||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderTargetWidget;
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrderTargetWidget;
|
||||||
@ -38,6 +39,16 @@ public class CPlayerUnitOrderExecutor implements CPlayerUnitOrderListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void issueDropItemAtTargetOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
||||||
|
final int targetItemHandleId, final int targetHeroHandleId, final boolean queue) {
|
||||||
|
final CUnit unit = this.game.getUnit(unitHandleId);
|
||||||
|
if (this.playerIndex == unit.getPlayerIndex()) {
|
||||||
|
unit.order(this.game, new COrderDropItemAtTargetWidget(abilityHandleId, orderId, targetItemHandleId,
|
||||||
|
targetHeroHandleId, queue), queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void issuePointOrder(final int unitHandleId, final int abilityHandleId, final int orderId, final float x,
|
public void issuePointOrder(final int unitHandleId, final int abilityHandleId, final int orderId, final float x,
|
||||||
final float y, final boolean queue) {
|
final float y, final boolean queue) {
|
||||||
|
@ -8,6 +8,9 @@ public interface CPlayerUnitOrderListener {
|
|||||||
void issueDropItemAtPointOrder(int unitHandleId, int abilityHandleId, int orderId, int targetHandleId, float x,
|
void issueDropItemAtPointOrder(int unitHandleId, int abilityHandleId, int orderId, int targetHandleId, float x,
|
||||||
float y, final boolean queue);
|
float y, final boolean queue);
|
||||||
|
|
||||||
|
void issueDropItemAtTargetOrder(int unitHandleId, int abilityHandleId, int orderId, int targetItemHandleId,
|
||||||
|
int targetHeroHandleId, final boolean queue);
|
||||||
|
|
||||||
void issueImmediateOrder(int unitHandleId, int abilityHandleId, int orderId, boolean queue);
|
void issueImmediateOrder(int unitHandleId, int abilityHandleId, int orderId, boolean queue);
|
||||||
|
|
||||||
void unitCancelTrainingItem(int unitHandleId, int cancelIndex);
|
void unitCancelTrainingItem(int unitHandleId, int cancelIndex);
|
||||||
|
@ -14,7 +14,7 @@ public enum CRace {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CRace[] VALUES = values();
|
public static CRace[] VALUES = { null, HUMAN, ORC, UNDEAD, NIGHTELF, DEMON, null, OTHER };
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return this.id;
|
return this.id;
|
||||||
|
@ -20,10 +20,10 @@ public class CRegionTriggerEnter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void fire(final CUnit unit, final CRegion region) {
|
public void fire(final CUnit unit, final CRegion region) {
|
||||||
if (this.filter.evaluate(this.globalScope,
|
if ((this.filter == null) || this.filter.evaluate(this.globalScope,
|
||||||
CommonTriggerExecutionScope.filterScope(TriggerExecutionScope.EMPTY, unit))) {
|
CommonTriggerExecutionScope.filterScope(TriggerExecutionScope.EMPTY, unit))) {
|
||||||
final CommonTriggerExecutionScope eventScope = CommonTriggerExecutionScope
|
final CommonTriggerExecutionScope eventScope = CommonTriggerExecutionScope
|
||||||
.unitEnterRegionScope(TriggerExecutionScope.EMPTY, unit, region);
|
.unitEnterRegionScope(this.trigger, TriggerExecutionScope.EMPTY, unit, region);
|
||||||
if (this.trigger.evaluate(this.globalScope, eventScope)) {
|
if (this.trigger.evaluate(this.globalScope, eventScope)) {
|
||||||
this.trigger.execute(this.globalScope, eventScope);
|
this.trigger.execute(this.globalScope, eventScope);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ public class CRegionTriggerLeave {
|
|||||||
if (this.filter.evaluate(this.globalScope,
|
if (this.filter.evaluate(this.globalScope,
|
||||||
CommonTriggerExecutionScope.filterScope(TriggerExecutionScope.EMPTY, unit))) {
|
CommonTriggerExecutionScope.filterScope(TriggerExecutionScope.EMPTY, unit))) {
|
||||||
final CommonTriggerExecutionScope eventScope = CommonTriggerExecutionScope
|
final CommonTriggerExecutionScope eventScope = CommonTriggerExecutionScope
|
||||||
.unitLeaveRegionScope(TriggerExecutionScope.EMPTY, unit, region);
|
.unitLeaveRegionScope(this.trigger, TriggerExecutionScope.EMPTY, unit, region);
|
||||||
if (this.trigger.evaluate(this.globalScope, eventScope)) {
|
if (this.trigger.evaluate(this.globalScope, eventScope)) {
|
||||||
this.trigger.execute(this.globalScope, eventScope);
|
this.trigger.execute(this.globalScope, eventScope);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.sound;
|
||||||
|
|
||||||
|
public class CMIDISound implements CSound {
|
||||||
|
private final String soundLabel;
|
||||||
|
private final int fadeInRate;
|
||||||
|
private final int fadeOutRate;
|
||||||
|
|
||||||
|
public CMIDISound(final String soundLabel, final int fadeInRate, final int fadeOutRate) {
|
||||||
|
this.soundLabel = soundLabel;
|
||||||
|
this.fadeInRate = fadeInRate;
|
||||||
|
this.fadeOutRate = fadeOutRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
System.err.println(
|
||||||
|
"Not starting MIDI sound because we don't have a LibGDX API to play those: " + this.soundLabel);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.sound;
|
||||||
|
|
||||||
|
public interface CSound {
|
||||||
|
void start();
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.sound;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.audio.Sound;
|
||||||
|
import com.etheller.warsmash.viewer5.AudioBufferSource;
|
||||||
|
import com.etheller.warsmash.viewer5.AudioContext;
|
||||||
|
import com.etheller.warsmash.viewer5.AudioPanner;
|
||||||
|
|
||||||
|
public class CSoundFilename implements CSound {
|
||||||
|
|
||||||
|
private final Sound sound;
|
||||||
|
private final boolean looping;
|
||||||
|
private final boolean stopWhenOutOfRange;
|
||||||
|
private final int fadeInRate;
|
||||||
|
private final int fadeOutRate;
|
||||||
|
private final AudioContext audioContext;
|
||||||
|
private float x;
|
||||||
|
private float y;
|
||||||
|
private float z;
|
||||||
|
private final float volume = 1.0f;
|
||||||
|
private final float pitch = 1.0f;
|
||||||
|
private final float minDistance = 99999;
|
||||||
|
private final float distanceCutoff = 99999;
|
||||||
|
private final String eaxSetting;
|
||||||
|
|
||||||
|
public CSoundFilename(final Sound sound, final AudioContext audioContext, final boolean looping,
|
||||||
|
final boolean stopWhenOutOfRange, final int fadeInRate, final int fadeOutRate, final String eaxSetting) {
|
||||||
|
this.sound = sound;
|
||||||
|
this.audioContext = audioContext;
|
||||||
|
this.looping = looping;
|
||||||
|
this.stopWhenOutOfRange = stopWhenOutOfRange;
|
||||||
|
this.fadeInRate = fadeInRate;
|
||||||
|
this.fadeOutRate = fadeOutRate;
|
||||||
|
this.eaxSetting = eaxSetting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(final float x, final float y, final float z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
if (this.audioContext == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final AudioPanner panner = this.audioContext.createPanner(this.stopWhenOutOfRange);
|
||||||
|
final AudioBufferSource source = this.audioContext.createBufferSource();
|
||||||
|
|
||||||
|
// Panner settings
|
||||||
|
panner.setPosition(this.x, this.y, this.z);
|
||||||
|
panner.setDistances(this.distanceCutoff, this.minDistance);
|
||||||
|
panner.connect(this.audioContext.destination);
|
||||||
|
|
||||||
|
// Source.
|
||||||
|
source.buffer = this.sound;
|
||||||
|
source.connect(panner);
|
||||||
|
|
||||||
|
// Make a sound.
|
||||||
|
source.start(0, this.volume, this.pitch, this.looping);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.sound;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.viewer5.AudioContext;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSound;
|
||||||
|
|
||||||
|
public class CSoundFromLabel implements CSound {
|
||||||
|
|
||||||
|
private final UnitSound sound;
|
||||||
|
private final boolean looping;
|
||||||
|
private final boolean is3d;
|
||||||
|
private final boolean stopWhenOutOfRange;
|
||||||
|
private final int fadeInRate;
|
||||||
|
private final int fadeOutRate;
|
||||||
|
private final AudioContext audioContext;
|
||||||
|
|
||||||
|
public CSoundFromLabel(final UnitSound sound, final AudioContext audioContext, final boolean looping,
|
||||||
|
final boolean is3d, final boolean stopWhenOutOfRange, final int fadeInRate, final int fadeOutRate) {
|
||||||
|
this.sound = sound;
|
||||||
|
this.audioContext = audioContext;
|
||||||
|
this.looping = looping;
|
||||||
|
this.is3d = is3d;
|
||||||
|
this.stopWhenOutOfRange = stopWhenOutOfRange;
|
||||||
|
this.fadeInRate = fadeInRate;
|
||||||
|
this.fadeOutRate = fadeOutRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
this.sound.play(this.audioContext, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -24,9 +24,10 @@ public class CTimerJass extends CTimer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFire() {
|
public void onFire() {
|
||||||
final CommonTriggerExecutionScope executionScope = CommonTriggerExecutionScope.expiringTimer(this);
|
final CommonTriggerExecutionScope handlerScope = CommonTriggerExecutionScope.expiringTimer(null, this);
|
||||||
this.handlerFunc.call(Collections.emptyList(), this.jassGlobalScope, executionScope);
|
this.handlerFunc.call(Collections.emptyList(), this.jassGlobalScope, handlerScope);
|
||||||
for (final Trigger trigger : this.eventTriggers) {
|
for (final Trigger trigger : this.eventTriggers) {
|
||||||
|
final CommonTriggerExecutionScope executionScope = CommonTriggerExecutionScope.expiringTimer(trigger, this);
|
||||||
if (trigger.evaluate(this.jassGlobalScope, executionScope)) {
|
if (trigger.evaluate(this.jassGlobalScope, executionScope)) {
|
||||||
trigger.execute(this.jassGlobalScope, executionScope);
|
trigger.execute(this.jassGlobalScope, executionScope);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ public enum CDamageType {
|
|||||||
DEMOLITION,
|
DEMOLITION,
|
||||||
SLOW_POISON,
|
SLOW_POISON,
|
||||||
SPIRIT_LINK,
|
SPIRIT_LINK,
|
||||||
SHADOW_STRIKE;
|
SHADOW_STRIKE,
|
||||||
|
UNIVERSAL;
|
||||||
|
|
||||||
public static CDamageType[] VALUES = values();
|
public static CDamageType[] VALUES = values();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.unit;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.trigger.RemovableTriggerEvent;
|
||||||
|
import com.etheller.interpreter.ast.scope.trigger.Trigger;
|
||||||
|
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
|
||||||
|
import com.etheller.warsmash.parsers.jass.scope.CommonTriggerExecutionScope;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CItem;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetVisitor;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
|
||||||
|
|
||||||
|
public class CWidgetEvent implements RemovableTriggerEvent {
|
||||||
|
private final GlobalScope globalScope;
|
||||||
|
private final CWidget widget;
|
||||||
|
private final Trigger trigger;
|
||||||
|
private final JassGameEventsWar3 eventType;
|
||||||
|
private final TriggerBooleanExpression filter;
|
||||||
|
|
||||||
|
public CWidgetEvent(final GlobalScope globalScope, final CWidget widget, final Trigger trigger,
|
||||||
|
final JassGameEventsWar3 eventType, final TriggerBooleanExpression filter) {
|
||||||
|
this.globalScope = globalScope;
|
||||||
|
this.widget = widget;
|
||||||
|
this.trigger = trigger;
|
||||||
|
this.eventType = eventType;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Trigger getTrigger() {
|
||||||
|
return this.trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassGameEventsWar3 getEventType() {
|
||||||
|
return this.eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
this.widget.removeEvent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fire(final CWidget triggerWidget, final TriggerExecutionScope scope) {
|
||||||
|
if (this.filter != null) {
|
||||||
|
if (!this.filter.evaluate(this.globalScope, triggerWidget.visit(ScopeBuilder.INSTANCE.reset(scope)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.trigger.evaluate(this.globalScope, scope)) {
|
||||||
|
this.trigger.execute(this.globalScope, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ScopeBuilder implements AbilityTargetVisitor<CommonTriggerExecutionScope> {
|
||||||
|
public static final ScopeBuilder INSTANCE = new ScopeBuilder();
|
||||||
|
private TriggerExecutionScope parentScope;
|
||||||
|
|
||||||
|
public ScopeBuilder reset(final TriggerExecutionScope parentScope) {
|
||||||
|
this.parentScope = parentScope;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonTriggerExecutionScope accept(final AbilityPointTarget target) {
|
||||||
|
throw new IllegalStateException("what?");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonTriggerExecutionScope accept(final CUnit target) {
|
||||||
|
return CommonTriggerExecutionScope.filterScope(this.parentScope, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonTriggerExecutionScope accept(final CDestructable target) {
|
||||||
|
return CommonTriggerExecutionScope.filterScope(this.parentScope, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonTriggerExecutionScope accept(final CItem target) {
|
||||||
|
return CommonTriggerExecutionScope.filterScope(this.parentScope, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -16,4 +16,6 @@ public interface AbilityActivationReceiver {
|
|||||||
void cargoCapacityUnavailable();
|
void cargoCapacityUnavailable();
|
||||||
|
|
||||||
void disabled();
|
void disabled();
|
||||||
|
|
||||||
|
void techtreeMaximumReached();
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,11 @@ public class BooleanAbilityActivationReceiver implements AbilityActivationReceiv
|
|||||||
this.ok = false;
|
this.ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void techtreeMaximumReached() {
|
||||||
|
this.ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void casterMovementDisabled() {
|
public void casterMovementDisabled() {
|
||||||
this.ok = false;
|
this.ok = false;
|
||||||
|
@ -64,6 +64,11 @@ public class MeleeUIAbilityActivationReceiver implements AbilityActivationReceiv
|
|||||||
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
|
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void techtreeMaximumReached() {
|
||||||
|
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void casterMovementDisabled() {
|
public void casterMovementDisabled() {
|
||||||
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
|
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
|
||||||
|
@ -22,6 +22,13 @@ public interface SimulationRenderController {
|
|||||||
CUnit createUnit(CSimulation simulation, final War3ID typeId, final int playerIndex, final float x, final float y,
|
CUnit createUnit(CSimulation simulation, final War3ID typeId, final int playerIndex, final float x, final float y,
|
||||||
final float facing);
|
final float facing);
|
||||||
|
|
||||||
|
CItem createItem(CSimulation simulation, final War3ID typeId, final float x, final float y);
|
||||||
|
|
||||||
|
CDestructable createDestructable(War3ID typeId, float x, float y, float facing, float scale, int variation);
|
||||||
|
|
||||||
|
CDestructable createDestructableZ(War3ID typeId, float x, float y, float z, float facing, float scale,
|
||||||
|
int variation);
|
||||||
|
|
||||||
void createInstantAttackEffect(CSimulation cSimulation, CUnit source, CUnitAttackInstant attack, CWidget target);
|
void createInstantAttackEffect(CSimulation cSimulation, CUnit source, CUnitAttackInstant attack, CWidget target);
|
||||||
|
|
||||||
void spawnDamageSound(CWidget damagedDestructable, String weaponSound, String armorType);
|
void spawnDamageSound(CWidget damagedDestructable, String weaponSound, String armorType);
|
||||||
|
@ -40,6 +40,11 @@ public class StringMsgAbilityActivationReceiver implements AbilityActivationRece
|
|||||||
this.message = "NOTEXTERN: Requires " + type;
|
this.message = "NOTEXTERN: Requires " + type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void techtreeMaximumReached() {
|
||||||
|
this.message = "NOTEXTERN: Techtree maximum reached.";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cargoCapacityUnavailable() {
|
public void cargoCapacityUnavailable() {
|
||||||
this.message = "NOTEXTERN: Cargo capacity unavailable.";
|
this.message = "NOTEXTERN: Cargo capacity unavailable.";
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@ public enum MenuCursorState {
|
|||||||
SCROLL_DOWN_RIGHT("Scroll Down Right"),
|
SCROLL_DOWN_RIGHT("Scroll Down Right"),
|
||||||
SCROLL_UP_LEFT("Scroll Up Left"),
|
SCROLL_UP_LEFT("Scroll Up Left"),
|
||||||
SCROLL_UP_RIGHT("Scroll Up Right"),
|
SCROLL_UP_RIGHT("Scroll Up Right"),
|
||||||
|
SELECT("Select"),
|
||||||
TARGET_CURSOR(null), // handled specially
|
TARGET_CURSOR(null), // handled specially
|
||||||
HOLD_ITEM("HoldItem");
|
HOLD_ITEM("HoldItem");
|
||||||
private String animationName;
|
private String animationName;
|
||||||
|
@ -0,0 +1,215 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.ui;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.GameUI;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.AbstractRenderableFrame;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.SimpleStatusBarFrame;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.ClickableActionFrame;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.MultiSelectionIconListener;
|
||||||
|
|
||||||
|
public class MultiSelectionIcon extends AbstractRenderableFrame implements ClickableActionFrame {
|
||||||
|
|
||||||
|
public static final float HP_BAR_HEIGHT_RATIO = 0.175f;
|
||||||
|
public static final float HP_BAR_SPACING_RATIO = 0.02f;
|
||||||
|
private TextureFrame iconFrame;
|
||||||
|
private final MultiSelectionIconListener clickListener;
|
||||||
|
private float defaultWidth;
|
||||||
|
private float defaultHeight;
|
||||||
|
private final int queueIconIndexId;
|
||||||
|
|
||||||
|
private String toolTip;
|
||||||
|
private String uberTip;
|
||||||
|
private boolean focused;
|
||||||
|
private SimpleStatusBarFrame hpBarFrame;
|
||||||
|
private SimpleStatusBarFrame manaBarFrame;
|
||||||
|
|
||||||
|
public MultiSelectionIcon(final String name, final UIFrame parent, final MultiSelectionIconListener clickListener,
|
||||||
|
final int queueIconIndexId) {
|
||||||
|
super(name, parent);
|
||||||
|
this.clickListener = clickListener;
|
||||||
|
this.queueIconIndexId = queueIconIndexId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(final TextureFrame iconFrame, final SimpleStatusBarFrame hpBarFrame,
|
||||||
|
final SimpleStatusBarFrame manaBarFrame) {
|
||||||
|
this.iconFrame = iconFrame;
|
||||||
|
this.hpBarFrame = hpBarFrame;
|
||||||
|
this.manaBarFrame = manaBarFrame;
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTexture(final Texture texture) {
|
||||||
|
this.iconFrame.setTexture(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
|
||||||
|
this.iconFrame.positionBounds(gameUI, viewport);
|
||||||
|
this.hpBarFrame.positionBounds(gameUI, viewport);
|
||||||
|
this.manaBarFrame.positionBounds(gameUI, viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
|
||||||
|
this.iconFrame.render(batch, baseFont, glyphLayout);
|
||||||
|
this.hpBarFrame.render(batch, baseFont, glyphLayout);
|
||||||
|
this.manaBarFrame.render(batch, baseFont, glyphLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
|
||||||
|
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return super.touchDown(screenX, screenY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UIFrame touchUp(final float screenX, final float screenY, final int button) {
|
||||||
|
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return super.touchUp(screenX, screenY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(final int button) {
|
||||||
|
this.clickListener.multiSelectIconClicked(this.queueIconIndexId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWidth(final float width) {
|
||||||
|
this.defaultWidth = width;
|
||||||
|
super.setWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHeight(final float height) {
|
||||||
|
this.defaultHeight = height;
|
||||||
|
super.setHeight(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void innerSetDimensions(final float newWidth, final float newHeight) {
|
||||||
|
this.iconFrame.setWidth(newWidth);
|
||||||
|
this.iconFrame.setHeight(newHeight);
|
||||||
|
this.hpBarFrame.setWidth(newWidth * 1.05f);
|
||||||
|
this.hpBarFrame.setHeight(newHeight * HP_BAR_HEIGHT_RATIO);
|
||||||
|
this.manaBarFrame.setWidth(newWidth * 1.05f);
|
||||||
|
this.manaBarFrame.setHeight(newHeight * HP_BAR_HEIGHT_RATIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showUnFocused(final GameUI gameUI, final Viewport uiViewport) {
|
||||||
|
final float newWidth = this.defaultWidth * 0.75f;
|
||||||
|
final float newHeight = this.defaultHeight * 0.75f;
|
||||||
|
innerSetDimensions(newWidth, newHeight);
|
||||||
|
positionBounds(gameUI, uiViewport);
|
||||||
|
this.focused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showFocused(final GameUI gameUI, final Viewport uiViewport) {
|
||||||
|
innerSetDimensions(this.defaultWidth, this.defaultHeight);
|
||||||
|
positionBounds(gameUI, uiViewport);
|
||||||
|
this.focused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showMousePressed(final GameUI gameUI, final Viewport uiViewport) {
|
||||||
|
final float ratio = this.focused ? 0.95f : 0.70f;
|
||||||
|
final float newWidth = this.defaultWidth * ratio;
|
||||||
|
final float newHeight = this.defaultHeight * ratio;
|
||||||
|
innerSetDimensions(newWidth, newHeight);
|
||||||
|
positionBounds(gameUI, uiViewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDown(final GameUI gameUI, final Viewport uiViewport) {
|
||||||
|
this.clickListener.multiSelectIconPress(this.queueIconIndexId);
|
||||||
|
showMousePressed(gameUI, uiViewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showMouseReleased(final GameUI gameUI, final Viewport uiViewport) {
|
||||||
|
final float ratio = this.focused ? 1.00f : 0.75f;
|
||||||
|
final float newWidth = this.defaultWidth * ratio;
|
||||||
|
final float newHeight = this.defaultHeight * ratio;
|
||||||
|
innerSetDimensions(newWidth, newHeight);
|
||||||
|
positionBounds(gameUI, uiViewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseUp(final GameUI gameUI, final Viewport uiViewport) {
|
||||||
|
this.clickListener.multiSelectIconRelease(this.queueIconIndexId);
|
||||||
|
showMouseReleased(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)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToolTip(final String toolTip) {
|
||||||
|
this.toolTip = toolTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUberTip(final String uberTip) {
|
||||||
|
this.uberTip = uberTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getToolTip() {
|
||||||
|
return this.toolTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUberTip() {
|
||||||
|
return this.uberTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getToolTipFoodCost() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getToolTipGoldCost() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getToolTipLumberCost() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLifeRatioRemaining(final float lifeRatioRemaining) {
|
||||||
|
this.hpBarFrame.getBarFrame().setColor(Math.min(1.0f, 2.0f - (lifeRatioRemaining * 2)),
|
||||||
|
Math.min(1.0f, lifeRatioRemaining * 2), 0, 1.0f);
|
||||||
|
this.hpBarFrame.setValue(lifeRatioRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setManaRatioRemaining(final float lifeRatioRemaining) {
|
||||||
|
this.manaBarFrame.setValue(lifeRatioRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setManaBarVisible(final boolean visible) {
|
||||||
|
this.manaBarFrame.setVisible(visible);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.ui.command;
|
||||||
|
|
||||||
|
public interface MultiSelectionIconListener {
|
||||||
|
void multiSelectIconClicked(int index);
|
||||||
|
|
||||||
|
void multiSelectIconPress(int index);
|
||||||
|
|
||||||
|
void multiSelectIconRelease(int index);
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.parsers.fdf.GameUI;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||||
|
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.timers.CTimer;
|
||||||
|
|
||||||
|
public class CTimerDialog {
|
||||||
|
private final CTimer timer;
|
||||||
|
private final UIFrame timerDialogFrame;
|
||||||
|
private final StringFrame valueFrame;
|
||||||
|
private final StringFrame titleFrame;
|
||||||
|
|
||||||
|
public CTimerDialog(final CTimer timer, final UIFrame timerDialogFrame, final StringFrame valueFrame,
|
||||||
|
final StringFrame titleFrame) {
|
||||||
|
this.timer = timer;
|
||||||
|
this.timerDialogFrame = timerDialogFrame;
|
||||||
|
this.valueFrame = valueFrame;
|
||||||
|
this.titleFrame = titleFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(final GameUI rootFrame, final String title) {
|
||||||
|
rootFrame.setText(this.titleFrame, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(final GameUI rootFrame, final String value) {
|
||||||
|
rootFrame.setText(this.valueFrame, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(final boolean visible) {
|
||||||
|
this.timerDialogFrame.setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(final GameUI rootFrame, final CSimulation simulation) {
|
||||||
|
if (this.timerDialogFrame.isVisible() && (this.timer != null)) {
|
||||||
|
final float remaining = this.timer.getRemaining(simulation);
|
||||||
|
final int secondsRemaining = (int) remaining;
|
||||||
|
final int minutes = secondsRemaining / 60;
|
||||||
|
final int seconds = secondsRemaining % 60;
|
||||||
|
|
||||||
|
rootFrame.setText(this.valueFrame, minutes + ":" + seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -34,17 +34,74 @@ global :
|
|||||||
|
|
|
|
||||||
CONSTANT? type ID assignTail newlines # DefinitionGlobal
|
CONSTANT? type ID assignTail newlines # DefinitionGlobal
|
||||||
;
|
;
|
||||||
|
local :
|
||||||
|
LOCAL type ID newlines # BasicLocal
|
||||||
|
|
|
||||||
|
LOCAL type ID assignTail newlines # DefinitionLocal
|
||||||
|
;
|
||||||
|
|
||||||
assignTail:
|
assignTail:
|
||||||
EQUALS expression;
|
EQUALS expression;
|
||||||
|
|
||||||
expression:
|
multDivExpression:
|
||||||
|
multDivExpression '*' baseExpression # MultiplicationExpression
|
||||||
|
|
|
||||||
|
multDivExpression '/' baseExpression # DivisionExpression
|
||||||
|
|
|
||||||
|
baseExpression # BaseMultiplicationExpression
|
||||||
|
;
|
||||||
|
|
||||||
|
simpleArithmeticExpression:
|
||||||
|
simpleArithmeticExpression '+' multDivExpression # AdditionExpression
|
||||||
|
|
|
||||||
|
simpleArithmeticExpression '-' multDivExpression # SubtrationExpression
|
||||||
|
|
|
||||||
|
multDivExpression # BaseAdditionExpression
|
||||||
|
;
|
||||||
|
|
||||||
|
boolComparisonExpression:
|
||||||
|
boolComparisonExpression '<' simpleArithmeticExpression # BooleanLessExpression
|
||||||
|
|
|
||||||
|
boolComparisonExpression '>' simpleArithmeticExpression # BooleanGreaterExpression
|
||||||
|
|
|
||||||
|
boolComparisonExpression '<=' simpleArithmeticExpression # BooleanLessOrEqualsExpression
|
||||||
|
|
|
||||||
|
boolComparisonExpression '>=' simpleArithmeticExpression # BooleanGreaterOrEqualsExpression
|
||||||
|
|
|
||||||
|
simpleArithmeticExpression # BaseBoolComparisonExpression
|
||||||
|
;
|
||||||
|
|
||||||
|
boolEqualityExpression:
|
||||||
|
boolEqualityExpression '==' boolComparisonExpression # EqualsExpression
|
||||||
|
|
|
||||||
|
boolEqualityExpression '!=' boolComparisonExpression # NotEqualsExpression
|
||||||
|
|
|
||||||
|
boolComparisonExpression # BaseBoolExpression
|
||||||
|
;
|
||||||
|
|
||||||
|
boolAndsExpression:
|
||||||
|
boolAndsExpression AND boolEqualityExpression # BooleanAndExpression
|
||||||
|
|
|
||||||
|
boolEqualityExpression # BaseBoolAndsExpression
|
||||||
|
;
|
||||||
|
|
||||||
|
boolExpression:
|
||||||
|
boolExpression OR boolAndsExpression # BooleanOrExpression
|
||||||
|
|
|
||||||
|
boolAndsExpression # BaseBoolOrsExpression
|
||||||
|
;
|
||||||
|
|
||||||
|
baseExpression:
|
||||||
ID # ReferenceExpression
|
ID # ReferenceExpression
|
||||||
|
|
|
|
||||||
STRING_LITERAL #StringLiteralExpression
|
STRING_LITERAL #StringLiteralExpression
|
||||||
|
|
|
|
||||||
INTEGER #IntegerLiteralExpression
|
INTEGER #IntegerLiteralExpression
|
||||||
|
|
|
|
||||||
|
RAWCODE #RawcodeLiteralExpression
|
||||||
|
|
|
||||||
|
REAL #RealLiteralExpression
|
||||||
|
|
|
||||||
FUNCTION ID #FunctionReferenceExpression
|
FUNCTION ID #FunctionReferenceExpression
|
||||||
|
|
|
|
||||||
NULL # NullExpression
|
NULL # NullExpression
|
||||||
@ -59,8 +116,13 @@ expression:
|
|||||||
|
|
|
|
||||||
'(' expression ')' # ParentheticalExpression
|
'(' expression ')' # ParentheticalExpression
|
||||||
|
|
|
|
||||||
NOT expression # NotExpression
|
NOT baseExpression # NotExpression
|
||||||
|
|
|
||||||
|
'-' baseExpression # NegateExpression
|
||||||
;
|
;
|
||||||
|
|
||||||
|
expression:
|
||||||
|
boolExpression;
|
||||||
|
|
||||||
functionExpression:
|
functionExpression:
|
||||||
ID '(' argsList ')'
|
ID '(' argsList ')'
|
||||||
@ -72,6 +134,8 @@ argsList:
|
|||||||
expression # SingleArgument
|
expression # SingleArgument
|
||||||
|
|
|
|
||||||
expression ',' argsList # ListArgument
|
expression ',' argsList # ListArgument
|
||||||
|
|
|
||||||
|
# EmptyArgument
|
||||||
;
|
;
|
||||||
|
|
||||||
//#booleanExpression:
|
//#booleanExpression:
|
||||||
@ -87,6 +151,14 @@ statement:
|
|||||||
|
|
|
|
||||||
RETURN expression newlines # ReturnStatement
|
RETURN expression newlines # ReturnStatement
|
||||||
|
|
|
|
||||||
|
RETURN newlines # ReturnNothingStatement
|
||||||
|
|
|
||||||
|
EXITWHEN expression newlines # ExitWhenStatement
|
||||||
|
|
|
||||||
|
local # LocalStatement
|
||||||
|
|
|
||||||
|
LOOP newlines statements ENDLOOP newlines # LoopStatement
|
||||||
|
|
|
||||||
IF ifStatementPartial # IfStatement
|
IF ifStatementPartial # IfStatement
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -182,16 +254,27 @@ ELSE : 'else';
|
|||||||
ENDIF : 'endif';
|
ENDIF : 'endif';
|
||||||
ELSEIF : 'elseif';
|
ELSEIF : 'elseif';
|
||||||
CONSTANT : 'constant';
|
CONSTANT : 'constant';
|
||||||
|
LOCAL : 'local';
|
||||||
|
LOOP : 'loop';
|
||||||
|
ENDLOOP : 'endloop';
|
||||||
|
EXITWHEN : 'exitwhen';
|
||||||
|
|
||||||
STRING_LITERAL : ('"'.*?'"');
|
STRING_LITERAL : ('"'.*?'"');
|
||||||
|
|
||||||
|
|
||||||
INTEGER : [0]|([1-9][0-9]*) ;
|
INTEGER : [0]|([1-9][0-9]*) ;
|
||||||
|
|
||||||
|
RAWCODE : ('\''.*?'\'');
|
||||||
|
|
||||||
|
REAL : (([0]|([1-9][0-9]*))'.'[0-9]*)|('.'([0]|([1-9][0-9]*))) ;
|
||||||
|
|
||||||
NULL : 'null' ;
|
NULL : 'null' ;
|
||||||
TRUE : 'true' ;
|
TRUE : 'true' ;
|
||||||
FALSE : 'false' ;
|
FALSE : 'false' ;
|
||||||
|
|
||||||
NOT : 'not';
|
NOT : 'not';
|
||||||
|
OR : 'or';
|
||||||
|
AND : 'and';
|
||||||
|
|
||||||
ID : ([a-zA-Z_][a-zA-Z_0-9]*) ; // match identifiers
|
ID : ([a-zA-Z_][a-zA-Z_0-9]*) ; // match identifiers
|
||||||
|
|
||||||
|
@ -13,11 +13,19 @@ public class Assignable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(final JassValue value) {
|
public void setValue(final JassValue value) {
|
||||||
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
|
if (value == null) {
|
||||||
if (!this.type.isAssignableFrom(valueType)) {
|
if (!this.type.isNullable()) {
|
||||||
throw new RuntimeException("Incompatible types " + valueType.getName() + " != " + this.type.getName());
|
throw new RuntimeException("Type " + this.type.getName() + " cannot be assigned to null!");
|
||||||
|
}
|
||||||
|
this.value = this.type.getNullValue();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
|
||||||
|
if (!this.type.isAssignableFrom(valueType)) {
|
||||||
|
throw new RuntimeException("Incompatible types " + valueType.getName() + " != " + this.type.getName());
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
}
|
}
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JassValue getValue() {
|
public JassValue getValue() {
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.ArithmeticJassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.ArithmeticLeftHandNullJassValueVisitor;
|
||||||
|
|
||||||
|
public class ArithmeticJassExpression implements JassExpression {
|
||||||
|
|
||||||
|
private final JassExpression leftExpression;
|
||||||
|
private final JassExpression rightExpression;
|
||||||
|
private final ArithmeticSign arithmeticSign;
|
||||||
|
|
||||||
|
public ArithmeticJassExpression(final JassExpression leftExpression, final JassExpression rightExpression,
|
||||||
|
final ArithmeticSign arithmeticSign) {
|
||||||
|
this.leftExpression = leftExpression;
|
||||||
|
this.rightExpression = rightExpression;
|
||||||
|
this.arithmeticSign = arithmeticSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope,
|
||||||
|
final TriggerExecutionScope triggerScope) {
|
||||||
|
final JassValue leftValue = this.leftExpression.evaluate(globalScope, localScope, triggerScope);
|
||||||
|
final JassValue rightValue = this.rightExpression.evaluate(globalScope, localScope, triggerScope);
|
||||||
|
if (leftValue == null) {
|
||||||
|
if (rightValue == null) {
|
||||||
|
return this.arithmeticSign.apply((String) null, (String) null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return rightValue.visit(ArithmeticLeftHandNullJassValueVisitor.INSTANCE.reset(this.arithmeticSign));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return leftValue.visit(ArithmeticJassValueVisitor.INSTANCE.reset(rightValue, this.arithmeticSign));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.HandleJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.RealJassValue;
|
||||||
|
|
||||||
|
public interface ArithmeticSign {
|
||||||
|
JassValue apply(BooleanJassValue left, BooleanJassValue right);
|
||||||
|
|
||||||
|
JassValue apply(RealJassValue left, RealJassValue right);
|
||||||
|
|
||||||
|
JassValue apply(RealJassValue left, IntegerJassValue right);
|
||||||
|
|
||||||
|
JassValue apply(IntegerJassValue left, RealJassValue right);
|
||||||
|
|
||||||
|
JassValue apply(IntegerJassValue left, IntegerJassValue right);
|
||||||
|
|
||||||
|
JassValue apply(String left, String right);
|
||||||
|
|
||||||
|
JassValue apply(HandleJassValue left, HandleJassValue right);
|
||||||
|
|
||||||
|
JassValue apply(CodeJassValue left, CodeJassValue right);
|
||||||
|
}
|
@ -0,0 +1,528 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.HandleJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.RealJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public enum ArithmeticSigns implements ArithmeticSign {
|
||||||
|
ADD() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform numeric arithmetic on boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() + right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() + right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() + right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return new IntegerJassValue(left.getValue() + right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
return new StringJassValue(left + right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on code");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SUBTRACT() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform numeric arithmetic on boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() - right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() - right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() - right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return new IntegerJassValue(left.getValue() - right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on string");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on code");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MULTIPLY() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform numeric arithmetic on boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() * right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() * right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() * right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return new IntegerJassValue(left.getValue() * right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on string");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on code");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DIVIDE() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform numeric arithmetic on boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() / right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() / right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return new RealJassValue(left.getValue() / right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return new IntegerJassValue(left.getValue() / right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on string");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform arithmetic on code");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OR() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() || right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on string");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on code");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AND() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() && right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on string");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Cannot perform boolean arithmetic on code");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
EQUALS() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() == right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(Math.abs(left.getValue() - right.getValue()) <= 0.00001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(Math.abs(left.getValue() - right.getValue()) <= 0.00001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(Math.abs(left.getValue() - right.getValue()) <= 0.00001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(Math.abs(left.getValue() - right.getValue()) <= 0.00001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final String left, final String right) {
|
||||||
|
return BooleanJassValue.of(equals(left, right));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
return BooleanJassValue.of(equals(left, right));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
return BooleanJassValue.of(equals(left, right));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NOT_EQUALS() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() != right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() != right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() != right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() != right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() != right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
return BooleanJassValue.of(!equals(left, right));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
return BooleanJassValue.of(!equals(left, right));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
return BooleanJassValue.of(!equals(left, right));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LESS() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() < right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() < right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() < right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() < right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LESS_OR_EQUALS() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() <= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() <= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() <= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() <= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GREATER() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() > right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() > right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() > right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() > right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GREATER_OR_EQUALS() {
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final BooleanJassValue left, final BooleanJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() >= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final RealJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() >= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final RealJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() >= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final IntegerJassValue left, final IntegerJassValue right) {
|
||||||
|
return BooleanJassValue.of(left.getValue() >= right.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final String left, final String right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue apply(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanJassValue apply(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
throw new UnsupportedOperationException("Invalid type for specified operator");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static boolean equals(final String left, final String right) {
|
||||||
|
boolean equals;
|
||||||
|
if (left == null) {
|
||||||
|
if (right == null) {
|
||||||
|
equals = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
equals = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
equals = left.equals(right);
|
||||||
|
}
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean equals(final HandleJassValue left, final HandleJassValue right) {
|
||||||
|
return (left.getJavaValue() == right.getJavaValue()) && (left.getType() == right.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean equals(final CodeJassValue left, final CodeJassValue right) {
|
||||||
|
return (left.getValue() == right.getValue());
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,12 @@ public class FunctionCallJassExpression implements JassExpression {
|
|||||||
final JassValue evaluatedExpression = expr.evaluate(globalScope, localScope, triggerScope);
|
final JassValue evaluatedExpression = expr.evaluate(globalScope, localScope, triggerScope);
|
||||||
evaluatedExpressions.add(evaluatedExpression);
|
evaluatedExpressions.add(evaluatedExpression);
|
||||||
}
|
}
|
||||||
return functionByName.call(evaluatedExpressions, globalScope, triggerScope);
|
try {
|
||||||
|
return functionByName.call(evaluatedExpressions, globalScope, triggerScope);
|
||||||
|
}
|
||||||
|
catch (final Exception exc) {
|
||||||
|
throw new RuntimeException("Function call by name failed for name: " + this.functionName, exc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.NegateJassValueVisitor;
|
||||||
|
|
||||||
|
public class NegateJassExpression implements JassExpression {
|
||||||
|
private final JassExpression expression;
|
||||||
|
|
||||||
|
public NegateJassExpression(final JassExpression expression) {
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope,
|
||||||
|
final TriggerExecutionScope triggerScope) {
|
||||||
|
return this.expression.evaluate(globalScope, localScope, triggerScope)
|
||||||
|
.visit(NegateJassValueVisitor.getInstance());
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,9 @@ public class JassParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean matchesType(final JassValue value) {
|
public boolean matchesType(final JassValue value) {
|
||||||
|
if (value == null) {
|
||||||
|
return this.type.isNullable();
|
||||||
|
}
|
||||||
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
|
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
|
||||||
return this.type.isAssignableFrom(valueType);
|
return this.type.isAssignableFrom(valueType);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,13 @@ public class NativeJassFunction extends AbstractJassFunction {
|
|||||||
@Override
|
@Override
|
||||||
protected JassValue innerCall(final List<JassValue> arguments, final GlobalScope globalScope,
|
protected JassValue innerCall(final List<JassValue> arguments, final GlobalScope globalScope,
|
||||||
final TriggerExecutionScope triggerScope, final LocalScope localScope) {
|
final TriggerExecutionScope triggerScope, final LocalScope localScope) {
|
||||||
|
if (this.implementation == null) {
|
||||||
|
System.err.println(
|
||||||
|
"Call to native function that was declared but had no native implementation: " + this.name);
|
||||||
|
return null;
|
||||||
|
// throw new UnsupportedOperationException(
|
||||||
|
// "Call to native function that was declared but had no native implementation: " + this.name);
|
||||||
|
}
|
||||||
return this.implementation.call(arguments, globalScope, triggerScope);
|
return this.implementation.call(arguments, globalScope, triggerScope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
import com.etheller.interpreter.ast.scope.GlobalScope;
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
import com.etheller.interpreter.ast.scope.LocalScope;
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassReturnNothingStatement;
|
||||||
import com.etheller.interpreter.ast.statement.JassStatement;
|
import com.etheller.interpreter.ast.statement.JassStatement;
|
||||||
import com.etheller.interpreter.ast.value.JassType;
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
import com.etheller.interpreter.ast.value.JassValue;
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
@ -32,7 +33,13 @@ public final class UserJassFunction extends AbstractJassFunction {
|
|||||||
final JassValue returnValue = statement.execute(globalScope, localScope, triggerScope);
|
final JassValue returnValue = statement.execute(globalScope, localScope, triggerScope);
|
||||||
if (returnValue != null) {
|
if (returnValue != null) {
|
||||||
if (returnValue.visit(JassTypeGettingValueVisitor.getInstance()) != this.returnType) {
|
if (returnValue.visit(JassTypeGettingValueVisitor.getInstance()) != this.returnType) {
|
||||||
throw new RuntimeException("Invalid return type");
|
if ((this.returnType == JassType.NOTHING)
|
||||||
|
&& (returnValue == JassReturnNothingStatement.RETURN_NOTHING_NOTICE)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new RuntimeException("Invalid return type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,12 @@ public final class GlobalScope {
|
|||||||
|
|
||||||
public void createGlobal(final String name, final JassType type, final JassValue value) {
|
public void createGlobal(final String name, final JassType type, final JassValue value) {
|
||||||
final GlobalScopeAssignable assignable = new GlobalScopeAssignable(type, this);
|
final GlobalScopeAssignable assignable = new GlobalScopeAssignable(type, this);
|
||||||
assignable.setValue(value);
|
try {
|
||||||
|
assignable.setValue(value);
|
||||||
|
}
|
||||||
|
catch (final Exception exc) {
|
||||||
|
throw new RuntimeException("Global initialization failed for name: " + name, exc);
|
||||||
|
}
|
||||||
this.globals.put(name, assignable);
|
this.globals.put(name, assignable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,9 @@ public class Trigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void execute(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
|
public void execute(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
|
||||||
|
if (!this.enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (final JassFunction action : this.actions) {
|
for (final JassFunction action : this.actions) {
|
||||||
action.call(Collections.emptyList(), globalScope, triggerScope);
|
action.call(Collections.emptyList(), globalScope, triggerScope);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.BooleanJassValueVisitor;
|
||||||
|
|
||||||
|
public class JassExitWhenStatement implements JassStatement {
|
||||||
|
public static final StringJassValue LOOP_EXIT_NOTICE = new StringJassValue("EXIT");
|
||||||
|
private final int lineNo;
|
||||||
|
private final JassExpression expression;
|
||||||
|
|
||||||
|
public JassExitWhenStatement(final int lineNo, final JassExpression expression) {
|
||||||
|
this.lineNo = lineNo;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope,
|
||||||
|
final TriggerExecutionScope triggerScope) {
|
||||||
|
globalScope.setLineNumber(this.lineNo);
|
||||||
|
if (this.expression.evaluate(globalScope, localScope, triggerScope)
|
||||||
|
.visit(BooleanJassValueVisitor.getInstance())) {
|
||||||
|
return LOOP_EXIT_NOTICE;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class JassLocalDefinitionStatement implements JassStatement {
|
||||||
|
private final String identifier;
|
||||||
|
private final JassExpression expression;
|
||||||
|
private final int lineNo;
|
||||||
|
private final JassType type;
|
||||||
|
|
||||||
|
public JassLocalDefinitionStatement(final int lineNo, final String identifier, final JassType type,
|
||||||
|
final JassExpression expression) {
|
||||||
|
this.lineNo = lineNo;
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.type = type;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope,
|
||||||
|
final TriggerExecutionScope triggerScope) {
|
||||||
|
globalScope.setLineNumber(this.lineNo);
|
||||||
|
localScope.createLocal(this.identifier, this.type,
|
||||||
|
this.expression.evaluate(globalScope, localScope, triggerScope));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class JassLocalStatement implements JassStatement {
|
||||||
|
private final String identifier;
|
||||||
|
private final int lineNo;
|
||||||
|
private final JassType type;
|
||||||
|
|
||||||
|
public JassLocalStatement(final int lineNo, final String identifier, final JassType type) {
|
||||||
|
this.lineNo = lineNo;
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope,
|
||||||
|
final TriggerExecutionScope triggerScope) {
|
||||||
|
globalScope.setLineNumber(this.lineNo);
|
||||||
|
localScope.createLocal(this.identifier, this.type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class JassLoopStatement implements JassStatement {
|
||||||
|
private final int lineNo;
|
||||||
|
private final List<JassStatement> statements;
|
||||||
|
|
||||||
|
public JassLoopStatement(final int lineNo, final List<JassStatement> statements) {
|
||||||
|
this.lineNo = lineNo;
|
||||||
|
this.statements = statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope,
|
||||||
|
final TriggerExecutionScope triggerScope) {
|
||||||
|
globalScope.setLineNumber(this.lineNo);
|
||||||
|
while (true) {
|
||||||
|
for (final JassStatement statement : this.statements) {
|
||||||
|
final JassValue returnValue = statement.execute(globalScope, localScope, triggerScope);
|
||||||
|
if (returnValue != null) {
|
||||||
|
if (returnValue == JassExitWhenStatement.LOOP_EXIT_NOTICE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public class JassReturnNothingStatement implements JassStatement {
|
||||||
|
public static final StringJassValue RETURN_NOTHING_NOTICE = new StringJassValue("nothing");
|
||||||
|
private final int lineNo;
|
||||||
|
|
||||||
|
public JassReturnNothingStatement(final int lineNo) {
|
||||||
|
this.lineNo = lineNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope,
|
||||||
|
final TriggerExecutionScope triggerScope) {
|
||||||
|
globalScope.setLineNumber(this.lineNo);
|
||||||
|
return RETURN_NOTHING_NOTICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,4 +27,14 @@ public class ArrayJassType implements JassType {
|
|||||||
public <TYPE> TYPE visit(final JassTypeVisitor<TYPE> visitor) {
|
public <TYPE> TYPE visit(final JassTypeVisitor<TYPE> visitor) {
|
||||||
return visitor.accept(this);
|
return visitor.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNullable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue getNullValue() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user