Updates for playing Titancraft and fix hero train delayed limit

This commit is contained in:
Retera 2022-01-06 15:03:39 -05:00
parent 7bcf7cad7e
commit b4f67eb1e5
42 changed files with 746 additions and 122 deletions

View File

@ -58,7 +58,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
public void run() {
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(currentServerTurnInProgress) {
@Override
public void run() {
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
@ -85,7 +85,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
public void run() {
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(currentServerTurnInProgress) {
@Override
public void run() {
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
@ -114,7 +114,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
public void run() {
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(currentServerTurnInProgress) {
@Override
public void run() {
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId,
@ -143,7 +143,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
public void run() {
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(currentServerTurnInProgress) {
@Override
public void run() {
executor.issueDropItemAtTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId,
@ -172,7 +172,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
public void run() {
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(currentServerTurnInProgress) {
@Override
public void run() {
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
@ -198,7 +198,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
public void run() {
final int currentServerTurnInProgress = WarsmashClient.this.latestCompletedTurn + 1;
if (currentServerTurnInProgress > WarsmashClient.this.latestLocallyRequestedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(WarsmashClient.this.latestCompletedTurn) {
WarsmashClient.this.queuedMessages.add(new QueuedMessage(currentServerTurnInProgress) {
@Override
public void run() {
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
@ -238,6 +238,10 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
&& (this.queuedMessages.peek().messageTurnTick == this.latestLocallyRequestedTurn)) {
this.queuedMessages.poll().run();
}
if (!this.queuedMessages.isEmpty()) {
System.out.println("stopped with " + this.queuedMessages.peek().messageTurnTick + " != "
+ this.latestLocallyRequestedTurn);
}
}
@Override

View File

@ -64,6 +64,18 @@ public class WarsmashClientParser implements OrderedUdpClientListener {
targetHandleId, x, y, queue);
break;
}
case ServerToClientProtocol.ISSUE_DROP_ITEM_ON_TARGET_ORDER: {
final int playerIndex = buffer.getInt();
final int unitHandleId = buffer.getInt();
final int abilityHandleId = buffer.getInt();
final int orderId = buffer.getInt();
final int targetHandleId = buffer.getInt();
final int targetHeroHandleId = buffer.getInt();
final boolean queue = buffer.get() == 1;
this.listener.issueDropItemAtTargetOrder(playerIndex, unitHandleId, abilityHandleId, orderId,
targetHandleId, targetHeroHandleId, queue);
break;
}
case ServerToClientProtocol.ISSUE_IMMEDIATE_ORDER: {
final int playerIndex = buffer.getInt();
final int unitHandleId = buffer.getInt();

View File

@ -49,6 +49,12 @@ public class WarsmashServer implements ClientToServerListener {
Integer playerIndex = this.socketAddressToPlayerIndex.get(sourceAddress);
if (playerIndex == null) {
playerIndex = this.socketAddressToPlayerIndex.size();
if (playerIndex == 2) {
playerIndex = 5;
}
else if (playerIndex == 3) {
playerIndex = 6;
}
this.socketAddressToPlayerIndex.put(sourceAddress, playerIndex);
}
return playerIndex;

View File

@ -231,7 +231,8 @@ public class StringFrame extends AbstractRenderableFrame {
this.internalFrames.add(singleStringFrame);
currentXCoordForFrames = currentXCoordForWord;
currentColor = new Color((colorInt << 8) | (colorInt >>> 24));
currentColor = new Color((colorInt << 8) | (colorInt >>> 24)
| 0xFF /* always show, hacky setting alpha=1 */);
}
}
break;

View File

@ -2238,12 +2238,19 @@ public class Jass2 {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final double left = arguments.get(0).visit(RealJassValueVisitor.getInstance());
final double bottom = arguments.get(1).visit(RealJassValueVisitor.getInstance());
final double right = arguments.get(2).visit(RealJassValueVisitor.getInstance());
final double top = arguments.get(3).visit(RealJassValueVisitor.getInstance());
meleeUI.getCameraManager().setCameraBounds(new Rectangle((float) left, (float) bottom,
(float) (right - left), (float) (top - bottom)));
final double x1 = arguments.get(0).visit(RealJassValueVisitor.getInstance());
final double y1 = arguments.get(1).visit(RealJassValueVisitor.getInstance());
final double x2 = arguments.get(2).visit(RealJassValueVisitor.getInstance());
final double y2 = arguments.get(3).visit(RealJassValueVisitor.getInstance());
final double x3 = arguments.get(4).visit(RealJassValueVisitor.getInstance());
final double y3 = arguments.get(5).visit(RealJassValueVisitor.getInstance());
final double x4 = arguments.get(6).visit(RealJassValueVisitor.getInstance());
final double y4 = arguments.get(7).visit(RealJassValueVisitor.getInstance());
final float left = (float) Math.min(Math.min(x1, x2), Math.min(x3, x4));
final float bottom = (float) Math.min(Math.min(y1, y2), Math.min(y3, y4));
final float right = (float) Math.max(Math.max(x1, x2), Math.max(x3, x4));
final float top = (float) Math.max(Math.max(y1, y2), Math.max(y3, y4));
meleeUI.getCameraManager().setCameraBounds(new Rectangle(left, bottom, right - left, top - bottom));
return null;
}
});
@ -2355,6 +2362,32 @@ public class Jass2 {
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("PlayMusic", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final String musicName = arguments.get(0).visit(StringJassValueVisitor.getInstance());
String musicField;
if (!CommonEnvironment.this.gameUI.hasSkinField(musicName)) {
// TODO this versioning system should probably be more general case than this,
// maybe at the level
// of skin field lookup???
final String versionedMusic = "Music_V" + WarsmashConstants.GAME_VERSION;
if (!CommonEnvironment.this.gameUI.hasSkinField(versionedMusic)) {
musicField = musicName;
}
else {
musicField = CommonEnvironment.this.gameUI.getSkinField(versionedMusic);
}
}
else {
musicField = CommonEnvironment.this.gameUI.getSkinField(musicName);
}
meleeUI.playMusic(musicField, true, 0);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("CreateItem", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -2863,6 +2896,9 @@ public class Jass2 {
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CUnit unit = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
if (unit == null) {
return BooleanJassValue.TRUE; // TODO this is a workaround, probably
}
return BooleanJassValue.of(unit.isHidden());
}
});
@ -3006,7 +3042,10 @@ public class Jass2 {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CUnit whichWidget = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final CUnit whichWidget = nullable(arguments, 0, ObjectJassValueVisitor.getInstance());
if (whichWidget == null) {
return new HandleJassValue(locationType, new Point2D.Double(0, 0));
}
return new HandleJassValue(locationType,
new Point2D.Double(whichWidget.getX(), whichWidget.getY()));
}
@ -3072,15 +3111,7 @@ public class Jass2 {
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final double time = arguments.get(0).visit(RealJassValueVisitor.getInstance());
new CTimer((float) time) {
@Override
public void onFire() {
globalScope.queueTrigger(null, null, triggerScope.getTriggeringTrigger(), null,
triggerScope);
}
}.start(CommonEnvironment.this.simulation);
// throw new JassException(globalScope, "Needs to sleep " + time, null);
return JassValue.I_AM_SLEEP;
throw new JassException(globalScope, "Needs to sleep " + time, null);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetPlayerNeutralAggressive", new JassFunction() {
@ -3241,6 +3272,19 @@ public class Jass2 {
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("SetUnitPositionLoc", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CUnit whichUnit = nullable(arguments, 0, ObjectJassValueVisitor.getInstance());
final Point2D.Double positionLoc = arguments.get(1).visit(ObjectJassValueVisitor.getInstance());
if (whichUnit != null) {
whichUnit.setPointAndCheckUnstuck((float) positionLoc.x, (float) positionLoc.y,
CommonEnvironment.this.simulation);
}
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("ShowUnit", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -3499,6 +3543,58 @@ public class Jass2 {
((CommonTriggerExecutionScope) triggerScope).getTriggeringUnit());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetSpellAbilityUnit", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new HandleJassValue(unitType,
((CommonTriggerExecutionScope) triggerScope).getSpellAbilityUnit());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetSpellTargetUnit", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new HandleJassValue(unitType,
((CommonTriggerExecutionScope) triggerScope).getSpellTargetUnit());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetSpellTargetPoint", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final AbilityPointTarget spellTargetPoint = ((CommonTriggerExecutionScope) triggerScope)
.getSpellTargetPoint();
final Point2D.Double jassLocation = new Point2D.Double(spellTargetPoint.x, spellTargetPoint.y);
return new HandleJassValue(locationType, jassLocation);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetSpellTargetX", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final AbilityPointTarget spellTargetPoint = ((CommonTriggerExecutionScope) triggerScope)
.getSpellTargetPoint();
return new RealJassValue(spellTargetPoint.x);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetSpellTargetY", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final AbilityPointTarget spellTargetPoint = ((CommonTriggerExecutionScope) triggerScope)
.getSpellTargetPoint();
return new RealJassValue(spellTargetPoint.y);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetSpellAbilityId", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new IntegerJassValue(
((CommonTriggerExecutionScope) triggerScope).getSpellAbilityId().getValue());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetEnumPlayer", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -4032,7 +4128,7 @@ public class Jass2 {
System.out.println("ExecuteFunc (\"" + funcName + "\")");
if (functionByName != null) {
// TODO below TriggerExecutionScope.EMPTY is probably not correct
functionByName.call(Collections.emptyList(), globalScope, TriggerExecutionScope.createEmptyStack());
functionByName.call(Collections.emptyList(), globalScope, TriggerExecutionScope.EMPTY);
}
return null;
}

View File

@ -2,10 +2,12 @@ package com.etheller.warsmash.parsers.jass.scope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.scope.trigger.Trigger;
import com.etheller.warsmash.util.War3ID;
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.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.players.CPlayerJass;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegion;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.timers.CTimerJass;
@ -70,6 +72,10 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
private CWidget triggerWidget;
private CScriptDialog clickedDialog;
private CScriptDialogButton clickedButton;
private CUnit spellAbilityUnit;
private CUnit spellTargetUnit;
private AbilityPointTarget spellTargetPoint;
private War3ID spellAbilityId;
private JassGameEventsWar3 triggerEventId;
public CommonTriggerExecutionScope(final Trigger triggeringTrigger) {
@ -375,6 +381,22 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
return this.triggerEventId;
}
public CUnit getSpellAbilityUnit() {
return this.spellAbilityUnit;
}
public CUnit getSpellTargetUnit() {
return this.spellTargetUnit;
}
public AbilityPointTarget getSpellTargetPoint() {
return this.spellTargetPoint;
}
public War3ID getSpellAbilityId() {
return this.spellAbilityId;
}
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
final CUnit filterUnit) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
@ -511,6 +533,29 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
return scope;
}
public static CommonTriggerExecutionScope unitSpellEffectTargetScope(final JassGameEventsWar3 triggerEventId,
final Trigger trigger, final CUnit spellAbilityUnit, final CUnit targetUnit, final War3ID spellAbilityId) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
scope.spellAbilityUnit = spellAbilityUnit;
scope.triggeringUnit = spellAbilityUnit;
scope.spellTargetUnit = targetUnit;
scope.spellAbilityId = spellAbilityId;
scope.triggerEventId = triggerEventId;
return scope;
}
public static CommonTriggerExecutionScope unitSpellEffectPointScope(final JassGameEventsWar3 triggerEventId,
final Trigger trigger, final CUnit spellAbilityUnit, final AbilityPointTarget targetPoint,
final War3ID spellAbilityId) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
scope.spellAbilityUnit = spellAbilityUnit;
scope.triggeringUnit = spellAbilityUnit;
scope.spellTargetPoint = targetPoint;
scope.spellAbilityId = spellAbilityId;
scope.triggerEventId = triggerEventId;
return scope;
}
public static interface UnitEventScopeBuilder {
CommonTriggerExecutionScope create(JassGameEventsWar3 triggerEventId, Trigger trigger, CUnit unit);
}

View File

@ -25,7 +25,7 @@ public class WarsmashConstants {
// find it yet so I used this
public static final String DEFAULT_STRING = "Default string";
public static final boolean CATCH_CURSOR = true;
public static final boolean CATCH_CURSOR = false;
public static final boolean VERBOSE_LOGGING = true;
public static final boolean ENABLE_DEBUG = true;
public static final char SPECIAL_ESCAPE_KEYCODE = 0x7E;
@ -36,7 +36,8 @@ public class WarsmashConstants {
// workaround to fix it if you need the local files
// to take priority over built-ins for tilesets.
public static final boolean FIX_FLAT_FILES_TILESET_LOADING = false;
public static final boolean ENABLE_MUSIC = true;
public static final boolean ENABLE_MUSIC = false;
public static final boolean LOAD_UNITS_FROM_WORLDEDIT_DATA = false;
public static final boolean CRASH_ON_INCOMPATIBLE_132_FEATURES = false;
public static final boolean FIRE_DEATH_EVENTS_ON_REMOVEUNIT = false;
}

View File

@ -2367,6 +2367,11 @@ public class War3MapViewer extends AbstractMdxModelViewer {
final String attachPointName) {
if (targetWidget instanceof CUnit) {
final RenderUnit renderUnit = War3MapViewer.this.unitToRenderPeer.get(targetWidget);
if (renderUnit == null) {
throw new NullPointerException(
"renderUnit is null! targetWidget is \"" + ((CUnit) targetWidget).getUnitType().getName()
+ "\", attachPointName=\"" + attachPointName + "\"");
}
final MdxModel spawnedEffectModel = loadModelMdx(modelName);
if (spawnedEffectModel != null) {
final MdxComplexInstance modelInstance = (MdxComplexInstance) spawnedEffectModel.addInstance();

View File

@ -333,8 +333,8 @@ public class RenderUnit implements RenderWidget {
this.instance.setLocalRotation(tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.facing));
final float facingRadians = (float) Math.toRadians(this.facing);
final float maxPitch = this.typeData.getMaxPitch();
final float maxRoll = this.typeData.getMaxRoll();
final float maxPitch = (float) Math.toRadians(this.typeData.getMaxPitch());
final float maxRoll = (float) Math.toRadians(this.typeData.getMaxRoll());
final float sampleRadius = this.typeData.getElevationSampleRadius();
float pitch, roll;
final float pitchSampleForwardX = this.location[0] + (sampleRadius * (float) Math.cos(facingRadians));

View File

@ -50,7 +50,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CRacePrefer
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.region.CRegionManager;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.timers.CTimer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.enumtypes.CPlayerSlotState;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.ResourceType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderComponent;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
@ -447,13 +446,11 @@ public class CSimulation implements CPlayerAPI {
return this.defaultPlayerUnitOrderExecutors.get(index);
}
public CommandErrorListener getCommandErrorListener(final int playerIndex) {
public CommandErrorListener getCommandErrorListener() {
return this.commandErrorListener;
}
public void unitConstructFinishEvent(final CUnit constructedStructure) {
final CPlayer player = this.getPlayer(constructedStructure.getPlayerIndex());
player.addTechtreeUnlocked(constructedStructure.getTypeId());
this.simulationRenderController.spawnUnitConstructionFinishSound(constructedStructure);
}
@ -662,10 +659,4 @@ public class CSimulation implements CPlayerAPI {
return !this.daytime;
}
public void updateIsPlaying(final War3MapConfig mapConfig) {
for (int i = 0; i < mapConfig.getPlayerCount(); i++) {
this.players.get(i).setSlotState(CPlayerSlotState.PLAYING);
}
}
}

View File

@ -383,10 +383,12 @@ public class CUnit extends CWidget {
ability.setIconShowing(true);
}
}
if (this.unitType.getFoodMade() != 0) {
final CPlayer player = game.getPlayer(this.playerIndex);
if (this.unitType.getFoodMade() != 0) {
player.setFoodCap(player.getFoodCap() + this.unitType.getFoodMade());
}
player.removeTechtreeInProgress(this.unitType.getTypeId());
player.addTechtreeUnlocked(this.unitType.getTypeId());
game.unitConstructFinishEvent(this);
this.stateNotifier.ordersChanged();
}
@ -402,9 +404,16 @@ public class CUnit extends CWidget {
if (this.buildQueueTypes[0] == QueueItemType.UNIT) {
final CPlayer player = game.getPlayer(this.playerIndex);
final CUnitType trainedUnitType = game.getUnitData().getUnitType(queuedRawcode);
if (trainedUnitType.getFoodUsed() != 0) {
final int newFoodUsed = player.getFoodUsed() + trainedUnitType.getFoodUsed();
if (newFoodUsed <= player.getFoodCap()) {
player.setFoodUsed(newFoodUsed);
player.addTechtreeInProgress(queuedRawcode);
this.queuedUnitFoodPaid = true;
}
}
else {
player.addTechtreeInProgress(queuedRawcode);
this.queuedUnitFoodPaid = true;
}
}
@ -433,6 +442,7 @@ public class CUnit extends CWidget {
trainedUnit.setFoodUsed(trainedUnitType.getFoodUsed());
final CPlayer player = game.getPlayer(this.playerIndex);
player.setUnitFoodMade(trainedUnit, trainedUnitType.getFoodMade());
player.removeTechtreeInProgress(queuedRawcode);
player.addTechtreeUnlocked(queuedRawcode);
// nudge the trained unit out around us
trainedUnit.nudgeAround(game, this);
@ -478,6 +488,7 @@ public class CUnit extends CWidget {
player.addTechtreeUnlocked(queuedRawcode);
// nudge the trained unit out around us
revivingHero.nudgeAround(game, this);
game.unitRepositioned(revivingHero); // dont blend animation
game.heroReviveEvent(this, revivingHero);
if (this.rallyPoint != null) {
final int rallyOrderId = OrderIds.smart;
@ -1014,6 +1025,16 @@ public class CUnit extends CWidget {
if (this.foodUsed != 0) {
player.setUnitFoodUsed(this, 0);
}
if (getHeroData() == null) {
if (this.constructing) {
player.removeTechtreeInProgress(this.unitType.getTypeId());
}
else {
player.removeTechtreeUnlocked(this.unitType.getTypeId());
}
}
// else its a hero and techtree "remains unlocked" which is currently meaning
// the "limit of 1" remains limited
// Award hero experience
if (source != null) {
@ -1468,6 +1489,7 @@ public class CUnit extends CWidget {
final CPlayer player = game.getPlayer(this.playerIndex);
final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[cancelIndex]);
player.setFoodUsed(player.getFoodUsed() - unitType.getFoodUsed());
player.removeTechtreeInProgress(this.buildQueue[cancelIndex]);
break;
}
case HERO_REVIVE: {
@ -1524,12 +1546,16 @@ public class CUnit extends CWidget {
final int newFoodUsed = player.getFoodUsed() + unitType.getFoodUsed();
if (newFoodUsed <= player.getFoodCap()) {
player.setFoodUsed(newFoodUsed);
player.addTechtreeInProgress(rawcode);
}
else {
this.queuedUnitFoodPaid = false;
game.getCommandErrorListener(this.playerIndex).showNoFoodError();
game.getCommandErrorListener().showNoFoodError(this.playerIndex);
}
}
else {
player.addTechtreeInProgress(rawcode);
}
}
else if (queueItemType == QueueItemType.HERO_REVIVE) {
final CPlayer player = game.getPlayer(this.playerIndex);
@ -1541,7 +1567,7 @@ public class CUnit extends CWidget {
}
else {
this.queuedUnitFoodPaid = false;
game.getCommandErrorListener(this.playerIndex).showNoFoodError();
game.getCommandErrorListener().showNoFoodError(this.playerIndex);
}
}
}
@ -1818,7 +1844,21 @@ public class CUnit extends CWidget {
}
public void onRemove(final CSimulation simulation) {
final CPlayer player = simulation.getPlayer(this.playerIndex);
if (WarsmashConstants.FIRE_DEATH_EVENTS_ON_REMOVEUNIT) {
// Firing userspace triggers here causes items to appear around the player bases
// in melee games.
// (See "Remove creeps and critters from used start locations" implementation)
setLife(simulation, 0);
}
else {
if (this.constructing) {
player.removeTechtreeInProgress(this.unitType.getTypeId());
}
else {
player.removeTechtreeUnlocked(this.unitType.getTypeId());
}
}
simulation.getWorldCollision().removeUnit(this);
}
@ -1989,4 +2029,11 @@ public class CUnit extends CWidget {
public void setTriggerEditorCustomValue(final int triggerEditorCustomValue) {
this.triggerEditorCustomValue = triggerEditorCustomValue;
}
public static String maybeMeaningfulName(final CUnit unit) {
if (unit == null) {
return "null";
}
return unit.getUnitType().getName();
}
}

View File

@ -2,6 +2,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build;
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.CUnitType;
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;
@ -34,9 +35,12 @@ public class CAbilityBuildInProgress extends AbstractCAbility {
}
@Override
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId, AbilityTarget target) {
public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId,
final AbilityTarget target) {
final CPlayer player = game.getPlayer(caster.getPlayerIndex());
player.refundFor(caster.getUnitType());
final CUnitType unitType = caster.getUnitType();
player.refundFor(unitType);
player.removeTechtreeInProgress(unitType.getTypeId());
caster.setLife(game, 0);
return false;
}

View File

@ -319,7 +319,7 @@ public class CAbilityInventory extends AbstractGenericNoIconAbility {
}
}
if (playUserUISounds) {
simulation.getCommandErrorListener(hero.getPlayerIndex()).showInventoryFullError();
simulation.getCommandErrorListener().showInventoryFullError(hero.getPlayerIndex());
}
}
}

View File

@ -0,0 +1,118 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.test;
import java.util.EnumSet;
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.generic.AbstractGenericSingleIconNoSmartActiveAbility;
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.test.CBehaviorCarrionSwarmDummy;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
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;
public class CAbilityCarrionSwarmDummy extends AbstractGenericSingleIconNoSmartActiveAbility {
private final float castRange;
private final EnumSet<CTargetType> targetsAllowed;
private CBehaviorCarrionSwarmDummy behaviorCarrionSwarmDummy;
public CAbilityCarrionSwarmDummy(final int handleId, final War3ID alias, final float castRange,
final EnumSet<CTargetType> targetsAllowed) {
super(handleId, alias);
this.castRange = castRange;
this.targetsAllowed = targetsAllowed;
}
@Override
public int getBaseOrderId() {
return OrderIds.carrionswarm;
}
@Override
public boolean isToggleOn() {
return false;
}
@Override
public void onAdd(final CSimulation game, final CUnit unit) {
this.behaviorCarrionSwarmDummy = new CBehaviorCarrionSwarmDummy(unit, this);
}
@Override
public void onRemove(final CSimulation game, final CUnit unit) {
}
@Override
public void onTick(final CSimulation game, final CUnit unit) {
}
@Override
public void onCancelFromQueue(final CSimulation game, final CUnit unit, final int orderId) {
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
return this.behaviorCarrionSwarmDummy.reset(target);
}
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId,
final AbilityPointTarget point) {
return this.behaviorCarrionSwarmDummy.reset(point);
}
@Override
public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) {
return caster.pollNextOrderBehavior(game);
}
@Override
protected void innerCheckCanTarget(final CSimulation game, final CUnit unit, final int orderId,
final CWidget target, final AbilityTargetCheckReceiver<CWidget> receiver) {
if (unit.canReach(target, this.castRange) && target.canBeTargetedBy(game, unit, this.targetsAllowed)) {
receiver.targetOk(target);
}
else {
receiver.targetOutsideRange();
}
}
@Override
protected void innerCheckCanTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityPointTarget target, final AbilityTargetCheckReceiver<AbilityPointTarget> receiver) {
if (unit.canReach(target, this.castRange)) {
receiver.targetOk(target);
}
else {
receiver.targetOutsideRange();
}
}
@Override
protected void innerCheckCanTargetNoTarget(final CSimulation game, final CUnit unit, final int orderId,
final AbilityTargetCheckReceiver<Void> receiver) {
receiver.orderIdNotAccepted();
}
@Override
protected void innerCheckCanUse(final CSimulation game, final CUnit unit, final int orderId,
final AbilityActivationReceiver receiver) {
receiver.useOk();
}
public float getCastRange() {
return this.castRange;
}
public EnumSet<CTargetType> getTargetsAllowed() {
return this.targetsAllowed;
}
}

View File

@ -100,7 +100,7 @@ public class CAbilityCoupleInstant extends AbstractGenericSingleIconNoSmartActiv
possiblePairFinder);
final CUnit coupleTarget = possiblePairFinder.pairMatchFound;
if (coupleTarget == null) {
game.getCommandErrorListener(caster.getPlayerIndex()).showUnableToFindCoupleTargetError();
game.getCommandErrorListener().showUnableToFindCoupleTargetError(caster.getPlayerIndex());
return caster.pollNextOrderBehavior(game);
}
coupleTarget.order(game, new COrderTargetWidget(possiblePairFinder.pairMatchAbility.getHandleId(),

View File

@ -0,0 +1,32 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl;
import java.util.EnumSet;
import java.util.List;
import com.etheller.warsmash.units.manager.MutableObjectData.MutableGameObject;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.CAbilityTypeDefinition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl.CAbilityTypeCarrionSwarmDummy;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl.CAbilityTypeCarrionSwarmDummyLevelData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
public class CAbilityTypeDefinitionCarrionSwarmDummy extends
AbstractCAbilityTypeDefinition<CAbilityTypeCarrionSwarmDummyLevelData> implements CAbilityTypeDefinition {
@Override
protected CAbilityTypeCarrionSwarmDummyLevelData createLevelData(final MutableGameObject abilityEditorData,
final int level) {
final String targetsAllowedAtLevelString = abilityEditorData.getFieldAsString(TARGETS_ALLOWED, level);
final float castRange = abilityEditorData.getFieldAsFloat(CAST_RANGE, level);
final EnumSet<CTargetType> targetsAllowedAtLevel = CTargetType.parseTargetTypeSet(targetsAllowedAtLevelString);
return new CAbilityTypeCarrionSwarmDummyLevelData(targetsAllowedAtLevel, castRange);
}
@Override
protected CAbilityType<?> innerCreateAbilityType(final War3ID alias, final MutableGameObject abilityEditorData,
final List<CAbilityTypeCarrionSwarmDummyLevelData> levelData) {
return new CAbilityTypeCarrionSwarmDummy(alias, abilityEditorData.getCode(), levelData);
}
}

View File

@ -0,0 +1,24 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl;
import java.util.List;
import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.test.CAbilityCarrionSwarmDummy;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
public class CAbilityTypeCarrionSwarmDummy extends CAbilityType<CAbilityTypeCarrionSwarmDummyLevelData> {
public CAbilityTypeCarrionSwarmDummy(final War3ID alias, final War3ID code,
final List<CAbilityTypeCarrionSwarmDummyLevelData> levelData) {
super(alias, code, levelData);
}
@Override
public CAbility createAbility(final int handleId) {
final CAbilityTypeCarrionSwarmDummyLevelData levelData = getLevelData(0);
return new CAbilityCarrionSwarmDummy(handleId, getAlias(), levelData.getCastRange(),
levelData.getTargetsAllowed());
}
}

View File

@ -0,0 +1,20 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.impl;
import java.util.EnumSet;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityTypeLevelData;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType;
public class CAbilityTypeCarrionSwarmDummyLevelData extends CAbilityTypeLevelData {
private final float castRange;
public CAbilityTypeCarrionSwarmDummyLevelData(final EnumSet<CTargetType> targetsAllowed, final float castRange) {
super(targetsAllowed);
this.castRange = castRange;
}
public float getCastRange() {
return this.castRange;
}
}

View File

@ -83,7 +83,7 @@ public class CBehaviorOrcBuild extends CAbstractRangedBehavior {
else {
final CPlayer player = simulation.getPlayer(playerIndex);
refund(player, unitTypeToCreate);
simulation.getCommandErrorListener(playerIndex).showCantPlaceError();
simulation.getCommandErrorListener().showCantPlaceError(playerIndex);
}
}
return this.unit.pollNextOrderBehavior(simulation);

View File

@ -104,7 +104,7 @@ public class CBehaviorUndeadBuild extends CAbstractRangedBehavior {
else {
final CPlayer player = simulation.getPlayer(playerIndex);
refund(player, unitTypeToCreate);
simulation.getCommandErrorListener(playerIndex).showCantPlaceError();
simulation.getCommandErrorListener().showCantPlaceError(playerIndex);
return this.unit.pollNextOrderBehavior(simulation);
}
}

View File

@ -0,0 +1,83 @@
package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.test;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityTargetStillAliveAndTargetableVisitor;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.test.CAbilityCarrionSwarmDummy;
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;
public class CBehaviorCarrionSwarmDummy extends CAbstractRangedBehavior {
private final CAbilityCarrionSwarmDummy abilityCarrionSwarmDummy;
private final AbilityTargetStillAliveAndTargetableVisitor stillAliveAndTargetableVisitor = new AbilityTargetStillAliveAndTargetableVisitor();
public CBehaviorCarrionSwarmDummy(final CUnit unit, final CAbilityCarrionSwarmDummy abilityCarrionSwarmDummy) {
super(unit);
this.abilityCarrionSwarmDummy = abilityCarrionSwarmDummy;
}
public CBehaviorCarrionSwarmDummy reset(final AbilityTarget target) {
innerReset(target);
return this;
}
@Override
public boolean isWithinRange(final CSimulation simulation) {
return this.unit.canReach(this.target, this.abilityCarrionSwarmDummy.getCastRange());
}
@Override
public void endMove(final CSimulation game, final boolean interrupted) {
}
@Override
public void begin(final CSimulation game) {
}
@Override
public void end(final CSimulation game, final boolean interrupted) {
}
@Override
public int getHighlightOrderId() {
return OrderIds.carrionswarm;
}
@Override
protected CBehavior update(final CSimulation simulation, final boolean withinFacingWindow) {
final int playerIndex = this.unit.getPlayerIndex();
if (this.target instanceof AbilityPointTarget) {
simulation.getPlayer(playerIndex).fireAbilityEffectEventsPoint(this.unit,
((AbilityPointTarget) this.target), this.abilityCarrionSwarmDummy.getAlias());
}
else if (this.target instanceof CUnit) {
simulation.getPlayer(playerIndex).fireAbilityEffectEventsTarget(this.unit, ((CUnit) this.target),
this.abilityCarrionSwarmDummy.getAlias());
} // TODO other kinds of widgets
return this.unit.pollNextOrderBehavior(simulation);
}
@Override
protected CBehavior updateOnInvalidTarget(final CSimulation simulation) {
return this.unit.pollNextOrderBehavior(simulation);
}
@Override
protected boolean checkTargetStillValid(final CSimulation simulation) {
return this.target.visit(this.stillAliveAndTargetableVisitor.reset(simulation, this.unit,
this.abilityCarrionSwarmDummy.getTargetsAllowed()));
}
@Override
protected void resetBeforeMoving(final CSimulation simulation) {
}
}

View File

@ -10,7 +10,24 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityGeneric;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.CAbilityType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.CAbilityTypeDefinition;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.*;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionCarrionSwarmDummy;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionChannelTest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionColdArrows;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionCoupleInstant;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionGoldMine;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHarvest;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHarvestLumber;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionHumanRepair;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionInventory;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionInvulnerable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemAttackBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemDefenseBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemHeal;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemLifeBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemPermanentStatGain;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionItemStatBonus;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionReturnResources;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.types.definitions.impl.CAbilityTypeDefinitionWispHarvest;
public class CAbilityData {
@ -32,6 +49,7 @@ public class CAbilityData {
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Awha"), new CAbilityTypeDefinitionWispHarvest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Ahrl"), new CAbilityTypeDefinitionHarvestLumber());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("ANcl"), new CAbilityTypeDefinitionChannelTest());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("AUcs"), new CAbilityTypeDefinitionCarrionSwarmDummy());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("AInv"), new CAbilityTypeDefinitionInventory());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Arep"), new CAbilityTypeDefinitionHumanRepair());
this.codeToAbilityTypeDefinition.put(War3ID.fromString("Avul"), new CAbilityTypeDefinitionInvulnerable());

View File

@ -54,8 +54,8 @@ public class COrderDropItemAtPoint implements COrder {
return ability.beginDropItem(game, caster, this.orderId, itemToDrop, this.target);
}
else {
game.getCommandErrorListener(caster.getPlayerIndex())
.showCommandError(this.abilityActivationReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(),
this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}

View File

@ -54,8 +54,8 @@ public class COrderDropItemAtTargetWidget implements COrder {
return ability.beginDropItem(game, caster, this.orderId, itemToDrop, targetHero);
}
else {
game.getCommandErrorListener(caster.getPlayerIndex())
.showCommandError(this.abilityActivationReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(),
this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}

View File

@ -44,13 +44,13 @@ public class COrderNoTarget implements COrder {
return ability.beginNoTarget(game, caster, this.orderId);
}
else {
game.getCommandErrorListener(caster.getPlayerIndex()).showCommandError(targetReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(), targetReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
else {
game.getCommandErrorListener(caster.getPlayerIndex())
.showCommandError(this.abilityActivationReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(),
this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}

View File

@ -52,13 +52,13 @@ public class COrderTargetPoint implements COrder {
return ability.begin(game, caster, this.orderId, this.target);
}
else {
game.getCommandErrorListener(caster.getPlayerIndex()).showCommandError(targetReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(), targetReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
else {
game.getCommandErrorListener(caster.getPlayerIndex())
.showCommandError(this.abilityActivationReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(),
this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}

View File

@ -55,13 +55,13 @@ public class COrderTargetWidget implements COrder {
return ability.begin(game, caster, this.orderId, targetReceiver.getTarget());
}
else {
game.getCommandErrorListener(caster.getPlayerIndex()).showCommandError(targetReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(), targetReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}
else {
game.getCommandErrorListener(caster.getPlayerIndex())
.showCommandError(this.abilityActivationReceiver.getMessage());
game.getCommandErrorListener().showCommandError(caster.getPlayerIndex(),
this.abilityActivationReceiver.getMessage());
return caster.pollNextOrderBehavior(game);
}
}

View File

@ -29,6 +29,7 @@ public class CPathfindingProcessor {
private int pathfindJobId = 0;
private int totalIterations = 0;
private int totalJobLoops = 0;
private final int pathingGridCellCount;
public CPathfindingProcessor(final PathingGrid pathingGrid, final CWorldCollision worldCollision) {
this.pathingGrid = pathingGrid;
@ -46,6 +47,7 @@ public class CPathfindingProcessor {
new Point2D.Float(pathingGrid.getWorldXFromCorner(j), pathingGrid.getWorldYFromCorner(i)));
}
}
this.pathingGridCellCount = pathingGrid.getWidth() * pathingGrid.getHeight();
}
/**
@ -365,6 +367,7 @@ public class CPathfindingProcessor {
}
lastCameFromDirection = current.cameFromDirection;
Node lastNode = null;
int stepsBackward = 0;
while (current.cameFrom != null) {
lastNode = current;
current = current.cameFrom;
@ -387,6 +390,16 @@ public class CPathfindingProcessor {
lastCameFromDirection = current.cameFromDirection;
}
}
if (stepsBackward > this.pathingGridCellCount) {
throw new IllegalStateException(
"PATHING SYSTEM ERROR: The path finding algorithm hit an infinite cycle at or near pt: "
+ current.cameFrom.point
+ ".\nThis means the A* search algorithm heuristic 'admissable' constraint was probably violated.\n\nUnit1:"
+ CUnit.maybeMeaningfulName(job.ignoreIntersectionsWithThisUnit)
+ "\nUnit2:"
+ CUnit.maybeMeaningfulName(job.ignoreIntersectionsWithThisSecondUnit));
}
stepsBackward++;
}
job.queueItem.pathFound(totalPath, simulation);
this.moveQueue.poll();

View File

@ -17,6 +17,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CPlayerStateListene
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.CUnitType;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.config.CBasePlayer;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.JassGameEventsWar3;
@ -30,6 +31,7 @@ public class CPlayer extends CBasePlayer {
private int foodUsed;
private int foodCapCeiling = 101; // TODO should not have a default, I put 101 to make it stand out
private final Map<War3ID, Integer> rawcodeToTechtreeUnlocked = new HashMap<>();
private final Map<War3ID, Integer> rawcodeToTechtreeInProgress = new HashMap<>();
private final Map<War3ID, Integer> rawcodeToTechtreeMaxAllowed = new HashMap<>();
private final List<CUnit> heroes = new ArrayList<>();
private final EnumMap<JassGameEventsWar3, List<CPlayerEvent>> eventTypeToEvents = new EnumMap<>(
@ -53,7 +55,7 @@ public class CPlayer extends CBasePlayer {
// questionable -- it already was -- but I meant for those to inform us
// which fields shouldn't be persisted if we do game state save later
private transient CPlayerStateNotifier stateNotifier = new CPlayerStateNotifier();
private float handicapXP;
private float handicapXP = 1.0f;
private float handicap = 0.9f;
public CPlayer(final CRace race, final float[] startLocation, final CBasePlayer configPlayer) {
@ -136,6 +138,18 @@ public class CPlayer extends CBasePlayer {
return techtreeUnlocked;
}
public int getTechtreeInProgress(final War3ID rawcode) {
final Integer techtreeInProgress = this.rawcodeToTechtreeInProgress.get(rawcode);
if (techtreeInProgress == null) {
return 0;
}
return techtreeInProgress;
}
public int getTechtreeUnlockedOrInProgress(final War3ID rawcode) {
return getTechtreeUnlocked(rawcode) + getTechtreeInProgress(rawcode);
}
public void addTechtreeUnlocked(final War3ID rawcode) {
final Integer techtreeUnlocked = this.rawcodeToTechtreeUnlocked.get(rawcode);
if (techtreeUnlocked == null) {
@ -156,6 +170,26 @@ public class CPlayer extends CBasePlayer {
}
}
public void addTechtreeInProgress(final War3ID rawcode) {
final Integer techtreeUnlocked = this.rawcodeToTechtreeInProgress.get(rawcode);
if (techtreeUnlocked == null) {
this.rawcodeToTechtreeInProgress.put(rawcode, 1);
}
else {
this.rawcodeToTechtreeInProgress.put(rawcode, techtreeUnlocked + 1);
}
}
public void removeTechtreeInProgress(final War3ID rawcode) {
final Integer techtreeUnlocked = this.rawcodeToTechtreeInProgress.get(rawcode);
if (techtreeUnlocked == null) {
this.rawcodeToTechtreeInProgress.put(rawcode, -1);
}
else {
this.rawcodeToTechtreeInProgress.put(rawcode, techtreeUnlocked - 1);
}
}
public void setTechtreeMaxAllowed(final War3ID war3id, final int maximum) {
this.rawcodeToTechtreeMaxAllowed.put(war3id, maximum);
}
@ -397,7 +431,7 @@ public class CPlayer extends CBasePlayer {
public boolean isTechtreeAllowedByMax(final War3ID techtree) {
final int techtreeMaxAllowed = getTechtreeMaxAllowed(techtree);
if (techtreeMaxAllowed > 0) {
if (getTechtreeUnlocked(techtree) >= techtreeMaxAllowed) {
if (getTechtreeUnlockedOrInProgress(techtree) >= techtreeMaxAllowed) {
return false;
}
}
@ -419,4 +453,30 @@ public class CPlayer extends CBasePlayer {
public float getHandicap() {
return this.handicap;
}
public void fireAbilityEffectEventsTarget(final CUnit spellAbilityUnit, final CUnit spellTargetUnit,
final War3ID alias) {
final List<CPlayerEvent> eventList = getEventList(JassGameEventsWar3.EVENT_PLAYER_UNIT_SPELL_EFFECT);
if (eventList != null) {
for (final CPlayerEvent event : eventList) {
event.fire(spellAbilityUnit,
CommonTriggerExecutionScope.unitSpellEffectTargetScope(
JassGameEventsWar3.EVENT_PLAYER_UNIT_SPELL_EFFECT, event.getTrigger(), spellAbilityUnit,
spellTargetUnit, alias));
}
}
}
public void fireAbilityEffectEventsPoint(final CUnit spellAbilityUnit, final AbilityPointTarget abilityPointTarget,
final War3ID alias) {
final List<CPlayerEvent> eventList = getEventList(JassGameEventsWar3.EVENT_PLAYER_UNIT_SPELL_EFFECT);
if (eventList != null) {
for (final CPlayerEvent event : eventList) {
event.fire(spellAbilityUnit,
CommonTriggerExecutionScope.unitSpellEffectPointScope(
JassGameEventsWar3.EVENT_PLAYER_UNIT_SPELL_EFFECT, event.getTrigger(), spellAbilityUnit,
abilityPointTarget, alias));
}
}
}
}

View File

@ -6,17 +6,20 @@ import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
public class AbilityActivationErrorHandler {
private final int localPlayerIndex;
private final String errorString;
private final UnitSound errorSound;
public AbilityActivationErrorHandler(final String errorString, final UnitSound errorSound) {
public AbilityActivationErrorHandler(final int localPlayerIndex, final String errorString,
final UnitSound errorSound) {
this.localPlayerIndex = localPlayerIndex;
this.errorString = errorString;
this.errorSound = errorSound;
}
public void onClick(final CommandErrorListener commandErrorListener, final AudioContext worldSceneAudioContext,
final RenderUnit commandedUnit) {
commandErrorListener.showCommandError(this.errorString);
commandErrorListener.showCommandError(this.localPlayerIndex, this.errorString);
this.errorSound.playUnitResponse(worldSceneAudioContext, commandedUnit);
}
}

View File

@ -9,7 +9,7 @@ public interface AbilityTargetCheckReceiver<TARGET_TYPE> {
void mustTargetResources();
void targetOutsideRange(double howMuch);
void targetOutsideRange();
void notAnActiveAbility();

View File

@ -39,7 +39,7 @@ public final class BooleanAbilityTargetCheckReceiver<TARGET_TYPE> implements Abi
}
@Override
public void targetOutsideRange(final double howMuch) {
public void targetOutsideRange() {
this.targetable = false;
}

View File

@ -33,7 +33,7 @@ public class CWidgetAbilityTargetCheckReceiver implements AbilityTargetCheckRece
}
@Override
public void targetOutsideRange(final double howMuch) {
public void targetOutsideRange() {
this.target = null;
}

View File

@ -33,7 +33,7 @@ public class PointAbilityTargetCheckReceiver implements AbilityTargetCheckReceiv
}
@Override
public void targetOutsideRange(final double howMuch) {
public void targetOutsideRange() {
this.target = null;
}

View File

@ -69,7 +69,7 @@ public final class StringMsgTargetCheckReceiver<TARGET_TYPE> implements AbilityT
}
@Override
public void targetOutsideRange(final double howMuch) {
public void targetOutsideRange() {
this.message = "NOTEXTERN: Target is outside range.";
}

View File

@ -1089,13 +1089,17 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
createMinimap(this.war3MapViewer);
this.meleeUIAbilityActivationReceiver = new MeleeUIAbilityActivationReceiver(
new AbilityActivationErrorHandler(this.rootFrame.getErrorString("NoGold"),
new AbilityActivationErrorHandler(this.war3MapViewer.getLocalPlayerIndex(),
this.rootFrame.getErrorString("NoGold"),
this.war3MapViewer.getUiSounds().getSound(this.rootFrame.getSkinField("NoGoldSound"))),
new AbilityActivationErrorHandler(this.rootFrame.getErrorString("NoLumber"),
new AbilityActivationErrorHandler(this.war3MapViewer.getLocalPlayerIndex(),
this.rootFrame.getErrorString("NoLumber"),
this.war3MapViewer.getUiSounds().getSound(this.rootFrame.getSkinField("NoLumberSound"))),
new AbilityActivationErrorHandler(this.rootFrame.getErrorString("NoFood"),
new AbilityActivationErrorHandler(this.war3MapViewer.getLocalPlayerIndex(),
this.rootFrame.getErrorString("NoFood"),
this.war3MapViewer.getUiSounds().getSound(this.rootFrame.getSkinField("NoFoodSound"))),
new AbilityActivationErrorHandler("", this.war3MapViewer.getUiSounds().getSound("InterfaceError")));
new AbilityActivationErrorHandler(this.war3MapViewer.getLocalPlayerIndex(), "",
this.war3MapViewer.getUiSounds().getSound("InterfaceError")));
final MdxModel rallyModel = this.war3MapViewer.loadModelMdx(this.rootFrame.getSkinField("RallyIndicatorDst"));
this.rallyPointInstance = (MdxComplexInstance) rallyModel.addInstance();
@ -1217,7 +1221,8 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
@Override
public void showCommandError(final String message) {
public void showCommandError(final int playerIndex, final String message) {
if (playerIndex == this.war3MapViewer.getLocalPlayerIndex()) {
this.rootFrame.setText(this.errorMessageFrame, message);
this.errorMessageFrame.setVisible(true);
final long millis = TimeUtils.millis();
@ -1225,6 +1230,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.lastErrorMessageFadeTime = millis + WORLD_FRAME_MESSAGE_FADEOUT_MILLIS;
this.errorMessageFrame.setAlpha(1.0f);
}
}
public void showGameMessage(final String message, final float expireTime) {
this.rootFrame.setText(this.gameMessagesFrame, message);
@ -1237,31 +1243,39 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
}
@Override
public void showCantPlaceError() {
showCommandError(this.rootFrame.getErrorString("Cantplace"));
public void showCantPlaceError(final int playerIndex) {
if (playerIndex == this.war3MapViewer.getLocalPlayerIndex()) {
showCommandError(playerIndex, this.rootFrame.getErrorString("Cantplace"));
this.war3MapViewer.getUiSounds().getSound(this.rootFrame.getSkinField("CantPlaceSound"))
.play(this.uiScene.audioContext, 0, 0, 0);
}
}
@Override
public void showNoFoodError() {
showCommandError(this.rootFrame.getErrorString("NoFood"));
public void showNoFoodError(final int playerIndex) {
if (playerIndex == this.war3MapViewer.getLocalPlayerIndex()) {
showCommandError(playerIndex, this.rootFrame.getErrorString("NoFood"));
this.war3MapViewer.getUiSounds().getSound(this.rootFrame.getSkinField("NoFoodSound"))
.play(this.uiScene.audioContext, 0, 0, 0);
}
@Override
public void showUnableToFindCoupleTargetError() {
showCommandError(this.rootFrame.getErrorString("Cantfindcoupletarget"));
this.war3MapViewer.getUiSounds().getSound("InterfaceError").play(this.uiScene.audioContext, 0, 0, 0);
}
@Override
public void showInventoryFullError() {
showCommandError(this.rootFrame.getErrorString("InventoryFull"));
public void showUnableToFindCoupleTargetError(final int playerIndex) {
if (playerIndex == this.war3MapViewer.getLocalPlayerIndex()) {
showCommandError(playerIndex, this.rootFrame.getErrorString("Cantfindcoupletarget"));
this.war3MapViewer.getUiSounds().getSound("InterfaceError").play(this.uiScene.audioContext, 0, 0, 0);
}
}
@Override
public void showInventoryFullError(final int playerIndex) {
if (playerIndex == this.war3MapViewer.getLocalPlayerIndex()) {
showCommandError(playerIndex, this.rootFrame.getErrorString("InventoryFull"));
this.war3MapViewer.getUiSounds().getSound(this.rootFrame.getSkinField("InventoryFullSound"))
.play(this.uiScene.audioContext, 0, 0, 0);
}
}
public void update(final float deltaTime) {
this.portrait.update();

View File

@ -533,20 +533,19 @@ public class MenuUI {
mapListBox.setSelectionListener(new ListBoxSelelectionListener() {
@Override
public void onSelectionChanged(final int newSelectedIndex, final String newSelectedItem) {
War3Map map;
try {
map = War3MapViewer.beginLoadingMap(MenuUI.this.dataSource, newSelectedItem);
final War3Map map = War3MapViewer.beginLoadingMap(MenuUI.this.dataSource, newSelectedItem);
final War3MapW3i mapInfo = map.readMapInformation();
final WTS wtsFile = Warcraft3MapObjectData.loadWTS(map);
MenuUI.this.rootFrame.setMapStrings(wtsFile);
final War3MapConfig war3MapConfig = new War3MapConfig(WarsmashConstants.MAX_PLAYERS);
for (int i = 0; (i < war3MapConfig.getPlayerCount()) && (i < mapInfo.getPlayers().size()); i++) {
for (int i = 0; (i < WarsmashConstants.MAX_PLAYERS) && (i < mapInfo.getPlayers().size()); i++) {
final CBasePlayer player = war3MapConfig.getPlayer(i);
player.setName(MenuUI.this.rootFrame.getTrigStr(mapInfo.getPlayers().get(i).getName()));
}
Jass2.loadConfig(map, MenuUI.this.uiViewport, MenuUI.this.uiScene, MenuUI.this.rootFrame,
war3MapConfig, "Scripts\\common.j", "Scripts\\Blizzard.j", "war3map.j").config();
for (int i = 0; i < war3MapConfig.getPlayerCount(); i++) {
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
final CBasePlayer player = war3MapConfig.getPlayer(i);
if (player.getController() == CMapControl.USER) {
player.setSlotState(CPlayerSlotState.PLAYING);
@ -817,6 +816,33 @@ public class MenuUI {
public void startMap(final String mapFilename) {
this.mainMenuFrame.setVisible(false);
try {
final War3Map map = War3MapViewer.beginLoadingMap(MenuUI.this.dataSource, mapFilename);
final War3MapW3i mapInfo = map.readMapInformation();
final WTS wtsFile = Warcraft3MapObjectData.loadWTS(map);
MenuUI.this.rootFrame.setMapStrings(wtsFile);
final War3MapConfig war3MapConfig = new War3MapConfig(WarsmashConstants.MAX_PLAYERS);
for (int i = 0; (i < WarsmashConstants.MAX_PLAYERS) && (i < mapInfo.getPlayers().size()); i++) {
final CBasePlayer player = war3MapConfig.getPlayer(i);
player.setName(MenuUI.this.rootFrame.getTrigStr(mapInfo.getPlayers().get(i).getName()));
}
Jass2.loadConfig(map, MenuUI.this.uiViewport, MenuUI.this.uiScene, MenuUI.this.rootFrame, war3MapConfig,
"Scripts\\common.j", "Scripts\\Blizzard.j", "war3map.j").config();
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
final CBasePlayer player = war3MapConfig.getPlayer(i);
if (player.getController() == CMapControl.USER) {
player.setSlotState(CPlayerSlotState.PLAYING);
// player.setName(MenuUI.this.profileManager.getCurrentProfile());
// break;
}
}
MenuUI.this.currentMapConfig = war3MapConfig;
}
catch (final IOException e) {
e.printStackTrace();
}
internalStartMap(mapFilename);
}

View File

@ -1,13 +1,13 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui.command;
public interface CommandErrorListener {
void showCommandError(String message);
void showCommandError(int playerIndex, String message);
void showCantPlaceError();
void showCantPlaceError(int playerIndex);
void showNoFoodError();
void showNoFoodError(int playerIndex);
void showInventoryFullError();
void showInventoryFullError(int playerIndex);
void showUnableToFindCoupleTargetError();
void showUnableToFindCoupleTargetError(int playerIndex);
}

View File

@ -4,23 +4,23 @@ public class SettableCommandErrorListener implements CommandErrorListener {
private CommandErrorListener delegate;
@Override
public void showCommandError(final String message) {
this.delegate.showCommandError(message);
public void showCommandError(final int playerIndex, final String message) {
this.delegate.showCommandError(playerIndex, message);
}
@Override
public void showCantPlaceError() {
this.delegate.showCantPlaceError();
public void showCantPlaceError(final int playerIndex) {
this.delegate.showCantPlaceError(playerIndex);
}
@Override
public void showNoFoodError() {
this.delegate.showNoFoodError();
public void showNoFoodError(final int playerIndex) {
this.delegate.showNoFoodError(playerIndex);
}
@Override
public void showInventoryFullError() {
this.delegate.showInventoryFullError();
public void showInventoryFullError(final int playerIndex) {
this.delegate.showInventoryFullError(playerIndex);
}
public void setDelegate(final CommandErrorListener delegate) {
@ -28,7 +28,7 @@ public class SettableCommandErrorListener implements CommandErrorListener {
}
@Override
public void showUnableToFindCoupleTargetError() {
this.delegate.showUnableToFindCoupleTargetError();
public void showUnableToFindCoupleTargetError(final int playerIndex) {
this.delegate.showUnableToFindCoupleTargetError(playerIndex);
}
}

View File

@ -37,7 +37,8 @@ public class PlayerSlotPane {
public PlayerSlotPane(final GameUI rootFrame, final Viewport uiViewport, final SimpleFrame container,
final int index) {
this.index = index;
this.playerSlotFrame = (SimpleFrame) rootFrame.createFrame("PlayerSlot", container, 0, index);
this.playerSlotFrame = (SimpleFrame) rootFrame.createFrameByType("SIMPLEFRAME", "PlayerSlot", container,
"WITHCHILDREN", index);
container.add(this.playerSlotFrame);
this.downloadValue = (StringFrame) rootFrame.getFrameByName("DownloadValue", index);

View File

@ -232,10 +232,10 @@ public final class GlobalScope {
public void replayQueuedTriggers() {
this.runningTriggerQueue.clear();
this.runningTriggerQueue.addAll(this.triggerQueue);
this.triggerQueue.clear();
for (final QueuedCallback trigger : this.runningTriggerQueue) {
trigger.fire(this);
}
this.triggerQueue.clear();
}
private static interface QueuedCallback {

View File

@ -69,7 +69,7 @@ public class Trigger {
action.call(Collections.emptyList(), globalScope, triggerScope);
}
catch (final Exception e) {
if (e.getMessage().startsWith("Needs to sleep")) {
if ((e.getMessage() != null) && e.getMessage().startsWith("Needs to sleep")) {
// TODO not good design
e.printStackTrace();
}