Updates to harvesting, reduce max depth of the quad trees

This commit is contained in:
Retera 2021-01-17 21:40:22 -05:00
parent eeed5953cc
commit 9a2dc090ca
23 changed files with 369 additions and 64 deletions

View File

@ -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"

View File

@ -6,7 +6,7 @@ import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
public class Quadtree<T> {
private static final int MAX_DEPTH = 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<T> {
}
}
public boolean intersect(float x, float y, final QuadtreeIntersector<T> intersector) {
public boolean intersect(final float x, final float y, final QuadtreeIntersector<T> intersector) {
if (this.leaf) {
for (int i = 0; i < this.nodes.size; i++) {
final Node<T> node = this.nodes.get(i);
@ -123,17 +123,25 @@ public class Quadtree<T> {
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!");
}
}

View File

@ -15,6 +15,8 @@ public class Test {
else {
System.out.println("no match");
}
// Quadtree<String> myQT = new Quadtree<>(new Rectangle(-, y, width, height))
}
}

View File

@ -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;
}

View File

@ -57,9 +57,9 @@ public class Particle extends EmittedObject<MdxComplexInstance, ParticleEmitter>
// 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);

View File

@ -1,5 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.mdx;
import com.etheller.warsmash.util.WarsmashConstants;
public class ParticleEmitter2 extends MdxEmitter<MdxComplexInstance, ParticleEmitter2Object, Particle2> {
private static final float[] emissionRateHeap = new float[1];
@ -30,7 +32,7 @@ public class ParticleEmitter2 extends MdxEmitter<MdxComplexInstance, ParticleEmi
this.lastEmissionKey = keyframe;
}
else {
this.currentEmission += emissionRateHeap[0] * dt;
this.currentEmission += emissionRateHeap[0] * dt * WarsmashConstants.MODEL_DETAIL_PARTICLE_FACTOR;
}
}
}

View File

@ -1,6 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.mdx;
import com.etheller.warsmash.parsers.mdlx.AnimationMap;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Texture;
import com.etheller.warsmash.viewer5.handlers.EmitterObject;
@ -82,7 +83,8 @@ public class ParticleEmitter2Object extends GenericObject implements EmitterObje
for (int i = 0; i < 3; i++) {
final float[] color = colors[i];
this.colors[i] = new float[] { color[0], color[1], color[2], alpha[i] / 255f };
this.colors[i] = new float[] { color[0], color[1], color[2],
(alpha[i] / 255f) * WarsmashConstants.MODEL_DETAIL_PARTICLE_FACTOR_INVERSE };
}
this.scaling = emitter.getSegmentScaling();

View File

@ -18,7 +18,7 @@ public class PathingGrid {
private static final Map<String, MovementType> 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) {

View File

@ -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;

View File

@ -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<CUnit> groundUnitCollision;
private final Quadtree<CUnit> airUnitCollision;
private final Quadtree<CUnit> 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);

View File

@ -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<CWidget> receiver);
protected abstract void innerCheckCanSmartTarget(CSimulation game, CUnit unit, int orderId, CWidget target,
AbilityTargetCheckReceiver<CWidget> receiver);
@Override
public void checkCanTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> 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<AbilityPointTarget> receiver);
protected abstract void innerCheckCanSmartTarget(CSimulation game, CUnit unit, int orderId,
AbilityPointTarget target, AbilityTargetCheckReceiver<AbilityPointTarget> receiver);
@Override
public void checkCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {

View File

@ -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<AbilityPointTarget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId,
final CWidget target, final AbilityTargetCheckReceiver<CWidget> receiver) {
receiver.orderIdNotAccepted();
}
}

View File

@ -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<CWidget> 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<AbilityPointTarget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
protected void innerCheckCanSmartTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
receiver.orderIdNotAccepted();
}
@Override
protected void innerCheckCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> 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;
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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) {

View File

@ -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)) {

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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<CBehavior> {
@ -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

View File

@ -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<CBehavior> {
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;
}
}

View File

@ -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;
}

View File

@ -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