Update ui

This commit is contained in:
Retera 2020-10-26 08:34:33 -04:00
parent e21bb492c1
commit 0c0141cd71
39 changed files with 2194 additions and 1760 deletions

View File

@ -309,7 +309,8 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.font.setColor(Color.YELLOW);
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
this.glyphLayout.setText(this.font, fpsString);
this.font.draw(this.batch, fpsString, (this.uiViewport.getMinWorldWidth() - this.glyphLayout.width) / 2, 1100);
this.font.draw(this.batch, fpsString, (this.uiViewport.getMinWorldWidth() - this.glyphLayout.width) / 2,
1100 * this.meleeUI.getHeightRatioCorrection());
this.batch.end();
Gdx.gl30.glEnable(GL30.GL_SCISSOR_TEST);

View File

@ -21,6 +21,8 @@ public abstract class SkeletalNode extends GenericNode {
public boolean billboardedY;
public boolean billboardedZ;
public Matrix4 localBlendMatrix;
public SkeletalNode() {
this.pivot = new Vector3();
this.localLocation = new Vector3();
@ -33,6 +35,7 @@ public abstract class SkeletalNode extends GenericNode {
this.inverseWorldRotation = new Quaternion();
this.inverseWorldScale = new Vector3();
this.localMatrix = new Matrix4();
this.localBlendMatrix = new Matrix4();
this.worldMatrix = new Matrix4();
this.dontInheritTranslation = false;
this.dontInheritRotation = false;
@ -66,7 +69,7 @@ public abstract class SkeletalNode extends GenericNode {
this.billboardedZ = false;
}
public void recalculateTransformation(final Scene scene) {
public void recalculateTransformation(final Scene scene, final float blendTimeRatio) {
final Quaternion computedRotation;
Vector3 computedScaling;
@ -135,6 +138,12 @@ public abstract class SkeletalNode extends GenericNode {
RenderMathUtils.fromRotationTranslationScaleOrigin(computedRotation, this.localLocation, computedScaling,
this.localMatrix, this.pivot);
if (!Float.isNaN(blendTimeRatio) && (blendTimeRatio > 0)) {
for (int i = 0; i < this.localMatrix.val.length; i++) {
this.localMatrix.val[i] = (this.localBlendMatrix.val[i] * blendTimeRatio)
+ (this.localMatrix.val[i] * (1 - blendTimeRatio));
}
}
RenderMathUtils.mul(this.worldMatrix, this.parent.worldMatrix, this.localMatrix);
@ -168,6 +177,10 @@ public abstract class SkeletalNode extends GenericNode {
this.inverseWorldLocation.z = -this.worldLocation.z;
}
public void beginBlending() {
this.localBlendMatrix.set(this.localMatrix);
}
public void updateChildren(final float dt, final Scene scene) {
for (int i = 0, l = this.children.size(); i < l; i++) {
this.children.get(i).update(dt, scene);

View File

@ -86,16 +86,9 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitFilterFunction;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackInstant;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.projectile.CAttackProjectile;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CWidgetAbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.PointAbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
import mpq.MPQArchive;
@ -1275,74 +1268,6 @@ public class War3MapViewer extends ModelViewer {
return (numElements < 0) ? 1 : (numElements >= MAXIMUM_ACCEPTED) ? MAXIMUM_ACCEPTED : numElements + 1;
}
public boolean orderSmart(final float x, final float y) {
mousePosHeap.x = x;
mousePosHeap.y = y;
boolean ordered = false;
for (final RenderUnit unit : this.selected) {
for (final CAbility ability : unit.getSimulationUnit().getAbilities()) {
if (ability instanceof CAbilityMove) {
ability.checkCanUse(this.simulation, unit.getSimulationUnit(), OrderIds.smart,
BooleanAbilityActivationReceiver.INSTANCE);
if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) {
ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap,
PointAbilityTargetCheckReceiver.INSTANCE);
final Vector2 target = PointAbilityTargetCheckReceiver.INSTANCE.getTarget();
if (target != null) {
ability.onOrder(this.simulation, unit.getSimulationUnit(), OrderIds.smart, mousePosHeap,
false);
ordered = true;
}
else {
System.err.println("Target not valid.");
}
}
else {
System.err.println("Ability not ok to use.");
}
}
else {
System.err.println("Ability not move.");
}
}
}
return ordered;
}
public boolean orderSmart(final RenderUnit target) {
boolean ordered = false;
for (final RenderUnit unit : this.selected) {
for (final CAbility ability : unit.getSimulationUnit().getAbilities()) {
if (ability instanceof CAbilityAttack) {
ability.checkCanUse(this.simulation, unit.getSimulationUnit(), OrderIds.smart,
BooleanAbilityActivationReceiver.INSTANCE);
if (BooleanAbilityActivationReceiver.INSTANCE.isOk()) {
ability.checkCanTarget(this.simulation, unit.getSimulationUnit(), OrderIds.smart,
target.getSimulationUnit(), CWidgetAbilityTargetCheckReceiver.INSTANCE);
final CWidget targetWidget = CWidgetAbilityTargetCheckReceiver.INSTANCE.getTarget();
if (targetWidget != null) {
ability.onOrder(this.simulation, unit.getSimulationUnit(), OrderIds.smart, targetWidget,
false);
ordered = true;
}
else {
System.err.println("Target not valid.");
}
}
else {
System.err.println("Ability not ok to use.");
}
}
else {
System.err.println("Ability not move.");
}
}
}
return ordered;
}
public void standOnRepeat(final MdxComplexInstance instance) {
instance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
SequenceUtils.randomStandSequence(instance);

View File

@ -38,6 +38,7 @@ public class RenderUnit {
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
private static final War3ID ORIENTATION_INTERPOLATION = War3ID.fromString("uori");
private static final War3ID ANIM_PROPS = War3ID.fromString("uani");
private static final War3ID BLEND_TIME = War3ID.fromString("uble");
private static final float[] heapZ = new float[3];
public final MdxComplexInstance instance;
public final MutableGameObject row;
@ -124,6 +125,9 @@ public class RenderUnit {
orientationInterpolationOrdinal = 0;
}
this.orientationInterpolation = OrientationInterpolation.VALUES[orientationInterpolationOrdinal];
final float blendTime = row.getFieldAsFloat(BLEND_TIME, 0);
instance.setBlendTime(blendTime * 1000.0f);
}
this.instance = instance;

View File

@ -35,5 +35,5 @@ public interface CommandButtonListener {
//
// int getOrderId();
void commandButton(int buttonPositionX, int buttonPositionY, Texture icon, int abilityHandleId, int orderId,
boolean active);
int autoCastOrderId, boolean active, boolean autoCastActive);
}

View File

@ -6,10 +6,11 @@ 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.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityGeneric;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void> {
public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor();
@ -33,41 +34,54 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
@Override
public Void accept(final CAbilityAttack ability) {
addCommandButton(ability, this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack);
addCommandButton(ability, this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack, 0, false);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(null, this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
addCommandButton(null, this.abilityDataUI.getStopUI(), 0, OrderIds.stop, 0, false);
}
return null;
}
@Override
public Void accept(final CAbilityMove ability) {
addCommandButton(ability, this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move);
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition);
addCommandButton(ability, this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol);
addCommandButton(ability, this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move, 0, false);
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition, 0,
false);
addCommandButton(ability, this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol, 0, false);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(null, this.abilityDataUI.getStopUI(), -1, OrderIds.stop);
addCommandButton(null, this.abilityDataUI.getStopUI(), 0, OrderIds.stop, 0, false);
}
return null;
}
private void addCommandButton(final CAbility ability, final IconUI iconUI, final int handleId, final int orderId) {
final boolean active;
if (this.unit.getCurrentOrder() == null) {
active = (orderId == OrderIds.stop);
@Override
public Void accept(final CAbilityGeneric ability) {
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(), ability.getHandleId(),
OrderIds.channel, 0, false);
return null;
}
@Override
public Void accept(final CAbilityColdArrows ability) {
final boolean autoCastActive = ability.isAutoCastActive();
int autoCastId;
if (autoCastActive) {
autoCastId = OrderIds.coldarrows;
}
else {
if (ability == null) {
active = false;
}
else {
ability.checkCanUse(this.game, this.unit, orderId, BooleanAbilityActivationReceiver.INSTANCE);
active = BooleanAbilityActivationReceiver.INSTANCE.isOk();
}
autoCastId = OrderIds.uncoldarrows;
}
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(), ability.getHandleId(),
OrderIds.coldarrowstarg, autoCastId, autoCastActive);
return null;
}
private void addCommandButton(final CAbility ability, final IconUI iconUI, final int handleId, final int orderId,
final int autoCastOrderId, final boolean autoCastActive) {
final boolean active = ((handleId == this.unit.getCurrentAbilityHandleId())
&& (orderId == this.unit.getCurrentOrderId()));
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
iconUI.getIcon(), handleId, orderId, active);
iconUI.getIcon(), handleId, orderId, autoCastOrderId, active, autoCastActive);
}
}

View File

@ -28,10 +28,11 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CMapControl
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CRace;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
public class CSimulation {
private final CUnitData unitData;
private final CAbilityData abilityData;
private final CUnitData unitData;
private final List<CUnit> units;
private final List<CPlayer> players;
private final List<CAttackProjectile> projectiles;
@ -47,6 +48,7 @@ public class CSimulation {
private float currentGameDayTimeElapsed;
private final Map<Integer, CUnit> handleIdToUnit = new HashMap<>();
private final Map<Integer, CAbility> handleIdToAbility = new HashMap<>();
private transient CommandErrorListener commandErrorListener;
public CSimulation(final DataTable miscData, final MutableObjectData parsedUnitData,
final MutableObjectData parsedAbilityData, final SimulationRenderController simulationRenderController,
@ -55,8 +57,8 @@ public class CSimulation {
this.gameplayConstants = new CGameplayConstants(miscData);
this.simulationRenderController = simulationRenderController;
this.pathingGrid = pathingGrid;
this.unitData = new CUnitData(parsedUnitData);
this.abilityData = new CAbilityData(parsedAbilityData);
this.unitData = new CUnitData(parsedUnitData, this.abilityData);
this.units = new ArrayList<>();
this.projectiles = new ArrayList<>();
this.newProjectiles = new ArrayList<>();
@ -92,6 +94,13 @@ public class CSimulation {
neutralPassive.setAlliance(cPlayer, CAllianceType.PASSIVE, true);
}
this.commandErrorListener = new CommandErrorListener() {
@Override
public void showCommandError(final String message) {
throw new RuntimeException(message);
}
};
}
public CUnitData getUnitData() {
@ -208,4 +217,8 @@ public class CSimulation {
public CPlayer getPlayer(final int index) {
return this.players.get(index);
}
public CommandErrorListener getCommandErrorListener() {
return this.commandErrorListener;
}
}

View File

@ -14,11 +14,16 @@ import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitStateListener.CUnitStateNotifier;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorFollow;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorPatrol;
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.attacks.CUnitAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.COrder;
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.players.CPlayer;
@ -38,8 +43,9 @@ public class CUnit extends CWidget {
private final List<CAbility> abilities = new ArrayList<>();
private CBehavior currentOrder;
private final Queue<CBehavior> orderQueue = new LinkedList<>();
private CBehavior currentBehavior;
private COrder currentOrder;
private final Queue<COrder> orderQueue = new LinkedList<>();
private final CUnitType unitType;
private Rectangle collisionRectangle;
@ -59,6 +65,12 @@ public class CUnit extends CWidget {
private final float acquisitionRange;
private transient static AutoAttackTargetFinderEnum autoAttackTargetFinderEnum = new AutoAttackTargetFinderEnum();
private transient CBehaviorMove moveBehavior;
private transient CBehaviorAttack attackBehavior;
private transient CBehaviorFollow followBehavior;
private transient CBehaviorPatrol patrolBehavior;
private transient CBehaviorStop stopBehavior;
public CUnit(final int handleId, final int playerIndex, final float x, final float y, final float life,
final War3ID typeId, final float facing, final float mana, final int maximumLife, final int maximumMana,
final int speed, final int defense, final CUnitType unitType) {
@ -75,6 +87,8 @@ public class CUnit extends CWidget {
this.unitType = unitType;
this.classifications.addAll(unitType.getClassifications());
this.acquisitionRange = unitType.getDefaultAcquisitionRange();
this.stopBehavior = new CBehaviorStop(this);
this.currentBehavior = this.stopBehavior;
}
public void setUnitAnimationListener(final CUnitAnimationListener unitAnimationListener) {
@ -185,38 +199,33 @@ public class CUnit extends CWidget {
return true;
}
}
else if (this.currentOrder != null) {
if (this.currentOrder.update(game)) {
// remove current order, because it's completed, polling next
// item from order queue
this.currentOrder = this.orderQueue.poll();
this.stateNotifier.ordersChanged();
}
if (this.currentOrder == null) {
// maybe order "stop" here
this.unitAnimationListener.playAnimation(true, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, true);
}
else if (this.currentBehavior != null) {
this.currentBehavior = this.currentBehavior.update(game);
}
else {
// check to auto acquire targets
if (!this.unitType.getAttacks().isEmpty()) {
if (this.collisionRectangle != null) {
tempRect.set(this.collisionRectangle);
}
else {
tempRect.set(this.getX(), this.getY(), 0, 0);
}
final float halfSize = this.acquisitionRange;
tempRect.x -= halfSize;
tempRect.y -= halfSize;
tempRect.width += halfSize * 2;
tempRect.height += halfSize * 2;
game.getWorldCollision().enumUnitsInRect(tempRect, autoAttackTargetFinderEnum.reset(game, this));
}
autoAcquireAttackTargets(game);
}
return false;
}
public void autoAcquireAttackTargets(final CSimulation game) {
if (!this.unitType.getAttacks().isEmpty()) {
if (this.collisionRectangle != null) {
tempRect.set(this.collisionRectangle);
}
else {
tempRect.set(this.getX(), this.getY(), 0, 0);
}
final float halfSize = this.acquisitionRange;
tempRect.x -= halfSize;
tempRect.y -= halfSize;
tempRect.width += halfSize * 2;
tempRect.height += halfSize * 2;
game.getWorldCollision().enumUnitsInRect(tempRect, autoAttackTargetFinderEnum.reset(game, this));
}
}
public float getEndingDecayTime(final CSimulation game) {
if (this.unitType.isBuilding()) {
return game.getGameplayConstants().getStructureDecayTime();
@ -224,7 +233,7 @@ public class CUnit extends CWidget {
return game.getGameplayConstants().getBoneDecayTime();
}
public void order(final CBehavior order, final boolean queue) {
public void order(final CSimulation game, final COrder order, final boolean queue) {
if (isDead()) {
return;
}
@ -232,14 +241,37 @@ public class CUnit extends CWidget {
this.orderQueue.add(order);
}
else {
this.currentOrder = order;
this.currentBehavior = beginOrder(game, order);
this.orderQueue.clear();
}
this.stateNotifier.ordersChanged();
}
public CBehavior getCurrentOrder() {
return this.currentOrder;
private CBehavior beginOrder(final CSimulation game, final COrder order) {
final boolean omitNotify = (this.currentOrder == null) && (order == null);
this.currentOrder = order;
if (!omitNotify) {
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
}
CBehavior nextBehavior;
if (order != null) {
nextBehavior = order.begin(game, this);
}
else {
nextBehavior = this.stopBehavior;
}
return nextBehavior;
}
public CBehavior getCurrentBehavior() {
return this.currentBehavior;
}
public int getCurrentAbilityHandleId() {
return this.currentOrder == null ? 0 : this.currentOrder.getAbilityHandleId();
}
public int getCurrentOrderId() {
return this.currentOrder == null ? OrderIds.stop : this.currentOrder.getOrderId();
}
public List<CAbility> getAbilities() {
@ -389,12 +421,12 @@ public class CUnit extends CWidget {
}
}
else {
if (this.currentOrder == null) {
if (this.currentBehavior == null) {
if (!simulation.getPlayer(getPlayerIndex()).hasAlliance(source.getPlayerIndex(),
CAllianceType.PASSIVE)) {
for (final CUnitAttack attack : this.unitType.getAttacks()) {
if (source.canBeTargetedBy(simulation, this, attack.getTargetsAllowed())) {
this.order(new CBehaviorAttack(this, attack, OrderIds.attack, source), false);
this.currentBehavior = getAttackBehavior().reset(attack, source);
break;
}
}
@ -404,7 +436,7 @@ public class CUnit extends CWidget {
}
private void kill(final CSimulation simulation) {
this.currentOrder = null;
this.currentBehavior = null;
this.orderQueue.clear();
this.deathTurnTick = simulation.getGameTurnTick();
}
@ -558,7 +590,7 @@ public class CUnit extends CWidget {
if (this.source.canReach(unit, this.source.acquisitionRange)
&& unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed())
&& (this.source.distance(unit) >= this.source.getUnitType().getMinimumAttackRange())) {
this.source.order(new CBehaviorAttack(this.source, attack, OrderIds.attack, unit), false);
this.source.currentBehavior = this.source.getAttackBehavior().reset(attack, unit);
return true;
}
}
@ -566,4 +598,45 @@ public class CUnit extends CWidget {
return false;
}
}
public CBehaviorMove getMoveBehavior() {
return this.moveBehavior;
}
public void setMoveBehavior(final CBehaviorMove moveBehavior) {
this.moveBehavior = moveBehavior;
}
public CBehaviorAttack getAttackBehavior() {
return this.attackBehavior;
}
public void setAttackBehavior(final CBehaviorAttack attackBehavior) {
this.attackBehavior = attackBehavior;
}
public CBehaviorStop getStopBehavior() {
return this.stopBehavior;
}
public void setFollowBehavior(final CBehaviorFollow followBehavior) {
this.followBehavior = followBehavior;
}
public void setPatrolBehavior(final CBehaviorPatrol patrolBehavior) {
this.patrolBehavior = patrolBehavior;
}
public CBehaviorFollow getFollowBehavior() {
return this.followBehavior;
}
public CBehaviorPatrol getPatrolBehavior() {
return this.patrolBehavior;
}
public CBehavior pollNextOrderBehavior(final CSimulation game) {
final COrder order = this.orderQueue.poll();
return beginOrder(game, order);
}
}

View File

@ -5,7 +5,7 @@ import com.etheller.warsmash.util.SubscriberSetNotifier;
public interface CUnitStateListener {
void lifeChanged(); // hp (current) changes
void ordersChanged();
void ordersChanged(int abilityHandleId, int orderId);
public static final class CUnitStateNotifier extends SubscriberSetNotifier<CUnitStateListener>
implements CUnitStateListener {
@ -17,9 +17,9 @@ public interface CUnitStateListener {
}
@Override
public void ordersChanged() {
public void ordersChanged(final int abilityHandleId, final int orderId) {
for (final CUnitStateListener listener : set) {
listener.ordersChanged();
listener.ordersChanged(abilityHandleId, orderId);
}
}
}

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.math.Vector2;
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.behaviors.CBehavior;
public interface CAbility extends CAbilityView {
/* should fire when ability added to unit */
@ -12,10 +13,10 @@ public interface CAbility extends CAbilityView {
/* should fire when ability removed from unit */
void onRemove(CSimulation game, CUnit unit);
void onOrder(CSimulation game, CUnit caster, int orderId, CWidget target, boolean queue);
CBehavior begin(CSimulation game, CUnit caster, int orderId, CWidget target);
void onOrder(CSimulation game, CUnit caster, int orderId, Vector2 point, boolean queue);
CBehavior begin(CSimulation game, CUnit caster, int orderId, Vector2 point);
void onOrderNoTarget(CSimulation game, CUnit caster, int orderId, boolean queue);
CBehavior beginNoTarget(CSimulation game, CUnit caster, int orderId);
}

View File

@ -4,12 +4,10 @@ import com.badlogic.gdx.math.Vector2;
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.StringsToExternalizeLater;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttack;
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.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorMove;
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;
@ -99,6 +97,7 @@ public class CAbilityAttack implements CAbility {
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
unit.setAttackBehavior(new CBehaviorAttack(unit));
}
@Override
@ -106,30 +105,28 @@ public class CAbilityAttack implements CAbility {
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final CWidget target,
final boolean queue) {
CBehavior order = null;
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
order = new CBehaviorAttack(caster, attack, orderId, target);
behavior = caster.getAttackBehavior().reset(attack, target);
break;
}
}
if (order == null) {
order = new CBehaviorMove(caster, orderId, target.getX(), target.getY());
if (behavior == null) {
behavior = caster.getMoveBehavior().reset(target.getX(), target.getY());
}
caster.order(order, queue);
return behavior;
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final Vector2 target,
final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_WIDGET);
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) {
return caster.pollNextOrderBehavior(game);
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final int orderId, final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_WIDGET);
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
return caster.pollNextOrderBehavior(game);
}
@Override

View File

@ -0,0 +1,117 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
import com.badlogic.gdx.math.Vector2;
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.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
/**
* Represents an ability from the object data
*/
public class CAbilityColdArrows implements CAbility {
private final War3ID rawcode;
private final int handleId;
private boolean autoCastActive;
public CAbilityColdArrows(final War3ID rawcode, final int handleId) {
this.rawcode = rawcode;
this.handleId = handleId;
}
@Override
public void checkCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.useOk();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
switch (orderId) {
case OrderIds.coldarrowstarg:
receiver.targetOk(target);
break;
default:
receiver.orderIdNotAccepted();
break;
}
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target,
final AbilityTargetCheckReceiver<Vector2> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
switch (orderId) {
case OrderIds.coldarrows:
case OrderIds.uncoldarrows:
receiver.targetOk(null);
break;
default:
receiver.orderIdNotAccepted();
break;
}
}
public War3ID getRawcode() {
return this.rawcode;
}
@Override
public int getHandleId() {
return this.handleId;
}
public boolean isAutoCastActive() {
return this.autoCastActive;
}
@Override
public <T> T visit(final CAbilityVisitor<T> visitor) {
return visitor.accept(this);
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
behavior = caster.getAttackBehavior().reset(attack, target);
break;
}
}
if (behavior != null) {
return behavior;
}
return caster.pollNextOrderBehavior(game);
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) {
return caster.pollNextOrderBehavior(game);
}
@Override
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
this.autoCastActive = !this.autoCastActive;
return caster.pollNextOrderBehavior(game);
}
}

View File

@ -0,0 +1,84 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities;
import com.badlogic.gdx.math.Vector2;
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.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
/**
* Represents an ability from the object data
*/
public class CAbilityGeneric implements CAbility {
private final War3ID rawcode;
private final int handleId;
public CAbilityGeneric(final War3ID rawcode, final int handleId) {
this.rawcode = rawcode;
this.handleId = handleId;
}
public War3ID getRawcode() {
return this.rawcode;
}
@Override
public void checkCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.notAnActiveAbility();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final CWidget target,
final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final Vector2 target,
final AbilityTargetCheckReceiver<Vector2> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.orderIdNotAccepted();
}
@Override
public int getHandleId() {
return this.handleId;
}
@Override
public <T> T visit(final CAbilityVisitor<T> visitor) {
return visitor.accept(this);
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
return caster.pollNextOrderBehavior(game);
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) {
return caster.pollNextOrderBehavior(game);
}
@Override
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
return caster.pollNextOrderBehavior(game);
}
}

View File

@ -4,9 +4,10 @@ import com.badlogic.gdx.math.Vector2;
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.StringsToExternalizeLater;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.CBehaviorPatrol;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorFollow;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorMove;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorPatrol;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver;
@ -31,7 +32,7 @@ public class CAbilityMove implements CAbility {
switch (orderId) {
case OrderIds.smart:
case OrderIds.patrol:
if (target instanceof CUnit) {
if ((target instanceof CUnit) && (target != unit)) {
receiver.targetOk(target);
}
else {
@ -74,7 +75,9 @@ public class CAbilityMove implements CAbility {
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
unit.setMoveBehavior(new CBehaviorMove(unit));
unit.setFollowBehavior(new CBehaviorFollow(unit));
unit.setPatrolBehavior(new CBehaviorPatrol(unit));
}
@Override
@ -83,20 +86,23 @@ public class CAbilityMove implements CAbility {
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final CWidget target,
final boolean queue) {
caster.order(new CBehaviorPatrol(caster, orderId, (CUnit) target), queue);
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
return caster.getFollowBehavior().reset((CUnit) target);
}
@Override
public void onOrder(final CSimulation game, final CUnit caster, final int orderId, final Vector2 target,
final boolean queue) {
caster.order(new CBehaviorMove(caster, orderId, target.x, target.y), queue);
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final Vector2 point) {
if (orderId == OrderIds.patrol) {
return caster.getPatrolBehavior().reset(point);
}
else {
return caster.getMoveBehavior().reset(point.x, point.y);
}
}
@Override
public void onOrderNoTarget(final CSimulation game, final CUnit caster, final int orderId, final boolean queue) {
throw new IllegalArgumentException(StringsToExternalizeLater.MUST_TARGET_POINT);
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
return caster.pollNextOrderBehavior(game);
}
@Override

View File

@ -12,4 +12,8 @@ public interface CAbilityVisitor<T> {
T accept(CAbilityAttack ability);
T accept(CAbilityMove ability);
T accept(CAbilityGeneric ability);
T accept(CAbilityColdArrows ability);
}

View File

@ -0,0 +1,108 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
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;
public abstract class CAbstractRangedBehavior implements CRangedBehavior {
protected final CUnit unit;
public CAbstractRangedBehavior(final CUnit unit) {
this.unit = unit;
}
private boolean wasWithinPropWindow = false;
protected CWidget target;
private boolean wasInRange = false;
private CBehaviorMove moveBehavior;
protected final CAbstractRangedBehavior innerReset(final CWidget target) {
this.wasWithinPropWindow = false;
this.target = target;
this.wasInRange = false;
if (!this.unit.isMovementDisabled()) {
if ((target instanceof CUnit) && !((CUnit) target).getUnitType().isBuilding()) {
this.moveBehavior = this.unit.getMoveBehavior().reset((CUnit) target, this);
}
else {
this.moveBehavior = this.unit.getMoveBehavior().reset(target.getX(), target.getY(), this);
}
}
else {
this.moveBehavior = null;
}
return this;
}
protected abstract CBehavior update(CSimulation simulation, boolean withinRange);
protected abstract boolean checkTargetStillValid(CSimulation simulation);
protected abstract void resetBeforeMoving(CSimulation simulation);
@Override
public final CBehavior update(final CSimulation simulation) {
if (!checkTargetStillValid(simulation)) {
return this.unit.pollNextOrderBehavior(simulation);
}
if (!isWithinRange(simulation)) {
if (this.moveBehavior == null) {
return this.unit.pollNextOrderBehavior(simulation);
}
this.wasInRange = false;
resetBeforeMoving(simulation);
;
return this.unit.getMoveBehavior();
}
this.wasInRange = true;
if (!this.unit.isMovementDisabled()) {
final float prevX = this.unit.getX();
final float prevY = this.unit.getY();
final float deltaY = this.target.getY() - prevY;
final float deltaX = this.target.getX() - prevX;
final double goalAngleRad = Math.atan2(deltaY, deltaX);
float goalAngle = (float) Math.toDegrees(goalAngleRad);
if (goalAngle < 0) {
goalAngle += 360;
}
float facing = this.unit.getFacing();
float delta = goalAngle - facing;
final float propulsionWindow = simulation.getGameplayConstants().getAttackHalfAngle();
final float turnRate = simulation.getUnitData().getTurnRate(this.unit.getTypeId());
if (delta < -180) {
delta = 360 + delta;
}
if (delta > 180) {
delta = -360 + delta;
}
final float absDelta = Math.abs(delta);
if ((absDelta <= 1.0) && (absDelta != 0)) {
this.unit.setFacing(goalAngle);
}
else {
float angleToAdd = Math.signum(delta) * (float) Math.toDegrees(turnRate);
if (absDelta < Math.abs(angleToAdd)) {
angleToAdd = delta;
}
facing += angleToAdd;
this.unit.setFacing(facing);
}
if (absDelta < propulsionWindow) {
this.wasWithinPropWindow = true;
}
else {
// If this happens, the unit is facing the wrong way, and has to turn before
// moving.
this.wasWithinPropWindow = false;
}
}
else {
this.wasWithinPropWindow = true;
}
return update(simulation, this.wasWithinPropWindow);
}
}

View File

@ -0,0 +1,13 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
public interface CBehavior {
/**
* Executes one step of game simulation of the current order, and then returns
* the next behavior for the unit after the result of the update cycle.
*
* @return
*/
CBehavior update(CSimulation game);
}

View File

@ -0,0 +1,111 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
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.combat.attacks.CUnitAttack;
public class CBehaviorAttack extends CAbstractRangedBehavior {
public CBehaviorAttack(final CUnit unit) {
super(unit);
}
private CUnitAttack unitAttack;
private int damagePointLaunchTime;
private int backSwingTime;
private int thisOrderCooldownEndTime;
public CBehaviorAttack reset(final CUnitAttack unitAttack, final CWidget target) {
super.innerReset(target);
this.unitAttack = unitAttack;
this.damagePointLaunchTime = 0;
this.backSwingTime = 0;
this.thisOrderCooldownEndTime = 0;
return this;
}
@Override
public boolean isWithinRange(final CSimulation simulation) {
float range = this.unitAttack.getRange();
if ((this.target instanceof CUnit) && (((CUnit) this.target).getCurrentBehavior() instanceof CBehaviorMove)
&& (this.damagePointLaunchTime != 0 /*
* only apply range motion buffer if they were already in range and
* attacked
*/)) {
range += this.unitAttack.getRangeMotionBuffer();
}
return this.unit.canReach(this.target, range)
&& (this.unit.distance(this.target) >= this.unit.getUnitType().getMinimumAttackRange());
}
@Override
protected boolean checkTargetStillValid(final CSimulation simulation) {
return !this.target.isDead()
&& this.target.canBeTargetedBy(simulation, this.unit, this.unitAttack.getTargetsAllowed());
}
@Override
protected void resetBeforeMoving(final CSimulation simulation) {
this.damagePointLaunchTime = 0;
this.thisOrderCooldownEndTime = 0;
}
@Override
public CBehavior update(final CSimulation simulation, final boolean withinRange) {
final int cooldownEndTime = this.unit.getCooldownEndTime();
final int currentTurnTick = simulation.getGameTurnTick();
if (withinRange) {
if (this.damagePointLaunchTime != 0) {
if (currentTurnTick >= this.damagePointLaunchTime) {
int minDamage = this.unitAttack.getMinDamage();
final int maxDamage = Math.max(0, this.unitAttack.getMaxDamage());
if (minDamage > maxDamage) {
minDamage = maxDamage;
}
final int damage;
if (maxDamage == 0) {
damage = 0;
}
else if (minDamage == maxDamage) {
damage = minDamage;
}
else {
damage = simulation.getSeededRandom().nextInt(maxDamage - minDamage) + minDamage;
}
this.unitAttack.launch(simulation, this.unit, this.target, damage);
this.damagePointLaunchTime = 0;
}
}
else if (currentTurnTick >= cooldownEndTime) {
final float cooldownTime = this.unitAttack.getCooldownTime();
final float animationBackswingPoint = this.unitAttack.getAnimationBackswingPoint();
final int a1CooldownSteps = (int) (cooldownTime / WarsmashConstants.SIMULATION_STEP_TIME);
final int a1BackswingSteps = (int) (animationBackswingPoint / WarsmashConstants.SIMULATION_STEP_TIME);
final int a1DamagePointSteps = (int) (this.unitAttack.getAnimationDamagePoint()
/ WarsmashConstants.SIMULATION_STEP_TIME);
this.unit.setCooldownEndTime(currentTurnTick + a1CooldownSteps);
this.thisOrderCooldownEndTime = currentTurnTick + a1CooldownSteps;
this.damagePointLaunchTime = currentTurnTick + a1DamagePointSteps;
this.backSwingTime = currentTurnTick + a1DamagePointSteps + a1BackswingSteps;
this.unit.getUnitAnimationListener().playAnimation(true, PrimaryTag.ATTACK, SequenceUtils.EMPTY, 1.0f,
true);
this.unit.getUnitAnimationListener().queueAnimation(PrimaryTag.STAND, SequenceUtils.READY, false);
}
else if ((currentTurnTick >= this.thisOrderCooldownEndTime)) {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.READY, 1.0f,
false);
}
}
else {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.READY, 1.0f,
false);
}
return this;
}
}

View File

@ -0,0 +1,38 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
public class CBehaviorFollow extends CAbstractRangedBehavior {
public CBehaviorFollow(final CUnit unit) {
super(unit);
}
public CBehavior reset(final CUnit target) {
return innerReset(target);
}
@Override
public boolean isWithinRange(final CSimulation simulation) {
return this.unit.canReach(this.target, this.unit.getAcquisitionRange());
}
@Override
protected CBehavior update(final CSimulation simulation, final boolean withinRange) {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, false);
return this;
}
@Override
protected boolean checkTargetStillValid(final CSimulation simulation) {
return !this.target.isDead();
}
@Override
protected void resetBeforeMoving(final CSimulation simulation) {
}
}

View File

@ -1,4 +1,4 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Float;
@ -18,35 +18,58 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CPathfindin
public class CBehaviorMove implements CBehavior {
private static final Rectangle tempRect = new Rectangle();
private final CUnit unit;
private final int orderId;
private boolean wasWithinPropWindow = false;
private List<Point2D.Float> path = null;
private final CPathfindingProcessor.GridMapping gridMapping;
private final Point2D.Float target;
private int searchCycles = 0;
private CUnit followUnit;
public CBehaviorMove(final CUnit unit, final int orderId, final float targetX, final float targetY) {
public CBehaviorMove(final CUnit unit) {
this.unit = unit;
this.orderId = orderId;
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
: CPathfindingProcessor.GridMapping.CELLS;
this.target = new Point2D.Float(targetX, targetY);
}
public CBehaviorMove(final CUnit unit, final int orderId, final CUnit followUnit) {
this.unit = unit;
this.orderId = orderId;
private boolean wasWithinPropWindow = false;
private List<Point2D.Float> path = null;
private CPathfindingProcessor.GridMapping gridMapping;
private Point2D.Float target;
private int searchCycles = 0;
private CUnit followUnit;
private CRangedBehavior rangedBehavior;
public CBehaviorMove reset(final float targetX, final float targetY) {
return reset(targetX, targetY, null);
}
public CBehaviorMove reset(final float targetX, final float targetY, final CRangedBehavior rangedBehavior) {
this.wasWithinPropWindow = false;
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
this.unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
: CPathfindingProcessor.GridMapping.CELLS;
this.target = new Point2D.Float(targetX, targetY);
this.path = null;
this.searchCycles = 0;
this.followUnit = null;
this.rangedBehavior = rangedBehavior;
return this;
}
public CBehaviorMove reset(final CUnit followUnit) {
return reset(followUnit, null);
}
public CBehaviorMove reset(final CUnit followUnit, final CRangedBehavior rangedBehavior) {
this.wasWithinPropWindow = false;
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
this.unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
: CPathfindingProcessor.GridMapping.CELLS;
this.target = new Point2D.Float(followUnit.getX(), followUnit.getY());
this.path = null;
this.searchCycles = 0;
this.followUnit = followUnit;
this.rangedBehavior = rangedBehavior;
return this;
}
@Override
public boolean update(final CSimulation simulation) {
public CBehavior update(final CSimulation simulation) {
if ((this.rangedBehavior != null) && this.rangedBehavior.isWithinRange(simulation)) {
return this.rangedBehavior;
}
final float prevX = this.unit.getX();
final float prevY = this.unit.getY();
@ -119,7 +142,7 @@ public class CBehaviorMove implements CBehavior {
this.searchCycles < 4);
System.out.println("new path (for target) " + this.path);
if (this.path.isEmpty()) {
return true;
return this.unit.pollNextOrderBehavior(simulation);
}
}
float currentTargetX;
@ -217,7 +240,7 @@ public class CBehaviorMove implements CBehavior {
this.searchCycles = 0;
}
if (this.path.isEmpty()) {
return true;
return this.unit.pollNextOrderBehavior(simulation);
}
else {
System.out.println(this.path);
@ -249,7 +272,7 @@ public class CBehaviorMove implements CBehavior {
deltaY = currentTargetY - nextY;
deltaX = currentTargetX - nextX;
if ((deltaX == 0.000f) && (deltaY == 0.000f) && this.path.isEmpty()) {
return true;
return this.unit.pollNextOrderBehavior(simulation);
}
System.out.println("new target: " + currentTargetX + "," + currentTargetY);
System.out.println("new delta: " + deltaX + "," + deltaY);
@ -274,7 +297,7 @@ public class CBehaviorMove implements CBehavior {
SequenceUtils.EMPTY, 1.0f, true);
}
this.wasWithinPropWindow = false;
return false;
return this;
}
}
}
@ -290,7 +313,7 @@ public class CBehaviorMove implements CBehavior {
this.searchCycles++;
System.out.println("new path " + this.path);
if (this.path.isEmpty() || (this.searchCycles > 5)) {
return true;
return this.unit.pollNextOrderBehavior(simulation);
}
}
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.WALK, SequenceUtils.EMPTY, 1.0f,
@ -309,12 +332,7 @@ public class CBehaviorMove implements CBehavior {
this.wasWithinPropWindow = false;
}
return false;
}
@Override
public int getOrderId() {
return this.orderId;
return this;
}
}

View File

@ -0,0 +1,37 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import com.badlogic.gdx.math.Vector2;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
public class CBehaviorPatrol implements CRangedBehavior {
private final CUnit unit;
private Vector2 target;
private Vector2 startPoint;
public CBehaviorPatrol(final CUnit unit) {
this.unit = unit;
}
public CBehavior reset(final Vector2 target) {
this.target = target;
this.startPoint = new Vector2(this.unit.getX(), this.unit.getY());
return this;
}
@Override
public boolean isWithinRange(final CSimulation simulation) {
return this.unit.distance(this.target.x, this.target.y) <= simulation.getGameplayConstants()
.getCloseEnoughRange(); // TODO this is not how it was meant to be used
}
@Override
public CBehavior update(final CSimulation simulation) {
final Vector2 temp = this.target;
this.target = this.startPoint;
this.startPoint = temp;
return this.unit.getMoveBehavior().reset(this.target.x, this.target.y, this);
}
}

View File

@ -0,0 +1,22 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
public class CBehaviorStop implements CBehavior {
private final CUnit unit;
public CBehaviorStop(final CUnit unit) {
this.unit = unit;
}
@Override
public CBehavior update(final CSimulation game) {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, true);
return this.unit.pollNextOrderBehavior(game);
}
}

View File

@ -0,0 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
public interface CRangedBehavior extends CBehavior {
boolean isWithinRange(final CSimulation simulation);
}

View File

@ -1,27 +1,24 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.data;
import com.etheller.warsmash.units.manager.MutableObjectData;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityGeneric;
public class CAbilityData {
private static final War3ID ABILITY_ICON = War3ID.fromString("aart");
private static final War3ID COLD_ARROWS = War3ID.fromString("ACcw");
private final MutableObjectData abilityData;
public CAbilityData(final MutableObjectData abilityData) {
this.abilityData = abilityData;
}
public String getIconPath(final War3ID id, final int level) {
final MutableGameObject mutableGameObject = this.abilityData.get(id);
if (mutableGameObject == null) {
return ImageUtils.DEFAULT_ICON_PATH;
public CAbility createAbility(final String ability, final int handleId) {
final War3ID war3Id = War3ID.fromString(ability);
if (war3Id.equals(COLD_ARROWS)) {
return new CAbilityColdArrows(war3Id, handleId);
}
final String iconPath = mutableGameObject.getFieldAsString(ABILITY_ICON, level);
if ((iconPath == null) || "".equals(iconPath)) {
return ImageUtils.DEFAULT_ICON_PATH;
}
return iconPath;
return new CAbilityGeneric(war3Id, handleId);
}
}

View File

@ -32,396 +32,410 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUni
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
public class CUnitData {
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
private static final War3ID MANA_MAXIMUM = War3ID.fromString("umpm");
private static final War3ID HIT_POINT_MAXIMUM = War3ID.fromString("uhpm");
private static final War3ID MOVEMENT_SPEED_BASE = War3ID.fromString("umvs");
private static final War3ID PROPULSION_WINDOW = War3ID.fromString("uprw");
private static final War3ID TURN_RATE = War3ID.fromString("umvr");
private static final War3ID IS_BLDG = War3ID.fromString("ubdg");
private static final War3ID NAME = War3ID.fromString("unam");
private static final War3ID PROJECTILE_LAUNCH_X = War3ID.fromString("ulpx");
private static final War3ID PROJECTILE_LAUNCH_Y = War3ID.fromString("ulpy");
private static final War3ID PROJECTILE_LAUNCH_Z = War3ID.fromString("ulpz");
private static final War3ID ATTACKS_ENABLED = War3ID.fromString("uaen");
private static final War3ID ATTACK1_BACKSWING_POINT = War3ID.fromString("ubs1");
private static final War3ID ATTACK1_DAMAGE_POINT = War3ID.fromString("udp1");
private static final War3ID ATTACK1_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua1f");
private static final War3ID ATTACK1_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua1h");
private static final War3ID ATTACK1_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua1q");
private static final War3ID ATTACK1_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua1p");
private static final War3ID ATTACK1_ATTACK_TYPE = War3ID.fromString("ua1t");
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
private static final War3ID ATTACK1_DMG_BASE = War3ID.fromString("ua1b");
private static final War3ID ATTACK1_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd1");
private static final War3ID ATTACK1_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd1");
private static final War3ID ATTACK1_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl1");
private static final War3ID ATTACK1_DMG_DICE = War3ID.fromString("ua1d");
private static final War3ID ATTACK1_DMG_SIDES_PER_DIE = War3ID.fromString("ua1s");
private static final War3ID ATTACK1_DMG_SPILL_DIST = War3ID.fromString("usd1");
private static final War3ID ATTACK1_DMG_SPILL_RADIUS = War3ID.fromString("usr1");
private static final War3ID ATTACK1_DMG_UPGRADE_AMT = War3ID.fromString("udu1");
private static final War3ID ATTACK1_TARGET_COUNT = War3ID.fromString("utc1");
private static final War3ID ATTACK1_PROJECTILE_ARC = War3ID.fromString("uma1");
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
private static final War3ID ATTACK1_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh1");
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
private static final War3ID ATTACK1_RANGE = War3ID.fromString("ua1r");
private static final War3ID ATTACK1_RANGE_MOTION_BUFFER = War3ID.fromString("urb1");
private static final War3ID ATTACK1_SHOW_UI = War3ID.fromString("uwu1");
private static final War3ID ATTACK1_TARGETS_ALLOWED = War3ID.fromString("ua1g");
private static final War3ID ATTACK1_WEAPON_SOUND = War3ID.fromString("ucs1");
private static final War3ID ATTACK1_WEAPON_TYPE = War3ID.fromString("ua1w");
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
private static final War3ID MANA_MAXIMUM = War3ID.fromString("umpm");
private static final War3ID HIT_POINT_MAXIMUM = War3ID.fromString("uhpm");
private static final War3ID MOVEMENT_SPEED_BASE = War3ID.fromString("umvs");
private static final War3ID PROPULSION_WINDOW = War3ID.fromString("uprw");
private static final War3ID TURN_RATE = War3ID.fromString("umvr");
private static final War3ID IS_BLDG = War3ID.fromString("ubdg");
private static final War3ID NAME = War3ID.fromString("unam");
private static final War3ID PROJECTILE_LAUNCH_X = War3ID.fromString("ulpx");
private static final War3ID PROJECTILE_LAUNCH_Y = War3ID.fromString("ulpy");
private static final War3ID PROJECTILE_LAUNCH_Z = War3ID.fromString("ulpz");
private static final War3ID ATTACKS_ENABLED = War3ID.fromString("uaen");
private static final War3ID ATTACK1_BACKSWING_POINT = War3ID.fromString("ubs1");
private static final War3ID ATTACK1_DAMAGE_POINT = War3ID.fromString("udp1");
private static final War3ID ATTACK1_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua1f");
private static final War3ID ATTACK1_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua1h");
private static final War3ID ATTACK1_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua1q");
private static final War3ID ATTACK1_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua1p");
private static final War3ID ATTACK1_ATTACK_TYPE = War3ID.fromString("ua1t");
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
private static final War3ID ATTACK1_DMG_BASE = War3ID.fromString("ua1b");
private static final War3ID ATTACK1_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd1");
private static final War3ID ATTACK1_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd1");
private static final War3ID ATTACK1_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl1");
private static final War3ID ATTACK1_DMG_DICE = War3ID.fromString("ua1d");
private static final War3ID ATTACK1_DMG_SIDES_PER_DIE = War3ID.fromString("ua1s");
private static final War3ID ATTACK1_DMG_SPILL_DIST = War3ID.fromString("usd1");
private static final War3ID ATTACK1_DMG_SPILL_RADIUS = War3ID.fromString("usr1");
private static final War3ID ATTACK1_DMG_UPGRADE_AMT = War3ID.fromString("udu1");
private static final War3ID ATTACK1_TARGET_COUNT = War3ID.fromString("utc1");
private static final War3ID ATTACK1_PROJECTILE_ARC = War3ID.fromString("uma1");
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
private static final War3ID ATTACK1_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh1");
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
private static final War3ID ATTACK1_RANGE = War3ID.fromString("ua1r");
private static final War3ID ATTACK1_RANGE_MOTION_BUFFER = War3ID.fromString("urb1");
private static final War3ID ATTACK1_SHOW_UI = War3ID.fromString("uwu1");
private static final War3ID ATTACK1_TARGETS_ALLOWED = War3ID.fromString("ua1g");
private static final War3ID ATTACK1_WEAPON_SOUND = War3ID.fromString("ucs1");
private static final War3ID ATTACK1_WEAPON_TYPE = War3ID.fromString("ua1w");
private static final War3ID ATTACK2_BACKSWING_POINT = War3ID.fromString("ubs2");
private static final War3ID ATTACK2_DAMAGE_POINT = War3ID.fromString("udp2");
private static final War3ID ATTACK2_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua2f");
private static final War3ID ATTACK2_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua2h");
private static final War3ID ATTACK2_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua2q");
private static final War3ID ATTACK2_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua2p");
private static final War3ID ATTACK2_ATTACK_TYPE = War3ID.fromString("ua2t");
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
private static final War3ID ATTACK2_DMG_BASE = War3ID.fromString("ua2b");
private static final War3ID ATTACK2_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd2");
private static final War3ID ATTACK2_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd2");
private static final War3ID ATTACK2_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl2");
private static final War3ID ATTACK2_DMG_DICE = War3ID.fromString("ua2d");
private static final War3ID ATTACK2_DMG_SIDES_PER_DIE = War3ID.fromString("ua2s");
private static final War3ID ATTACK2_DMG_SPILL_DIST = War3ID.fromString("usd2");
private static final War3ID ATTACK2_DMG_SPILL_RADIUS = War3ID.fromString("usr2");
private static final War3ID ATTACK2_DMG_UPGRADE_AMT = War3ID.fromString("udu2");
private static final War3ID ATTACK2_TARGET_COUNT = War3ID.fromString("utc2");
private static final War3ID ATTACK2_PROJECTILE_ARC = War3ID.fromString("uma2");
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
private static final War3ID ATTACK2_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh2");
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
private static final War3ID ATTACK2_RANGE = War3ID.fromString("ua2r");
private static final War3ID ATTACK2_RANGE_MOTION_BUFFER = War3ID.fromString("urb2");
private static final War3ID ATTACK2_SHOW_UI = War3ID.fromString("uwu2");
private static final War3ID ATTACK2_TARGETS_ALLOWED = War3ID.fromString("ua2g");
private static final War3ID ATTACK2_WEAPON_SOUND = War3ID.fromString("ucs2");
private static final War3ID ATTACK2_WEAPON_TYPE = War3ID.fromString("ua2w");
private static final War3ID ATTACK2_BACKSWING_POINT = War3ID.fromString("ubs2");
private static final War3ID ATTACK2_DAMAGE_POINT = War3ID.fromString("udp2");
private static final War3ID ATTACK2_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua2f");
private static final War3ID ATTACK2_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua2h");
private static final War3ID ATTACK2_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua2q");
private static final War3ID ATTACK2_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua2p");
private static final War3ID ATTACK2_ATTACK_TYPE = War3ID.fromString("ua2t");
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
private static final War3ID ATTACK2_DMG_BASE = War3ID.fromString("ua2b");
private static final War3ID ATTACK2_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd2");
private static final War3ID ATTACK2_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd2");
private static final War3ID ATTACK2_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl2");
private static final War3ID ATTACK2_DMG_DICE = War3ID.fromString("ua2d");
private static final War3ID ATTACK2_DMG_SIDES_PER_DIE = War3ID.fromString("ua2s");
private static final War3ID ATTACK2_DMG_SPILL_DIST = War3ID.fromString("usd2");
private static final War3ID ATTACK2_DMG_SPILL_RADIUS = War3ID.fromString("usr2");
private static final War3ID ATTACK2_DMG_UPGRADE_AMT = War3ID.fromString("udu2");
private static final War3ID ATTACK2_TARGET_COUNT = War3ID.fromString("utc2");
private static final War3ID ATTACK2_PROJECTILE_ARC = War3ID.fromString("uma2");
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
private static final War3ID ATTACK2_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh2");
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
private static final War3ID ATTACK2_RANGE = War3ID.fromString("ua2r");
private static final War3ID ATTACK2_RANGE_MOTION_BUFFER = War3ID.fromString("urb2");
private static final War3ID ATTACK2_SHOW_UI = War3ID.fromString("uwu2");
private static final War3ID ATTACK2_TARGETS_ALLOWED = War3ID.fromString("ua2g");
private static final War3ID ATTACK2_WEAPON_SOUND = War3ID.fromString("ucs2");
private static final War3ID ATTACK2_WEAPON_TYPE = War3ID.fromString("ua2w");
private static final War3ID ACQUISITION_RANGE = War3ID.fromString("uacq");
private static final War3ID MINIMUM_ATTACK_RANGE = War3ID.fromString("uamn");
private static final War3ID ACQUISITION_RANGE = War3ID.fromString("uacq");
private static final War3ID MINIMUM_ATTACK_RANGE = War3ID.fromString("uamn");
private static final War3ID PROJECTILE_IMPACT_Z = War3ID.fromString("uimz");
private static final War3ID PROJECTILE_IMPACT_Z = War3ID.fromString("uimz");
private static final War3ID DEATH_TYPE = War3ID.fromString("udea");
private static final War3ID ARMOR_TYPE = War3ID.fromString("uarm");
private static final War3ID DEATH_TYPE = War3ID.fromString("udea");
private static final War3ID ARMOR_TYPE = War3ID.fromString("uarm");
private static final War3ID DEFENSE = War3ID.fromString("udef");
private static final War3ID DEFENSE_TYPE = War3ID.fromString("udty");
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
private static final War3ID MOVE_TYPE = War3ID.fromString("umvt");
private static final War3ID COLLISION_SIZE = War3ID.fromString("ucol");
private static final War3ID CLASSIFICATION = War3ID.fromString("utyp");
private static final War3ID DEATH_TIME = War3ID.fromString("udtm");
private static final War3ID TARGETED_AS = War3ID.fromString("utar");
private final MutableObjectData unitData;
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
private static final War3ID DEFENSE = War3ID.fromString("udef");
private static final War3ID DEFENSE_TYPE = War3ID.fromString("udty");
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
private static final War3ID MOVE_TYPE = War3ID.fromString("umvt");
private static final War3ID COLLISION_SIZE = War3ID.fromString("ucol");
private static final War3ID CLASSIFICATION = War3ID.fromString("utyp");
private static final War3ID DEATH_TIME = War3ID.fromString("udtm");
private static final War3ID TARGETED_AS = War3ID.fromString("utar");
public CUnitData(final MutableObjectData unitData) {
this.unitData = unitData;
}
private static final War3ID ABILITIES_NORMAL = War3ID.fromString("uabi");
private final MutableObjectData unitData;
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
private final CAbilityData abilityData;
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
final MutableGameObject unitType = this.unitData.get(typeId);
final int handleId = handleIdAllocator.createId();
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
final int manaInitial = unitType.getFieldAsInteger(MANA_INITIAL_AMOUNT, 0);
final int manaMaximum = unitType.getFieldAsInteger(MANA_MAXIMUM, 0);
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
public CUnitData(final MutableObjectData unitData, final CAbilityData abilityData) {
this.unitData = unitData;
this.abilityData = abilityData;
}
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
final MutableGameObject unitType = this.unitData.get(typeId);
final int handleId = handleIdAllocator.createId();
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
final int manaInitial = unitType.getFieldAsInteger(MANA_INITIAL_AMOUNT, 0);
final int manaMaximum = unitType.getFieldAsInteger(MANA_MAXIMUM, 0);
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
final String abilityList = unitType.getFieldAsString(ABILITIES_NORMAL, 0);
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
speed, defense, unitTypeInstance);
if (speed > 0) {
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
}
if (!unitTypeInstance.getAttacks().isEmpty()) {
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
}
return unit;
}
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap,
final MutableGameObject unitType) {
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
if (unitTypeInstance == null) {
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
final float collisionSize = unitType.getFieldAsFloat(COLLISION_SIZE, 0);
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
final PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
final String unitName = unitType.getFieldAsString(NAME, 0);
final float acquisitionRange = unitType.getFieldAsFloat(ACQUISITION_RANGE, 0);
final float minimumAttackRange = unitType.getFieldAsFloat(MINIMUM_ATTACK_RANGE, 0);
final EnumSet<CTargetType> targetedAs = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(TARGETED_AS, 0));
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
if (classificationString != null) {
final String[] classificationValues = classificationString.split(",");
for (final String unitEditorKey : classificationValues) {
final CUnitClassification unitClassification = CUnitClassification
.parseUnitClassification(unitEditorKey);
if (unitClassification != null) {
classifications.add(unitClassification);
}
}
}
final List<CUnitAttack> attacks = new ArrayList<>();
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
if ((attacksEnabled & 0x1) != 0) {
try {
// attack one
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_QUARTER_DMG, 0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK1_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK1_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK1_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK1_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK1_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK1_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK1_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK1_PROJECTILE_HOMING_ENABLED,
0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK1_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK1_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK1_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK1_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK1_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice,
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
} catch (Exception exc) {
System.err.println("Attack 1 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
if ((attacksEnabled & 0x2) != 0) {
try {
// attack two
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_QUARTER_DMG, 0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK2_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK2_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK2_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK2_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK2_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK2_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK2_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType.getFieldAsBoolean(ATTACK2_PROJECTILE_HOMING_ENABLED,
0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK2_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK2_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK2_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK2_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK2_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor, damageDice,
damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled, projectileSpeed,
range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType));
} catch (Exception exc) {
System.err.println("Attack 2 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
final boolean raise = (deathType & 0x1) != 0;
final boolean decay = (deathType & 0x2) != 0;
final String armorType = unitType.getFieldAsString(ARMOR_TYPE, 0);
final float impactZ = unitType.getFieldAsFloat(PROJECTILE_IMPACT_Z, 0);
final CDefenseType defenseType = CDefenseType.parseDefenseType(unitType.getFieldAsString(DEFENSE_TYPE, 0));
final float deathTime = unitType.getFieldAsFloat(DEATH_TIME, 0);
unitTypeInstance = new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize, classifications,
attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime,
targetedAs, acquisitionRange, minimumAttackRange);
this.unitIdToUnitType.put(typeId, unitTypeInstance);
}
return unitTypeInstance;
}
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
speed, defense, unitTypeInstance);
if (speed > 0) {
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
}
if (!unitTypeInstance.getAttacks().isEmpty()) {
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
}
for (final String ability : abilityList.split(",")) {
unit.add(simulation, this.abilityData.createAbility(ability, handleIdAllocator.createId()));
}
return unit;
}
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
final EnumSet<CTargetType> areaOfEffectTargets, final CAttackType attackType, final float cooldownTime,
final int damageBase, final float damageFactorMedium, final float damageFactorSmall,
final float damageLossFactor, final int damageDice, final int damageSidesPerDie,
final float damageSpillDistance, final float damageSpillRadius, final int damageUpgradeAmount,
final int maximumNumberOfTargets, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final int range,
final float rangeMotionBuffer, final boolean showUI, final EnumSet<CTargetType> targetsAllowed,
final String weaponSound, final CWeaponType weaponType) {
final CUnitAttack attack;
switch (weaponType) {
case MISSILE:
attack = new CUnitAttackMissile(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed);
break;
case MBOUNCE:
attack = new CUnitAttackMissileBounce(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, damageLossFactor, maximumNumberOfTargets,
areaOfEffectFullDamage, areaOfEffectTargets);
break;
case MSPLASH:
case ARTILLERY:
attack = new CUnitAttackMissileSplash(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, areaOfEffectFullDamage, areaOfEffectMediumDamage,
areaOfEffectSmallDamage, areaOfEffectTargets, damageFactorMedium, damageFactorSmall);
break;
case MLINE:
case ALINE:
attack = new CUnitAttackMissileLine(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, damageSpillDistance, damageSpillRadius);
break;
case INSTANT:
attack = new CUnitAttackInstant(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArt);
break;
default:
case NORMAL:
attack = new CUnitAttackNormal(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType);
break;
}
return attack;
}
private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap,
final MutableGameObject unitType) {
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
if (unitTypeInstance == null) {
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
final float collisionSize = unitType.getFieldAsFloat(COLLISION_SIZE, 0);
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
final PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
final String unitName = unitType.getFieldAsString(NAME, 0);
final float acquisitionRange = unitType.getFieldAsFloat(ACQUISITION_RANGE, 0);
final float minimumAttackRange = unitType.getFieldAsFloat(MINIMUM_ATTACK_RANGE, 0);
final EnumSet<CTargetType> targetedAs = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(TARGETED_AS, 0));
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
if (classificationString != null) {
final String[] classificationValues = classificationString.split(",");
for (final String unitEditorKey : classificationValues) {
final CUnitClassification unitClassification = CUnitClassification
.parseUnitClassification(unitEditorKey);
if (unitClassification != null) {
classifications.add(unitClassification);
}
}
}
final List<CUnitAttack> attacks = new ArrayList<>();
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
if ((attacksEnabled & 0x1) != 0) {
try {
// attack one
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_QUARTER_DMG,
0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK1_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK1_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK1_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK1_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK1_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK1_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK1_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType
.getFieldAsBoolean(ATTACK1_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK1_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK1_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK1_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK1_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK1_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor,
damageDice, damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType));
}
catch (final Exception exc) {
System.err.println("Attack 1 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
if ((attacksEnabled & 0x2) != 0) {
try {
// attack two
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_QUARTER_DMG,
0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK2_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK2_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK2_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK2_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK2_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK2_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK2_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType
.getFieldAsBoolean(ATTACK2_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK2_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK2_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK2_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK2_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK2_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor,
damageDice, damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType));
}
catch (final Exception exc) {
System.err.println("Attack 2 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
final boolean raise = (deathType & 0x1) != 0;
final boolean decay = (deathType & 0x2) != 0;
final String armorType = unitType.getFieldAsString(ARMOR_TYPE, 0);
final float impactZ = unitType.getFieldAsFloat(PROJECTILE_IMPACT_Z, 0);
final CDefenseType defenseType = CDefenseType.parseDefenseType(unitType.getFieldAsString(DEFENSE_TYPE, 0));
final float deathTime = unitType.getFieldAsFloat(DEATH_TIME, 0);
unitTypeInstance = new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize, classifications,
attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime,
targetedAs, acquisitionRange, minimumAttackRange);
this.unitIdToUnitType.put(typeId, unitTypeInstance);
}
return unitTypeInstance;
}
public float getPropulsionWindow(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROPULSION_WINDOW, 0);
}
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
final EnumSet<CTargetType> areaOfEffectTargets, final CAttackType attackType, final float cooldownTime,
final int damageBase, final float damageFactorMedium, final float damageFactorSmall,
final float damageLossFactor, final int damageDice, final int damageSidesPerDie,
final float damageSpillDistance, final float damageSpillRadius, final int damageUpgradeAmount,
final int maximumNumberOfTargets, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final int range,
final float rangeMotionBuffer, final boolean showUI, final EnumSet<CTargetType> targetsAllowed,
final String weaponSound, final CWeaponType weaponType) {
final CUnitAttack attack;
switch (weaponType) {
case MISSILE:
attack = new CUnitAttackMissile(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed);
break;
case MBOUNCE:
attack = new CUnitAttackMissileBounce(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, damageLossFactor, maximumNumberOfTargets,
areaOfEffectFullDamage, areaOfEffectTargets);
break;
case MSPLASH:
case ARTILLERY:
attack = new CUnitAttackMissileSplash(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, areaOfEffectFullDamage, areaOfEffectMediumDamage,
areaOfEffectSmallDamage, areaOfEffectTargets, damageFactorMedium, damageFactorSmall);
break;
case MLINE:
case ALINE:
attack = new CUnitAttackMissileLine(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, damageSpillDistance, damageSpillRadius);
break;
case INSTANT:
attack = new CUnitAttackInstant(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArt);
break;
default:
case NORMAL:
attack = new CUnitAttackNormal(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType);
break;
}
return attack;
}
public float getTurnRate(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(TURN_RATE, 0);
}
public float getPropulsionWindow(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROPULSION_WINDOW, 0);
}
public boolean isBuilding(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsBoolean(IS_BLDG, 0);
}
public float getTurnRate(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(TURN_RATE, 0);
}
public String getName(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getName();
}
public boolean isBuilding(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsBoolean(IS_BLDG, 0);
}
public int getA1MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0);
}
public String getName(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getName();
}
public int getA1MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0));
}
public int getA1MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0);
}
public int getA2MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0);
}
public int getA1MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0));
}
public int getA2MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0));
}
public int getA2MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0);
}
public int getDefense(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(DEFENSE, 0);
}
public int getA2MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0));
}
public int getA1ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
}
public int getDefense(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(DEFENSE, 0);
}
public float getA1ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
}
public int getA1ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
}
public int getA2ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
}
public float getA1ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
}
public float getA2ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
}
public int getA2ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
}
public String getA1MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK1_MISSILE_ART, 0);
}
public float getA2ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
}
public String getA2MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK2_MISSILE_ART, 0);
}
public String getA1MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK1_MISSILE_ART, 0);
}
public float getA1Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_COOLDOWN, 0);
}
public String getA2MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK2_MISSILE_ART, 0);
}
public float getA2Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_COOLDOWN, 0);
}
public float getA1Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_COOLDOWN, 0);
}
public float getProjectileLaunchX(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_X, 0);
}
public float getA2Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_COOLDOWN, 0);
}
public float getProjectileLaunchY(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Y, 0);
}
public float getProjectileLaunchX(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_X, 0);
}
public float getProjectileLaunchZ(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Z, 0);
}
public float getProjectileLaunchY(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Y, 0);
}
public float getProjectileLaunchZ(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Z, 0);
}
}

View File

@ -1,23 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
public interface CBehavior {
/**
* Executes one step of game simulation of the current order, returning true if
* the order has completed. Many orders may wrap the move order and spend a
* number of simulation steps moving to get within range of the target point
* before completing.
*
* @return
*/
boolean update(CSimulation game);
/**
* Gets the Order ID of the order, useful for determining which icon to
* highlight on the unit's command card.
*
* @return
*/
int getOrderId();
}

View File

@ -1,177 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
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.combat.attacks.CUnitAttack;
public class CBehaviorAttack implements CBehavior {
private final CUnit unit;
private final int orderId;
private boolean wasWithinPropWindow = false;
private final CUnitAttack unitAttack;
private final CWidget target;
private int damagePointLaunchTime;
private int backSwingTime;
private CBehavior moveOrder;
private int thisOrderCooldownEndTime;
private boolean wasInRange = false;
public CBehaviorAttack(final CUnit unit, final CUnitAttack unitAttack, final int orderId, final CWidget target) {
this.unit = unit;
this.unitAttack = unitAttack;
this.orderId = orderId;
this.target = target;
createMoveOrder(unit, target);
}
private void createMoveOrder(final CUnit unit, final CWidget target) {
if (!unit.isMovementDisabled()) { // TODO: Check mobility instead
if ((target instanceof CUnit) && !(((CUnit) target).getUnitType().isBuilding())) {
this.moveOrder = new CBehaviorMove(unit, this.orderId, (CUnit) target);
}
else {
this.moveOrder = new CBehaviorMove(unit, this.orderId, target.getX(), target.getY());
}
}
else {
this.moveOrder = null;
}
}
@Override
public boolean update(final CSimulation simulation) {
if (this.target.isDead()
|| !this.target.canBeTargetedBy(simulation, this.unit, this.unitAttack.getTargetsAllowed())) {
return true;
}
float range = this.unitAttack.getRange();
if ((this.target instanceof CUnit) && (((CUnit) this.target).getCurrentOrder() instanceof CBehaviorMove)
&& (this.damagePointLaunchTime != 0 /*
* only apply range motion buffer if they were already in range and
* attacked
*/)) {
range += this.unitAttack.getRangeMotionBuffer();
}
if (!this.unit.canReach(this.target, range)
|| (this.unit.distance(this.target) < this.unit.getUnitType().getMinimumAttackRange())) {
if (this.moveOrder == null) {
return true;
}
if (this.moveOrder.update(simulation)) {
return true; // we just cant reach them
}
this.wasInRange = false;
this.damagePointLaunchTime = 0;
this.thisOrderCooldownEndTime = 0;
return false;
}
this.wasInRange = true;
if (!this.unit.isMovementDisabled()) {
final float prevX = this.unit.getX();
final float prevY = this.unit.getY();
final float deltaY = this.target.getY() - prevY;
final float deltaX = this.target.getX() - prevX;
final double goalAngleRad = Math.atan2(deltaY, deltaX);
float goalAngle = (float) Math.toDegrees(goalAngleRad);
if (goalAngle < 0) {
goalAngle += 360;
}
float facing = this.unit.getFacing();
float delta = goalAngle - facing;
final float propulsionWindow = simulation.getGameplayConstants().getAttackHalfAngle();
final float turnRate = simulation.getUnitData().getTurnRate(this.unit.getTypeId());
if (delta < -180) {
delta = 360 + delta;
}
if (delta > 180) {
delta = -360 + delta;
}
final float absDelta = Math.abs(delta);
if ((absDelta <= 1.0) && (absDelta != 0)) {
this.unit.setFacing(goalAngle);
}
else {
float angleToAdd = Math.signum(delta) * (float) Math.toDegrees(turnRate);
if (absDelta < Math.abs(angleToAdd)) {
angleToAdd = delta;
}
facing += angleToAdd;
this.unit.setFacing(facing);
}
if (absDelta < propulsionWindow) {
this.wasWithinPropWindow = true;
}
else {
// If this happens, the unit is facing the wrong way, and has to turn before
// moving.
this.wasWithinPropWindow = false;
}
}
else {
this.wasWithinPropWindow = true;
}
final int cooldownEndTime = this.unit.getCooldownEndTime();
final int currentTurnTick = simulation.getGameTurnTick();
if (this.wasWithinPropWindow) {
if (this.damagePointLaunchTime != 0) {
if (currentTurnTick >= this.damagePointLaunchTime) {
int minDamage = this.unitAttack.getMinDamage();
final int maxDamage = Math.max(0, this.unitAttack.getMaxDamage());
if (minDamage > maxDamage) {
minDamage = maxDamage;
}
final int damage;
if (maxDamage == 0) {
damage = 0;
}
else if (minDamage == maxDamage) {
damage = minDamage;
}
else {
damage = simulation.getSeededRandom().nextInt(maxDamage - minDamage) + minDamage;
}
this.unitAttack.launch(simulation, this.unit, this.target, damage);
this.damagePointLaunchTime = 0;
}
}
else if (currentTurnTick >= cooldownEndTime) {
final float cooldownTime = this.unitAttack.getCooldownTime();
final float animationBackswingPoint = this.unitAttack.getAnimationBackswingPoint();
final int a1CooldownSteps = (int) (cooldownTime / WarsmashConstants.SIMULATION_STEP_TIME);
final int a1BackswingSteps = (int) (animationBackswingPoint / WarsmashConstants.SIMULATION_STEP_TIME);
final int a1DamagePointSteps = (int) (this.unitAttack.getAnimationDamagePoint()
/ WarsmashConstants.SIMULATION_STEP_TIME);
this.unit.setCooldownEndTime(currentTurnTick + a1CooldownSteps);
this.thisOrderCooldownEndTime = currentTurnTick + a1CooldownSteps;
this.damagePointLaunchTime = currentTurnTick + a1DamagePointSteps;
this.backSwingTime = currentTurnTick + a1DamagePointSteps + a1BackswingSteps;
this.unit.getUnitAnimationListener().playAnimation(true, PrimaryTag.ATTACK, SequenceUtils.EMPTY, 1.0f,
true);
this.unit.getUnitAnimationListener().queueAnimation(PrimaryTag.STAND, SequenceUtils.READY, false);
}
else if ((currentTurnTick >= this.thisOrderCooldownEndTime)) {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.READY, 1.0f,
false);
}
}
else {
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.READY, 1.0f,
false);
}
return false;
}
@Override
public int getOrderId() {
return this.orderId;
}
}

View File

@ -1,96 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
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;
public class CBehaviorPatrol implements CBehavior {
private final CUnit unit;
private final int orderId;
private final CWidget target;
private CBehavior moveOrder;
public CBehaviorPatrol(final CUnit unit, final int orderId, final CUnit target) {
this.unit = unit;
this.orderId = orderId;
this.target = target;
createMoveOrder(unit, target);
}
private void createMoveOrder(final CUnit unit, final CUnit target) {
if (!unit.isMovementDisabled()) { // TODO: Check mobility instead
if ((target instanceof CUnit) && !(target.getUnitType().isBuilding())) {
this.moveOrder = new CBehaviorMove(unit, this.orderId, target);
}
else {
this.moveOrder = new CBehaviorMove(unit, this.orderId, target.getX(), target.getY());
}
}
else {
this.moveOrder = null;
}
}
@Override
public boolean update(final CSimulation simulation) {
if (this.target.isDead()) {
return true;
}
final float range = this.unit.getAcquisitionRange();
if (!this.unit.canReach(this.target, range)) {
if (this.moveOrder == null) {
return true;
}
if (this.moveOrder.update(simulation)) {
return true; // we just cant reach them
}
return false;
}
if (!this.unit.isMovementDisabled()) {
final float prevX = this.unit.getX();
final float prevY = this.unit.getY();
final float deltaY = this.target.getY() - prevY;
final float deltaX = this.target.getX() - prevX;
final double goalAngleRad = Math.atan2(deltaY, deltaX);
float goalAngle = (float) Math.toDegrees(goalAngleRad);
if (goalAngle < 0) {
goalAngle += 360;
}
float facing = this.unit.getFacing();
float delta = goalAngle - facing;
final float turnRate = simulation.getUnitData().getTurnRate(this.unit.getTypeId());
if (delta < -180) {
delta = 360 + delta;
}
if (delta > 180) {
delta = -360 + delta;
}
final float absDelta = Math.abs(delta);
if ((absDelta <= 1.0) && (absDelta != 0)) {
this.unit.setFacing(goalAngle);
}
else {
float angleToAdd = Math.signum(delta) * (float) Math.toDegrees(turnRate);
if (absDelta < Math.abs(angleToAdd)) {
angleToAdd = delta;
}
facing += angleToAdd;
this.unit.setFacing(facing);
}
}
else {
}
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, false);
return false;
}
@Override
public int getOrderId() {
return this.orderId;
}
}

View File

@ -1,22 +0,0 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
public class CBehaviorStop implements CBehavior {
private final int orderId;
public CBehaviorStop(final int orderId) {
this.orderId = orderId;
}
@Override
public boolean update(final CSimulation game) {
return true;
}
@Override
public int getOrderId() {
return this.orderId;
}
}

View File

@ -0,0 +1,18 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
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.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgAbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgTargetCheckReceiver;
public interface COrder {
int getAbilityHandleId();
int getOrderId();
CBehavior begin(final CSimulation game, CUnit caster);
final StringMsgTargetCheckReceiver<?> targetCheckReceiver = new StringMsgTargetCheckReceiver<>();
final StringMsgAbilityActivationReceiver abilityActivationReceiver = new StringMsgAbilityActivationReceiver();
}

View File

@ -0,0 +1,33 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
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.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
public class COrderNoTarget implements COrder {
private final int abilityHandleId;
private final int orderId;
public COrderNoTarget(final int abilityHandleId, final int orderId) {
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
}
@Override
public int getAbilityHandleId() {
return this.abilityHandleId;
}
@Override
public int getOrderId() {
return this.orderId;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster) {
final CAbility ability = game.getAbility(this.abilityHandleId);
return ability.beginNoTarget(game, caster, this.orderId);
}
}

View File

@ -0,0 +1,57 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
import com.badlogic.gdx.math.Vector2;
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.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgTargetCheckReceiver;
public class COrderTargetPoint implements COrder {
private final int abilityHandleId;
private final int orderId;
private final Vector2 target;
public COrderTargetPoint(final int abilityHandleId, final int orderId, final Vector2 target) {
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
this.target = target;
}
@Override
public int getAbilityHandleId() {
return this.abilityHandleId;
}
@Override
public int getOrderId() {
return this.orderId;
}
public Vector2 getTarget() {
return this.target;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster) {
final CAbility ability = game.getAbility(this.abilityHandleId);
ability.checkCanUse(game, caster, this.orderId, this.abilityActivationReceiver.reset());
if (this.abilityActivationReceiver.isUseOk()) {
final StringMsgTargetCheckReceiver<Vector2> targetReceiver = (StringMsgTargetCheckReceiver<Vector2>) targetCheckReceiver;
ability.checkCanTarget(game, caster, this.orderId, this.target, targetReceiver);
if (targetReceiver.getTarget() != null) {
return ability.begin(game, caster, this.orderId, this.target);
}
else {
game.getCommandErrorListener().showCommandError(targetReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
else {
game.getCommandErrorListener().showCommandError(this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
}

View File

@ -1,5 +1,52 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders;
public class COrderTargetWidget {
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.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgTargetCheckReceiver;
public class COrderTargetWidget implements COrder {
private final int abilityHandleId;
private final int orderId;
private final int targetHandleId;
public COrderTargetWidget(final int abilityHandleId, final int orderId, final int targetHandleId) {
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
this.targetHandleId = targetHandleId;
}
@Override
public int getAbilityHandleId() {
return this.abilityHandleId;
}
@Override
public int getOrderId() {
return this.orderId;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster) {
final CAbility ability = game.getAbility(this.abilityHandleId);
ability.checkCanUse(game, caster, this.orderId, abilityActivationReceiver.reset());
if (abilityActivationReceiver.isUseOk()) {
final CUnit target = game.getUnit(this.targetHandleId);
final StringMsgTargetCheckReceiver<CWidget> targetReceiver = (StringMsgTargetCheckReceiver<CWidget>) targetCheckReceiver;
ability.checkCanTarget(game, caster, this.orderId, target, targetReceiver);
if (targetReceiver.getTarget() != null) {
return ability.begin(game, caster, this.orderId, targetReceiver.getTarget());
}
else {
game.getCommandErrorListener().showCommandError(targetReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
else {
game.getCommandErrorListener().showCommandError(this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
}

View File

@ -3,21 +3,14 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players;
import com.badlogic.gdx.math.Vector2;
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.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgAbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgTargetCheckReceiver;
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;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
public class CPlayerUnitOrderExecutor implements CPlayerUnitOrderListener {
private final CSimulation game;
private final CommandErrorListener errorListener;
private final StringMsgTargetCheckReceiver<?> targetCheckReceiver = new StringMsgTargetCheckReceiver<>();
private final StringMsgAbilityActivationReceiver abilityActivationReceiver = new StringMsgAbilityActivationReceiver();
private <T> StringMsgTargetCheckReceiver<T> targetCheckReceiver() {
return (StringMsgTargetCheckReceiver<T>) this.targetCheckReceiver.reset();
}
public CPlayerUnitOrderExecutor(final CSimulation game, final CommandErrorListener errorListener) {
this.game = game;
@ -25,77 +18,24 @@ public class CPlayerUnitOrderExecutor implements CPlayerUnitOrderListener {
}
@Override
public boolean issueTargetOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
public void issueTargetOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
final int targetHandleId, final boolean queue) {
final CUnit unit = this.game.getUnit(unitHandleId);
final CAbility ability = this.game.getAbility(abilityHandleId);
ability.checkCanUse(this.game, unit, orderId, this.abilityActivationReceiver.reset());
if (this.abilityActivationReceiver.isUseOk()) {
final CUnit target = this.game.getUnit(targetHandleId);
final StringMsgTargetCheckReceiver<CWidget> targetReceiver = this.<CWidget>targetCheckReceiver();
ability.checkCanTarget(this.game, unit, orderId, target, targetReceiver);
if (targetReceiver.getTarget() != null) {
ability.onOrder(this.game, unit, orderId, target, queue);
return true;
}
else {
this.errorListener.showCommandError(targetReceiver.getMessage());
return false;
}
}
else {
this.errorListener.showCommandError(this.abilityActivationReceiver.getMessage());
return false;
}
unit.order(this.game, new COrderTargetWidget(abilityHandleId, orderId, targetHandleId), queue);
}
@Override
public boolean issuePointOrder(final int unitHandleId, final int abilityHandleId, final int orderId, final float x,
public void issuePointOrder(final int unitHandleId, final int abilityHandleId, final int orderId, final float x,
final float y, final boolean queue) {
final CUnit unit = this.game.getUnit(unitHandleId);
final CAbility ability = this.game.getAbility(abilityHandleId);
ability.checkCanUse(this.game, unit, orderId, this.abilityActivationReceiver.reset());
if (this.abilityActivationReceiver.isUseOk()) {
final Vector2 target = new Vector2(x, y);
final StringMsgTargetCheckReceiver<Vector2> targetReceiver = this.<Vector2>targetCheckReceiver();
ability.checkCanTarget(this.game, unit, orderId, target, targetReceiver);
if (targetReceiver.getTarget() != null) {
ability.onOrder(this.game, unit, orderId, target, queue);
return true;
}
else {
this.errorListener.showCommandError(targetReceiver.getMessage());
return false;
}
}
else {
this.errorListener.showCommandError(this.abilityActivationReceiver.getMessage());
return false;
}
unit.order(this.game, new COrderTargetPoint(abilityHandleId, orderId, new Vector2(x, y)), queue);
}
@Override
public boolean issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
public void issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
final boolean queue) {
final CUnit unit = this.game.getUnit(unitHandleId);
final CAbility ability = this.game.getAbility(abilityHandleId);
ability.checkCanUse(this.game, unit, orderId, this.abilityActivationReceiver.reset());
if (this.abilityActivationReceiver.isUseOk()) {
final StringMsgTargetCheckReceiver<Void> targetReceiver = this.<Void>targetCheckReceiver();
ability.checkCanTargetNoTarget(this.game, unit, orderId, targetReceiver);
if (targetReceiver.getMessage() == null) {
ability.onOrderNoTarget(this.game, unit, orderId, queue);
return true;
}
else {
this.errorListener.showCommandError(targetReceiver.getMessage());
return false;
}
}
else {
this.errorListener.showCommandError(this.abilityActivationReceiver.getMessage());
return false;
}
unit.order(this.game, new COrderNoTarget(abilityHandleId, orderId), queue);
}
}

View File

@ -1,12 +1,12 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.players;
public interface CPlayerUnitOrderListener {
boolean issueTargetOrder(int unitHandleId, int abilityHandleId, int orderId, int targetHandleId, boolean queue);
void issueTargetOrder(int unitHandleId, int abilityHandleId, int orderId, int targetHandleId, boolean queue);
boolean issuePointOrder(int unitHandleId, int abilityHandleId, int orderId, float x, float y, boolean queue);
void issuePointOrder(int unitHandleId, int abilityHandleId, int orderId, float x, float y, boolean queue);
// Below: used for "DROP ITEM AT POINT" ????
// boolean issueTargetAndPointOrder(int unitHandleId, int orderId, int targetHandleId, float x, float y);
boolean issueImmediateOrder(int unitHandleId, int abilityHandleId, int orderId, boolean queue);
void issueImmediateOrder(int unitHandleId, int abilityHandleId, int orderId, boolean queue);
}

View File

@ -23,6 +23,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
private CommandButton commandButton;
private int abilityHandleId;
private int orderId;
private int autoCastOrderId;
private final CommandCardCommandListener commandCardCommandListener;
public CommandCardIcon(final String name, final UIFrame parent,
@ -45,7 +46,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
this.iconFrame.setVisible(false);
this.activeHighlightFrame.setVisible(false);
this.cooldownFrame.setVisible(false);
this.autocastFrame.setVisible(false);
this.autocastFrame.setSequence(PrimaryTag.DEATH);
}
else {
if (commandButton.isEnabled()) {
@ -64,19 +65,24 @@ public class CommandCardIcon extends AbstractRenderableFrame {
this.cooldownFrame
.setFrameByRatio(1 - (commandButton.getCooldownRemaining() / commandButton.getCooldown()));
}
this.autocastFrame.setVisible(commandButton.isAutoCastActive());
}
}
public void setCommandButtonData(final Texture texture, final int abilityHandleId, final int orderId,
final boolean active) {
final int autoCastOrderId, final boolean active, final boolean autoCastActive) {
this.iconFrame.setVisible(true);
this.activeHighlightFrame.setVisible(active);
this.cooldownFrame.setVisible(false);
this.autocastFrame.setVisible(false);
if (autoCastActive) {
this.autocastFrame.setSequence(PrimaryTag.STAND);
}
else {
this.autocastFrame.setSequence(-1);
}
this.iconFrame.setTexture(texture);
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
this.autoCastOrderId = autoCastOrderId;
}
@Override
@ -102,7 +108,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
this.commandCardCommandListener.startUsingAbility(this.abilityHandleId, this.orderId);
}
else if (button == Input.Buttons.RIGHT) {
this.commandCardCommandListener.toggleAutoCastAbility(this.abilityHandleId);
this.commandCardCommandListener.startUsingAbility(this.abilityHandleId, this.autoCastOrderId);
}
return this;
}

View File

@ -13,11 +13,10 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
@ -77,7 +76,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private static final Vector3 clickLocationTemp = new Vector3();
private static final Vector2 clickLocationTemp2 = new Vector2();
private final DataSource dataSource;
private final Viewport uiViewport;
private final ExtendViewport uiViewport;
private final FreeTypeFontGenerator fontGenerator;
private final Scene uiScene;
private final Scene portraitScene;
@ -137,10 +136,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private int selectedSoundCount = 0;
private final ActiveCommandUnitTargetFilter activeCommandUnitTargetFilter;
public MeleeUI(final DataSource dataSource, final Viewport uiViewport, final FreeTypeFontGenerator fontGenerator,
final Scene uiScene, final Scene portraitScene, final CameraPreset[] cameraPresets,
final CameraRates cameraRates, final War3MapViewer war3MapViewer, final RootFrameListener rootFrameListener,
final CPlayerUnitOrderListener unitOrderListener) {
// TODO these corrections are used for old hardcoded UI stuff, we should
// probably remove them later
private final float widthRatioCorrection;
private final float heightRatioCorrection;
public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport,
final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final Scene portraitScene,
final CameraPreset[] cameraPresets, final CameraRates cameraRates, final War3MapViewer war3MapViewer,
final RootFrameListener rootFrameListener, final CPlayerUnitOrderListener unitOrderListener) {
this.dataSource = dataSource;
this.uiViewport = uiViewport;
this.fontGenerator = fontGenerator;
@ -161,11 +165,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.activeButtonTexture = ImageUtils.getBLPTexture(war3MapViewer.mapMpq,
"UI\\Widgets\\Console\\Human\\CommandButton\\human-activebutton.blp");
this.activeCommandUnitTargetFilter = new ActiveCommandUnitTargetFilter();
this.widthRatioCorrection = this.uiViewport.getMinWorldWidth() / 1600f;
this.heightRatioCorrection = this.uiViewport.getMinWorldHeight() / 1200f;
}
private MeleeUIMinimap createMinimap(final War3MapViewer war3MapViewer) {
final Rectangle minimapDisplayArea = new Rectangle(18.75f, 13.75f, 278.75f, 276.25f);
final Rectangle minimapDisplayArea = new Rectangle(18.75f * this.widthRatioCorrection,
13.75f * this.heightRatioCorrection, 278.75f * this.widthRatioCorrection,
276.25f * this.heightRatioCorrection);
Texture minimapTexture = null;
if (war3MapViewer.dataSource.has("war3mapMap.tga")) {
try {
@ -396,11 +404,6 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.errorMessageFrame.setText(message);
}
@Override
public void toggleAutoCastAbility(final int abilityHandleId) {
}
public void update(final float deltaTime) {
this.portrait.update();
@ -468,8 +471,6 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.cameraManager.updateCamera();
}
private final ShapeRenderer shapeRenderer = new ShapeRenderer();
public void render(final SpriteBatch batch, final BitmapFont font20, final GlyphLayout glyphLayout) {
this.rootFrame.render(batch, font20, glyphLayout);
if (this.selectedUnit != null) {
@ -658,10 +659,11 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
@Override
public void commandButton(final int buttonPositionX, final int buttonPositionY, final Texture icon,
final int abilityHandleId, final int orderId, final boolean active) {
final int abilityHandleId, final int orderId, final int autoCastId, final boolean active,
final boolean autoCastActive) {
final int x = Math.max(0, Math.min(COMMAND_CARD_WIDTH - 1, buttonPositionX));
final int y = Math.max(0, Math.min(COMMAND_CARD_HEIGHT - 1, buttonPositionY));
this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId, active);
this.commandCard[y][x].setCommandButtonData(icon, abilityHandleId, orderId, autoCastId, active, autoCastActive);
}
public void resize(final Rectangle viewport) {
@ -670,10 +672,10 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
public void positionPortrait() {
this.projectionTemp1.x = 422;
this.projectionTemp1.y = 57;
this.projectionTemp2.x = 422 + 167;
this.projectionTemp2.y = 57 + 170;
this.projectionTemp1.x = 422 * this.widthRatioCorrection;
this.projectionTemp1.y = 57 * this.heightRatioCorrection;
this.projectionTemp2.x = (422 + 167) * this.widthRatioCorrection;
this.projectionTemp2.y = (57 + 170) * this.heightRatioCorrection;
this.uiViewport.project(this.projectionTemp1);
this.uiViewport.project(this.projectionTemp2);
@ -752,7 +754,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
@Override
public void ordersChanged() {
public void ordersChanged(final int abilityHandleId, final int orderId) {
clearCommandCard();
this.selectedUnit.populateCommandCard(this.war3MapViewer.simulation, this,
this.war3MapViewer.getAbilityDataUI());
@ -798,20 +800,19 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.activeCommandUnitTargetFilter);
final boolean shiftDown = isShiftDown();
if (rayPickUnit != null) {
if (this.unitOrderListener.issueTargetOrder(
this.unitOrderListener.issueTargetOrder(
this.activeCommandUnit.getSimulationUnit().getHandleId(),
this.activeCommand.getHandleId(), this.activeCommandOrderId,
rayPickUnit.getSimulationUnit().getHandleId(), shiftDown)) {
if (getSelectedUnit().soundset.yesAttack
.playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) {
portraitTalk();
}
this.selectedSoundCount = 0;
if (!shiftDown) {
this.activeCommandUnit = null;
this.activeCommand = null;
this.activeCommandOrderId = -1;
}
rayPickUnit.getSimulationUnit().getHandleId(), shiftDown);
if (getSelectedUnit().soundset.yesAttack
.playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) {
portraitTalk();
}
this.selectedSoundCount = 0;
if (!shiftDown) {
this.activeCommandUnit = null;
this.activeCommand = null;
this.activeCommandOrderId = -1;
}
}
else {
@ -829,21 +830,21 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
else {
this.war3MapViewer.showConfirmation(clickLocationTemp, 0, 1, 0);
}
if (this.unitOrderListener.issuePointOrder(
this.unitOrderListener.issuePointOrder(
this.activeCommandUnit.getSimulationUnit().getHandleId(),
this.activeCommand.getHandleId(), this.activeCommandOrderId, clickLocationTemp2.x,
clickLocationTemp2.y, shiftDown)) {
if (getSelectedUnit().soundset.yes.playUnitResponse(
this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) {
portraitTalk();
}
this.selectedSoundCount = 0;
if (!shiftDown) {
this.activeCommandUnit = null;
this.activeCommand = null;
this.activeCommandOrderId = -1;
}
clickLocationTemp2.y, shiftDown);
if (getSelectedUnit().soundset.yes
.playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) {
portraitTalk();
}
this.selectedSoundCount = 0;
if (!shiftDown) {
this.activeCommandUnit = null;
this.activeCommand = null;
this.activeCommandOrderId = -1;
}
}
}
}
@ -975,4 +976,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
return false;
}
public float getHeightRatioCorrection() {
return this.heightRatioCorrection;
}
}

View File

@ -2,6 +2,4 @@ package com.etheller.warsmash.viewer5.handlers.w3x.ui.command;
public interface CommandCardCommandListener {
void startUsingAbility(int abilityHandleId, int orderId);
void toggleAutoCastAbility(int abilityHandleId);
}