Update build and train to show requirements, also sRGB filter change for fun

This commit is contained in:
Retera 2021-02-15 01:40:57 -05:00
parent 780ed7b60b
commit 2c5c00d4ea
26 changed files with 284 additions and 50 deletions

View File

@ -18,7 +18,8 @@ Path04="."
//FilePath="PrivateDontShare/Cult 8.w3x" //FilePath="PrivateDontShare/Cult 8.w3x"
//FilePath="TorchLight2.w3x" //FilePath="TorchLight2.w3x"
//FilePath="OrcAssault.w3x" //FilePath="OrcAssault.w3x"
FilePath="PeonStartingBase.w3x" //FilePath="PeonStartingBase.w3x"
//FilePath="PhoenixAttack.w3x" //FilePath="PhoenixAttack.w3x"
//FilePath="OperationReforged.w3x" //FilePath="OperationReforged.w3x"
//FilePath="AzerothRoleplay1.909t03DecoratedV2.w3x" //FilePath="AzerothRoleplay1.909t03DecoratedV2.w3x"
FilePath="American Colo EX 1.0 unpro.w3x"

View File

@ -218,7 +218,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
final String[] musics = musicField.split(";"); final String[] musics = musicField.split(";");
String musicPath = musics[(int) (Math.random() * musics.length)]; String musicPath = musics[(int) (Math.random() * musics.length)];
if (true) { if (true) {
musicPath = "Sound\\Music\\mp3Music\\DarkAgents.mp3"; musicPath = "Sound\\Music\\mp3Music\\PH1.mp3";
} }
final Music music = Gdx.audio.newMusic( final Music music = Gdx.audio.newMusic(
new DataSourceFileHandle(WarsmashGdxMapGame.this.viewer.dataSource, musicPath)); new DataSourceFileHandle(WarsmashGdxMapGame.this.viewer.dataSource, musicPath));

View File

@ -58,7 +58,7 @@ public class FolderDataSource implements DataSource {
if (!has(path)) { if (!has(path)) {
return null; return null;
} }
return ByteBuffer.wrap(Files.readAllBytes(Paths.get(path))); return ByteBuffer.wrap(Files.readAllBytes(Paths.get(this.folderPath.toString(), path)));
} }
@Override @Override

View File

@ -97,6 +97,7 @@ public class StringFrame extends AbstractRenderableFrame {
final char escapedCharacter = this.text.charAt(i + 1); final char escapedCharacter = this.text.charAt(i + 1);
switch (escapedCharacter) { switch (escapedCharacter) {
case 'c': case 'c':
case 'C':
if ((i + 9) < this.text.length()) { if ((i + 9) < this.text.length()) {
int colorInt; int colorInt;
try { try {
@ -161,6 +162,7 @@ public class StringFrame extends AbstractRenderableFrame {
} }
break; break;
case 'r': case 'r':
case 'R':
i++; { i++; {
final String wordString = currentWord.toString(); final String wordString = currentWord.toString();
currentWord.setLength(0); currentWord.setLength(0);
@ -210,7 +212,8 @@ public class StringFrame extends AbstractRenderableFrame {
} }
currentColor = this.color; currentColor = this.color;
break; break;
case 'n': { case 'n':
case 'N': {
final String wordString = currentWord.toString(); final String wordString = currentWord.toString();
currentWord.setLength(0); currentWord.setLength(0);
@ -344,6 +347,9 @@ public class StringFrame extends AbstractRenderableFrame {
singleStringFrame.setHeight(this.frameFont.getLineHeight()); singleStringFrame.setHeight(this.frameFont.getLineHeight());
singleStringFrame.setWidth(glyphLayout.width); singleStringFrame.setWidth(glyphLayout.width);
singleStringFrame.setAlpha(this.alpha); singleStringFrame.setAlpha(this.alpha);
singleStringFrame.setFontShadowColor(this.fontShadowColor);
singleStringFrame.setFontShadowOffsetX(this.fontShadowOffsetX);
singleStringFrame.setFontShadowOffsetY(this.fontShadowOffsetY);
singleStringFrame.addAnchor(new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight)); singleStringFrame.addAnchor(new AnchorDefinition(FramePoint.TOPLEFT, currentXCoordForFrames, -usedHeight));
this.internalFrames.add(singleStringFrame); this.internalFrames.add(singleStringFrame);
currentXCoordForFrames = currentXCoordForWord; currentXCoordForFrames = currentXCoordForWord;

View File

@ -98,7 +98,7 @@ public final class ImageUtils {
} }
public boolean isNeedsSRGBFix() { public boolean isNeedsSRGBFix() {
return this.needsSRGBFix; return false;
} }
} }
@ -217,6 +217,9 @@ public final class ImageUtils {
* @return Resulting sRGB image. * @return Resulting sRGB image.
*/ */
public static BufferedImage forceBufferedImagesRGB(final BufferedImage in) { public static BufferedImage forceBufferedImagesRGB(final BufferedImage in) {
if (true) {
return in;
}
// Resolve input ColorSpace. // Resolve input ColorSpace.
final ColorSpace inCS = in.getColorModel().getColorSpace(); final ColorSpace inCS = in.getColorModel().getColorSpace();
final ColorSpace sRGBCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); final ColorSpace sRGBCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);

View File

@ -91,7 +91,8 @@ public abstract class RawOpenGLTextureResource extends Texture {
final GL20 gl = this.viewer.gl; final GL20 gl = this.viewer.gl;
} }
public void update(final BufferedImage image, final boolean sRGBFix) { public void update(final BufferedImage image, boolean sRGBFix) {
sRGBFix = false;
final GL20 gl = this.viewer.gl; final GL20 gl = this.viewer.gl;
final int imageWidth = image.getWidth(); final int imageWidth = image.getWidth();

View File

@ -57,7 +57,7 @@ public class WorldScene extends Scene {
// Update and collect all of the visible instances. // Update and collect all of the visible instances.
for (final GridCell cell : this.grid.cells) { for (final GridCell cell : this.grid.cells) {
if (cell.isVisible(this.camera)) { if (cell.isVisible(this.camera) || true) {
this.visibleCells += 1; this.visibleCells += 1;
for (final ModelInstance instance : new ArrayList<>(cell.instances)) { for (final ModelInstance instance : new ArrayList<>(cell.instances)) {

View File

@ -4,6 +4,7 @@ import java.util.EnumSet;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Quaternion; import com.badlogic.gdx.math.Quaternion;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject; import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.RenderMathUtils; import com.etheller.warsmash.util.RenderMathUtils;
import com.etheller.warsmash.util.War3ID; import com.etheller.warsmash.util.War3ID;
@ -142,10 +143,11 @@ public class RenderUnit implements RenderWidget {
} }
public void populateCommandCard(final CSimulation game, final CommandButtonListener commandButtonListener, public void populateCommandCard(final CSimulation game, final GameUI gameUI,
final AbilityDataUI abilityDataUI, final int subMenuOrderId) { final CommandButtonListener commandButtonListener, final AbilityDataUI abilityDataUI,
final int subMenuOrderId) {
final CommandCardPopulatingAbilityVisitor commandCardPopulatingVisitor = CommandCardPopulatingAbilityVisitor.INSTANCE final CommandCardPopulatingAbilityVisitor commandCardPopulatingVisitor = CommandCardPopulatingAbilityVisitor.INSTANCE
.reset(game, this.simulationUnit, commandButtonListener, abilityDataUI, subMenuOrderId); .reset(game, gameUI, this.simulationUnit, commandButtonListener, abilityDataUI, subMenuOrderId);
for (final CAbility ability : this.simulationUnit.getAbilities()) { for (final CAbility ability : this.simulationUnit.getAbilities()) {
ability.visit(commandCardPopulatingVisitor); ability.visit(commandCardPopulatingVisitor);
} }

View File

@ -44,7 +44,7 @@ public interface RenderWidget {
private final EnumSet<AnimationTokens.SecondaryTag> recycleSet = EnumSet private final EnumSet<AnimationTokens.SecondaryTag> recycleSet = EnumSet
.noneOf(AnimationTokens.SecondaryTag.class); .noneOf(AnimationTokens.SecondaryTag.class);
private PrimaryTag currentAnimation; private PrimaryTag currentAnimation;
private EnumSet<SecondaryTag> currentAnimationSecondaryTags; private EnumSet<SecondaryTag> currentAnimationSecondaryTags = SequenceUtils.EMPTY;
private float currentSpeedRatio; private float currentSpeedRatio;
private boolean currentlyAllowingRarityVariations; private boolean currentlyAllowingRarityVariations;
private final Queue<QueuedAnimation> animationQueue = new LinkedList<>(); private final Queue<QueuedAnimation> animationQueue = new LinkedList<>();

View File

@ -1,5 +1,6 @@
package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons; package com.etheller.warsmash.viewer5.handlers.w3x.rendersim.commandbuttons;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.util.War3ID; import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityIconUI; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityIconUI;
@ -28,6 +29,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAb
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack; 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.orders.OrderIds;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.AbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void> { public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void> {
public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor(); public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor();
@ -38,11 +41,14 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
private AbilityDataUI abilityDataUI; private AbilityDataUI abilityDataUI;
private int menuBaseOrderId; private int menuBaseOrderId;
private boolean hasStop; private boolean hasStop;
private final CommandCardActivationReceiverPreviewCallback previewCallback = new CommandCardActivationReceiverPreviewCallback();
private GameUI gameUI;
public CommandCardPopulatingAbilityVisitor reset(final CSimulation game, final CUnit unit, public CommandCardPopulatingAbilityVisitor reset(final CSimulation game, final GameUI gameUI, final CUnit unit,
final CommandButtonListener commandButtonListener, final AbilityDataUI abilityDataUI, final CommandButtonListener commandButtonListener, final AbilityDataUI abilityDataUI,
final int menuBaseOrderId) { final int menuBaseOrderId) {
this.game = game; this.game = game;
this.gameUI = gameUI;
this.unit = unit; this.unit = unit;
this.commandButtonListener = commandButtonListener; this.commandButtonListener = commandButtonListener;
this.abilityDataUI = abilityDataUI; this.abilityDataUI = abilityDataUI;
@ -201,15 +207,26 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
} }
private void addCommandButton(final CAbility ability, final IconUI iconUI, final int handleId, final int orderId, private void addCommandButton(final CAbility ability, final IconUI iconUI, final int handleId, final int orderId,
final int autoCastOrderId, final boolean autoCastActive, final boolean menuButton, final int goldCost, final int autoCastOrderId, final boolean autoCastActive, final boolean menuButton, int goldCost,
final int lumberCost, final int foodCost) { int lumberCost, int foodCost) {
ability.checkCanUse(this.game, this.unit, orderId, this.previewCallback.reset());
final boolean active = ((this.unit.getCurrentBehavior() != null) final boolean active = ((this.unit.getCurrentBehavior() != null)
&& (orderId == this.unit.getCurrentBehavior().getHighlightOrderId())); && (orderId == this.unit.getCurrentBehavior().getHighlightOrderId()));
final boolean disabled = (ability != null) && ability.isDisabled(); final boolean disabled = ((ability != null) && ability.isDisabled()) || this.previewCallback.disabled;
String uberTip = iconUI.getUberTip();
if (disabled) {
// dont show these on disabled
goldCost = 0;
lumberCost = 0;
foodCost = 0;
}
if (this.previewCallback.isShowingRequirements()) {
uberTip = this.previewCallback.getRequirementsText() + "|r" + uberTip;
}
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(), this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
disabled ? iconUI.getIconDisabled() : iconUI.getIcon(), handleId, disabled ? 0 : orderId, disabled ? iconUI.getIconDisabled() : iconUI.getIcon(), handleId, disabled ? 0 : orderId,
autoCastOrderId, active, autoCastActive, menuButton, iconUI.getToolTip(), iconUI.getUberTip(), goldCost, autoCastOrderId, active, autoCastActive, menuButton, iconUI.getToolTip(), uberTip, goldCost, lumberCost,
lumberCost, foodCost); foodCost);
} }
@Override @Override
@ -247,4 +264,69 @@ public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void
} }
return null; return null;
} }
private final class CommandCardActivationReceiverPreviewCallback implements AbilityActivationReceiver {
private boolean disabled;
private final StringBuilder requirementsTextBuilder = new StringBuilder();
public CommandCardActivationReceiverPreviewCallback reset() {
this.disabled = false;
this.requirementsTextBuilder.setLength(0);
return this;
}
@Override
public void useOk() {
}
@Override
public void notEnoughResources(final ResourceType resource) {
}
@Override
public void notAnActiveAbility() {
}
@Override
public void missingRequirement(final War3ID type, final int level) {
this.disabled = true;
if (this.requirementsTextBuilder.length() == 0) {
this.requirementsTextBuilder.append(CommandCardPopulatingAbilityVisitor.this.gameUI.getTemplates()
.getDecoratedString("REQUIRESTOOLTIP"));
this.requirementsTextBuilder.append("|n - ");
}
else {
this.requirementsTextBuilder.append(" - ");
}
final CUnitType unitType = CommandCardPopulatingAbilityVisitor.this.game.getUnitData().getUnitType(type);
this.requirementsTextBuilder
.append(unitType == null ? "NOTEXTERN Unknown ('" + type + "')" : unitType.getName());
this.requirementsTextBuilder.append("|n");
}
@Override
public void casterMovementDisabled() {
}
@Override
public void cargoCapacityUnavailable() {
}
@Override
public void disabled() {
this.disabled = true;
}
public boolean isShowingRequirements() {
return this.requirementsTextBuilder.length() != 0;
}
public String getRequirementsText() {
return this.requirementsTextBuilder.toString();
}
}
} }

View File

@ -279,6 +279,8 @@ public class CSimulation {
} }
public void unitConstructFinishEvent(final CUnit constructedStructure) { public void unitConstructFinishEvent(final CUnit constructedStructure) {
final CPlayer player = getPlayer(constructedStructure.getPlayerIndex());
player.addTechtreeUnlocked(constructedStructure.getTypeId());
this.simulationRenderController.spawnUnitConstructionFinishSound(constructedStructure); this.simulationRenderController.spawnUnitConstructionFinishSound(constructedStructure);
} }
@ -310,6 +312,7 @@ public class CSimulation {
final CPlayer player = this.players.get(unit.getPlayerIndex()); final CPlayer player = this.players.get(unit.getPlayerIndex());
player.setUnitFoodUsed(unit, unit.getUnitType().getFoodUsed()); player.setUnitFoodUsed(unit, unit.getUnitType().getFoodUsed());
player.setUnitFoodMade(unit, unit.getUnitType().getFoodMade()); player.setUnitFoodMade(unit, unit.getUnitType().getFoodMade());
player.addTechtreeUnlocked(unit.getTypeId());
} }
} }

View File

@ -236,6 +236,9 @@ public class CUnit extends CWidget {
} }
} }
else if (!this.paused) { else if (!this.paused) {
if ((this.rallyPoint != this) && (this.rallyPoint instanceof CUnit) && ((CUnit) this.rallyPoint).isDead()) {
setRallyPoint(this);
}
if (this.constructing) { if (this.constructing) {
this.constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME; this.constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME;
final int buildTime = this.unitType.getBuildTime(); final int buildTime = this.unitType.getBuildTime();
@ -296,8 +299,9 @@ public class CUnit extends CWidget {
game.getGameplayConstants().getBuildingAngle()); game.getGameplayConstants().getBuildingAngle());
// dont add food cost to player 2x // dont add food cost to player 2x
trainedUnit.setFoodUsed(trainedUnitType.getFoodUsed()); trainedUnit.setFoodUsed(trainedUnitType.getFoodUsed());
game.getPlayer(this.playerIndex).setUnitFoodMade(trainedUnit, final CPlayer player = game.getPlayer(this.playerIndex);
trainedUnitType.getFoodMade()); player.setUnitFoodMade(trainedUnit, trainedUnitType.getFoodMade());
player.addTechtreeUnlocked(queuedRawcode);
// nudge the trained unit out around us // nudge the trained unit out around us
trainedUnit.nudgeAround(game, this); trainedUnit.nudgeAround(game, this);
game.unitTrainedEvent(this, trainedUnit); game.unitTrainedEvent(this, trainedUnit);

View File

@ -57,6 +57,7 @@ public class CUnitType {
private final EnumSet<CBuildingPathingType> requiredPathingTypes; private final EnumSet<CBuildingPathingType> requiredPathingTypes;
private final float propWindow; private final float propWindow;
private final float turnRate; private final float turnRate;
private final List<CUnitTypeRequirement> requirements;
public CUnitType(final String name, final int life, final int manaInitial, final int manaMaximum, final int speed, public CUnitType(final String name, final int life, final int manaInitial, final int manaMaximum, final int speed,
final int defense, final String abilityList, final boolean isBldg, final MovementType movementType, final int defense, final String abilityList, final boolean isBldg, final MovementType movementType,
@ -68,7 +69,8 @@ public class CUnitType {
final List<War3ID> unitsTrained, final List<War3ID> researchesAvailable, final CUnitRace unitRace, final List<War3ID> unitsTrained, final List<War3ID> researchesAvailable, final CUnitRace unitRace,
final int goldCost, final int lumberCost, final int foodUsed, final int foodMade, final int buildTime, final int goldCost, final int lumberCost, final int foodUsed, final int foodMade, final int buildTime,
final EnumSet<CBuildingPathingType> preventedPathingTypes, final EnumSet<CBuildingPathingType> preventedPathingTypes,
final EnumSet<CBuildingPathingType> requiredPathingTypes, final float propWindow, final float turnRate) { final EnumSet<CBuildingPathingType> requiredPathingTypes, final float propWindow, final float turnRate,
final List<CUnitTypeRequirement> requirements) {
this.name = name; this.name = name;
this.life = life; this.life = life;
this.manaInitial = manaInitial; this.manaInitial = manaInitial;
@ -105,6 +107,7 @@ public class CUnitType {
this.requiredPathingTypes = requiredPathingTypes; this.requiredPathingTypes = requiredPathingTypes;
this.propWindow = propWindow; this.propWindow = propWindow;
this.turnRate = turnRate; this.turnRate = turnRate;
this.requirements = requirements;
} }
public String getName() { public String getName() {
@ -250,4 +253,8 @@ public class CUnitType {
public float getTurnRate() { public float getTurnRate() {
return this.turnRate; return this.turnRate;
} }
public List<CUnitTypeRequirement> getRequirements() {
return this.requirements;
}
} }

View File

@ -0,0 +1,21 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation;
import com.etheller.warsmash.util.War3ID;
public class CUnitTypeRequirement {
private final War3ID requirement;
private final int requiredLevel;
public CUnitTypeRequirement(final War3ID requirement, final int requiredLevel) {
this.requirement = requirement;
this.requiredLevel = requiredLevel;
}
public War3ID getRequirement() {
return this.requirement;
}
public int getRequiredLevel() {
return this.requiredLevel;
}
}

View File

@ -9,6 +9,7 @@ import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; 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.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitTypeRequirement;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; 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.AbstractCAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.menu.CAbilityMenu; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.menu.CAbilityMenu;
@ -39,22 +40,37 @@ public abstract class AbstractCAbilityBuild extends AbstractCAbility implements
final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype); final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype);
if (unitType != null) { if (unitType != null) {
final CPlayer player = game.getPlayer(unit.getPlayerIndex()); final CPlayer player = game.getPlayer(unit.getPlayerIndex());
if (player.getGold() >= unitType.getGoldCost()) { final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
if (player.getLumber() >= unitType.getLumberCost()) { boolean requirementsMet = true;
if ((unitType.getFoodUsed() == 0) for (final CUnitTypeRequirement requirement : requirements) {
|| ((player.getFoodUsed() + unitType.getFoodUsed()) <= player.getFoodCap())) { if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
receiver.useOk(); requirementsMet = false;
}
}
if (requirementsMet) {
if (player.getGold() >= unitType.getGoldCost()) {
if (player.getLumber() >= unitType.getLumberCost()) {
if ((unitType.getFoodUsed() == 0)
|| ((player.getFoodUsed() + unitType.getFoodUsed()) <= player.getFoodCap())) {
receiver.useOk();
}
else {
receiver.notEnoughResources(ResourceType.FOOD);
}
} }
else { else {
receiver.notEnoughResources(ResourceType.FOOD); receiver.notEnoughResources(ResourceType.LUMBER);
} }
} }
else { else {
receiver.notEnoughResources(ResourceType.LUMBER); receiver.notEnoughResources(ResourceType.GOLD);
} }
} }
else { else {
receiver.notEnoughResources(ResourceType.GOLD); for (final CUnitTypeRequirement requirement : requirements) {
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
}
} }
} }
else { else {

View File

@ -8,6 +8,7 @@ import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation; 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.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitTypeRequirement;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; 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.AbstractCAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor;
@ -45,22 +46,36 @@ public final class CAbilityQueue extends AbstractCAbility {
final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype); final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype);
if (unitType != null) { if (unitType != null) {
final CPlayer player = game.getPlayer(unit.getPlayerIndex()); final CPlayer player = game.getPlayer(unit.getPlayerIndex());
if (player.getGold() >= unitType.getGoldCost()) { final List<CUnitTypeRequirement> requirements = unitType.getRequirements();
if (player.getLumber() >= unitType.getLumberCost()) { boolean requirementsMet = true;
if ((unitType.getFoodUsed() == 0) for (final CUnitTypeRequirement requirement : requirements) {
|| ((player.getFoodUsed() + unitType.getFoodUsed()) <= player.getFoodCap())) { if (player.getTechtreeUnlocked(requirement.getRequirement()) < requirement.getRequiredLevel()) {
receiver.useOk(); requirementsMet = false;
}
}
if (requirementsMet) {
if (player.getGold() >= unitType.getGoldCost()) {
if (player.getLumber() >= unitType.getLumberCost()) {
if ((unitType.getFoodUsed() == 0)
|| ((player.getFoodUsed() + unitType.getFoodUsed()) <= player.getFoodCap())) {
receiver.useOk();
}
else {
receiver.notEnoughResources(ResourceType.FOOD);
}
} }
else { else {
receiver.notEnoughResources(ResourceType.FOOD); receiver.notEnoughResources(ResourceType.LUMBER);
} }
} }
else { else {
receiver.notEnoughResources(ResourceType.LUMBER); receiver.notEnoughResources(ResourceType.GOLD);
} }
} }
else { else {
receiver.notEnoughResources(ResourceType.GOLD); for (final CUnitTypeRequirement requirement : requirements) {
receiver.missingRequirement(requirement.getRequirement(), requirement.getRequiredLevel());
}
} }
} }
else { else {

View File

@ -19,7 +19,7 @@ public class CAbilityRally extends AbstractCAbility {
@Override @Override
public void onAdd(final CSimulation game, final CUnit unit) { public void onAdd(final CSimulation game, final CUnit unit) {
unit.setRallyPoint(unit);
} }
@Override @Override

View File

@ -92,7 +92,12 @@ public class CBehaviorHarvest extends CAbstractRangedBehavior
} }
} }
// weird invalid target and we have no resources, consider harvesting done // weird invalid target and we have no resources, consider harvesting done
return this.unit.pollNextOrderBehavior(this.simulation); if (this.abilityHarvest.getCarriedResourceAmount() == 0) {
return this.unit.pollNextOrderBehavior(this.simulation);
}
else {
return this.abilityHarvest.getBehaviorReturnResources().reset(this.simulation);
}
} }
else { else {
// we have some GOLD and we're not in a mine (?) lets do a return resources // we have some GOLD and we're not in a mine (?) lets do a return resources

View File

@ -16,6 +16,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitClassification;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitTypeRequirement;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.HandleIdAllocator; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.HandleIdAllocator;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; 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.CAbilityAttack;
@ -137,6 +138,9 @@ public class CUnitData {
private static final War3ID RESEARCHES_AVAILABLE = War3ID.fromString("ures"); private static final War3ID RESEARCHES_AVAILABLE = War3ID.fromString("ures");
private static final War3ID UNIT_RACE = War3ID.fromString("urac"); private static final War3ID UNIT_RACE = War3ID.fromString("urac");
private static final War3ID REQUIRES = War3ID.fromString("ureq");
private static final War3ID REQUIRES_AMOUNT = War3ID.fromString("urqc");
private static final War3ID GOLD_COST = War3ID.fromString("ugol"); private static final War3ID GOLD_COST = War3ID.fromString("ugol");
private static final War3ID LUMBER_COST = War3ID.fromString("ulum"); private static final War3ID LUMBER_COST = War3ID.fromString("ulum");
private static final War3ID BUILD_TIME = War3ID.fromString("ubld"); private static final War3ID BUILD_TIME = War3ID.fromString("ubld");
@ -416,6 +420,40 @@ public class CUnitData {
} }
} }
final String requirementsString = unitType.getFieldAsString(REQUIRES, 0);
final String requirementsLevelsString = unitType.getFieldAsString(REQUIRES_AMOUNT, 0);
final String[] requirementsStringItems = requirementsString.split(",");
final String[] requirementsLevelsStringItems = requirementsLevelsString.split(",");
final List<CUnitTypeRequirement> requirements = new ArrayList<>();
for (int i = 0; i < requirementsStringItems.length; i++) {
final String item = requirementsStringItems[i];
if (!item.isEmpty()) {
int level;
if (i < requirementsLevelsStringItems.length) {
if (requirementsLevelsStringItems[i].isEmpty()) {
level = 1;
}
else {
level = Integer.parseInt(requirementsLevelsStringItems[i]);
}
}
else if (requirementsLevelsStringItems.length > 0) {
final String requirementLevel = requirementsLevelsStringItems[requirementsLevelsStringItems.length
- 1];
if (requirementLevel.isEmpty()) {
level = 1;
}
else {
level = Integer.parseInt(requirementLevel);
}
}
else {
level = 1;
}
requirements.add(new CUnitTypeRequirement(War3ID.fromString(item), level));
}
}
final EnumSet<CBuildingPathingType> preventedPathingTypes = CBuildingPathingType final EnumSet<CBuildingPathingType> preventedPathingTypes = CBuildingPathingType
.parsePathingTypeListSet(unitType.getFieldAsString(PREVENT_PLACE, 0)); .parsePathingTypeListSet(unitType.getFieldAsString(PREVENT_PLACE, 0));
final EnumSet<CBuildingPathingType> requiredPathingTypes = CBuildingPathingType final EnumSet<CBuildingPathingType> requiredPathingTypes = CBuildingPathingType
@ -429,7 +467,7 @@ public class CUnitData {
defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs, acquisitionRange, defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs, acquisitionRange,
minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable, unitRace, goldCost, minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable, unitRace, goldCost,
lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes, propWindow, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes, propWindow,
turnRate); turnRate, requirements);
this.unitIdToUnitType.put(typeId, unitTypeInstance); this.unitIdToUnitType.put(typeId, unitTypeInstance);
} }
return unitTypeInstance; return unitTypeInstance;

View File

@ -150,6 +150,26 @@ public class CPlayer {
return techtreeUnlocked; return techtreeUnlocked;
} }
public void addTechtreeUnlocked(final War3ID rawcode) {
final Integer techtreeUnlocked = this.rawcodeToTechtreeUnlocked.get(rawcode);
if (techtreeUnlocked == null) {
this.rawcodeToTechtreeUnlocked.put(rawcode, 1);
}
else {
this.rawcodeToTechtreeUnlocked.put(rawcode, techtreeUnlocked + 1);
}
}
public void removeTechtreeUnlocked(final War3ID rawcode) {
final Integer techtreeUnlocked = this.rawcodeToTechtreeUnlocked.get(rawcode);
if (techtreeUnlocked == null) {
this.rawcodeToTechtreeUnlocked.put(rawcode, -1);
}
else {
this.rawcodeToTechtreeUnlocked.put(rawcode, techtreeUnlocked - 1);
}
}
public void addStateListener(final CPlayerStateListener listener) { public void addStateListener(final CPlayerStateListener listener) {
this.stateNotifier.subscribe(listener); this.stateNotifier.subscribe(listener);
} }

View File

@ -1,5 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util; package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
import com.etheller.warsmash.util.War3ID;
public interface AbilityActivationReceiver { public interface AbilityActivationReceiver {
void useOk(); void useOk();
@ -7,7 +9,7 @@ public interface AbilityActivationReceiver {
void notAnActiveAbility(); void notAnActiveAbility();
void missingRequirement(String name); void missingRequirement(War3ID type, int level);
void casterMovementDisabled(); void casterMovementDisabled();

View File

@ -1,5 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util; package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
import com.etheller.warsmash.util.War3ID;
public class BooleanAbilityActivationReceiver implements AbilityActivationReceiver { public class BooleanAbilityActivationReceiver implements AbilityActivationReceiver {
public static final BooleanAbilityActivationReceiver INSTANCE = new BooleanAbilityActivationReceiver(); public static final BooleanAbilityActivationReceiver INSTANCE = new BooleanAbilityActivationReceiver();
private boolean ok; private boolean ok;
@ -20,7 +22,7 @@ public class BooleanAbilityActivationReceiver implements AbilityActivationReceiv
} }
@Override @Override
public void missingRequirement(final String name) { public void missingRequirement(final War3ID type, final int level) {
this.ok = false; this.ok = false;
} }

View File

@ -1,5 +1,6 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util; package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.AudioContext; import com.etheller.warsmash.viewer5.AudioContext;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener; import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
@ -59,7 +60,7 @@ public class MeleeUIAbilityActivationReceiver implements AbilityActivationReceiv
} }
@Override @Override
public void missingRequirement(final String name) { public void missingRequirement(final War3ID type, final int level) {
this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit); this.genericError.onClick(this.commandErrorListener, this.worldSceneAudioContext, this.commandedUnit);
} }

View File

@ -1,5 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util; package com.etheller.warsmash.viewer5.handlers.w3x.simulation.util;
import com.etheller.warsmash.util.War3ID;
public class StringMsgAbilityActivationReceiver implements AbilityActivationReceiver { public class StringMsgAbilityActivationReceiver implements AbilityActivationReceiver {
private String message; private String message;
private boolean useOk = false; private boolean useOk = false;
@ -34,8 +36,8 @@ public class StringMsgAbilityActivationReceiver implements AbilityActivationRece
} }
@Override @Override
public void missingRequirement(final String name) { public void missingRequirement(final War3ID type, final int level) {
this.message = "NOTEXTERN: Requires " + name; this.message = "NOTEXTERN: Requires " + type;
} }
@Override @Override

View File

@ -418,7 +418,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.unitManaText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitManaPointText", 0); this.unitManaText = (StringFrame) this.rootFrame.getFrameByName("UnitPortraitManaPointText", 0);
final float infoPanelUnitDetailWidth = GameUI.convertY(this.uiViewport, 0.180f); final float infoPanelUnitDetailWidth = GameUI.convertY(this.uiViewport, 0.180f);
final float infoPanelUnitDetailHeight = GameUI.convertY(this.uiViewport, 0.105f); final float infoPanelUnitDetailHeight = GameUI.convertY(this.uiViewport, 0.110f);
this.smashSimpleInfoPanel = this.rootFrame.createSimpleFrame("SmashSimpleInfoPanel", this.rootFrame, 0); this.smashSimpleInfoPanel = this.rootFrame.createSimpleFrame("SmashSimpleInfoPanel", this.rootFrame, 0);
this.smashSimpleInfoPanel this.smashSimpleInfoPanel
.addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f))); .addAnchor(new AnchorDefinition(FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, 0.0f)));
@ -556,7 +556,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
new Color(0xFFCC00FF), TextJustify.LEFT, TextJustify.MIDDLE, worldFrameMessageFontHeight); new Color(0xFFCC00FF), TextJustify.LEFT, TextJustify.MIDDLE, worldFrameMessageFontHeight);
this.errorMessageFrame.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT, this.errorMessageFrame.addAnchor(new AnchorDefinition(FramePoint.BOTTOMLEFT,
GameUI.convertX(this.uiViewport, 0.212f), GameUI.convertY(this.uiViewport, 0.182f))); GameUI.convertX(this.uiViewport, 0.212f), GameUI.convertY(this.uiViewport, 0.182f)));
this.errorMessageFrame.setWidth(GameUI.convertX(this.uiViewport, 0.25f)); this.errorMessageFrame.setWidth(GameUI.convertX(this.uiViewport, 0.35f));
this.errorMessageFrame.setHeight(GameUI.convertY(this.uiViewport, worldFrameMessageFontHeight)); this.errorMessageFrame.setHeight(GameUI.convertY(this.uiViewport, worldFrameMessageFontHeight));
this.errorMessageFrame.setFontShadowColor(new Color(0f, 0f, 0f, 0.9f)); this.errorMessageFrame.setFontShadowColor(new Color(0f, 0f, 0f, 0.9f));
@ -1773,7 +1773,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0, this.commandButton(cancelUI.getButtonPositionX(), cancelUI.getButtonPositionY(), cancelUI.getIcon(), 0,
exitOrderId, 0, false, false, true, cancelUI.getToolTip(), cancelUI.getUberTip(), 0, 0, 0); exitOrderId, 0, false, false, true, cancelUI.getToolTip(), cancelUI.getUberTip(), 0, 0, 0);
} }
this.selectedUnit.populateCommandCard(this.war3MapViewer.simulation, this, abilityDataUI, menuOrderId); this.selectedUnit.populateCommandCard(this.war3MapViewer.simulation, this.rootFrame, this, abilityDataUI,
menuOrderId);
} }
} }
@ -1941,7 +1942,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
else { else {
final List<RenderWidget> selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY, final List<RenderWidget> selectedUnits = this.war3MapViewer.selectUnit(screenX, worldScreenY,
false); false);
selectWidgets(selectedUnits); if (!selectedUnits.isEmpty()) {
selectWidgets(selectedUnits);
}
} }
} }
} }

View File

@ -31,13 +31,13 @@ Frame "SIMPLEFRAME" "UnitPortrait" {
} }
String "UnitPortraitHitPointText" INHERITS "UnitPortraitTextTemplate" { String "UnitPortraitHitPointText" INHERITS "UnitPortraitTextTemplate" {
Anchor BOTTOM, 0, 0.0115, Anchor BOTTOM, 0, 0.014,
FontJustificationH JUSTIFYCENTER, FontJustificationH JUSTIFYCENTER,
FontColor 0.0 1.0 0.0 1.0, FontColor 0.0 1.0 0.0 1.0,
} }
String "UnitPortraitManaPointText" INHERITS "UnitPortraitTextTemplate" { String "UnitPortraitManaPointText" INHERITS "UnitPortraitTextTemplate" {
Anchor BOTTOM, 0, -0.0030, Anchor BOTTOM, 0, -0.0005,
FontJustificationH JUSTIFYCENTER, FontJustificationH JUSTIFYCENTER,
FontColor 1.0 1.0 1.0 1.0, FontColor 1.0 1.0 1.0 1.0,
} }