Improve hold position and show shift click waypoints

This commit is contained in:
Retera 2021-01-18 08:20:01 -05:00
parent 9a2dc090ca
commit fa1656922f
29 changed files with 465 additions and 103 deletions

View File

@ -38,3 +38,4 @@ Path06="."
FilePath="PeonMiningMultiHall.w3x"
//FilePath="QuadtreeBugs.w3x"
//FilePath="test2.w3x"
//FilePath="FarseerHoldPositionTest.w3x"

View File

@ -6,7 +6,7 @@ import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
public class Quadtree<T> {
private static final int MAX_DEPTH = 9;
private static final int MAX_DEPTH = 9; // 2^9 = 512, and 512 is the biggest map size...
private static final int SPLIT_THRESHOLD = 6;
private final Rectangle bounds;

View File

@ -508,6 +508,8 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final float height = War3MapViewer.this.terrain.getGroundHeight(targetX, targetY)
+ target.getFlyHeight() + target.getImpactZ();
System.out.println(
"Spawning INSTANT: " + missileArt + " at " + targetX + ", " + targetY + ", " + height);
final MdxModel model = (MdxModel) load(missileArt, War3MapViewer.this.mapPathSolver,
War3MapViewer.this.solverParams);
final MdxComplexInstance modelInstance = (MdxComplexInstance) model.addInstance();

View File

@ -1,14 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim;
import java.util.List;
import com.etheller.warsmash.parsers.mdlx.Sequence;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.IndexedSequence;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
public class RenderAttackInstant implements RenderEffect {
@ -18,14 +11,15 @@ public class RenderAttackInstant implements RenderEffect {
final float yaw) {
this.modelInstance = modelInstance;
final MdxModel model = (MdxModel) this.modelInstance.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = SequenceUtils.selectSequence(PrimaryTag.DEATH, SequenceUtils.EMPTY, sequences,
true);
if (sequence != null) {
this.modelInstance.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
this.modelInstance.setSequence(sequence.index);
}
// final List<Sequence> sequences = model.getSequences();
// final IndexedSequence sequence = SequenceUtils.selectSequence(PrimaryTag.DEATH, SequenceUtils.EMPTY, sequences,
// true);
// if ((sequence != null) && (sequence.index != -1)) {
// this.modelInstance.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
// this.modelInstance.setSequence(sequence.index);
// }
this.modelInstance.localRotation.setFromAxisRad(0, 0, 1, yaw);
System.out.println("creating " + this);
}
@Override
@ -33,6 +27,7 @@ public class RenderAttackInstant implements RenderEffect {
final boolean everythingDone = this.modelInstance.sequenceEnded;
if (everythingDone) {
System.out.println("removing " + this);
war3MapViewer.worldScene.removeInstance(this.modelInstance);
}
return everythingDone;

View File

@ -79,8 +79,7 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
if ((this.menuBaseOrderId == 0) && ability.isIconShowing()) {
addCommandButton(ability, this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move, 0, false,
false);
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition,
0, false, false);
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), 0, OrderIds.holdposition, 0, false, false);
addCommandButton(ability, this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol, 0,
false, false);
if (!this.hasStop) {

View File

@ -27,6 +27,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting
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.CBehaviorHoldPosition;
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;
@ -58,7 +59,6 @@ public class CUnit extends CWidget {
private final List<CAbility> abilities = new ArrayList<>();
private CBehavior currentBehavior;
private COrder currentOrder;
private final Queue<COrder> orderQueue = new LinkedList<>();
private final CUnitType unitType;
@ -86,12 +86,15 @@ public class CUnit extends CWidget {
private transient CBehaviorFollow followBehavior;
private transient CBehaviorPatrol patrolBehavior;
private transient CBehaviorStop stopBehavior;
private transient CBehaviorHoldPosition holdPositionBehavior;
private boolean constructing = false;
private float constructionProgress;
private boolean hidden = false;
private boolean paused = false;
private boolean acceptingOrders = true;
private boolean invulnerable = false;
private boolean holdingPosition = false;
private COrder currentOrder = null;
private CUnit workerInside;
private final War3ID[] buildQueue = new War3ID[WarsmashConstants.BUILD_QUEUE_SIZE];
private final QueueItemType[] buildQueueTypes = new QueueItemType[WarsmashConstants.BUILD_QUEUE_SIZE];
@ -259,7 +262,7 @@ public class CUnit extends CWidget {
player.setFoodCap(player.getFoodCap() + this.unitType.getFoodMade());
}
game.unitConstructFinishEvent(this);
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
this.stateNotifier.ordersChanged();
}
}
else {
@ -307,13 +310,17 @@ public class CUnit extends CWidget {
if (this.currentBehavior != null) {
final CBehavior lastBehavior = this.currentBehavior;
this.currentBehavior = this.currentBehavior.update(game);
if (lastBehavior != this.currentBehavior) {
lastBehavior.end(game);
this.currentBehavior.begin(game);
}
if (this.currentBehavior.getHighlightOrderId() != lastBehavior.getHighlightOrderId()) {
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
this.stateNotifier.ordersChanged();
}
}
else {
// check to auto acquire targets
autoAcquireAttackTargets(game);
autoAcquireAttackTargets(game, false);
}
}
}
@ -330,7 +337,7 @@ public class CUnit extends CWidget {
}
}
public void autoAcquireAttackTargets(final CSimulation game) {
public boolean autoAcquireAttackTargets(final CSimulation game, final boolean disableMove) {
if (!this.unitType.getAttacks().isEmpty()) {
if (this.collisionRectangle != null) {
tempRect.set(this.collisionRectangle);
@ -343,8 +350,11 @@ public class CUnit extends CWidget {
tempRect.y -= halfSize;
tempRect.width += halfSize * 2;
tempRect.height += halfSize * 2;
game.getWorldCollision().enumUnitsInRect(tempRect, autoAttackTargetFinderEnum.reset(game, this));
game.getWorldCollision().enumUnitsInRect(tempRect,
autoAttackTargetFinderEnum.reset(game, this, disableMove));
return autoAttackTargetFinderEnum.foundAnyTarget;
}
return false;
}
public float getEndingDecayTime(final CSimulation game) {
@ -359,26 +369,35 @@ public class CUnit extends CWidget {
return;
}
if (order != null) {
final CAbility ability = game.getAbility(order.getAbilityHandleId());
if (ability != null) {
// Allow the ability to response to the order without actually placing itself in
// the queue, nor modifying (interrupting) the queue.
if (!ability.checkBeforeQueue(game, this, order.getOrderId())) {
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
this.stateNotifier.ordersChanged();
return;
}
}
}
if ((queue || !this.acceptingOrders) && (this.currentOrder != null)) {
if ((queue || !this.acceptingOrders) && ((this.currentBehavior != this.stopBehavior)
&& (this.currentBehavior != this.holdPositionBehavior))) {
this.orderQueue.add(order);
this.stateNotifier.waypointsChanged();
}
else {
this.currentBehavior = beginOrder(game, order);
this.orderQueue.clear();
final boolean omitNotify = (this.currentOrder == null) && (order == null);
if (!omitNotify) {
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
setHoldingPosition(false);
if (this.currentBehavior != null) {
this.currentBehavior.end(game);
}
this.currentBehavior = beginOrder(game, order);
if (this.currentBehavior != null) {
this.currentBehavior.begin(game);
}
this.orderQueue.clear();
this.stateNotifier.ordersChanged();
this.stateNotifier.waypointsChanged();
}
}
@ -388,9 +407,14 @@ public class CUnit extends CWidget {
if (order != null) {
nextBehavior = order.begin(game, this);
}
else {
if (this.holdingPosition) {
nextBehavior = this.holdPositionBehavior;
}
else {
nextBehavior = this.stopBehavior;
}
}
return nextBehavior;
}
@ -398,14 +422,6 @@ public class CUnit extends CWidget {
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() {
return this.abilities;
}
@ -625,7 +641,8 @@ public class CUnit extends CWidget {
CAllianceType.PASSIVE)) {
for (final CUnitAttack attack : this.unitType.getAttacks()) {
if (source.canBeTargetedBy(simulation, this, attack.getTargetsAllowed())) {
this.currentBehavior = getAttackBehavior().reset(OrderIds.attack, attack, source);
this.currentBehavior = getAttackBehavior().reset(OrderIds.attack, attack, source, false);
this.currentBehavior.begin(simulation);
break;
}
}
@ -635,6 +652,9 @@ public class CUnit extends CWidget {
}
private void kill(final CSimulation simulation) {
if (this.currentBehavior != null) {
this.currentBehavior.end(simulation);
}
this.currentBehavior = null;
this.orderQueue.clear();
if (this.constructing) {
@ -809,10 +829,15 @@ public class CUnit extends CWidget {
private static final class AutoAttackTargetFinderEnum implements CUnitEnumFunction {
private CSimulation game;
private CUnit source;
private boolean disableMove;
private boolean foundAnyTarget;
private AutoAttackTargetFinderEnum reset(final CSimulation game, final CUnit source) {
private AutoAttackTargetFinderEnum reset(final CSimulation game, final CUnit source,
final boolean disableMove) {
this.game = game;
this.source = source;
this.disableMove = disableMove;
this.foundAnyTarget = false;
return this;
}
@ -824,8 +849,13 @@ 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())) {
if (this.source.currentBehavior != null) {
this.source.currentBehavior.end(this.game);
}
this.source.currentBehavior = this.source.getAttackBehavior().reset(OrderIds.attack, attack,
unit);
unit, this.disableMove);
this.source.currentBehavior.begin(this.game);
this.foundAnyTarget = true;
return true;
}
}
@ -862,6 +892,10 @@ public class CUnit extends CWidget {
this.patrolBehavior = patrolBehavior;
}
public void setHoldPositionBehavior(final CBehaviorHoldPosition holdPositionBehavior) {
this.holdPositionBehavior = holdPositionBehavior;
}
public CBehaviorFollow getFollowBehavior() {
return this.followBehavior;
}
@ -870,9 +904,20 @@ public class CUnit extends CWidget {
return this.patrolBehavior;
}
public CBehaviorHoldPosition getHoldPositionBehavior() {
return this.holdPositionBehavior;
}
public CBehavior pollNextOrderBehavior(final CSimulation game) {
if (this.holdingPosition) {
// kind of a stupid hack, meant to align in feel with some behaviors that were
// observed on War3
return this.holdPositionBehavior;
}
final COrder order = this.orderQueue.poll();
return beginOrder(game, order);
final CBehavior nextOrderBehavior = beginOrder(game, order);
this.stateNotifier.waypointsChanged();
return nextOrderBehavior;
}
public boolean isMoving() {
@ -1087,7 +1132,7 @@ public class CUnit extends CWidget {
ability.checkCanTarget(this.game, this.trainedUnit, this.rallyOrderId, target, targetCheckReceiver);
if (targetCheckReceiver.isTargetable()) {
this.trainedUnit.order(this.game,
new COrderTargetPoint(ability.getHandleId(), this.rallyOrderId, target), false);
new COrderTargetPoint(ability.getHandleId(), this.rallyOrderId, target, false), false);
return null;
}
}
@ -1109,9 +1154,8 @@ public class CUnit extends CWidget {
.<CWidget>getInstance().reset();
ability.checkCanTarget(game, trainedUnit, rallyOrderId, target, targetCheckReceiver);
if (targetCheckReceiver.isTargetable()) {
trainedUnit.order(game,
new COrderTargetWidget(ability.getHandleId(), rallyOrderId, target.getHandleId()),
false);
trainedUnit.order(game, new COrderTargetWidget(ability.getHandleId(), rallyOrderId,
target.getHandleId(), false), false);
return null;
}
}
@ -1166,4 +1210,16 @@ public class CUnit extends CWidget {
}
}
}
public void setHoldingPosition(final boolean holdingPosition) {
this.holdingPosition = holdingPosition;
}
public Queue<COrder> getOrderQueue() {
return this.orderQueue;
}
public COrder getCurrentOrder() {
return this.currentOrder;
}
}

View File

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

View File

@ -111,7 +111,7 @@ public class CAbilityAttack extends AbstractCAbility {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
behavior = caster.getAttackBehavior().reset(OrderIds.attack, attack, target);
behavior = caster.getAttackBehavior().reset(OrderIds.attack, attack, target, false);
break;
}
}
@ -131,7 +131,7 @@ public class CAbilityAttack extends AbstractCAbility {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (attack.getWeaponType().isAttackGroundSupported()) {
behavior = caster.getAttackBehavior().reset(OrderIds.attackground, attack, point);
behavior = caster.getAttackBehavior().reset(OrderIds.attackground, attack, point, false);
break;
}
}

View File

@ -6,6 +6,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorFollow;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorHoldPosition;
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;
@ -77,6 +78,7 @@ public class CAbilityMove extends AbstractCAbility {
unit.setMoveBehavior(new CBehaviorMove(unit));
unit.setFollowBehavior(new CBehaviorFollow(unit));
unit.setPatrolBehavior(new CBehaviorPatrol(unit));
unit.setHoldPositionBehavior(new CBehaviorHoldPosition(unit));
}
@Override
@ -107,6 +109,9 @@ public class CAbilityMove extends AbstractCAbility {
@Override
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
if (orderId == OrderIds.holdposition) {
caster.setHoldingPosition(true);
}
return caster.pollNextOrderBehavior(game);
}

View File

@ -102,7 +102,7 @@ public class CAbilityColdArrows extends AbstractCAbility {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
behavior = caster.getAttackBehavior().reset(OrderIds.coldarrowstarg, attack, target);
behavior = caster.getAttackBehavior().reset(OrderIds.coldarrowstarg, attack, target, false);
break;
}
}

View File

@ -28,7 +28,8 @@ public final class AbilityTargetStillAliveAndTargetableVisitor implements Abilit
@Override
public Boolean accept(final CUnit target) {
return !target.isDead() && target.canBeTargetedBy(this.simulation, this.unit, this.targetsAllowed);
return !target.isDead() && !target.isHidden()
&& target.canBeTargetedBy(this.simulation, this.unit, this.targetsAllowed);
}
@Override

View File

@ -14,7 +14,7 @@ public class AbilityTargetStillAliveVisitor implements AbilityTargetVisitor<Bool
@Override
public Boolean accept(final CUnit target) {
return !target.isDead();
return !target.isDead() && !target.isHidden();
}
@Override

View File

@ -16,6 +16,7 @@ public abstract class CAbstractRangedBehavior implements CRangedBehavior {
protected AbilityTarget target;
private boolean wasWithinPropWindow = false;
private boolean wasInRange = false;
private boolean disableMove = false;
private CBehaviorMove moveBehavior;
protected final CAbstractRangedBehavior innerReset(final AbilityTarget target) {
@ -45,7 +46,7 @@ public abstract class CAbstractRangedBehavior implements CRangedBehavior {
return this.unit.pollNextOrderBehavior(simulation);
}
if (!isWithinRange(simulation)) {
if (this.moveBehavior == null) {
if ((this.moveBehavior == null) || this.disableMove) {
return this.unit.pollNextOrderBehavior(simulation);
}
this.wasInRange = false;
@ -103,4 +104,8 @@ public abstract class CAbstractRangedBehavior implements CRangedBehavior {
return update(simulation, this.wasWithinPropWindow);
}
public void setDisableMove(final boolean disableMove) {
this.disableMove = disableMove;
}
}

View File

@ -11,5 +11,9 @@ public interface CBehavior {
*/
CBehavior update(CSimulation game);
void begin(CSimulation game);
void end(CSimulation game);
int getHighlightOrderId();
}

View File

@ -24,13 +24,15 @@ public class CBehaviorAttack extends CAbstractRangedBehavior {
private int backSwingTime;
private int thisOrderCooldownEndTime;
public CBehaviorAttack reset(final int highlightOrderId, final CUnitAttack unitAttack, final AbilityTarget target) {
public CBehaviorAttack reset(final int highlightOrderId, final CUnitAttack unitAttack, final AbilityTarget target,
final boolean disableMove) {
this.highlightOrderId = highlightOrderId;
super.innerReset(target);
this.unitAttack = unitAttack;
this.damagePointLaunchTime = 0;
this.backSwingTime = 0;
this.thisOrderCooldownEndTime = 0;
setDisableMove(disableMove);
return this;
}
@ -115,4 +117,14 @@ public class CBehaviorAttack extends CAbstractRangedBehavior {
return this;
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -44,4 +44,14 @@ public class CBehaviorFollow extends CAbstractRangedBehavior {
protected void resetBeforeMoving(final CSimulation simulation) {
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -0,0 +1,42 @@
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;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
public class CBehaviorHoldPosition implements CBehavior {
private final CUnit unit;
public CBehaviorHoldPosition(final CUnit unit) {
this.unit = unit;
}
@Override
public int getHighlightOrderId() {
return OrderIds.holdposition;
}
@Override
public CBehavior update(final CSimulation game) {
if (this.unit.autoAcquireAttackTargets(game, true)) {
// kind of a hack
return this.unit.getCurrentBehavior();
}
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, true);
return this.unit.pollNextOrderBehavior(game);
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -400,4 +400,14 @@ public class CBehaviorMove implements CBehavior {
return null;
}
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -40,4 +40,14 @@ public class CBehaviorPatrol implements CRangedBehavior {
return this.unit.getMoveBehavior().reset(this.target, this, false);
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -21,9 +21,21 @@ public class CBehaviorStop implements CBehavior {
@Override
public CBehavior update(final CSimulation game) {
this.unit.autoAcquireAttackTargets(game);
if (this.unit.autoAcquireAttackTargets(game, false)) {
return this.unit.getCurrentBehavior();
}
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, true);
return this.unit.pollNextOrderBehavior(game);
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -93,4 +93,14 @@ public class CBehaviorOrcBuild extends CAbstractRangedBehavior {
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -157,4 +157,14 @@ public class CBehaviorHarvest extends CAbstractRangedBehavior implements Ability
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -121,6 +121,7 @@ public class CBehaviorReturnResources extends CAbstractRangedBehavior implements
double nearestDropoffDistance = Float.MAX_VALUE;
for (final CUnit unit : simulation.getUnits()) {
if (unit.getPlayerIndex() == this.unit.getPlayerIndex()) {
if (unit.visit(AbilityTargetStillAliveVisitor.INSTANCE)) {
boolean acceptedUnit = false;
for (final CAbility ability : unit.getAbilities()) {
if (ability instanceof CAbilityReturnResources) {
@ -142,6 +143,7 @@ public class CBehaviorReturnResources extends CAbstractRangedBehavior implements
}
}
}
}
return nearestDropoffPoint;
}
@ -169,4 +171,14 @@ public class CBehaviorReturnResources extends CAbstractRangedBehavior implements
return nearestMine;
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game) {
}
}

View File

@ -2,6 +2,7 @@ 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.targeting.AbilityTarget;
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;
@ -13,6 +14,10 @@ public interface COrder {
CBehavior begin(final CSimulation game, CUnit caster);
AbilityTarget getTarget(CSimulation game);
boolean isQueued();
final StringMsgTargetCheckReceiver<?> targetCheckReceiver = new StringMsgTargetCheckReceiver<>();
final StringMsgAbilityActivationReceiver abilityActivationReceiver = new StringMsgAbilityActivationReceiver();
}

View File

@ -3,15 +3,19 @@ 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.abilities.targeting.AbilityTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgTargetCheckReceiver;
public class COrderNoTarget implements COrder {
private final int abilityHandleId;
private final int orderId;
private final boolean queued;
public COrderNoTarget(final int abilityHandleId, final int orderId) {
public COrderNoTarget(final int abilityHandleId, final int orderId, final boolean queued) {
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
this.queued = queued;
}
@Override
@ -24,14 +28,35 @@ public class COrderNoTarget implements COrder {
return this.orderId;
}
@Override
public boolean isQueued() {
return this.queued;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster) {
final CAbility ability = game.getAbility(this.abilityHandleId);
if ((ability == null) && (this.orderId == OrderIds.stop)) {
// stop
return caster.getStopBehavior();
}
ability.checkCanUse(game, caster, this.orderId, this.abilityActivationReceiver.reset());
if (this.abilityActivationReceiver.isUseOk()) {
final StringMsgTargetCheckReceiver<Void> targetReceiver = (StringMsgTargetCheckReceiver<Void>) targetCheckReceiver;
ability.checkCanTargetNoTarget(game, caster, this.orderId, targetReceiver);
if (targetReceiver.getMessage() == null) {
return ability.beginNoTarget(game, caster, this.orderId);
}
else {
game.getCommandErrorListener().showCommandError(targetReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
else {
game.getCommandErrorListener().showCommandError(this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
@Override
public AbilityTarget getTarget(final CSimulation game) {
return null;
}
}

View File

@ -1,6 +1,5 @@
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;
@ -12,11 +11,14 @@ public class COrderTargetPoint implements COrder {
private final int abilityHandleId;
private final int orderId;
private final AbilityPointTarget target;
private final boolean queued;
public COrderTargetPoint(final int abilityHandleId, final int orderId, final AbilityPointTarget target) {
public COrderTargetPoint(final int abilityHandleId, final int orderId, final AbilityPointTarget target,
final boolean queued) {
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
this.target = target;
this.queued = queued;
}
@Override
@ -29,10 +31,16 @@ public class COrderTargetPoint implements COrder {
return this.orderId;
}
public Vector2 getTarget() {
@Override
public AbilityPointTarget getTarget(final CSimulation game) {
return this.target;
}
@Override
public boolean isQueued() {
return this.queued;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster) {
final CAbility ability = game.getAbility(this.abilityHandleId);

View File

@ -4,6 +4,7 @@ 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.abilities.targeting.AbilityTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.StringMsgTargetCheckReceiver;
@ -11,11 +12,14 @@ public class COrderTargetWidget implements COrder {
private final int abilityHandleId;
private final int orderId;
private final int targetHandleId;
private final boolean queued;
public COrderTargetWidget(final int abilityHandleId, final int orderId, final int targetHandleId) {
public COrderTargetWidget(final int abilityHandleId, final int orderId, final int targetHandleId,
final boolean queued) {
this.abilityHandleId = abilityHandleId;
this.orderId = orderId;
this.targetHandleId = targetHandleId;
this.queued = queued;
}
@Override
@ -28,6 +32,17 @@ public class COrderTargetWidget implements COrder {
return this.orderId;
}
@Override
public AbilityTarget getTarget(final CSimulation game) {
final CUnit target = game.getUnit(this.targetHandleId);
return target;
}
@Override
public boolean isQueued() {
return this.queued;
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster) {
final CAbility ability = game.getAbility(this.abilityHandleId);

View File

@ -6,6 +6,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting
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.simulation.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
public class CPlayerUnitOrderExecutor implements CPlayerUnitOrderListener {
@ -21,21 +22,33 @@ public class CPlayerUnitOrderExecutor implements CPlayerUnitOrderListener {
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);
unit.order(this.game, new COrderTargetWidget(abilityHandleId, orderId, targetHandleId), queue);
unit.order(this.game, new COrderTargetWidget(abilityHandleId, orderId, targetHandleId, queue), queue);
}
@Override
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);
unit.order(this.game, new COrderTargetPoint(abilityHandleId, orderId, new AbilityPointTarget(x, y)), queue);
unit.order(this.game, new COrderTargetPoint(abilityHandleId, orderId, new AbilityPointTarget(x, y), queue),
queue);
}
@Override
public void issueImmediateOrder(final int unitHandleId, final int abilityHandleId, final int orderId,
final boolean queue) {
final CUnit unit = this.game.getUnit(unitHandleId);
unit.order(this.game, new COrderNoTarget(abilityHandleId, orderId), queue);
if (abilityHandleId == 0) {
if (orderId == OrderIds.stop) {
unit.order(this.game, null, queue);
}
else if (orderId == OrderIds.holdposition) {
unit.order(this.game, null, queue);
unit.setHoldingPosition(true);
}
}
else {
unit.order(this.game, new COrderNoTarget(abilityHandleId, orderId, queue), queue);
}
}
@Override

View File

@ -4,8 +4,11 @@ import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
@ -113,6 +116,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CodeKeyType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttackMissileSplash;
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.pathing.CBuildingPathingType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
@ -241,6 +245,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
private final RallyPositioningVisitor rallyPositioningVisitor;
private final CPlayer localPlayer;
private MeleeUIAbilityActivationReceiver meleeUIAbilityActivationReceiver;
private MdxModel waypointModel;
private final List<MdxComplexInstance> waypointModelInstances = new ArrayList<>();
public MeleeUI(final DataSource dataSource, final ExtendViewport uiViewport,
final FreeTypeFontGenerator fontGenerator, final Scene uiScene, final Scene portraitScene,
@ -618,6 +624,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.rallyPointInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
SequenceUtils.randomStandSequence(this.rallyPointInstance);
this.rallyPointInstance.hide();
this.waypointModel = (MdxModel) this.war3MapViewer.load(
War3MapViewer.mdx(this.rootFrame.getSkinField("WaypointIndicator")), this.war3MapViewer.mapPathSolver,
this.war3MapViewer.solverParams);
this.rootFrame.positionBounds(this.rootFrame, this.uiViewport);
@ -1062,12 +1071,19 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
private final class RallyPositioningVisitor implements AbilityTargetVisitor<Void> {
private MdxComplexInstance rallyPointInstance = null;
public RallyPositioningVisitor reset(final MdxComplexInstance rallyPointInstance) {
this.rallyPointInstance = rallyPointInstance;
return this;
}
@Override
public Void accept(final AbilityPointTarget target) {
MeleeUI.this.rallyPointInstance.setParent(null);
this.rallyPointInstance.setParent(null);
final float rallyPointX = target.getX();
final float rallyPointY = target.getY();
MeleeUI.this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
MeleeUI.this.war3MapViewer.terrain.getGroundHeight(rallyPointX, rallyPointY));
return null;
}
@ -1094,14 +1110,14 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
if (index != -1) {
final MdxNode attachment = renderUnit.instance.getAttachment(index);
MeleeUI.this.rallyPointInstance.setParent(attachment);
MeleeUI.this.rallyPointInstance.setLocation(0, 0, 0);
this.rallyPointInstance.setParent(attachment);
this.rallyPointInstance.setLocation(0, 0, 0);
}
else {
MeleeUI.this.rallyPointInstance.setParent(null);
this.rallyPointInstance.setParent(null);
final float rallyPointX = target.getX();
final float rallyPointY = target.getY();
MeleeUI.this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
MeleeUI.this.war3MapViewer.terrain.getGroundHeight(rallyPointX, rallyPointY));
}
return null;
@ -1109,20 +1125,20 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
@Override
public Void accept(final CDestructable target) {
MeleeUI.this.rallyPointInstance.setParent(null);
this.rallyPointInstance.setParent(null);
final float rallyPointX = target.getX();
final float rallyPointY = target.getY();
MeleeUI.this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
MeleeUI.this.war3MapViewer.terrain.getGroundHeight(rallyPointX, rallyPointY));
return null;
}
@Override
public Void accept(final CItem target) {
MeleeUI.this.rallyPointInstance.setParent(null);
this.rallyPointInstance.setParent(null);
final float rallyPointX = target.getX();
final float rallyPointY = target.getY();
MeleeUI.this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
this.rallyPointInstance.setLocation(rallyPointX, rallyPointY,
MeleeUI.this.war3MapViewer.terrain.getGroundHeight(rallyPointX, rallyPointY));
return null;
}
@ -1233,6 +1249,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.selectWorkerInsideFrame.setVisible(false);
this.rallyPointInstance.hide();
this.rallyPointInstance.detach();
repositionWaypointFlags(null);
}
else {
unit.getSimulationUnit().addStateListener(this);
@ -1255,7 +1272,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.war3MapViewer.simulation.getPlayer(simulationUnit.getPlayerIndex()).getColorIndex());
this.rallyPointInstance.show();
this.rallyPointInstance.detach();
rallyPoint.visit(this.rallyPositioningVisitor);
rallyPoint.visit(this.rallyPositioningVisitor.reset(this.rallyPointInstance));
this.rallyPointInstance.setScene(this.war3MapViewer.worldScene);
}
else {
@ -1264,6 +1281,79 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
}
@Override
public void waypointsChanged() {
if (this.selectedUnit != null) {
final CUnit simulationUnit = this.selectedUnit.getSimulationUnit();
repositionWaypointFlags(simulationUnit);
}
else {
repositionWaypointFlags(null);
}
}
private void repositionWaypointFlags(final CUnit simulationUnit) {
final Iterator<COrder> iterator;
int orderIndex = 0;
if (simulationUnit != null) {
final Queue<COrder> orderQueue = simulationUnit.getOrderQueue();
iterator = orderQueue.iterator();
final COrder order = simulationUnit.getCurrentOrder();
if ((order != null) && order.isQueued()) {
final MdxComplexInstance waypointModelInstance = getOrCreateWaypointIndicator(orderIndex);
final AbilityTarget target = order.getTarget(this.war3MapViewer.simulation);
if (target != null) {
waypointModelInstance.show();
waypointModelInstance.detach();
target.visit(this.rallyPositioningVisitor.reset(waypointModelInstance));
waypointModelInstance.setScene(this.war3MapViewer.worldScene);
}
else {
waypointModelInstance.hide();
waypointModelInstance.detach();
}
orderIndex++;
}
}
else {
iterator = Collections.emptyIterator();
}
for (; (orderIndex < this.waypointModelInstances.size()) || (iterator.hasNext()); orderIndex++) {
final MdxComplexInstance waypointModelInstance = getOrCreateWaypointIndicator(orderIndex);
if (iterator.hasNext()) {
final COrder order = iterator.next();
final AbilityTarget target = order.getTarget(this.war3MapViewer.simulation);
if (target != null) {
waypointModelInstance.show();
waypointModelInstance.detach();
target.visit(this.rallyPositioningVisitor.reset(waypointModelInstance));
waypointModelInstance.setScene(this.war3MapViewer.worldScene);
}
else {
waypointModelInstance.hide();
waypointModelInstance.detach();
}
}
else {
waypointModelInstance.hide();
waypointModelInstance.detach();
}
}
}
private MdxComplexInstance getOrCreateWaypointIndicator(final int index) {
while (index >= this.waypointModelInstances.size()) {
final MdxComplexInstance waypointModelInstance = (MdxComplexInstance) this.waypointModel.addInstance();
waypointModelInstance.rotate(RenderUnit.tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z,
this.war3MapViewer.simulation.getGameplayConstants().getBuildingAngle()));
waypointModelInstance.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
SequenceUtils.randomStandSequence(waypointModelInstance);
waypointModelInstance.hide();
this.waypointModelInstances.add(waypointModelInstance);
}
return this.waypointModelInstances.get(index);
}
private void reloadSelectedUnitUI(final RenderUnit unit) {
final CUnit simulationUnit = unit.getSimulationUnit();
this.unitLifeText.setText(
@ -1277,6 +1367,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.unitManaText.setText("");
}
repositionRallyPoint(simulationUnit);
repositionWaypointFlags(simulationUnit);
if (simulationUnit.getBuildQueue()[0] != null) {
for (int i = 0; i < this.queueIconFrames.length; i++) {
final QueueItemType queueItemType = simulationUnit.getBuildQueueTypes()[i];
@ -1558,7 +1649,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
@Override
public void ordersChanged(final int abilityHandleId, final int orderId) {
public void ordersChanged() {
reloadSelectedUnitUI(this.selectedUnit);
}