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]
|
||||
Count=9
|
||||
Count=8
|
||||
Type00=MPQ
|
||||
Path00="D:\Games\Warcraft III Patch 1.22\war3.mpq"
|
||||
Type01=MPQ
|
||||
@ -8,13 +8,11 @@ Type02=MPQ
|
||||
Path02="D:\Games\Warcraft III Patch 1.22\War3xlocal.mpq"
|
||||
Type03=MPQ
|
||||
Path03="D:\Games\Warcraft III Patch 1.22\War3Patch.mpq"
|
||||
Type04=MPQ
|
||||
Path04="D:\Games\Warcraft III Patch 1.22\Warsmash\War3Mod.mpq"
|
||||
Type04=Folder
|
||||
Path04="..\..\resources"
|
||||
Type05=Folder
|
||||
Path05="..\..\resources"
|
||||
Path05="D:\Backups\Warsmash\Data"
|
||||
Type06=Folder
|
||||
Path06="D:\Backups\Warsmash\Data"
|
||||
Path06="D:\Games\Warcraft III Patch 1.22\Maps"
|
||||
Type07=Folder
|
||||
Path07="D:\Games\Warcraft III Patch 1.22\Maps"
|
||||
Type08=Folder
|
||||
Path08="."
|
||||
Path07="."
|
||||
|
@ -30,12 +30,12 @@ import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
||||
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
||||
import com.etheller.warsmash.datasources.MpqDataSourceDescriptor;
|
||||
import com.etheller.warsmash.parsers.fdf.GameUI;
|
||||
import com.etheller.warsmash.parsers.jass.Jass2;
|
||||
import com.etheller.warsmash.parsers.jass.Jass2.CommonEnvironment;
|
||||
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
|
||||
import com.etheller.warsmash.units.DataTable;
|
||||
import com.etheller.warsmash.units.Element;
|
||||
import com.etheller.warsmash.util.DataSourceFileHandle;
|
||||
import com.etheller.warsmash.util.ImageUtils;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
import com.etheller.warsmash.viewer5.Model;
|
||||
import com.etheller.warsmash.viewer5.ModelInstance;
|
||||
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 static final boolean ENABLE_AUDIO = true;
|
||||
private static final boolean ENABLE_MUSIC = true;
|
||||
private final War3MapViewer viewer;
|
||||
private final Rectangle tempRect = new Rectangle();
|
||||
|
||||
@ -76,6 +75,7 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
||||
private final WarsmashGdxMultiScreenGame screenManager;
|
||||
private final WarsmashGdxMenuScreen menuScreen;
|
||||
private final CPlayerUnitOrderListener uiOrderListener;
|
||||
private CommonEnvironment commonEnv;
|
||||
|
||||
public WarsmashGdxMapScreen(final War3MapViewer mapViewer, final WarsmashGdxMultiScreenGame screenManager,
|
||||
final WarsmashGdxMenuScreen menuScreen, final CPlayerUnitOrderListener uiOrderListener) {
|
||||
@ -150,7 +150,8 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
||||
if (width < ((height * 4) / 3)) {
|
||||
aspect3By4Width = width;
|
||||
aspect3By4Height = (width * 3) / 4;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
aspect3By4Width = (height * 4) / 3;
|
||||
aspect3By4Height = height;
|
||||
}
|
||||
@ -171,13 +172,6 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
||||
|
||||
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 CameraRates cameraRates = new CameraRates(cameraRatesElement.getFieldFloatValue("AOA"),
|
||||
cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"),
|
||||
@ -188,22 +182,6 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
||||
@Override
|
||||
public void onCreate(final GameUI 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() {
|
||||
@Override
|
||||
@ -224,9 +202,12 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
||||
|
||||
try {
|
||||
this.viewer.loadAfterUI();
|
||||
} catch (final IOException e) {
|
||||
}
|
||||
catch (final IOException 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) {
|
||||
@ -508,8 +489,6 @@ public class WarsmashGdxMapScreen implements InputProcessor, Screen {
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if (this.currentMusic != null) {
|
||||
this.currentMusic.stop();
|
||||
}
|
||||
this.meleeUI.gameClosed();
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.MenuUI;
|
||||
|
||||
public class WarsmashGdxMenuScreen implements InputProcessor, Screen, SingleModelScreen {
|
||||
private static final boolean ENABLE_AUDIO = true;
|
||||
private static final boolean ENABLE_MUSIC = true;
|
||||
private DataSource codebase;
|
||||
private MdxViewer viewer;
|
||||
private MdxModel model;
|
||||
@ -185,7 +184,7 @@ public class WarsmashGdxMenuScreen implements InputProcessor, Screen, SingleMode
|
||||
public void onCreate(final GameUI rootFrame) {
|
||||
// WarsmashGdxMapGame.this.viewer.setGameUI(rootFrame);
|
||||
|
||||
if (ENABLE_MUSIC) {
|
||||
if (WarsmashConstants.ENABLE_MUSIC) {
|
||||
final String musicField = rootFrame
|
||||
.getSkinField("GlueMusic_V" + WarsmashConstants.GAME_VERSION);
|
||||
final String[] musics = musicField.split(";");
|
||||
|
@ -14,6 +14,9 @@ public interface ClientToServerListener {
|
||||
void issueDropItemAtPointOrder(SocketAddress sourceAddress, int unitHandleId, int abilityHandleId, int orderId,
|
||||
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,
|
||||
boolean queue);
|
||||
|
||||
|
@ -5,6 +5,7 @@ public class ClientToServerProtocol {
|
||||
public static final int ISSUE_TARGET_ORDER = 1;
|
||||
public static final int ISSUE_POINT_ORDER = 2;
|
||||
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 UNIT_CANCEL_TRAINING = 5;
|
||||
public static final int FINISHED_TURN = 6;
|
||||
|
@ -12,6 +12,9 @@ public interface ServerToClientListener {
|
||||
void issueDropItemAtPointOrder(int playerIndex, int unitHandleId, int abilityHandleId, int orderId,
|
||||
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 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_POINT_ORDER = 2;
|
||||
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 UNIT_CANCEL_TRAINING = 5;
|
||||
public static final int FINISHED_TURN = 6;
|
||||
|
@ -3,7 +3,10 @@ package com.etheller.warsmash.networking;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
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.etheller.warsmash.networking.udp.OrderedUdpClient;
|
||||
@ -53,18 +56,21 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
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.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
}
|
||||
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
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.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);;
|
||||
} else {
|
||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
||||
}
|
||||
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
|
||||
;
|
||||
}
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
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.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 {
|
||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
||||
}
|
||||
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, x, y,
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
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.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
}
|
||||
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
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.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
}
|
||||
else if (currentServerTurnInProgress == WarsmashClient.this.latestLocallyRequestedTurn) {
|
||||
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
|
||||
public void finishedTurn(final int gameTurnTick) {
|
||||
if(WarsmashConstants.VERBOSE_LOGGING) {
|
||||
if (WarsmashConstants.VERBOSE_LOGGING) {
|
||||
System.out.println("finishedTurn " + gameTurnTick);
|
||||
}
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@ -183,9 +233,10 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
public void turnCompleted(final int gameTurnTick) {
|
||||
this.writer.finishedTurn(gameTurnTick);
|
||||
this.writer.send();
|
||||
latestLocallyRequestedTurn = gameTurnTick;
|
||||
while(!queuedMessages.isEmpty() && queuedMessages.peek().messageTurnTick == latestLocallyRequestedTurn) {
|
||||
queuedMessages.poll().run();
|
||||
this.latestLocallyRequestedTurn = gameTurnTick;
|
||||
while (!this.queuedMessages.isEmpty()
|
||||
&& (this.queuedMessages.peek().messageTurnTick == this.latestLocallyRequestedTurn)) {
|
||||
this.queuedMessages.poll().run();
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,8 +258,10 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
|
||||
@Override
|
||||
public void heartbeat() {
|
||||
// Not doing anything here at the moment. The act of the server sending us that packet
|
||||
// will let the middle layer UDP system know to re-request any lost packets based
|
||||
// Not doing anything here at the moment. The act of the server sending us that
|
||||
// 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.
|
||||
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 int messageTurnTick;
|
||||
private final int messageTurnTick;
|
||||
|
||||
public QueuedMessage(int messageTurnTick) {
|
||||
public QueuedMessage(final int messageTurnTick) {
|
||||
this.messageTurnTick = messageTurnTick;
|
||||
}
|
||||
|
||||
public final int getMessageTurnTick() {
|
||||
return messageTurnTick;
|
||||
return this.messageTurnTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void run();
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,14 @@ public class WarsmashClientSendingOrderListener implements CPlayerUnitOrderListe
|
||||
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
|
||||
public void issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
|
||||
final boolean queue) {
|
||||
|
@ -53,6 +53,19 @@ public class WarsmashClientWriter {
|
||||
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,
|
||||
final boolean queue) {
|
||||
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
|
||||
public void issueImmediateOrder(final SocketAddress sourceAddress, final int unitHandleId,
|
||||
final int abilityHandleId, final int orderId, final boolean queue) {
|
||||
|
@ -60,6 +60,17 @@ public class WarsmashServerParser implements OrderedUdpServerListener {
|
||||
targetHandleId, x, y, queue);
|
||||
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: {
|
||||
final int unitHandleId = buffer.getInt();
|
||||
final int abilityHandleId = buffer.getInt();
|
||||
|
@ -63,6 +63,21 @@ public class WarsmashServerWriter implements ServerToClientListener {
|
||||
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
|
||||
public void issueImmediateOrder(final int playerIndex, final int unitHandleId, final int abilityHandleId,
|
||||
final int orderId, final boolean queue) {
|
||||
|
@ -1054,7 +1054,11 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
|
||||
}
|
||||
|
||||
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_")) {
|
||||
errorString = this.mapStrings.get(Integer.parseInt(errorString.substring(8)));
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
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.Vector4Definition;
|
||||
|
||||
@ -8,6 +10,7 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
|
||||
private final TextureFrame barFrame;
|
||||
private final TextureFrame borderFrame;
|
||||
private final float barInset;
|
||||
private float lastValue = Float.NaN;
|
||||
|
||||
public SimpleStatusBarFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
|
||||
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() {
|
||||
return this.decorateFileNames;
|
||||
}
|
||||
@ -38,6 +49,7 @@ public class SimpleStatusBarFrame extends AbstractUIFrame {
|
||||
public void setValue(final float value) {
|
||||
this.barFrame.setTexCoord(0, value, 0, 1);
|
||||
this.barFrame.setWidth(((this.renderBounds.width - (this.barInset * 2)) * value));
|
||||
this.lastValue = value;
|
||||
}
|
||||
|
||||
public TextureFrame getBarFrame() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.etheller.warsmash.parsers.fdf.frames;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
@ -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 final SimpleFrame internalFramesContainer;
|
||||
private float predictedViewportHeight;
|
||||
private float predictedViewportWidth;
|
||||
|
||||
static ShapeRenderer shapeRenderer = new ShapeRenderer();
|
||||
private final Color fontHighlightColor;
|
||||
@ -425,6 +426,7 @@ public class StringFrame extends AbstractRenderableFrame {
|
||||
this.internalFramesContainer.setWidth(usedWidthMax);
|
||||
this.internalFramesContainer.setHeight(usedHeight);
|
||||
this.predictedViewportHeight = (usedHeight - this.frameFont.getCapHeight()) + this.frameFont.getLineHeight();
|
||||
this.predictedViewportWidth = usedWidthMax;
|
||||
|
||||
this.internalFramesContainer.clearFramePointAssignments();
|
||||
switch (this.justifyH) {
|
||||
@ -490,6 +492,10 @@ public class StringFrame extends AbstractRenderableFrame {
|
||||
return this.predictedViewportHeight;
|
||||
}
|
||||
|
||||
public float getPredictedViewportWidth() {
|
||||
return this.predictedViewportWidth;
|
||||
}
|
||||
|
||||
public BitmapFont getFrameFont() {
|
||||
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 CItem orderTargetItem;
|
||||
private CUnit orderTargetUnit;
|
||||
private CWidget triggerWidget;
|
||||
|
||||
public CommonTriggerExecutionScope(final Trigger triggeringTrigger) {
|
||||
super(triggeringTrigger);
|
||||
}
|
||||
|
||||
public CommonTriggerExecutionScope(final TriggerExecutionScope parentScope) {
|
||||
super(parentScope.getTriggeringTrigger());
|
||||
public CommonTriggerExecutionScope(final Trigger triggeringTrigger, final TriggerExecutionScope parentScope) {
|
||||
super(triggeringTrigger);
|
||||
if (parentScope instanceof CommonTriggerExecutionScope) {
|
||||
copyFrom((CommonTriggerExecutionScope) parentScope);
|
||||
}
|
||||
@ -134,6 +135,7 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
|
||||
this.orderTargetDestructable = parentScope.orderTargetDestructable;
|
||||
this.orderTargetItem = parentScope.orderTargetItem;
|
||||
this.orderTargetUnit = parentScope.orderTargetUnit;
|
||||
this.triggerWidget = parentScope.triggerWidget;
|
||||
}
|
||||
|
||||
public CUnit getEnumUnit() {
|
||||
@ -144,6 +146,10 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
|
||||
return this.triggeringUnit;
|
||||
}
|
||||
|
||||
public CWidget getTriggerWidget() {
|
||||
return this.triggerWidget;
|
||||
}
|
||||
|
||||
public CUnit getFilterUnit() {
|
||||
return this.filterUnit;
|
||||
}
|
||||
@ -350,63 +356,121 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
|
||||
|
||||
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
|
||||
final CUnit filterUnit) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||
parentScope);
|
||||
scope.filterUnit = filterUnit;
|
||||
return scope;
|
||||
}
|
||||
|
||||
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;
|
||||
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,
|
||||
final CPlayerJass filterPlayer) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||
parentScope);
|
||||
scope.filterPlayer = filterPlayer;
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static CommonTriggerExecutionScope enumScope(final TriggerExecutionScope parentScope,
|
||||
final CPlayerJass enumPlayer) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
|
||||
parentScope);
|
||||
scope.enumPlayer = enumPlayer;
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static CommonTriggerExecutionScope expiringTimer(final CTimerJass cTimerJass) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(TriggerExecutionScope.EMPTY);
|
||||
public static CommonTriggerExecutionScope expiringTimer(final Trigger trigger, final CTimerJass cTimerJass) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||
scope.expiringTimer = cTimerJass;
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static CommonTriggerExecutionScope unitEnterRegionScope(final TriggerExecutionScope parentScope,
|
||||
final CUnit enteringUnit, final CRegion triggeringRegion) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
||||
public static CommonTriggerExecutionScope unitEnterRegionScope(final Trigger trigger,
|
||||
final TriggerExecutionScope parentScope, final CUnit enteringUnit, final CRegion triggeringRegion) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, parentScope);
|
||||
scope.enteringUnit = enteringUnit;
|
||||
scope.triggeringRegion = triggeringRegion;
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static CommonTriggerExecutionScope unitLeaveRegionScope(final TriggerExecutionScope parentScope,
|
||||
final CUnit leavingUnit, final CRegion triggeringRegion) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope);
|
||||
public static CommonTriggerExecutionScope unitLeaveRegionScope(final Trigger trigger,
|
||||
final TriggerExecutionScope parentScope, final CUnit leavingUnit, final CRegion triggeringRegion) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, parentScope);
|
||||
scope.leavingUnit = leavingUnit;
|
||||
scope.triggeringRegion = triggeringRegion;
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static CommonTriggerExecutionScope playerHeroLevelScope(final CUnit hero) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(TriggerExecutionScope.EMPTY);
|
||||
public static CommonTriggerExecutionScope playerHeroLevelScope(final Trigger trigger, final CUnit hero) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||
scope.levelingUnit = hero;
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static CommonTriggerExecutionScope playerHeroRevivableScope(final CUnit hero) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(TriggerExecutionScope.EMPTY);
|
||||
public static CommonTriggerExecutionScope playerHeroRevivableScope(final Trigger trigger, final CUnit hero) {
|
||||
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
|
||||
scope.revivableUnit = hero;
|
||||
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.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.etheller.warsmash.datasources.DataSource;
|
||||
import com.etheller.warsmash.units.DataTable;
|
||||
import com.etheller.warsmash.units.StandardObjectData;
|
||||
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.WTSFile;
|
||||
import com.etheller.warsmash.units.custom.War3ObjectDataChangeset;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
||||
import com.etheller.warsmash.util.War3ID;
|
||||
import com.etheller.warsmash.util.WorldEditStrings;
|
||||
import com.google.common.io.LittleEndianDataInputStream;
|
||||
|
||||
@ -135,6 +139,27 @@ public final class Warcraft3MapObjectData {
|
||||
if (dataSource.has("war3map.w3u")) {
|
||||
unitChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3u")), wts,
|
||||
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")) {
|
||||
itemChangeset.load(new LittleEndianDataInputStream(dataSource.getResourceAsStream("war3map.w3t")), wts,
|
||||
|
@ -107,6 +107,10 @@ public class Corner {
|
||||
return this.blight;
|
||||
}
|
||||
|
||||
public void setBlight(final boolean flag) {
|
||||
this.blight = flag ? 0b00100000 : 0;
|
||||
}
|
||||
|
||||
public int getWater() {
|
||||
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
|
||||
* 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 float SIMULATION_STEP_TIME = 1 / 20f;
|
||||
public static final int PORT_NUMBER = 6115;
|
||||
@ -36,4 +36,7 @@ public class WarsmashConstants {
|
||||
// workaround to fix it if you need the local files
|
||||
// to take priority over built-ins for tilesets.
|
||||
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() {
|
||||
return new AudioPanner(this.listener) {
|
||||
@Override
|
||||
public void connect(final AudioDestination destination) {
|
||||
}
|
||||
};
|
||||
return createPanner(true);
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -7,6 +7,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.math.Matrix4;
|
||||
import com.badlogic.gdx.math.Quaternion;
|
||||
@ -73,6 +74,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
private float blendTime;
|
||||
private float blendTimeRemaining;
|
||||
public boolean additiveOverrideMeshMode = false;
|
||||
private boolean hasAnyUnselectableMesh = false;
|
||||
|
||||
public MdxComplexInstance(final MdxModel model) {
|
||||
super(model);
|
||||
@ -85,6 +87,9 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
this.geosetColors = new float[model.geosets.size()][];
|
||||
for (int i = 0, l = model.geosets.size(); i < l; i++) {
|
||||
this.geosetColors[i] = new float[4];
|
||||
if (model.geosets.get(i).unselectable) {
|
||||
this.hasAnyUnselectableMesh = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.layerAlphas = new float[model.layers.size()];
|
||||
@ -677,6 +682,17 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
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) {
|
||||
this.vertexColor[3] = alpha;
|
||||
|
||||
@ -808,7 +824,7 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
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;
|
||||
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
|
||||
public class RibbonEmitter extends MdxEmitter<MdxComplexInstance, RibbonEmitterObject, Ribbon> {
|
||||
public Ribbon first;
|
||||
public Ribbon last;
|
||||
@ -16,7 +18,8 @@ public class RibbonEmitter extends MdxEmitter<MdxComplexInstance, RibbonEmitterO
|
||||
final RibbonEmitterObject emitterObject = this.emitterObject;
|
||||
|
||||
// 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,
|
||||
looping);
|
||||
for (final String fileName : fileNames.split(",")) {
|
||||
String filePath = directoryBase + fileName;
|
||||
final int lastDotIndex = filePath.lastIndexOf('.');
|
||||
if (lastDotIndex != -1) {
|
||||
filePath = filePath.substring(0, lastDotIndex);
|
||||
}
|
||||
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();
|
||||
}
|
||||
final String filePath = directoryBase + fileName;
|
||||
final Sound newSound = createSound(dataSource, filePath);
|
||||
if (newSound != null) {
|
||||
sound.sounds.add(newSound);
|
||||
}
|
||||
}
|
||||
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,
|
||||
final float maxDistance, final float distanceCutoff, final boolean looping) {
|
||||
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.RenderEffect;
|
||||
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.RenderUnitTypeData;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderWidget;
|
||||
@ -701,10 +702,36 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
@Override
|
||||
public CUnit createUnit(final CSimulation simulation, final War3ID typeId, final int playerIndex,
|
||||
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));
|
||||
}
|
||||
|
||||
@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
|
||||
public void spawnBuildingDeathEffect(final CUnit source) {
|
||||
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(source);
|
||||
@ -777,10 +804,11 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
modelInstance.setTeamColor(unit.getPlayerIndex());
|
||||
modelInstance.setLocation(renderUnit.location);
|
||||
modelInstance.setScene(War3MapViewer.this.worldScene);
|
||||
SequenceUtils.randomBirthSequence(modelInstance);
|
||||
War3MapViewer.this.projectiles
|
||||
.add(new RenderAttackInstant(modelInstance, War3MapViewer.this,
|
||||
(float) Math.toRadians(renderUnit.getSimulationUnit().getFacing())));
|
||||
final RenderSpellEffect renderAttackInstant = new RenderSpellEffect(modelInstance,
|
||||
War3MapViewer.this,
|
||||
(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();
|
||||
|
||||
this.terrain.createWaves();
|
||||
|
||||
loadLightsAndShading(tileset);
|
||||
}
|
||||
|
||||
public void spawnFxOnOrigin(final RenderUnit renderUnit, final String heroLevelUpArt) {
|
||||
@ -941,16 +967,6 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
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 {
|
||||
this.applyModificationFile(this.doodadsData, this.doodadMetaData, modifications.getDoodads(),
|
||||
WorldEditorDataType.DOODADS);
|
||||
@ -960,105 +976,17 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
final War3MapDoo doo = this.mapMpq.readDoodads();
|
||||
|
||||
for (final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad : doo.getDoodads()) {
|
||||
WorldEditorDataType type = WorldEditorDataType.DOODADS;
|
||||
MutableGameObject row = modifications.getDoodads().get(doodad.getId());
|
||||
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));
|
||||
}
|
||||
if ((doodad.getFlags() & 0x2) == 0) {
|
||||
continue;
|
||||
}
|
||||
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.
|
||||
@ -1124,6 +1052,125 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
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,
|
||||
final BoundingBox boundingBox) {
|
||||
final float x1 = boundingBox.min.x;
|
||||
@ -1170,7 +1217,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
|
||||
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();
|
||||
|
||||
// Collect the units and items data.
|
||||
@ -1184,9 +1231,10 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
final float unitAngle = unit.getAngle();
|
||||
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);
|
||||
if (unitCreated != null) {
|
||||
if (widgetCreated instanceof CUnit) {
|
||||
final CUnit unitCreated = (CUnit) widgetCreated;
|
||||
if (editorConfigHitPointPercent > 0) {
|
||||
unitCreated.setLife(this.simulation,
|
||||
unitCreated.getMaximumLife() * (editorConfigHitPointPercent / 100f));
|
||||
@ -1205,7 +1253,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
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) {
|
||||
UnitSoundset soundset = null;
|
||||
MutableGameObject row = null;
|
||||
@ -1215,7 +1263,6 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
Splat buildingUberSplat = null;
|
||||
SplatMover buildingUberSplatDynamicIngame = null;
|
||||
BufferedImage buildingPathingPixelMap = null;
|
||||
final float unitVertexScale = 1.0f;
|
||||
RemovablePathingMapInstance pathingInstance = null;
|
||||
BuildingShadow buildingShadowInstance = null;
|
||||
|
||||
@ -1421,7 +1468,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
}
|
||||
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,
|
||||
portraitModel, simulationItem);
|
||||
this.widgets.add(renderItem);
|
||||
@ -1438,6 +1485,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
if (unitShadowSplatDynamicIngame != null) {
|
||||
renderItem.shadow = unitShadowSplatDynamicIngame;
|
||||
}
|
||||
return simulationItem;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1671,7 +1719,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
if (!localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.PASSIVE)) {
|
||||
allyKey = "e:";
|
||||
}
|
||||
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.HELP_REQUEST)) {
|
||||
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.SHARED_CONTROL)) {
|
||||
allyKey = "f:";
|
||||
}
|
||||
}
|
||||
@ -1780,7 +1828,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
if (!localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.PASSIVE)) {
|
||||
allyKey = "e:";
|
||||
}
|
||||
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.HELP_REQUEST)) {
|
||||
else if (localPlayer.hasAlliance(selectedUnitPlayerIndex, CAllianceType.SHARED_CONTROL)) {
|
||||
allyKey = "f:";
|
||||
}
|
||||
}
|
||||
@ -2246,4 +2294,32 @@ public class War3MapViewer extends AbstractMdxModelViewer {
|
||||
public void setGameTurnManager(final 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.Input;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
|
||||
|
||||
public final class GameCameraManager extends CameraManager {
|
||||
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 CameraRates cameraRates;
|
||||
public final CameraPanControls cameraPanControls;
|
||||
private Rectangle cameraBounds;
|
||||
private int currentPreset = 0;
|
||||
private float fov;
|
||||
private RenderUnit targetControllerUnit;
|
||||
private float targetControllerXOffset;
|
||||
private float targetControllerYOffset;
|
||||
private boolean targetControllerInheritOrientation;
|
||||
|
||||
public GameCameraManager(final CameraPreset[] presets, final CameraRates cameraRates) {
|
||||
this.presets = presets;
|
||||
@ -20,6 +26,10 @@ public final class GameCameraManager extends CameraManager {
|
||||
this.cameraPanControls = new CameraPanControls();
|
||||
}
|
||||
|
||||
public void setCameraBounds(final Rectangle cameraBounds) {
|
||||
this.cameraBounds = cameraBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCamera() {
|
||||
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) {
|
||||
this.quatHeap2.idt();
|
||||
this.quatHeap.idt();
|
||||
this.horizontalAngle = applyAtRate(this.horizontalAngle, (float) Math.toRadians(
|
||||
cameraPreset.getRotation(this.cameraPanControls.insertDown, this.cameraPanControls.deleteDown) - 90),
|
||||
final float newHorizontalAngle;
|
||||
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));
|
||||
this.quatHeap.setFromAxisRad(0, 0, 1, this.horizontalAngle);
|
||||
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) {
|
||||
final float velocityX;
|
||||
final float velocityY;
|
||||
up |= this.cameraPanControls.up;
|
||||
down |= this.cameraPanControls.down;
|
||||
left |= this.cameraPanControls.left;
|
||||
right |= this.cameraPanControls.right;
|
||||
if (up) {
|
||||
if (down) {
|
||||
if (this.targetControllerUnit != null) {
|
||||
this.target.x = this.targetControllerUnit.getX() + this.targetControllerXOffset;
|
||||
this.target.y = this.targetControllerUnit.getY() + this.targetControllerYOffset;
|
||||
}
|
||||
else {
|
||||
final float velocityX;
|
||||
final float velocityY;
|
||||
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;
|
||||
}
|
||||
else {
|
||||
velocityY = this.cameraRates.forward;
|
||||
if (right) {
|
||||
if (left) {
|
||||
velocityX = 0;
|
||||
}
|
||||
else {
|
||||
velocityX = this.cameraRates.strafe;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (down) {
|
||||
velocityY = -this.cameraRates.forward;
|
||||
}
|
||||
else {
|
||||
velocityY = 0;
|
||||
}
|
||||
if (right) {
|
||||
if (left) {
|
||||
else if (left) {
|
||||
velocityX = -this.cameraRates.strafe;
|
||||
}
|
||||
else {
|
||||
velocityX = 0;
|
||||
}
|
||||
else {
|
||||
velocityX = this.cameraRates.strafe;
|
||||
this.target.add(velocityX * deltaTime, velocityY * deltaTime, 0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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) {
|
||||
return !PathingFlags.isPathingFlag(getPathing(x, y), pathingType.preventionFlag);
|
||||
}
|
||||
|
@ -406,6 +406,7 @@ public class Terrain {
|
||||
this.centerOffset = w3eFile.getCenterOffset();
|
||||
this.uberSplatModels = new LinkedHashMap<>();
|
||||
this.uberSplatModelsList = new ArrayList<>();
|
||||
this.defaultCameraBounds = w3iFile.getCameraBounds();
|
||||
this.mapBounds = w3iFile.getCameraBoundsComplements();
|
||||
this.shaderMapBounds = new float[] { (this.mapBounds[0] * 128.0f) + this.centerOffset[0],
|
||||
(this.mapBounds[2] * 128.0f) + this.centerOffset[1],
|
||||
@ -724,7 +725,7 @@ public class Terrain {
|
||||
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 updateArea = new Rectangle();
|
||||
Intersector.intersectRectangles(new Rectangle(0, 0, this.columns - 1, this.rows - 1), adjusted, updateArea);
|
||||
@ -1343,6 +1344,7 @@ public class Terrain {
|
||||
public PathingGrid pathingGrid;
|
||||
private final Rectangle shaderMapBoundsRectangle;
|
||||
private final Rectangle entireMapRectangle;
|
||||
private final float[] defaultCameraBounds;
|
||||
|
||||
private static final class UnloadedTexture {
|
||||
private final int width;
|
||||
@ -1390,6 +1392,19 @@ public class Terrain {
|
||||
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) {
|
||||
final float userCellSpaceX = (x - this.centerOffset[0]) / 128.0f;
|
||||
final float userCellSpaceY = (y - this.centerOffset[1]) / 128.0f;
|
||||
@ -1564,4 +1579,8 @@ public class Terrain {
|
||||
return (char) ('A' + layerHeightOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public float[] getDefaultCameraBounds() {
|
||||
return this.defaultCameraBounds;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
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.viewer5.handlers.mdx.MdxComplexInstance;
|
||||
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.SecondaryTag;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
|
||||
@ -34,10 +36,10 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
|
||||
private String replaceableTextureFile;
|
||||
|
||||
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 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.destructableShadow = destructableShadow;
|
||||
this.simulationDestructable = simulationDestructable;
|
||||
@ -187,4 +189,44 @@ public class RenderDestructable extends RenderDoodad implements RenderWidget {
|
||||
public SplatMover getSelectionCircle() {
|
||||
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.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
|
||||
import com.etheller.warsmash.units.manager.MutableObjectData.WorldEditorDataType;
|
||||
import com.etheller.warsmash.util.RenderMathUtils;
|
||||
import com.etheller.warsmash.viewer5.ModelInstance;
|
||||
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
|
||||
@ -23,8 +22,8 @@ public class RenderDoodad {
|
||||
protected float selectionScale;
|
||||
|
||||
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 maxPitch, final float maxRoll) {
|
||||
final float[] location3D, final float[] scale3D, final float facingRadians, final float maxPitch,
|
||||
final float maxRoll, final float selectionScale) {
|
||||
this.maxPitch = maxPitch;
|
||||
this.maxRoll = maxRoll;
|
||||
final boolean isSimple = row.readSLKTagBoolean("lightweight");
|
||||
@ -38,7 +37,7 @@ public class RenderDoodad {
|
||||
((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
|
||||
// revisit it later.
|
||||
// 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
|
||||
// (instead of measuring down from an imaginary flat ground plane, as we do
|
||||
// currently).
|
||||
final float facingRadians = doodad.getAngle();
|
||||
float pitch, roll;
|
||||
this.x = doodad.getLocation()[0];
|
||||
this.y = doodad.getLocation()[1];
|
||||
this.x = location3D[0];
|
||||
this.y = location3D[1];
|
||||
{
|
||||
if (!map.terrain.inPlayableArea(this.x, this.y)) {
|
||||
((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_X, roll));
|
||||
// instance.rotate(new Quaternion().setEulerAnglesRad(facingRadians, 0, 0));
|
||||
final float[] scale = doodad.getScale();
|
||||
instance.scale(scale);
|
||||
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.scale(scale3D);
|
||||
this.selectionScale = selectionScale;
|
||||
instance.setScene(map.worldScene);
|
||||
|
||||
this.instance = instance;
|
||||
|
@ -92,6 +92,7 @@ public class RenderItem implements RenderWidget {
|
||||
this.instance.show();
|
||||
if (this.shadow != null) {
|
||||
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 simulationX = this.simulationItem.getX();
|
||||
final float simulationY = this.simulationItem.getY();
|
||||
final float simDx = simulationX - this.location[0];
|
||||
final float simDy = simulationY - this.location[1];
|
||||
final float dx = simulationX - prevX;
|
||||
final float dy = simulationY - prevY;
|
||||
this.location[0] = simulationX;
|
||||
this.location[1] = simulationY;
|
||||
final float dx = this.location[0] - prevX;
|
||||
final float dy = this.location[1] - prevY;
|
||||
final float groundHeight;
|
||||
// land units will have their feet pass under the surface of the water, so items
|
||||
// here are in the same place
|
||||
@ -150,7 +149,7 @@ public class RenderItem implements RenderWidget {
|
||||
|
||||
@Override
|
||||
public float getSelectionScale() {
|
||||
return 1.0f;
|
||||
return 64.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -202,4 +201,8 @@ public class RenderItem implements RenderWidget {
|
||||
public SplatMover getSelectionCircle() {
|
||||
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;
|
||||
}
|
||||
|
||||
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.CAbilityRally;
|
||||
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.orders.OrderIds;
|
||||
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,
|
||||
int lumberCost, int foodCost) {
|
||||
ability.checkCanUse(this.game, this.unit, orderId, this.previewCallback.reset());
|
||||
final boolean active = ((this.unit.getCurrentBehavior() != null)
|
||||
&& (orderId == this.unit.getCurrentBehavior().getHighlightOrderId()));
|
||||
final boolean disabled = ((ability != null) && ability.isDisabled()) || this.previewCallback.disabled;
|
||||
String uberTip = iconUI.getUberTip();
|
||||
if (disabled) {
|
||||
// dont show these on disabled
|
||||
goldCost = 0;
|
||||
lumberCost = 0;
|
||||
foodCost = 0;
|
||||
if (!this.previewCallback.techtreeMaxReached) {
|
||||
final boolean active = ((this.unit.getCurrentBehavior() != null)
|
||||
&& (orderId == this.unit.getCurrentBehavior().getHighlightOrderId()));
|
||||
final boolean disabled = ((ability != null) && ability.isDisabled()) || this.previewCallback.disabled;
|
||||
String uberTip = iconUI.getUberTip();
|
||||
if (disabled) {
|
||||
// dont show these on disabled
|
||||
goldCost = 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
|
||||
@ -332,12 +335,37 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
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 boolean disabled;
|
||||
private boolean techtreeMaxReached;
|
||||
private final StringBuilder requirementsTextBuilder = new StringBuilder();
|
||||
|
||||
public CommandCardActivationReceiverPreviewCallback reset() {
|
||||
this.disabled = false;
|
||||
this.techtreeMaxReached = false;
|
||||
this.requirementsTextBuilder.setLength(0);
|
||||
return this;
|
||||
}
|
||||
@ -374,6 +402,11 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
|
||||
this.requirementsTextBuilder.append("|n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void techtreeMaximumReached() {
|
||||
this.techtreeMaxReached = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void casterMovementDisabled() {
|
||||
|
||||
|
@ -61,17 +61,34 @@ public class CDestructable extends CWidget {
|
||||
@Override
|
||||
public void damage(final CSimulation simulation, final CUnit source, final CAttackType attackType,
|
||||
final String weaponType, final float damage) {
|
||||
if (isInvulnerable()) {
|
||||
return;
|
||||
}
|
||||
final boolean wasDead = isDead();
|
||||
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());
|
||||
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
|
||||
@ -80,10 +97,12 @@ public class CDestructable extends CWidget {
|
||||
if (targetsAllowed.containsAll(this.destType.getTargetedAs())) {
|
||||
if (isDead()) {
|
||||
return targetsAllowed.contains(CTargetType.DEAD);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return !targetsAllowed.contains(CTargetType.DEAD) || targetsAllowed.contains(CTargetType.ALIVE);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
System.err.println("Not targeting because " + targetsAllowed + " does not contain all of "
|
||||
+ this.destType.getTargetedAs());
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ public class CItem extends CWidget {
|
||||
private final War3ID typeId;
|
||||
private final CItemType itemType;
|
||||
private boolean hidden;
|
||||
private boolean invulnerable;
|
||||
|
||||
public CItem(final int handleId, final float x, final float y, final float life, final War3ID typeId,
|
||||
final CItemType itemTypeInstance) {
|
||||
@ -34,8 +35,15 @@ public class CItem extends CWidget {
|
||||
@Override
|
||||
public void damage(final CSimulation simulation, final CUnit source, final CAttackType attackType,
|
||||
final String weaponType, final float damage) {
|
||||
if (this.invulnerable) {
|
||||
return;
|
||||
}
|
||||
final boolean wasDead = isDead();
|
||||
this.life -= damage;
|
||||
simulation.itemDamageEvent(this, weaponType, this.itemType.getArmorType());
|
||||
if (isDead() && !wasDead) {
|
||||
fireDeathEvents(simulation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,7 +83,7 @@ public class CItem extends CWidget {
|
||||
|
||||
@Override
|
||||
public float getMaxLife() {
|
||||
return itemType.getMaxLife();
|
||||
return this.itemType.getMaxLife();
|
||||
}
|
||||
|
||||
public void setPointAndCheckUnstuck(final float newX, final float newY, final CSimulation game) {
|
||||
@ -107,7 +115,11 @@ public class CItem extends CWidget {
|
||||
|
||||
@Override
|
||||
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 heroDeath();
|
||||
void heroDeath();
|
||||
|
||||
public static final class CPlayerStateNotifier extends SubscriberSetNotifier<CPlayerStateListener>
|
||||
void heroTokensChanged();
|
||||
|
||||
public static final class CPlayerStateNotifier extends SubscriberSetNotifier<CPlayerStateListener>
|
||||
implements CPlayerStateListener {
|
||||
@Override
|
||||
public void goldChanged() {
|
||||
@ -49,5 +51,12 @@ public interface CPlayerStateListener {
|
||||
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.region.CRegionManager;
|
||||
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.SimulationRenderController;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
|
||||
@ -79,6 +81,7 @@ public class CSimulation implements CPlayerAPI {
|
||||
private transient CommandErrorListener commandErrorListener;
|
||||
private final CRegionManager regionManager;
|
||||
private final List<TimeOfDayVariableEvent> timeOfDayVariableEvents = new ArrayList<>();
|
||||
private boolean timeOfDaySuspended;
|
||||
|
||||
public CSimulation(final War3MapConfig config, final DataTable miscData, final MutableObjectData parsedUnitData,
|
||||
final MutableObjectData parsedItemData, final MutableObjectData parsedDestructableData,
|
||||
@ -115,6 +118,9 @@ public class CSimulation implements CPlayerAPI {
|
||||
final CRace defaultRace = CRace.UNDEAD;
|
||||
final CPlayer newPlayer = new CPlayer(defaultRace, new float[] { startLoc.getX(), startLoc.getY() },
|
||||
configPlayer);
|
||||
if (WarsmashConstants.LOCAL_TEMP_TEST_ALL_PLAYERS_PLAYING) {
|
||||
newPlayer.setSlotState(CPlayerSlotState.PLAYING);
|
||||
}
|
||||
this.players.add(newPlayer);
|
||||
}
|
||||
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()) {
|
||||
listIterator.previous();
|
||||
listIterator.add(timer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.activeTimers.add(timer);
|
||||
@ -187,7 +194,7 @@ public class CSimulation implements CPlayerAPI {
|
||||
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 CDestructable dest = this.destructableData.create(this, typeId, x, y, this.handleIdAllocator,
|
||||
pathingInstance, pathingInstanceDeath);
|
||||
@ -198,18 +205,32 @@ public class CSimulation implements CPlayerAPI {
|
||||
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());
|
||||
this.handleIdToItem.put(item.getHandleId(), item);
|
||||
this.items.add(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,
|
||||
final float 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) {
|
||||
return this.handleIdToUnit.get(handleId);
|
||||
}
|
||||
@ -288,8 +309,10 @@ public class CSimulation implements CPlayerAPI {
|
||||
}
|
||||
this.gameTurnTick++;
|
||||
final float timeOfDayBefore = this.getGameTimeOfDay();
|
||||
this.currentGameDayTimeElapsed = (this.currentGameDayTimeElapsed + WarsmashConstants.SIMULATION_STEP_TIME)
|
||||
% this.gameplayConstants.getGameDayLength();
|
||||
if (!this.timeOfDaySuspended) {
|
||||
this.currentGameDayTimeElapsed = (this.currentGameDayTimeElapsed + WarsmashConstants.SIMULATION_STEP_TIME)
|
||||
% this.gameplayConstants.getGameDayLength();
|
||||
}
|
||||
final float timeOfDayAfter = this.getGameTimeOfDay();
|
||||
while (!this.activeTimers.isEmpty() && (this.activeTimers.peek().getEngineFireTick() <= this.gameTurnTick)) {
|
||||
this.activeTimers.pop().fire(this);
|
||||
@ -327,6 +350,11 @@ public class CSimulation implements CPlayerAPI {
|
||||
* 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() {
|
||||
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) {
|
||||
this.simulationRenderController.heroDeathEvent(cUnit);
|
||||
}
|
||||
@ -524,4 +562,19 @@ public class CSimulation implements CPlayerAPI {
|
||||
}
|
||||
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.combat.CAttackType;
|
||||
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.orders.COrder;
|
||||
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.CRegionEnumFunction;
|
||||
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.BooleanAbilityTargetCheckReceiver;
|
||||
|
||||
@ -263,6 +266,7 @@ public class CUnit extends CWidget {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.stateListenersUpdates.clear();
|
||||
if (isDead()) {
|
||||
if (this.collisionRectangle != null) {
|
||||
// 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) {
|
||||
@ -1610,6 +1616,15 @@ public class CUnit extends CWidget {
|
||||
this.defaultBehavior = defaultBehavior;
|
||||
}
|
||||
|
||||
public CAbilityGoldMine getGoldMineData() {
|
||||
for (final CAbility ability : this.abilities) {
|
||||
if (ability instanceof CAbilityGoldMine) {
|
||||
return ((CAbilityGoldMine) ability);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getGold() {
|
||||
for (final CAbility ability : this.abilities) {
|
||||
if (ability instanceof CAbilityGoldMine) {
|
||||
@ -1744,4 +1759,141 @@ public class CUnit extends CWidget {
|
||||
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> unitsTrained;
|
||||
private final List<War3ID> researchesAvailable;
|
||||
private final List<War3ID> upgradesTo;
|
||||
private final CUnitRace unitRace;
|
||||
private final int goldCost;
|
||||
private final int lumberCost;
|
||||
@ -85,8 +86,8 @@ public class CUnitType {
|
||||
final CDefenseType defenseType, final float impactZ, final BufferedImage buildingPathingPixelMap,
|
||||
final float deathTime, final EnumSet<CTargetType> targetedAs, final float defaultAcquisitionRange,
|
||||
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 int foodUsed, final int foodMade, final int buildTime,
|
||||
final List<War3ID> researchesAvailable, final List<War3ID> upgradesTo, final CUnitRace unitRace,
|
||||
final int goldCost, final int lumberCost, final int foodUsed, final int foodMade, final int buildTime,
|
||||
final EnumSet<CBuildingPathingType> preventedPathingTypes,
|
||||
final EnumSet<CBuildingPathingType> requiredPathingTypes, final float propWindow, final float turnRate,
|
||||
final List<CUnitTypeRequirement> requirements, final int level, final boolean hero, final int strength,
|
||||
@ -122,6 +123,7 @@ public class CUnitType {
|
||||
this.structuresBuilt = structuresBuilt;
|
||||
this.unitsTrained = unitsTrained;
|
||||
this.researchesAvailable = researchesAvailable;
|
||||
this.upgradesTo = upgradesTo;
|
||||
this.unitRace = unitRace;
|
||||
this.goldCost = goldCost;
|
||||
this.lumberCost = lumberCost;
|
||||
@ -262,6 +264,10 @@ public class CUnitType {
|
||||
return this.researchesAvailable;
|
||||
}
|
||||
|
||||
public List<War3ID> getUpgradesTo() {
|
||||
return this.upgradesTo;
|
||||
}
|
||||
|
||||
public CUnitRace getRace() {
|
||||
return this.unitRace;
|
||||
}
|
||||
|
@ -1,11 +1,20 @@
|
||||
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
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.combat.CAttackType;
|
||||
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 {
|
||||
protected static final Rectangle tempRect = new Rectangle();
|
||||
@ -13,6 +22,8 @@ public abstract class CWidget implements AbilityTarget {
|
||||
private float x;
|
||||
private float y;
|
||||
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) {
|
||||
this.handleId = handleId;
|
||||
@ -78,4 +89,49 @@ public abstract class CWidget implements AbilityTarget {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
|
||||
@ -43,6 +44,9 @@ public class CAbilityAttack extends AbstractCAbility {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (target instanceof CDestructable) {
|
||||
// fall thru to below
|
||||
}
|
||||
else {
|
||||
receiver.orderIdNotAccepted();
|
||||
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.CAbilityRally;
|
||||
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
|
||||
@ -48,6 +49,8 @@ public interface CAbilityVisitor<T> {
|
||||
|
||||
T accept(CAbilityQueue ability);
|
||||
|
||||
T accept(CAbilityUpgrade ability);
|
||||
|
||||
T accept(CAbilityReviveHero ability);
|
||||
|
||||
T accept(GenericSingleIconActiveAbility ability);
|
||||
|
@ -42,7 +42,8 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements
|
||||
if (unitType != null) {
|
||||
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||
final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
|
||||
boolean requirementsMet = true;
|
||||
final boolean techtreeAllowedByMax = player.isTechtreeAllowedByMax(orderIdAsRawtype);
|
||||
boolean requirementsMet = techtreeAllowedByMax;
|
||||
for (final CUnitTypeRequirement requirement : requirements) {
|
||||
if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
|
||||
requirementsMet = false;
|
||||
@ -69,8 +70,13 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (final CUnitTypeRequirement requirement : requirements) {
|
||||
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
|
||||
if (techtreeAllowedByMax) {
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ public class CAbilityHero extends AbstractCAbility {
|
||||
}
|
||||
|
||||
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();
|
||||
while ((this.heroLevel < gameplayConstants.getMaxHeroLevel())
|
||||
&& (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.inventory.CBehaviorDropItem;
|
||||
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.players.CAllianceType;
|
||||
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
|
||||
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 CBehaviorGetItem behaviorGetItem;
|
||||
private CBehaviorDropItem behaviorDropItem;
|
||||
private CBehaviorGiveItemToHero behaviorGiveItem;
|
||||
|
||||
public CAbilityInventory(final int handleId, final War3ID alias, final boolean canDropItems,
|
||||
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) {
|
||||
this.behaviorGetItem = new CBehaviorGetItem(unit, this);
|
||||
this.behaviorDropItem = new CBehaviorDropItem(unit, this);
|
||||
this.behaviorGiveItem = new CBehaviorGiveItemToHero(unit, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -81,16 +85,37 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (cAbility instanceof GenericSingleIconActiveAbility) {
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId,
|
||||
final AbilityPointTarget point) {
|
||||
@ -133,10 +163,7 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
||||
final int slot = orderId - OrderIds.itemuse00;
|
||||
final CBehavior behavior = this.itemsHeldAbilities[slot].get(0).beginNoTarget(game, caster, orderId);
|
||||
final CItem cItem = this.itemsHeld[slot];
|
||||
if (cItem.getItemType().isPerishable()) {
|
||||
dropItem(game, caster, slot, caster.getX(), caster.getY(), false);
|
||||
game.removeItem(cItem);
|
||||
}
|
||||
consumePerishableCharge(game, caster, slot, cItem);
|
||||
return behavior;
|
||||
}
|
||||
|
||||
@ -172,7 +199,24 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
|
||||
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
|
||||
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId,
|
||||
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
|
||||
if (orderId == OrderIds.dropitem) {
|
||||
if (orderId != OrderIds.dropitem) {
|
||||
receiver.orderIdNotAccepted();
|
||||
}
|
||||
else {
|
||||
receiver.targetOk(target);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,7 +48,8 @@ public final class CAbilityQueue extends AbstractCAbility {
|
||||
if (unitType != null) {
|
||||
final CPlayer player = game.getPlayer(unit.getPlayerIndex());
|
||||
final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
|
||||
boolean requirementsMet = true;
|
||||
final boolean techtreeAllowedByMax = player.isTechtreeAllowedByMax(orderIdAsRawtype);
|
||||
boolean requirementsMet = techtreeAllowedByMax;
|
||||
for (final CUnitTypeRequirement requirement : requirements) {
|
||||
if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
|
||||
requirementsMet = false;
|
||||
@ -74,8 +75,13 @@ public final class CAbilityQueue extends AbstractCAbility {
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (final CUnitTypeRequirement requirement : requirements) {
|
||||
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
|
||||
if (techtreeAllowedByMax) {
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,171 @@
|
||||
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.CAbilityRally;
|
||||
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 static final AbilityDisableWhileUnderConstructionVisitor INSTANCE = new AbilityDisableWhileUnderConstructionVisitor();
|
||||
@ -107,7 +108,14 @@ public class AbilityDisableWhileUnderConstructionVisitor implements CAbilityVisi
|
||||
}
|
||||
|
||||
@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.setIconShowing(false);
|
||||
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")) {
|
||||
return LARGE;
|
||||
}
|
||||
if (upperCaseTypeString.trim().isEmpty()) {
|
||||
System.err.println("bad");
|
||||
}
|
||||
return valueOf(upperCaseTypeString);
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +176,10 @@ public abstract class CBasePlayer implements CPlayerJass {
|
||||
return this.slotState;
|
||||
}
|
||||
|
||||
public void setSlotState(final CPlayerSlotState slotState) {
|
||||
this.slotState = slotState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTaxRate(final int otherPlayerIndex, final CPlayerState 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.CAbilityRally;
|
||||
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.CDefenseType;
|
||||
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 UNITS_TRAINED = War3ID.fromString("utra");
|
||||
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 UNIT_RACE = War3ID.fromString("urac");
|
||||
|
||||
@ -242,9 +244,13 @@ public class CUnitData {
|
||||
}
|
||||
final List<War3ID> unitsTrained = unitTypeInstance.getUnitsTrained();
|
||||
final List<War3ID> researchesAvailable = unitTypeInstance.getResearchesAvailable();
|
||||
final List<War3ID> upgradesTo = unitTypeInstance.getUpgradesTo();
|
||||
if (!unitsTrained.isEmpty() || !researchesAvailable.isEmpty()) {
|
||||
unit.add(simulation, new CAbilityQueue(handleIdAllocator.createId(), unitsTrained, researchesAvailable));
|
||||
}
|
||||
if (!upgradesTo.isEmpty()) {
|
||||
unit.add(simulation, new CAbilityUpgrade(handleIdAllocator.createId(), upgradesTo));
|
||||
}
|
||||
if (unitTypeInstance.isRevivesHeroes()) {
|
||||
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[] researchesAvailableStringItems = researchesAvailableString.trim().split(",");
|
||||
final List<War3ID> researchesAvailable = new ArrayList<>();
|
||||
@ -541,11 +556,11 @@ public class CUnitData {
|
||||
unitTypeInstance = new CUnitType(unitName, legacyName, typeId, life, manaInitial, manaMaximum, speed,
|
||||
defense, abilityList, isBldg, movementType, moveHeight, collisionSize, classifications, attacks,
|
||||
armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs,
|
||||
acquisitionRange, minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable, unitRace,
|
||||
goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes,
|
||||
propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus,
|
||||
intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames, properNamesCount,
|
||||
canFlee, priority, revivesHeroes);
|
||||
acquisitionRange, minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable,
|
||||
upgradesTo, unitRace, goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes,
|
||||
requiredPathingTypes, propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus,
|
||||
agility, agiPlus, intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames,
|
||||
properNamesCount, canFlee, priority, revivesHeroes);
|
||||
this.unitIdToUnitType.put(typeId, unitTypeInstance);
|
||||
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()) {
|
||||
final CWidget target = game.getWidget(this.targetHandleId);
|
||||
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) {
|
||||
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.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.util.War3ID;
|
||||
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.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.config.CBasePlayer;
|
||||
@ -21,19 +23,37 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEve
|
||||
public class CPlayer extends CBasePlayer {
|
||||
private final CRace race;
|
||||
private final float[] startLocation;
|
||||
private int gold = 500;
|
||||
private int lumber = 150;
|
||||
private int gold;
|
||||
private int lumber;
|
||||
private int heroTokens;
|
||||
private int foodCap;
|
||||
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> rawcodeToTechtreeMaxAllowed = new HashMap<>();
|
||||
private final List<CUnit> heroes = new ArrayList<>();
|
||||
private final EnumMap<JassGameEventsWar3, List<CPlayerEvent>> eventTypeToEvents = new EnumMap<>(
|
||||
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
|
||||
// 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
|
||||
private transient CPlayerStateNotifier stateNotifier = new CPlayerStateNotifier();
|
||||
private float handicapXP;
|
||||
|
||||
public CPlayer(final CRace race, final float[] startLocation, final CBasePlayer configPlayer) {
|
||||
super(configPlayer);
|
||||
@ -57,6 +77,10 @@ public class CPlayer extends CBasePlayer {
|
||||
return this.lumber;
|
||||
}
|
||||
|
||||
public int getHeroTokens() {
|
||||
return this.heroTokens;
|
||||
}
|
||||
|
||||
public int getFoodCap() {
|
||||
return this.foodCap;
|
||||
}
|
||||
@ -65,6 +89,10 @@ public class CPlayer extends CBasePlayer {
|
||||
return this.foodUsed;
|
||||
}
|
||||
|
||||
public int getFoodCapCeiling() {
|
||||
return this.foodCapCeiling;
|
||||
}
|
||||
|
||||
public float[] getStartLocation() {
|
||||
return this.startLocation;
|
||||
}
|
||||
@ -79,11 +107,21 @@ public class CPlayer extends CBasePlayer {
|
||||
this.stateNotifier.lumberChanged();
|
||||
}
|
||||
|
||||
public void setHeroTokens(final int heroTokens) {
|
||||
this.heroTokens = heroTokens;
|
||||
this.stateNotifier.heroTokensChanged();
|
||||
}
|
||||
|
||||
public void setFoodCap(final int foodCap) {
|
||||
this.foodCap = foodCap;
|
||||
this.stateNotifier.foodChanged();
|
||||
}
|
||||
|
||||
public void setFoodCapCeiling(final int foodCapCeiling) {
|
||||
this.foodCapCeiling = foodCapCeiling;
|
||||
this.stateNotifier.foodChanged();
|
||||
}
|
||||
|
||||
public void setFoodUsed(final int foodUsed) {
|
||||
this.foodUsed = foodUsed;
|
||||
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) {
|
||||
this.stateNotifier.subscribe(listener);
|
||||
}
|
||||
@ -169,16 +219,17 @@ public class CPlayer extends CBasePlayer {
|
||||
|
||||
public void onHeroDeath(final CUnit hero) {
|
||||
this.stateNotifier.heroDeath();
|
||||
firePlayerUnitEvents(hero, CommonTriggerExecutionScope.playerHeroRevivableScope(hero),
|
||||
firePlayerUnitEvents(hero, CommonTriggerExecutionScope::playerHeroRevivableScope,
|
||||
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 List<CPlayerEvent> eventList = getEventList(eventType);
|
||||
if (eventList != null) {
|
||||
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) {
|
||||
firePlayerUnitEvents(hero, CommonTriggerExecutionScope.playerHeroRevivableScope(hero),
|
||||
firePlayerUnitEvents(hero, CommonTriggerExecutionScope::playerHeroRevivableScope,
|
||||
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) {
|
||||
List<CPlayerEvent> playerEvents = this.eventTypeToEvents.get(eventType);
|
||||
if (playerEvents == null) {
|
||||
@ -208,7 +269,14 @@ public class CPlayer extends CBasePlayer {
|
||||
@Override
|
||||
public RemovableTriggerEvent addEvent(final GlobalScope globalScope, final Trigger whichTrigger,
|
||||
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);
|
||||
return playerEvent;
|
||||
}
|
||||
@ -220,4 +288,126 @@ public class CPlayer extends CBasePlayer {
|
||||
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.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.CUnit;
|
||||
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 Trigger trigger;
|
||||
private final JassGameEventsWar3 eventType;
|
||||
private final TriggerBooleanExpression filter;
|
||||
|
||||
public CPlayerEvent(final GlobalScope globalScope, final CPlayerJass player, final Trigger trigger,
|
||||
final JassGameEventsWar3 eventType) {
|
||||
final JassGameEventsWar3 eventType, final TriggerBooleanExpression filter) {
|
||||
this.globalScope = globalScope;
|
||||
this.player = player;
|
||||
this.trigger = trigger;
|
||||
this.eventType = eventType;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public Trigger getTrigger() {
|
||||
@ -35,6 +39,13 @@ public class CPlayerEvent implements RemovableTriggerEvent {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
public enum CPlayerState {
|
||||
GAME_RESULT,
|
||||
// current resource levels
|
||||
//
|
||||
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.behaviors.CBehaviorHoldPosition;
|
||||
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.COrderTargetPoint;
|
||||
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
|
||||
public void issuePointOrder(final int unitHandleId, final int abilityHandleId, final int orderId, final float x,
|
||||
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,
|
||||
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 unitCancelTrainingItem(int unitHandleId, int cancelIndex);
|
||||
|
@ -14,7 +14,7 @@ public enum CRace {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static CRace[] VALUES = values();
|
||||
public static CRace[] VALUES = { null, HUMAN, ORC, UNDEAD, NIGHTELF, DEMON, null, OTHER };
|
||||
|
||||
public int getId() {
|
||||
return this.id;
|
||||
|
@ -20,10 +20,10 @@ public class CRegionTriggerEnter {
|
||||
}
|
||||
|
||||
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))) {
|
||||
final CommonTriggerExecutionScope eventScope = CommonTriggerExecutionScope
|
||||
.unitEnterRegionScope(TriggerExecutionScope.EMPTY, unit, region);
|
||||
.unitEnterRegionScope(this.trigger, TriggerExecutionScope.EMPTY, unit, region);
|
||||
if (this.trigger.evaluate(this.globalScope, eventScope)) {
|
||||
this.trigger.execute(this.globalScope, eventScope);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class CRegionTriggerLeave {
|
||||
if (this.filter.evaluate(this.globalScope,
|
||||
CommonTriggerExecutionScope.filterScope(TriggerExecutionScope.EMPTY, unit))) {
|
||||
final CommonTriggerExecutionScope eventScope = CommonTriggerExecutionScope
|
||||
.unitLeaveRegionScope(TriggerExecutionScope.EMPTY, unit, region);
|
||||
.unitLeaveRegionScope(this.trigger, TriggerExecutionScope.EMPTY, unit, region);
|
||||
if (this.trigger.evaluate(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
|
||||
public void onFire() {
|
||||
final CommonTriggerExecutionScope executionScope = CommonTriggerExecutionScope.expiringTimer(this);
|
||||
this.handlerFunc.call(Collections.emptyList(), this.jassGlobalScope, executionScope);
|
||||
final CommonTriggerExecutionScope handlerScope = CommonTriggerExecutionScope.expiringTimer(null, this);
|
||||
this.handlerFunc.call(Collections.emptyList(), this.jassGlobalScope, handlerScope);
|
||||
for (final Trigger trigger : this.eventTriggers) {
|
||||
final CommonTriggerExecutionScope executionScope = CommonTriggerExecutionScope.expiringTimer(trigger, this);
|
||||
if (trigger.evaluate(this.jassGlobalScope, executionScope)) {
|
||||
trigger.execute(this.jassGlobalScope, executionScope);
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ public enum CDamageType {
|
||||
DEMOLITION,
|
||||
SLOW_POISON,
|
||||
SPIRIT_LINK,
|
||||
SHADOW_STRIKE;
|
||||
SHADOW_STRIKE,
|
||||
UNIVERSAL;
|
||||
|
||||
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 disabled();
|
||||
|
||||
void techtreeMaximumReached();
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ public class BooleanAbilityActivationReceiver implements AbilityActivationReceiv
|
||||
this.ok = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void techtreeMaximumReached() {
|
||||
this.ok = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void casterMovementDisabled() {
|
||||
this.ok = false;
|
||||
|
@ -64,6 +64,11 @@ public class MeleeUIAbilityActivationReceiver implements AbilityActivationReceiv
|
||||
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void techtreeMaximumReached() {
|
||||
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void casterMovementDisabled() {
|
||||
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,
|
||||
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 spawnDamageSound(CWidget damagedDestructable, String weaponSound, String armorType);
|
||||
|
@ -40,6 +40,11 @@ public class StringMsgAbilityActivationReceiver implements AbilityActivationRece
|
||||
this.message = "NOTEXTERN: Requires " + type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void techtreeMaximumReached() {
|
||||
this.message = "NOTEXTERN: Techtree maximum reached.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cargoCapacityUnavailable() {
|
||||
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_UP_LEFT("Scroll Up Left"),
|
||||
SCROLL_UP_RIGHT("Scroll Up Right"),
|
||||
SELECT("Select"),
|
||||
TARGET_CURSOR(null), // handled specially
|
||||
HOLD_ITEM("HoldItem");
|
||||
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
|
||||
;
|
||||
local :
|
||||
LOCAL type ID newlines # BasicLocal
|
||||
|
|
||||
LOCAL type ID assignTail newlines # DefinitionLocal
|
||||
;
|
||||
|
||||
assignTail:
|
||||
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
|
||||
|
|
||||
STRING_LITERAL #StringLiteralExpression
|
||||
|
|
||||
INTEGER #IntegerLiteralExpression
|
||||
|
|
||||
RAWCODE #RawcodeLiteralExpression
|
||||
|
|
||||
REAL #RealLiteralExpression
|
||||
|
|
||||
FUNCTION ID #FunctionReferenceExpression
|
||||
|
|
||||
NULL # NullExpression
|
||||
@ -59,9 +116,14 @@ expression:
|
||||
|
|
||||
'(' expression ')' # ParentheticalExpression
|
||||
|
|
||||
NOT expression # NotExpression
|
||||
NOT baseExpression # NotExpression
|
||||
|
|
||||
'-' baseExpression # NegateExpression
|
||||
;
|
||||
|
||||
expression:
|
||||
boolExpression;
|
||||
|
||||
functionExpression:
|
||||
ID '(' argsList ')'
|
||||
|
|
||||
@ -72,6 +134,8 @@ argsList:
|
||||
expression # SingleArgument
|
||||
|
|
||||
expression ',' argsList # ListArgument
|
||||
|
|
||||
# EmptyArgument
|
||||
;
|
||||
|
||||
//#booleanExpression:
|
||||
@ -87,6 +151,14 @@ statement:
|
||||
|
|
||||
RETURN expression newlines # ReturnStatement
|
||||
|
|
||||
RETURN newlines # ReturnNothingStatement
|
||||
|
|
||||
EXITWHEN expression newlines # ExitWhenStatement
|
||||
|
|
||||
local # LocalStatement
|
||||
|
|
||||
LOOP newlines statements ENDLOOP newlines # LoopStatement
|
||||
|
|
||||
IF ifStatementPartial # IfStatement
|
||||
;
|
||||
|
||||
@ -182,16 +254,27 @@ ELSE : 'else';
|
||||
ENDIF : 'endif';
|
||||
ELSEIF : 'elseif';
|
||||
CONSTANT : 'constant';
|
||||
LOCAL : 'local';
|
||||
LOOP : 'loop';
|
||||
ENDLOOP : 'endloop';
|
||||
EXITWHEN : 'exitwhen';
|
||||
|
||||
STRING_LITERAL : ('"'.*?'"');
|
||||
|
||||
|
||||
INTEGER : [0]|([1-9][0-9]*) ;
|
||||
|
||||
RAWCODE : ('\''.*?'\'');
|
||||
|
||||
REAL : (([0]|([1-9][0-9]*))'.'[0-9]*)|('.'([0]|([1-9][0-9]*))) ;
|
||||
|
||||
NULL : 'null' ;
|
||||
TRUE : 'true' ;
|
||||
FALSE : 'false' ;
|
||||
|
||||
NOT : 'not';
|
||||
OR : 'or';
|
||||
AND : 'and';
|
||||
|
||||
ID : ([a-zA-Z_][a-zA-Z_0-9]*) ; // match identifiers
|
||||
|
||||
|
@ -13,11 +13,19 @@ public class Assignable {
|
||||
}
|
||||
|
||||
public void setValue(final JassValue value) {
|
||||
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
|
||||
if (!this.type.isAssignableFrom(valueType)) {
|
||||
throw new RuntimeException("Incompatible types " + valueType.getName() + " != " + this.type.getName());
|
||||
if (value == null) {
|
||||
if (!this.type.isNullable()) {
|
||||
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() {
|
||||
|
@ -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);
|
||||
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) {
|
||||
if (value == null) {
|
||||
return this.type.isNullable();
|
||||
}
|
||||
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
|
||||
return this.type.isAssignableFrom(valueType);
|
||||
}
|
||||
|
@ -22,6 +22,13 @@ public class NativeJassFunction extends AbstractJassFunction {
|
||||
@Override
|
||||
protected JassValue innerCall(final List<JassValue> arguments, final GlobalScope globalScope,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ 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.statement.JassReturnNothingStatement;
|
||||
import com.etheller.interpreter.ast.statement.JassStatement;
|
||||
import com.etheller.interpreter.ast.value.JassType;
|
||||
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);
|
||||
if (returnValue != null) {
|
||||
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;
|
||||
}
|
||||
|
@ -69,7 +69,12 @@ public final class GlobalScope {
|
||||
|
||||
public void createGlobal(final String name, final JassType type, final JassValue value) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,9 @@ public class Trigger {
|
||||
}
|
||||
|
||||
public void execute(final GlobalScope globalScope, final TriggerExecutionScope triggerScope) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
for (final JassFunction action : this.actions) {
|
||||
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) {
|
||||
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