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

@ -66,6 +66,8 @@ public class MdxComplexInstance extends ModelInstance {
public DataTexture boneTexture;
public Texture[] replaceableTextures = new Texture[WarsmashConstants.REPLACEABLE_TEXTURE_LIMIT];
private float animationSpeed = 1.0f;
private float blendTime;
private float blendTimeRemaining;
public MdxComplexInstance(final MdxModel model) {
super(model);
@ -160,11 +162,14 @@ public class MdxComplexInstance extends ModelInstance {
if ("SPN".equals(type)) {
emitter = new EventObjectSpnEmitter(this, emitterObject);
} else if ("SPL".equals(type)) {
}
else if ("SPL".equals(type)) {
emitter = new EventObjectSplEmitter(this, emitterObject);
} else if ("UBR".equals(type)) {
}
else if ("UBR".equals(type)) {
emitter = new EventObjectUbrEmitter(this, emitterObject);
} else {
}
else {
emitter = new EventObjectSndEmitter(this, emitterObject);
}
@ -231,18 +236,22 @@ public class MdxComplexInstance extends ModelInstance {
if (genericObject.parentId == -1) {
node.parent = this;
} else {
}
else {
node.parent = nodes[genericObject.parentId];
}
/// TODO: single-axis billboarding
if (genericObject.billboarded != 0) {
node.billboarded = true;
} else if (genericObject.billboardedX != 0) {
}
else if (genericObject.billboardedX != 0) {
node.billboardedX = true;
} else if (genericObject.billboardedY != 0) {
}
else if (genericObject.billboardedY != 0) {
node.billboardedY = true;
} else if (genericObject.billboardedZ != 0) {
}
else if (genericObject.billboardedZ != 0) {
node.billboardedZ = true;
}
@ -345,7 +354,7 @@ public class MdxComplexInstance extends ModelInstance {
// If this is a forced update, or this node's local data was updated, or the
// parent node was updated, do a full world update.
if (wasReallyDirty) {
node.recalculateTransformation(scene);
node.recalculateTransformation(scene, this.blendTimeRemaining / this.blendTime);
}
// If there is an instance object associated with this node, and the node is
@ -405,7 +414,8 @@ public class MdxComplexInstance extends ModelInstance {
geosetColor[3] = alphaHeap[0];
}
} else if (forced) {
}
else if (forced) {
geosetColor[0] = 1;
geosetColor[1] = 1;
geosetColor[2] = 1;
@ -456,7 +466,8 @@ public class MdxComplexInstance extends ModelInstance {
uvAnim[4] = scaleHeap[0];
}
} else if (forced) {
}
else if (forced) {
uvAnim[0] = 0;
uvAnim[1] = 0;
uvAnim[2] = 0;
@ -525,6 +536,7 @@ public class MdxComplexInstance extends ModelInstance {
final int lastIntegerFrame = this.frame;
this.floatingFrame += frameTime;
this.blendTimeRemaining -= frameTime;
this.frame = (int) this.floatingFrame;
final int integerFrameTime = this.frame - lastIntegerFrame;
this.counter += integerFrameTime;
@ -536,7 +548,8 @@ public class MdxComplexInstance extends ModelInstance {
this.floatingFrame = this.frame = (int) interval[0]; // TODO not cast
this.resetEventEmitters();
} else if (this.sequenceLoopMode == SequenceLoopMode.LOOP_TO_NEXT_ANIMATION) { // faux queued animation
}
else if (this.sequenceLoopMode == SequenceLoopMode.LOOP_TO_NEXT_ANIMATION) { // faux queued animation
// mode
final float framesPast = this.floatingFrame - interval[1];
@ -547,7 +560,8 @@ public class MdxComplexInstance extends ModelInstance {
this.sequenceEnded = false;
this.resetEventEmitters();
this.forced = true;
} else {
}
else {
this.floatingFrame = this.frame = (int) interval[1]; // TODO not cast
this.counter -= integerFrameTime;
this.allowParticleSpawn = false;
@ -557,7 +571,8 @@ public class MdxComplexInstance extends ModelInstance {
}
this.sequenceEnded = true;
} else {
}
else {
this.sequenceEnded = false;
}
}
@ -574,7 +589,8 @@ public class MdxComplexInstance extends ModelInstance {
// Update the batches
this.updateBatches(forced);
}
} else {
}
else {
// let variants = model.variants;
// if (forced || variants.nodes[sequenceId]) {
@ -642,6 +658,7 @@ public class MdxComplexInstance extends ModelInstance {
public MdxComplexInstance setSequence(final int id) {
final MdxModel model = (MdxModel) this.model;
final int lastSequence = this.sequence;
this.sequence = id;
if (model.ok) {
@ -652,7 +669,16 @@ public class MdxComplexInstance extends ModelInstance {
this.frame = 0;
this.floatingFrame = 0;
this.allowParticleSpawn = false;
} else {
}
else {
if ((this.blendTime > 0) && (lastSequence != this.sequence)) {
this.blendTimeRemaining = this.blendTime;
for (int i = 0, l = this.sortedNodes.length; i < l; i++) {
final SkeletalNode node = this.sortedNodes[i];
node.beginBlending();
}
}
this.frame = (int) sequences.get(id).getInterval()[0]; // TODO not cast
this.floatingFrame = this.frame;
this.sequenceEnded = false;
@ -720,7 +746,8 @@ public class MdxComplexInstance extends ModelInstance {
*
* @param ray
*/
public boolean intersectRayWithCollision(final Ray ray, final Vector3 intersection, final boolean alwaysUseMesh, final boolean onlyUseMesh) {
public boolean intersectRayWithCollision(final Ray ray, final Vector3 intersection, final boolean alwaysUseMesh,
final boolean onlyUseMesh) {
final MdxModel mdxModel = (MdxModel) this.model;
final List<CollisionShape> collisionShapes = mdxModel.collisionShapes;
if (!onlyUseMesh) {
@ -752,6 +779,10 @@ public class MdxComplexInstance extends ModelInstance {
this.animationSpeed = speedRatio;
}
public void setBlendTime(final float blendTime) {
this.blendTime = blendTime;
}
public void setFrame(final int frame) {
this.frame = frame;
this.floatingFrame = frame;

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,20 +199,17 @@ 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
autoAcquireAttackTargets(game);
}
return false;
}
public void autoAcquireAttackTargets(final CSimulation game) {
if (!this.unitType.getAttacks().isEmpty()) {
if (this.collisionRectangle != null) {
tempRect.set(this.collisionRectangle);
@ -214,8 +225,6 @@ public class CUnit extends CWidget {
game.getWorldCollision().enumUnitsInRect(tempRect, autoAttackTargetFinderEnum.reset(game, this));
}
}
return false;
}
public float getEndingDecayTime(final CSimulation game) {
if (this.unitType.isBuilding()) {
@ -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

@ -118,11 +118,15 @@ public class CUnitData {
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 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 CUnitData(final MutableObjectData unitData) {
public CUnitData(final MutableObjectData unitData, final CAbilityData abilityData) {
this.unitData = unitData;
this.abilityData = abilityData;
}
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
@ -135,6 +139,7 @@ public class CUnitData {
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 CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
@ -146,6 +151,9 @@ public class CUnitData {
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;
}
@ -184,7 +192,8 @@ public class CUnitData {
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 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
@ -202,8 +211,8 @@ public class CUnitData {
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 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);
@ -215,11 +224,13 @@ public class CUnitData {
.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) {
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());
}
}
@ -230,7 +241,8 @@ public class CUnitData {
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 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
@ -248,8 +260,8 @@ public class CUnitData {
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 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);
@ -261,11 +273,13 @@ public class CUnitData {
.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) {
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());
}
}

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,10 +800,10 @@ 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)) {
rayPickUnit.getSimulationUnit().getHandleId(), shiftDown);
if (getSelectedUnit().soundset.yesAttack
.playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) {
portraitTalk();
@ -813,7 +815,6 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.activeCommandOrderId = -1;
}
}
}
else {
this.war3MapViewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY);
clickLocationTemp2.set(clickLocationTemp.x, clickLocationTemp.y);
@ -829,12 +830,12 @@ 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())) {
clickLocationTemp2.y, shiftDown);
if (getSelectedUnit().soundset.yes
.playUnitResponse(this.war3MapViewer.worldScene.audioContext, getSelectedUnit())) {
portraitTalk();
}
this.selectedSoundCount = 0;
@ -843,7 +844,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
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);
}