diff --git a/core/assets/warsmash.ini b/core/assets/warsmash.ini index d6740ea..5405aca 100644 --- a/core/assets/warsmash.ini +++ b/core/assets/warsmash.ini @@ -18,7 +18,7 @@ Path06="." [Map] //FilePath="CombatUnitTests.w3x" //FilePath="PitchRoll.w3x" -FilePath="PeonStartingBase.w3x" +//FilePath="PeonStartingBase.w3x" //FilePath="ColdArrows.w3m" //FilePath="DungeonGoldMine.w3m" //FilePath="PlayerPeasants.w3m" @@ -35,3 +35,6 @@ FilePath="PeonStartingBase.w3x" //FilePath="Pathing.w3x" //FilePath="ItemFacing.w3x" //FilePath=SomeParticleTests.w3x +FilePath="PeonMiningMultiHall.w3x" +//FilePath="QuadtreeBugs.w3x" +//FilePath="test2.w3x" diff --git a/core/src/com/etheller/warsmash/util/Quadtree.java b/core/src/com/etheller/warsmash/util/Quadtree.java index 9489fd8..cfaed78 100644 --- a/core/src/com/etheller/warsmash/util/Quadtree.java +++ b/core/src/com/etheller/warsmash/util/Quadtree.java @@ -6,7 +6,7 @@ import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Array; public class Quadtree { - private static final int MAX_DEPTH = 64; + private static final int MAX_DEPTH = 9; private static final int SPLIT_THRESHOLD = 6; private final Rectangle bounds; @@ -75,7 +75,7 @@ public class Quadtree { } } - public boolean intersect(float x, float y, final QuadtreeIntersector intersector) { + public boolean intersect(final float x, final float y, final QuadtreeIntersector intersector) { if (this.leaf) { for (int i = 0; i < this.nodes.size; i++) { final Node node = this.nodes.get(i); @@ -123,17 +123,25 @@ public class Quadtree { return; } } + boolean overlapsAny = false; if (this.northeast.bounds.overlaps(node.bounds)) { this.northeast.add(node, depth + 1); + overlapsAny = true; } if (this.northwest.bounds.overlaps(node.bounds)) { this.northwest.add(node, depth + 1); + overlapsAny = true; } if (this.southwest.bounds.overlaps(node.bounds)) { this.southwest.add(node, depth + 1); + overlapsAny = true; } if (this.southeast.bounds.overlaps(node.bounds)) { this.southeast.add(node, depth + 1); + overlapsAny = true; + } + if (!overlapsAny) { + throw new IllegalStateException("Does not overlap anything!"); } } diff --git a/core/src/com/etheller/warsmash/util/Test.java b/core/src/com/etheller/warsmash/util/Test.java index 8c0a983..9d88d96 100644 --- a/core/src/com/etheller/warsmash/util/Test.java +++ b/core/src/com/etheller/warsmash/util/Test.java @@ -15,6 +15,8 @@ public class Test { else { System.out.println("no match"); } + +// Quadtree myQT = new Quadtree<>(new Rectangle(-, y, width, height)) } } diff --git a/core/src/com/etheller/warsmash/util/WarsmashConstants.java b/core/src/com/etheller/warsmash/util/WarsmashConstants.java index c7cd7a4..d1876cc 100644 --- a/core/src/com/etheller/warsmash/util/WarsmashConstants.java +++ b/core/src/com/etheller/warsmash/util/WarsmashConstants.java @@ -7,4 +7,11 @@ public class WarsmashConstants { public static final int PORT_NUMBER = 6115; public static final float BUILDING_CONSTRUCT_START_LIFE = 0.1f; public static final int BUILD_QUEUE_SIZE = 7; + // It looks like in Patch 1.22, "Particle" in video settings will change this + // factor: + // Low - unknown ? + // Medium - 1.0f + // High - 1.5f + public static final float MODEL_DETAIL_PARTICLE_FACTOR = 1.5f; + public static final float MODEL_DETAIL_PARTICLE_FACTOR_INVERSE = 1f / MODEL_DETAIL_PARTICLE_FACTOR; } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/Particle.java b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/Particle.java index ff01c77..f146e7c 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/Particle.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/Particle.java @@ -57,9 +57,9 @@ public class Particle extends EmittedObject // Local rotation rotationHeap.idt(); - rotationHeap.mulLeft(rotationHeap2.setFromAxisRad(0, 0, 1, + rotationHeap.mul(rotationHeap2.setFromAxisRad(0, 0, 1, RenderMathUtils.randomInRange((float) -Math.PI, (float) Math.PI))); - rotationHeap.mulLeft(rotationHeap2.setFromAxisRad(0, 1, 0, + rotationHeap.mul(rotationHeap2.setFromAxisRad(0, 1, 0, RenderMathUtils.randomInRange(-latitudeHeap[0], latitudeHeap[0]))); velocity.set(RenderMathUtils.VEC3_UNIT_Z); rotationHeap.transform(velocity); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/ParticleEmitter2.java b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/ParticleEmitter2.java index 0394053..77b2a30 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/ParticleEmitter2.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/ParticleEmitter2.java @@ -1,5 +1,7 @@ package com.etheller.warsmash.viewer5.handlers.mdx; +import com.etheller.warsmash.util.WarsmashConstants; + public class ParticleEmitter2 extends MdxEmitter { private static final float[] emissionRateHeap = new float[1]; @@ -30,7 +32,7 @@ public class ParticleEmitter2 extends MdxEmitter movetpToMovementType = new HashMap<>(); static { for (final MovementType movementType : MovementType.values()) { - if (movementType != MovementType.DISABLED) { + if (!movementType.typeKey.isEmpty()) { movetpToMovementType.put(movementType.typeKey, movementType); } } @@ -360,6 +360,12 @@ public class PathingGrid { return !PathingFlags.isPathingFlag(pathingValue, PathingFlags.UNWALKABLE); } }, + FOOT_NO_COLLISION("") { + @Override + public boolean isPathable(final short pathingValue) { + return !PathingFlags.isPathingFlag(pathingValue, PathingFlags.UNWALKABLE); + } + }, HORSE("horse") { @Override public boolean isPathable(final short pathingValue) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java index 4827968..3d732b8 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java @@ -571,6 +571,12 @@ public class CUnit extends CWidget { return groundDistance; } + public double distanceSquaredNoCollision(final AbilityTarget target) { + final double dx = Math.abs(target.getX() - getX()); + final double dy = Math.abs(target.getY() - getY()); + return (dx * dx) + (dy * dy); + } + public double distance(final float x, final float y) { double dx = Math.abs(x - getX()); double dy = Math.abs(y - getY()); @@ -687,7 +693,7 @@ public class CUnit extends CWidget { : buildingPathingPixelMap.getHeight(); final int relativeGridX = (int) Math.floor(relativeOffsetX / 32f) + (gridWidth / 2); final int relativeGridY = (int) Math.floor(relativeOffsetY / 32f) + (gridHeight / 2); - final int rangeInCells = (int) Math.floor(range / 32f); + final int rangeInCells = (int) Math.floor(range / 32f) + 1; final int rangeInCellsSquare = rangeInCells * rangeInCells; int minCheckX = relativeGridX - rangeInCells; int minCheckY = relativeGridY - rangeInCells; diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CWorldCollision.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CWorldCollision.java index b488988..fdcffd5 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CWorldCollision.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CWorldCollision.java @@ -9,6 +9,7 @@ import com.etheller.warsmash.util.QuadtreeIntersector; import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType; public class CWorldCollision { + private static final float MINIMUM_COLLISION_SIZE = 0.001f /* THIS IS TO STOP QUADTREE FROM BUSTING */; private final Quadtree groundUnitCollision; private final Quadtree airUnitCollision; private final Quadtree seaUnitCollision; @@ -30,7 +31,8 @@ public class CWorldCollision { public void addUnit(final CUnit unit) { Rectangle bounds = unit.getCollisionRectangle(); if (bounds == null) { - final float collisionSize = Math.min(this.maxCollisionRadius, unit.getUnitType().getCollisionSize()); + final float collisionSize = Math.max(MINIMUM_COLLISION_SIZE, + Math.min(this.maxCollisionRadius, unit.getUnitType().getCollisionSize())); bounds = new Rectangle(unit.getX() - collisionSize, unit.getY() - collisionSize, collisionSize * 2, collisionSize * 2); unit.setCollisionRectangle(bounds); @@ -54,9 +56,11 @@ public class CWorldCollision { case FLY: this.airUnitCollision.add(unit, bounds); break; - default: case DISABLED: + break; + default: case FOOT: + case FOOT_NO_COLLISION: case HORSE: case HOVER: this.groundUnitCollision.add(unit, bounds); @@ -86,9 +90,11 @@ public class CWorldCollision { case FLY: this.airUnitCollision.remove(unit, bounds); break; - default: case DISABLED: + break; + default: case FOOT: + case FOOT_NO_COLLISION: case HORSE: case HOVER: this.groundUnitCollision.remove(unit, bounds); @@ -133,8 +139,10 @@ public class CWorldCollision { case FLY: return this.airUnitCollision.intersect(newPossibleRectangle, this.anyUnitExceptTwoIntersector.reset(sourceUnitToIgnore, sourceSecondUnitToIgnore)); - default: case DISABLED: + case FOOT_NO_COLLISION: + return false; + default: case FOOT: case HORSE: case HOVER: @@ -167,9 +175,11 @@ public class CWorldCollision { case FLY: this.airUnitCollision.translate(unit, bounds, xShift, yShift); break; - default: case DISABLED: + break; + default: case FOOT: + case FOOT_NO_COLLISION: case HORSE: case HOVER: this.groundUnitCollision.translate(unit, bounds, xShift, yShift); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/generic/AbstractGenericSingleIconActiveAbility.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/generic/AbstractGenericSingleIconActiveAbility.java index 579970e..155f253 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/generic/AbstractGenericSingleIconActiveAbility.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/generic/AbstractGenericSingleIconActiveAbility.java @@ -7,6 +7,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.AbstractCAbility; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver; public abstract class AbstractGenericSingleIconActiveAbility extends AbstractCAbility @@ -29,6 +30,9 @@ public abstract class AbstractGenericSingleIconActiveAbility extends AbstractCAb if (orderId == getBaseOrderId()) { innerCheckCanTarget(game, unit, orderId, target, receiver); } + else if (orderId == OrderIds.smart) { + innerCheckCanSmartTarget(game, unit, orderId, target, receiver); + } else { receiver.orderIdNotAccepted(); } @@ -37,12 +41,18 @@ public abstract class AbstractGenericSingleIconActiveAbility extends AbstractCAb protected abstract void innerCheckCanTarget(CSimulation game, CUnit unit, int orderId, CWidget target, AbilityTargetCheckReceiver receiver); + protected abstract void innerCheckCanSmartTarget(CSimulation game, CUnit unit, int orderId, CWidget target, + AbilityTargetCheckReceiver receiver); + @Override public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId, final AbilityPointTarget target, final AbilityTargetCheckReceiver receiver) { if (orderId == getBaseOrderId()) { innerCheckCanTarget(game, unit, orderId, target, receiver); } + else if (orderId == OrderIds.smart) { + innerCheckCanSmartTarget(game, unit, orderId, target, receiver); + } else { receiver.orderIdNotAccepted(); } @@ -51,6 +61,9 @@ public abstract class AbstractGenericSingleIconActiveAbility extends AbstractCAb protected abstract void innerCheckCanTarget(CSimulation game, CUnit unit, int orderId, AbilityPointTarget target, AbilityTargetCheckReceiver receiver); + protected abstract void innerCheckCanSmartTarget(CSimulation game, CUnit unit, int orderId, + AbilityPointTarget target, AbilityTargetCheckReceiver receiver); + @Override public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId, final AbilityTargetCheckReceiver receiver) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/generic/AbstractGenericSingleIconNoSmartActiveAbility.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/generic/AbstractGenericSingleIconNoSmartActiveAbility.java new file mode 100644 index 0000000..aa26147 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/generic/AbstractGenericSingleIconNoSmartActiveAbility.java @@ -0,0 +1,28 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.generic; + +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.abilities.targeting.AbilityPointTarget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityTargetCheckReceiver; + +public abstract class AbstractGenericSingleIconNoSmartActiveAbility extends AbstractGenericSingleIconActiveAbility { + + public AbstractGenericSingleIconNoSmartActiveAbility(final int handleId, final War3ID alias) { + super(handleId, alias); + } + + @Override + protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId, + final AbilityPointTarget target, final AbilityTargetCheckReceiver receiver) { + receiver.orderIdNotAccepted(); + } + + @Override + protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId, + final CWidget target, final AbilityTargetCheckReceiver receiver) { + receiver.orderIdNotAccepted(); + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/harvest/CAbilityHarvest.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/harvest/CAbilityHarvest.java index 64c0f26..849c83d 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/harvest/CAbilityHarvest.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/harvest/CAbilityHarvest.java @@ -10,6 +10,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.mine.CAbi import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.harvest.CBehaviorHarvest; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.harvest.CBehaviorReturnResources; 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; @@ -20,6 +21,7 @@ public class CAbilityHarvest extends AbstractGenericSingleIconActiveAbility { private final int goldCapacity; private final int lumberCapacity; private CBehaviorHarvest behaviorHarvest; + private CBehaviorReturnResources behaviorReturnResources; private int carriedResourceAmount; private ResourceType carriedResourceType; @@ -34,6 +36,7 @@ public class CAbilityHarvest extends AbstractGenericSingleIconActiveAbility { @Override public void onAdd(final CSimulation game, final CUnit unit) { this.behaviorHarvest = new CBehaviorHarvest(unit, this); + this.behaviorReturnResources = new CBehaviorReturnResources(unit, this); } @Override @@ -97,12 +100,24 @@ public class CAbilityHarvest extends AbstractGenericSingleIconActiveAbility { } } + @Override + protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId, + final CWidget target, final AbilityTargetCheckReceiver receiver) { + innerCheckCanTarget(game, unit, orderId, target, receiver); + } + @Override protected void innerCheckCanTarget(final CSimulation game, final CUnit unit, final int orderId, final AbilityPointTarget target, final AbilityTargetCheckReceiver receiver) { receiver.orderIdNotAccepted(); } + @Override + protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId, + final AbilityPointTarget target, final AbilityTargetCheckReceiver receiver) { + receiver.orderIdNotAccepted(); + } + @Override protected void innerCheckCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId, final AbilityTargetCheckReceiver receiver) { @@ -134,4 +149,12 @@ public class CAbilityHarvest extends AbstractGenericSingleIconActiveAbility { this.carriedResourceAmount = carriedResourceAmount; } + public CBehaviorHarvest getBehaviorHarvest() { + return this.behaviorHarvest; + } + + public CBehaviorReturnResources getBehaviorReturnResources() { + return this.behaviorReturnResources; + } + } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java index 83b7141..8ebc15c 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CAbstractRangedBehavior.java @@ -6,9 +6,11 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting public abstract class CAbstractRangedBehavior implements CRangedBehavior { protected final CUnit unit; + private final boolean disableCollision; - public CAbstractRangedBehavior(final CUnit unit) { + public CAbstractRangedBehavior(final CUnit unit, final boolean disableCollision) { this.unit = unit; + this.disableCollision = disableCollision; } protected AbilityTarget target; @@ -22,7 +24,7 @@ public abstract class CAbstractRangedBehavior implements CRangedBehavior { this.wasInRange = false; CBehaviorMove moveBehavior; if (!this.unit.isMovementDisabled()) { - moveBehavior = this.unit.getMoveBehavior().reset(this.target, this); + moveBehavior = this.unit.getMoveBehavior().reset(this.target, this, this.disableCollision); } else { moveBehavior = null; diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java index 78c28d0..650a2ae 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorAttack.java @@ -15,7 +15,7 @@ public class CBehaviorAttack extends CAbstractRangedBehavior { private final AbilityTargetStillAliveAndTargetableVisitor abilityTargetStillAliveVisitor; public CBehaviorAttack(final CUnit unit) { - super(unit); + super(unit, false); this.abilityTargetStillAliveVisitor = new AbilityTargetStillAliveAndTargetableVisitor(); } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java index 612f4a0..36733b5 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorFollow.java @@ -11,7 +11,7 @@ public class CBehaviorFollow extends CAbstractRangedBehavior { private int higlightOrderId; public CBehaviorFollow(final CUnit unit) { - super(unit); + super(unit, false); } public CBehavior reset(final int higlightOrderId, final CUnit target) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java index 6e0c415..3b6f827 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorMove.java @@ -40,17 +40,21 @@ public class CBehaviorMove implements CBehavior { private CUnit followUnit; private CRangedBehavior rangedBehavior; private boolean firstUpdate = true; + private boolean disableCollision = false; public CBehaviorMove reset(final int highlightOrderId, final AbilityTarget target) { target.visit(this.targetVisitingResetter.reset(highlightOrderId)); this.rangedBehavior = null; + this.disableCollision = false; return this; } - public CBehaviorMove reset(final AbilityTarget target, final CRangedBehavior rangedBehavior) { + public CBehaviorMove reset(final AbilityTarget target, final CRangedBehavior rangedBehavior, + final boolean disableCollision) { final int highlightOrderId = rangedBehavior.getHighlightOrderId(); target.visit(this.targetVisitingResetter.reset(highlightOrderId)); this.rangedBehavior = rangedBehavior; + this.disableCollision = disableCollision; return this; } @@ -99,7 +103,13 @@ public class CBehaviorMove implements CBehavior { final float prevX = this.unit.getX(); final float prevY = this.unit.getY(); - final MovementType movementType = this.unit.getUnitType().getMovementType(); + MovementType movementType = this.unit.getUnitType().getMovementType(); + if (movementType == null) { + movementType = MovementType.DISABLED; + } + else if ((movementType == MovementType.FOOT) && this.disableCollision) { + movementType = MovementType.FOOT_NO_COLLISION; + } final PathingGrid pathingGrid = simulation.getPathingGrid(); final CWorldCollision worldCollision = simulation.getWorldCollision(); final float collisionSize = this.unit.getUnitType().getCollisionSize(); @@ -111,7 +121,7 @@ public class CBehaviorMove implements CBehavior { this.target.y = this.followUnit.getY(); } this.path = simulation.findNaiveSlowPath(this.unit, this.followUnit, startFloatingX, startFloatingY, - this.target, movementType == null ? MovementType.FOOT : movementType, collisionSize, true); + this.target, movementType, collisionSize, true); System.out.println("init path " + this.path); // check for smoothing if (!this.path.isEmpty()) { @@ -130,8 +140,7 @@ public class CBehaviorMove implements CBehavior { if ((totalPathDistance < (1.15 * nextPossiblePathElement.distance(smoothingGroupStartX, smoothingGroupStartY))) && pathingGrid.isPathable((smoothingGroupStartX + nextPossiblePathElement.x) / 2, - (smoothingGroupStartY + nextPossiblePathElement.y) / 2, - movementType == null ? MovementType.DISABLED : movementType)) { + (smoothingGroupStartY + nextPossiblePathElement.y) / 2, movementType)) { if (smoothingStartIndex == -1) { smoothingStartIndex = i; } @@ -164,8 +173,7 @@ public class CBehaviorMove implements CBehavior { this.target.x = this.followUnit.getX(); this.target.y = this.followUnit.getY(); this.path = simulation.findNaiveSlowPath(this.unit, this.followUnit, startFloatingX, startFloatingY, - this.target, movementType == null ? MovementType.FOOT : movementType, collisionSize, - this.searchCycles < 4); + this.target, movementType, collisionSize, this.searchCycles < 4); System.out.println("new path (for target) " + this.path); if (this.path.isEmpty()) { return this.unit.pollNextOrderBehavior(simulation); @@ -334,8 +342,7 @@ public class CBehaviorMove implements CBehavior { this.target.y = this.followUnit.getY(); } this.path = simulation.findNaiveSlowPath(this.unit, this.followUnit, startFloatingX, startFloatingY, - this.target, movementType == null ? MovementType.FOOT : movementType, collisionSize, - this.searchCycles < 4); + this.target, movementType, collisionSize, this.searchCycles < 4); this.searchCycles++; System.out.println("new path " + this.path); if (this.path.isEmpty() || (this.searchCycles > 5)) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorPatrol.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorPatrol.java index 95b5d53..09f0c42 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorPatrol.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/CBehaviorPatrol.java @@ -37,7 +37,7 @@ public class CBehaviorPatrol implements CRangedBehavior { final AbilityPointTarget temp = this.target; this.target = this.startPoint; this.startPoint = temp; - return this.unit.getMoveBehavior().reset(this.target, this); + return this.unit.getMoveBehavior().reset(this.target, this, false); } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java index 37a5726..ae47a1e 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java @@ -21,7 +21,7 @@ public class CBehaviorOrcBuild extends CAbstractRangedBehavior { private War3ID orderId; public CBehaviorOrcBuild(final CUnit unit) { - super(unit); + super(unit, false); } public CBehavior reset(final AbilityPointTarget target, final int orderId, final int highlightOrderId) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/harvest/CBehaviorHarvest.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/harvest/CBehaviorHarvest.java index 7a08a0e..ba9b284 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/harvest/CBehaviorHarvest.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/harvest/CBehaviorHarvest.java @@ -1,7 +1,9 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.harvest; import com.etheller.warsmash.util.WarsmashConstants; +import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag; import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag; +import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CItem; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; @@ -9,7 +11,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityHarvest; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityReturnResources; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.mine.CAbilityGoldMine; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetStillAliveVisitor; @@ -17,7 +18,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedBehavior; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType; public class CBehaviorHarvest extends CAbstractRangedBehavior implements AbilityTargetVisitor { @@ -27,7 +27,7 @@ public class CBehaviorHarvest extends CAbstractRangedBehavior implements Ability private CAbilityGoldMine abilityGoldMine; public CBehaviorHarvest(final CUnit unit, final CAbilityHarvest abilityHarvest) { - super(unit); + super(unit, true); this.abilityHarvest = abilityHarvest; } @@ -44,8 +44,7 @@ public class CBehaviorHarvest extends CAbstractRangedBehavior implements Ability @Override public boolean isWithinRange(final CSimulation simulation) { - // TODO this is probably not what the CloseEnoughRange constant is for - return this.unit.canReach(this.target, simulation.getGameplayConstants().getCloseEnoughRange()); + return this.unit.canReach(this.target, this.unit.getUnitType().getCollisionSize()); } @Override @@ -75,40 +74,31 @@ public class CBehaviorHarvest extends CAbstractRangedBehavior implements Ability final int activeMiners = abilityGoldMine.getActiveMiners(); if (activeMiners < abilityGoldMine.getMiningCapacity()) { abilityGoldMine.setActiveMiners(activeMiners + 1); + if (activeMiners == 0) { + target.getUnitAnimationListener().addSecondaryTag(SecondaryTag.WORK); + } this.unit.setHidden(true); this.unit.setInvulnerable(true); this.popoutFromMineTurnTick = this.simulation.getGameTurnTick() + (int) (abilityGoldMine.getMiningDuration() / WarsmashConstants.SIMULATION_STEP_TIME); this.abilityGoldMine = abilityGoldMine; - break; } + else { + // we are stuck waiting to mine, let's make sure we play stand animation + this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, + SequenceUtils.EMPTY, 1.0f, true); + } + return this; } } + // weird invalid target and we have no resources, consider harvesting done + return this.unit.pollNextOrderBehavior(this.simulation); } else { - for (final CAbility ability : target.getAbilities()) { - if (ability instanceof CAbilityReturnResources) { - final CAbilityReturnResources abilityReturnResources = (CAbilityReturnResources) ability; - if (abilityReturnResources.accepts(this.abilityHarvest.getCarriedResourceType())) { - final CPlayer player = this.simulation.getPlayer(this.unit.getPlayerIndex()); - switch (this.abilityHarvest.getCarriedResourceType()) { - case FOOD: - throw new IllegalStateException("Unit used Harvest skill to carry FOOD resource!"); - case GOLD: - player.setGold(player.getGold() + this.abilityHarvest.getCarriedResourceAmount()); - this.unit.getUnitAnimationListener().removeSecondaryTag(SecondaryTag.GOLD); - break; - case LUMBER: - player.setLumber(player.getLumber() + this.abilityHarvest.getCarriedResourceAmount()); - this.unit.getUnitAnimationListener().removeSecondaryTag(SecondaryTag.LUMBER); - break; - } - this.abilityHarvest.setCarriedResources(null, 0); - return this.unit.pollNextOrderBehavior(this.simulation); - } - } - } + // we have some GOLD and we're not in a mine (?) lets do a return resources + // order + return this.abilityHarvest.getBehaviorReturnResources().reset(this.simulation); } } else { @@ -116,7 +106,11 @@ public class CBehaviorHarvest extends CAbstractRangedBehavior implements Ability this.popoutFromMineTurnTick = 0; this.unit.setHidden(false); this.unit.setInvulnerable(false); - this.abilityGoldMine.setActiveMiners(this.abilityGoldMine.getActiveMiners() - 1); + final int activeMiners = this.abilityGoldMine.getActiveMiners() - 1; + this.abilityGoldMine.setActiveMiners(activeMiners); + if (activeMiners == 0) { + target.getUnitAnimationListener().removeSecondaryTag(SecondaryTag.WORK); + } int mineGoldRemaining = this.abilityGoldMine.getGold(); final int goldMined = Math.min(mineGoldRemaining, this.abilityHarvest.getGoldCapacity()); this.abilityHarvest.setCarriedResources(ResourceType.GOLD, goldMined); @@ -127,16 +121,25 @@ public class CBehaviorHarvest extends CAbstractRangedBehavior implements Ability } this.unit.getUnitAnimationListener().addSecondaryTag(SecondaryTag.GOLD); this.simulation.unitRepositioned(this.unit); - return this.unit.pollNextOrderBehavior(this.simulation); + // we just finished getting gold, lets do a return resources order + return this.abilityHarvest.getBehaviorReturnResources().reset(this.simulation); + } + else { + // continue working inside mine + return this; } } - return this; } @Override public CBehavior accept(final CDestructable target) { // TODO cut trees! - return this.unit.pollNextOrderBehavior(this.simulation); + if (String.valueOf(target).length() > 5) { + return this.unit.pollNextOrderBehavior(this.simulation); + } + else { + return null; + } } @Override diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/harvest/CBehaviorReturnResources.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/harvest/CBehaviorReturnResources.java new file mode 100644 index 0000000..e0e6fa3 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/harvest/CBehaviorReturnResources.java @@ -0,0 +1,172 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.harvest; + +import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CDestructable; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CItem; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.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.harvest.CAbilityHarvest; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.harvest.CAbilityReturnResources; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.mine.CAbilityGoldMine; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetStillAliveVisitor; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetVisitor; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; + +public class CBehaviorReturnResources extends CAbstractRangedBehavior implements AbilityTargetVisitor { + private final CAbilityHarvest abilityHarvest; + private CSimulation simulation; + + public CBehaviorReturnResources(final CUnit unit, final CAbilityHarvest abilityHarvest) { + super(unit, true); + this.abilityHarvest = abilityHarvest; + } + + public CBehaviorReturnResources reset(final CSimulation simulation) { + innerReset(findNearestDropoffPoint(simulation)); + return this; + } + + @Override + public boolean isWithinRange(final CSimulation simulation) { + // TODO this is probably not what the CloseEnoughRange constant is for + return this.unit.canReach(this.target, this.unit.getUnitType().getCollisionSize()); + } + + @Override + public int getHighlightOrderId() { + return OrderIds.returnresources; + } + + @Override + protected CBehavior update(final CSimulation simulation, final boolean withinRange) { + this.simulation = simulation; + return this.target.visit(this); + } + + @Override + public CBehavior accept(final AbilityPointTarget target) { + return CBehaviorReturnResources.this.unit.pollNextOrderBehavior(this.simulation); + } + + @Override + public CBehavior accept(final CUnit target) { + for (final CAbility ability : target.getAbilities()) { + if (ability instanceof CAbilityReturnResources) { + final CAbilityReturnResources abilityReturnResources = (CAbilityReturnResources) ability; + if (abilityReturnResources.accepts(this.abilityHarvest.getCarriedResourceType())) { + final CPlayer player = this.simulation.getPlayer(this.unit.getPlayerIndex()); + switch (this.abilityHarvest.getCarriedResourceType()) { + case FOOD: + throw new IllegalStateException("Unit used Harvest skill to carry FOOD resource!"); + case GOLD: + player.setGold(player.getGold() + this.abilityHarvest.getCarriedResourceAmount()); + this.unit.getUnitAnimationListener().removeSecondaryTag(SecondaryTag.GOLD); + break; + case LUMBER: + player.setLumber(player.getLumber() + this.abilityHarvest.getCarriedResourceAmount()); + this.unit.getUnitAnimationListener().removeSecondaryTag(SecondaryTag.LUMBER); + break; + } + this.abilityHarvest.setCarriedResources(null, 0); + final CUnit nearestMine = findNearestMine(this.unit, this.simulation); + if (nearestMine != null) { + return this.abilityHarvest.getBehaviorHarvest().reset(nearestMine); + } + return this.unit.pollNextOrderBehavior(this.simulation); + } + } + } + return this; + } + + @Override + public CBehavior accept(final CDestructable target) { + // TODO cut trees! + return this.unit.pollNextOrderBehavior(this.simulation); + } + + @Override + public CBehavior accept(final CItem target) { + return this.unit.pollNextOrderBehavior(this.simulation); + } + + @Override + protected boolean checkTargetStillValid(final CSimulation simulation) { + final boolean aliveCheck = this.target.visit(AbilityTargetStillAliveVisitor.INSTANCE); + if (!aliveCheck) { + final CUnit nearestDropoff = findNearestDropoffPoint(simulation); + if (nearestDropoff == null) { + return false; + } + else { + this.target = nearestDropoff; + return true; + } + } + return true; + } + + @Override + protected void resetBeforeMoving(final CSimulation simulation) { + + } + + private CUnit findNearestDropoffPoint(final CSimulation simulation) { + CUnit nearestDropoffPoint = null; + double nearestDropoffDistance = Float.MAX_VALUE; + for (final CUnit unit : simulation.getUnits()) { + if (unit.getPlayerIndex() == this.unit.getPlayerIndex()) { + boolean acceptedUnit = false; + for (final CAbility ability : unit.getAbilities()) { + if (ability instanceof CAbilityReturnResources) { + final CAbilityReturnResources abilityReturnResources = (CAbilityReturnResources) ability; + if (abilityReturnResources.accepts(this.abilityHarvest.getCarriedResourceType())) { + acceptedUnit = true; + break; + } + } + } + if (acceptedUnit) { + // TODO maybe use distance squared, problem is that we're using this + // inefficient more complex distance function on unit + final double distance = unit.distanceSquaredNoCollision(this.unit); + if (distance < nearestDropoffDistance) { + nearestDropoffDistance = distance; + nearestDropoffPoint = unit; + } + } + } + } + return nearestDropoffPoint; + } + + private static CUnit findNearestMine(final CUnit worker, final CSimulation simulation) { + CUnit nearestMine = null; + double nearestMineDistance = Float.MAX_VALUE; + for (final CUnit unit : simulation.getUnits()) { + boolean acceptedUnit = false; + for (final CAbility ability : unit.getAbilities()) { + if (ability instanceof CAbilityGoldMine) { + acceptedUnit = true; + break; + } + } + if (acceptedUnit) { + // TODO maybe use distance squared, problem is that we're using this + // inefficient more complex distance function on unit + final double distance = unit.distanceSquaredNoCollision(worker); + if (distance < nearestMineDistance) { + nearestMineDistance = distance; + nearestMine = unit; + } + } + } + return nearestMine; + } + +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/combat/attacks/CUnitAttackMissileSplash.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/combat/attacks/CUnitAttackMissileSplash.java index 409623a..9cc4aab 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/combat/attacks/CUnitAttackMissileSplash.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/combat/attacks/CUnitAttackMissileSplash.java @@ -39,6 +39,11 @@ public class CUnitAttackMissileSplash extends CUnitAttackMissile { this.damageFactorSmall = damageFactorSmall; } + @Override + public int getRange() { + return super.getRange(); + } + public int getAreaOfEffectFullDamage() { return this.areaOfEffectFullDamage; } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java index 4ed5c0c..56ce02a 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java @@ -1540,9 +1540,15 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma @Override public void foodChanged() { - this.resourceBarSupplyText.setText(this.localPlayer.getFoodUsed() + "/" + this.localPlayer.getFoodCap()); - this.resourceBarSupplyText - .setColor(this.localPlayer.getFoodUsed() > this.localPlayer.getFoodCap() ? Color.RED : Color.WHITE); + final int foodCap = this.localPlayer.getFoodCap(); + if (foodCap == 0) { + this.resourceBarSupplyText.setText(Integer.toString(this.localPlayer.getFoodUsed())); + this.resourceBarSupplyText.setColor(Color.WHITE); + } + else { + this.resourceBarSupplyText.setText(this.localPlayer.getFoodUsed() + "/" + foodCap); + this.resourceBarSupplyText.setColor(this.localPlayer.getFoodUsed() > foodCap ? Color.RED : Color.WHITE); + } } @Override