Some updates to attempt to support loading a 1.32 map

This commit is contained in:
Retera 2021-11-03 20:05:06 -04:00
parent 38f67af599
commit 92fc60eb45
45 changed files with 756 additions and 93 deletions

View File

@ -29,6 +29,7 @@ import com.etheller.interpreter.ast.scope.trigger.Trigger;
import com.etheller.interpreter.ast.scope.trigger.TriggerBooleanExpression;
import com.etheller.interpreter.ast.scope.variableevent.CLimitOp;
import com.etheller.interpreter.ast.util.CHandle;
import com.etheller.interpreter.ast.util.JassSettings;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.HandleJassValue;
@ -68,6 +69,7 @@ import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSound;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.RenderCorner;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderDestructable;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.RenderUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.ItemUI;
@ -134,9 +136,11 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.enumtypes.C
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.trigger.enumtypes.CWeaponSoundTypeJass;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.unit.CUnitTypeJass;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityActivationReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.BooleanAbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.CHashtable;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.PointAbilityTargetCheckReceiver;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MeleeUI;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog.CScriptDialog;
public class Jass2 {
public static final boolean REPORT_SYNTAX_ERRORS = true;
@ -538,6 +542,7 @@ public class Jass2 {
final HandleJassType imageType = globals.registerHandleType("image");
final HandleJassType ubersplatType = globals.registerHandleType("ubersplat");
final HandleJassType hashtableType = globals.registerHandleType("hashtable");
final HandleJassType frameHandleType = globals.registerHandleType("framehandle");
jassProgramVisitor.getJassNativeManager().createNative("ConvertRace", new JassFunction() {
@Override
@ -1226,7 +1231,8 @@ public class Jass2 {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new HandleJassValue(timerType, new CTimerJass(globalScope));
return new HandleJassValue(timerType,
new CTimerJass(globalScope, simulation.getHandleIdAllocator().createId()));
}
});
jassProgramVisitor.getJassNativeManager().createNative("DestroyTimer", new JassFunction() {
@ -1245,7 +1251,7 @@ public class Jass2 {
final CTimerJass timer = arguments.get(0).visit(ObjectJassValueVisitor.<CTimerJass>getInstance());
final Double timeout = arguments.get(1).visit(RealJassValueVisitor.getInstance());
final boolean periodic = arguments.get(2).visit(BooleanJassValueVisitor.getInstance());
final JassFunction handlerFunc = arguments.get(3).visit(JassFunctionJassValueVisitor.getInstance());
final JassFunction handlerFunc = nullable(arguments, 3, JassFunctionJassValueVisitor.getInstance());
if (!timer.isRunning()) {
timer.setTimeoutTime(timeout.floatValue());
timer.setRepeats(periodic);
@ -1393,6 +1399,9 @@ public class Jass2 {
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CUnit whichUnit = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
if (whichUnit == null) {
return BooleanJassValue.FALSE;
}
final String orderString = arguments.get(1).visit(StringJassValueVisitor.getInstance());
final Point2D.Double whichLocation = arguments.get(2)
.visit(ObjectJassValueVisitor.<Point2D.Double>getInstance());
@ -1415,8 +1424,37 @@ public class Jass2 {
}
}
}
defaultPlayerUnitOrderExecutor.issuePointOrder(whichUnit.getHandleId(), abilityHandleId, orderId,
targetAsPoint.x, targetAsPoint.y, false);
if (abilityHandleId != 0) {
defaultPlayerUnitOrderExecutor.issuePointOrder(whichUnit.getHandleId(), abilityHandleId,
orderId, targetAsPoint.x, targetAsPoint.y, false);
}
return BooleanJassValue.of(abilityHandleId != 0);
}
});
jassProgramVisitor.getJassNativeManager().createNative("IssueImmediateOrder", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CUnit whichUnit = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final String orderString = arguments.get(1).visit(StringJassValueVisitor.getInstance());
final CPlayerUnitOrderExecutor defaultPlayerUnitOrderExecutor = simulation
.getDefaultPlayerUnitOrderExecutor(whichUnit.getPlayerIndex());
final BooleanAbilityActivationReceiver activationReceiver = BooleanAbilityActivationReceiver.INSTANCE;
final int orderId = OrderIdUtils.getOrderId(orderString);
int abilityHandleId = 0;
for (final CAbility ability : whichUnit.getAbilities()) {
ability.checkCanUse(simulation, whichUnit, orderId, activationReceiver);
if (activationReceiver.isOk()) {
final BooleanAbilityTargetCheckReceiver<Void> targetReceiver = BooleanAbilityTargetCheckReceiver
.<Void>getInstance();
ability.checkCanTargetNoTarget(simulation, whichUnit, orderId, targetReceiver.reset());
if (targetReceiver.isTargetable()) {
abilityHandleId = ability.getHandleId();
}
}
}
defaultPlayerUnitOrderExecutor.issueImmediateOrder(whichUnit.getHandleId(), abilityHandleId,
orderId, false);
return BooleanJassValue.of(abilityHandleId != 0);
}
});
@ -1915,12 +1953,12 @@ public class Jass2 {
.visit(ObjectJassValueVisitor.<List<CPlayerJass>>getInstance());
final CPlayerJass player = arguments.get(1)
.visit(ObjectJassValueVisitor.<CPlayerJass>getInstance());
final TriggerBooleanExpression filter = arguments.get(2)
.visit(ObjectJassValueVisitor.<TriggerBooleanExpression>getInstance());
final TriggerBooleanExpression filter = nullable(arguments, 2,
ObjectJassValueVisitor.<TriggerBooleanExpression>getInstance());
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
final CPlayerJass jassPlayer = simulation.getPlayer(i);
if (!player.hasAlliance(i, CAllianceType.PASSIVE)) {
if (filter.evaluate(globalScope,
if ((filter != null) && filter.evaluate(globalScope,
CommonTriggerExecutionScope.filterScope(triggerScope, jassPlayer))) {
force.add(jassPlayer);
}
@ -2337,7 +2375,7 @@ public class Jass2 {
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final Trigger trigger = arguments.get(0).visit(ObjectJassValueVisitor.<Trigger>getInstance());
final String varName = arguments.get(1).visit(ObjectJassValueVisitor.<String>getInstance());
final String varName = arguments.get(1).visit(StringJassValueVisitor.getInstance());
final CLimitOp limitOp = arguments.get(2).visit(ObjectJassValueVisitor.<CLimitOp>getInstance());
final Double limitval = arguments.get(3).visit(RealJassValueVisitor.getInstance());
final RemovableTriggerEvent event = globalScope.registerVariableEvent(trigger, varName, limitOp,
@ -2399,11 +2437,112 @@ public class Jass2 {
simulation.registerTimeOfDayEvent(globalScope, trigger, opcode, limitval.doubleValue()));
}
});
if (JassSettings.CONTINUE_EXECUTING_ON_ERROR) {
// TODO this is a dumb stub that wont function
jassProgramVisitor.getJassNativeManager().createNative("TriggerRegisterUnitStateEvent",
new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new HandleJassValue(eventType, RemovableTriggerEvent.DO_NOTHING);
}
});
}
jassProgramVisitor.getJassNativeManager().createNative("DialogCreate", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new HandleJassValue(dialogType, meleeUI.createScriptDialog(globalScope));
}
});
jassProgramVisitor.getJassNativeManager().createNative("DialogDestroy", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CScriptDialog dialog = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
meleeUI.destroyDialog(dialog);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("DialogClear", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CScriptDialog dialog = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
meleeUI.clearDialog(dialog);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("DialogSetMessage", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CScriptDialog dialog = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final String messageText = arguments.get(1).visit(StringJassValueVisitor.getInstance());
dialog.setTitle(CommonEnvironment.this.gameUI, messageText);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("DialogAddButton", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CScriptDialog dialog = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final String buttonText = arguments.get(1).visit(StringJassValueVisitor.getInstance());
final int hotkeyInt = arguments.get(2).visit(IntegerJassValueVisitor.getInstance());
meleeUI.createScriptDialogButton(dialog, buttonText, (char) hotkeyInt);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("DialogDisplay", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CPlayerJass player = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final CScriptDialog whichDialog = arguments.get(1).visit(ObjectJassValueVisitor.getInstance());
final boolean flag = arguments.get(2).visit(BooleanJassValueVisitor.getInstance());
if (player.getId() == war3MapViewer.getLocalPlayerIndex()) {
whichDialog.setVisible(flag);
}
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("SetUnitAcquireRange", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CUnit unit = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final double range = arguments.get(1).visit(RealJassValueVisitor.getInstance());
unit.setAcquisitionRange((float) range);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetClickedButton", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new HandleJassValue(buttonType,
((CommonTriggerExecutionScope) triggerScope).getClickedButton());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetClickedDialog", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
return new HandleJassValue(dialogType,
((CommonTriggerExecutionScope) triggerScope).getClickedDialog());
}
});
jassProgramVisitor.getJassNativeManager().createNative("TriggerRegisterDialogEvent", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
throw new UnsupportedOperationException("Not yet implemented: TriggerRegisterDialogEvent");
final Trigger trigger = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final CScriptDialog dialog = arguments.get(1).visit(ObjectJassValueVisitor.getInstance());
if (dialog == null) {
return new HandleJassValue(eventType, RemovableTriggerEvent.DO_NOTHING);
}
return new HandleJassValue(eventType, dialog.addEvent(trigger));
}
});
jassProgramVisitor.getJassNativeManager().createNative("TriggerRegisterDialogButtonEvent",
@ -2797,6 +2936,27 @@ public class Jass2 {
simulation.createDestructable(new War3ID(rawcode), x, y, facing, scale, variation));
}
});
jassProgramVisitor.getJassNativeManager().createNative("BlzCreateDestructableWithSkin", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
int rawcode = arguments.get(0).visit(IntegerJassValueVisitor.getInstance());
final float x = arguments.get(1).visit(RealJassValueVisitor.getInstance()).floatValue();
final float y = arguments.get(2).visit(RealJassValueVisitor.getInstance()).floatValue();
final float facing = arguments.get(3).visit(RealJassValueVisitor.getInstance()).floatValue();
final float scale = arguments.get(4).visit(RealJassValueVisitor.getInstance()).floatValue();
final int variation = arguments.get(5).visit(IntegerJassValueVisitor.getInstance());
final int skinId = arguments.get(6).visit(IntegerJassValueVisitor.getInstance());
if (skinId != rawcode) {
// throw new IllegalStateException(
// "Our engine does not support DestructableSkinID != DestructableID (skinId="
// + new War3ID(skinId) + ", destId=" + new War3ID(rawcode) + ")");
rawcode = skinId;
}
return new HandleJassValue(destructableType,
simulation.createDestructable(new War3ID(rawcode), x, y, facing, scale, variation));
}
});
jassProgramVisitor.getJassNativeManager().createNative("CreateDestructableZ", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -2853,6 +3013,35 @@ public class Jass2 {
return new HandleJassValue(unitType, newUnit);
}
});
jassProgramVisitor.getJassNativeManager().createNative("BlzCreateUnitWithSkin", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CPlayer player = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
int rawcode = arguments.get(1).visit(IntegerJassValueVisitor.getInstance());
final double x = arguments.get(2).visit(RealJassValueVisitor.getInstance());
final double y = arguments.get(3).visit(RealJassValueVisitor.getInstance());
final double facing = arguments.get(4).visit(RealJassValueVisitor.getInstance());
final int skinId = arguments.get(5).visit(IntegerJassValueVisitor.getInstance());
final CUnit newUnit = simulation.createUnit(new War3ID(rawcode), player.getId(), (float) x,
(float) y, (float) facing);
final CUnitType newUnitType = newUnit.getUnitType();
final int foodUsed = newUnitType.getFoodUsed();
newUnit.setFoodUsed(foodUsed);
player.setFoodUsed(player.getFoodUsed() + foodUsed);
if (newUnitType.getFoodMade() != 0) {
player.setFoodCap(player.getFoodCap() + newUnitType.getFoodMade());
}
// nudge unit
newUnit.setPointAndCheckUnstuck((float) x, (float) y, simulation);
if (skinId != rawcode) {
// throw new IllegalStateException("Our engine does not support UnitSkinID != UnitID (skinId="
// + new War3ID(skinId) + ", unitId=" + new War3ID(rawcode) + ")");
rawcode = skinId;
}
return new HandleJassValue(unitType, newUnit);
}
});
jassProgramVisitor.getJassNativeManager().createNative("CreateUnitAtLoc", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -2926,6 +3115,9 @@ public class Jass2 {
final TriggerExecutionScope triggerScope) {
final CUnit whichUnit = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final CUnitState whichUnitState = arguments.get(1).visit(ObjectJassValueVisitor.getInstance());
if (whichUnit == null) {
return RealJassValue.ZERO;
}
return new RealJassValue(whichUnit.getUnitState(simulation, whichUnitState));
}
});
@ -3297,6 +3489,23 @@ public class Jass2 {
return new RealJassValue(whichWidget.getY());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetUnitPointValue", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final CUnit whichWidget = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
return new IntegerJassValue(whichWidget.getUnitType().getPointValue());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetUnitPointValueByType", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final int rawcode = arguments.get(0).visit(IntegerJassValueVisitor.getInstance());
return new IntegerJassValue(
simulation.getUnitData().getUnitType(new War3ID(rawcode)).getPointValue());
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetItemX", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -3337,6 +3546,9 @@ public class Jass2 {
final TriggerExecutionScope triggerScope) {
final CUnit whichWidget = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final int rawcode = arguments.get(1).visit(IntegerJassValueVisitor.getInstance());
if (whichWidget == null) {
return IntegerJassValue.ZERO;
}
final CAbility ability = whichWidget
.getAbility(GetAbilityByRawcodeVisitor.getInstance().reset(new War3ID(rawcode)));
// TODO below code is very stupid!!
@ -3383,6 +3595,14 @@ public class Jass2 {
return new IntegerJassValue(whichHandle.getHandleId());
}
});
jassProgramVisitor.getJassNativeManager().createNative("TriggerSleepAction", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final double time = arguments.get(0).visit(RealJassValueVisitor.getInstance());
throw new IllegalStateException("Needs to sleep " + time);
}
});
jassProgramVisitor.getJassNativeManager().createNative("GetPlayerNeutralAggressive", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
@ -3484,6 +3704,9 @@ public class Jass2 {
final TriggerExecutionScope triggerScope) {
final CUnit whichUnit = arguments.get(0).visit(ObjectJassValueVisitor.getInstance());
final int whichSlot = arguments.get(1).visit(IntegerJassValueVisitor.getInstance());
if (whichUnit == null) {
return new HandleJassValue(itemType, null);
}
final CAbilityInventory inventoryData = whichUnit.getInventoryData();
if (inventoryData != null) {
return new HandleJassValue(itemType, inventoryData.getItemInSlot(whichSlot));
@ -3796,11 +4019,17 @@ public class Jass2 {
if (distSquared <= rSquared) {
for (float pathX = -64; pathX < 64; pathX += 32f) {
for (float pathY = -64; pathY < 64; pathY += 32f) {
simulation.getPathingGrid().setBlighted(x + pathX + 16, y + pathY + 16,
addBlight);
final float blightX = x + pathX + 16;
final float blightY = y + pathY + 16;
if (simulation.getPathingGrid().contains(blightX, blightY)) {
simulation.getPathingGrid().setBlighted(blightX, blightY, addBlight);
}
}
}
war3MapViewer.terrain.getCorner(x, y).setBlight(true);
final RenderCorner corner = war3MapViewer.terrain.getCorner(x, y);
if (corner != null) {
corner.setBlight(true);
}
}
}
}
@ -4773,6 +5002,15 @@ public class Jass2 {
return arg.visit(visitor);
}
private static JassFunction nullable(final List<JassValue> arguments, final int index,
final JassFunctionJassValueVisitor visitor) {
final JassValue arg = arguments.get(index);
if (arg == null) {
return null;
}
return arg.visit(visitor);
}
private static void doPreloadScript(final DataSource dataSource, final War3MapViewer war3MapViewer,
final String filename) {
final JassProgramVisitor jassProgramVisitor = new JassProgramVisitor();

View File

@ -9,6 +9,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget;
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;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog.CScriptDialog;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog.CScriptDialogButton;
public class CommonTriggerExecutionScope extends TriggerExecutionScope {
private CUnit triggeringUnit;
@ -65,6 +67,8 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
private CItem orderTargetItem;
private CUnit orderTargetUnit;
private CWidget triggerWidget;
private CScriptDialog clickedDialog;
private CScriptDialogButton clickedButton;
public CommonTriggerExecutionScope(final Trigger triggeringTrigger) {
super(triggeringTrigger);
@ -136,6 +140,8 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
this.orderTargetItem = parentScope.orderTargetItem;
this.orderTargetUnit = parentScope.orderTargetUnit;
this.triggerWidget = parentScope.triggerWidget;
this.clickedDialog = parentScope.clickedDialog;
this.clickedButton = parentScope.clickedButton;
}
public CUnit getEnumUnit() {
@ -354,6 +360,14 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
return this.orderTargetUnit;
}
public CScriptDialogButton getClickedButton() {
return this.clickedButton;
}
public CScriptDialog getClickedDialog() {
return this.clickedDialog;
}
public static CommonTriggerExecutionScope filterScope(final TriggerExecutionScope parentScope,
final CUnit filterUnit) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(parentScope.getTriggeringTrigger(),
@ -426,6 +440,7 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
final TriggerExecutionScope parentScope, final CUnit enteringUnit, final CRegion triggeringRegion) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, parentScope);
scope.enteringUnit = enteringUnit;
scope.triggeringUnit = enteringUnit;
scope.triggeringRegion = triggeringRegion;
return scope;
}
@ -434,18 +449,21 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
final TriggerExecutionScope parentScope, final CUnit leavingUnit, final CRegion triggeringRegion) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, parentScope);
scope.leavingUnit = leavingUnit;
scope.triggeringUnit = leavingUnit;
scope.triggeringRegion = triggeringRegion;
return scope;
}
public static CommonTriggerExecutionScope playerHeroLevelScope(final Trigger trigger, final CUnit hero) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
scope.triggeringUnit = hero;
scope.levelingUnit = hero;
return scope;
}
public static CommonTriggerExecutionScope playerHeroRevivableScope(final Trigger trigger, final CUnit hero) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
scope.triggeringUnit = hero;
scope.revivableUnit = hero;
return scope;
}
@ -466,6 +484,14 @@ public class CommonTriggerExecutionScope extends TriggerExecutionScope {
return scope;
}
public static CommonTriggerExecutionScope triggerDialogScope(final Trigger trigger,
final CScriptDialog clickedDialog, final CScriptDialogButton clickedButton) {
final CommonTriggerExecutionScope scope = new CommonTriggerExecutionScope(trigger, TriggerExecutionScope.EMPTY);
scope.clickedDialog = clickedDialog;
scope.clickedButton = clickedButton;
return scope;
}
public static interface UnitEventScopeBuilder {
CommonTriggerExecutionScope create(Trigger trigger, CUnit unit);
}

View File

@ -106,20 +106,20 @@ public class War3Map implements DataSource {
return pathingMap;
}
public War3MapDoo readDoodads() throws IOException {
public War3MapDoo readDoodads(final War3MapW3i war3MapW3i) throws IOException {
War3MapDoo doodadsFile;
try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream(
this.dataSource.getResourceAsStream("war3map.doo"))) {
doodadsFile = new War3MapDoo(stream);
doodadsFile = new War3MapDoo(stream, war3MapW3i);
}
return doodadsFile;
}
public War3MapUnitsDoo readUnits() throws IOException {
public War3MapUnitsDoo readUnits(final War3MapW3i war3MapW3i) throws IOException {
War3MapUnitsDoo unitsFile;
try (LittleEndianDataInputStream stream = new LittleEndianDataInputStream(
this.dataSource.getResourceAsStream("war3mapUnits.doo"))) {
unitsFile = new War3MapUnitsDoo(stream);
unitsFile = new War3MapUnitsDoo(stream, war3MapW3i);
}
return unitsFile;
}

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
@ -11,6 +12,7 @@ import com.google.common.io.LittleEndianDataOutputStream;
public class Doodad {
private War3ID id;
private War3ID skinId;
private int variation;
private final float[] location = new float[3];
private float angle;
@ -22,12 +24,21 @@ public class Doodad {
private int editorId;
private final short[] u1 = new short[8]; // short to store unsigned byte, java problem
public void load(final LittleEndianDataInputStream stream, final int version) throws IOException {
public void load(final LittleEndianDataInputStream stream, final int version, final War3MapW3i mapInformation)
throws IOException {
this.id = ParseUtils.readWar3ID(stream);
this.variation = stream.readInt();
ParseUtils.readFloatArray(stream, this.location);
this.angle = stream.readFloat();
ParseUtils.readFloatArray(stream, this.scale);
if (((mapInformation.getGameVersionMajor() * 100) + mapInformation.getGameVersionMinor()) >= 132) {
this.skinId = ParseUtils.readWar3ID(stream);
}
else {
this.skinId = this.id;
}
this.flags = ParseUtils.readUInt8(stream);
this.life = ParseUtils.readUInt8(stream);

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
@ -20,13 +21,13 @@ public class War3MapDoo {
private final short[] u2 = new short[4];
private final List<TerrainDoodad> terrainDoodads = new ArrayList<>();
public War3MapDoo(final LittleEndianDataInputStream stream) throws IOException {
public War3MapDoo(final LittleEndianDataInputStream stream, final War3MapW3i mapInformation) throws IOException {
if (stream != null) {
this.load(stream);
this.load(stream, mapInformation);
}
}
private boolean load(final LittleEndianDataInputStream stream) throws IOException {
private boolean load(final LittleEndianDataInputStream stream, final War3MapW3i mapInformation) throws IOException {
final War3ID firstId = ParseUtils.readWar3ID(stream);
if (!MAGIC_NUMBER.equals(firstId)) {
return false;
@ -38,7 +39,7 @@ public class War3MapDoo {
for (int i = 0, l = stream.readInt(); i < l; i++) {
final Doodad doodad = new Doodad();
doodad.load(stream, this.version);
doodad.load(stream, this.version, mapInformation);
this.doodads.add(doodad);
}

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
@ -11,6 +12,7 @@ import com.google.common.io.LittleEndianDataOutputStream;
public class Unit {
private War3ID id;
private War3ID skinId;
private int variation;
private final float[] location = new float[3];
private float angle;
@ -52,12 +54,21 @@ public class Unit {
private int waygate;
private int creationNumber;
public void load(final LittleEndianDataInputStream stream, final int version) throws IOException {
public void load(final LittleEndianDataInputStream stream, final int version, final War3MapW3i mapInformation)
throws IOException {
this.id = ParseUtils.readWar3ID(stream);
this.variation = stream.readInt();
ParseUtils.readFloatArray(stream, this.location);
this.angle = stream.readFloat();
ParseUtils.readFloatArray(stream, this.scale);
if (((mapInformation.getGameVersionMajor() * 100) + mapInformation.getGameVersionMinor()) >= 132) {
this.skinId = ParseUtils.readWar3ID(stream);
}
else {
this.skinId = this.id;
}
this.flags = ParseUtils.readUInt8(stream);
this.player = stream.readInt();
this.unknown = ParseUtils.readUInt16(stream);

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.etheller.warsmash.parsers.w3x.w3i.War3MapW3i;
import com.etheller.warsmash.util.ParseUtils;
import com.etheller.warsmash.util.War3ID;
import com.google.common.io.LittleEndianDataInputStream;
@ -15,13 +16,14 @@ public class War3MapUnitsDoo {
private long unknown = 11;
private final List<Unit> units = new ArrayList<>();
public War3MapUnitsDoo(final LittleEndianDataInputStream stream) throws IOException {
public War3MapUnitsDoo(final LittleEndianDataInputStream stream, final War3MapW3i mapInformation)
throws IOException {
if (stream != null) {
this.load(stream);
this.load(stream, mapInformation);
}
}
private boolean load(final LittleEndianDataInputStream stream) throws IOException {
private boolean load(final LittleEndianDataInputStream stream, final War3MapW3i mapInformation) throws IOException {
final War3ID firstId = ParseUtils.readWar3ID(stream);
if (!MAGIC_NUMBER.equals(firstId)) {
return false;
@ -33,7 +35,7 @@ public class War3MapUnitsDoo {
for (int i = 0, l = stream.readInt(); i < l; i++) {
final Unit unit = new Unit();
unit.load(stream, this.version);
unit.load(stream, this.version, mapInformation);
this.units.add(unit);
}

View File

@ -15,7 +15,10 @@ public class War3MapW3i {
private int version;
private int saves;
private int editorVersion;
private final short[] unknown1 = new short[16];
private int gameVersionMajor;
private int gameVersionMinor;
private int gameVersionPatch;
private int gameVersionBuild;
private String name;
private String author;
private String description;
@ -63,7 +66,10 @@ public class War3MapW3i {
this.editorVersion = stream.readInt();
if (this.version > 27) {
ParseUtils.readUInt8Array(stream, this.unknown1);
this.gameVersionMajor = stream.readInt();
this.gameVersionMinor = stream.readInt();
this.gameVersionPatch = stream.readInt();
this.gameVersionBuild = stream.readInt();
}
this.name = ParseUtils.readUntilNull(stream);
@ -182,7 +188,10 @@ public class War3MapW3i {
stream.writeInt(this.editorVersion);
if (this.version > 27) {
ParseUtils.writeUInt8Array(stream, this.unknown1);
stream.writeInt(this.gameVersionMajor);
stream.writeInt(this.gameVersionMinor);
stream.writeInt(this.gameVersionPatch);
stream.writeInt(this.gameVersionBuild);
}
ParseUtils.writeWithNullTerminator(stream, this.name);
@ -314,10 +323,6 @@ public class War3MapW3i {
return this.editorVersion;
}
public short[] getUnknown1() {
return this.unknown1;
}
public String getName() {
return this.name;
}
@ -453,4 +458,12 @@ public class War3MapW3i {
public List<RandomItemTable> getRandomItemTables() {
return this.randomItemTables;
}
public int getGameVersionMajor() {
return this.gameVersionMajor;
}
public int getGameVersionMinor() {
return this.gameVersionMinor;
}
}

View File

@ -91,6 +91,10 @@ public class StandardObjectData {
profile.readTXT(this.source.getResourceAsStream("Units\\ItemFunc.txt"), true);
profile.readTXT(this.source.getResourceAsStream("Units\\ItemStrings.txt"), true);
itemData.readSLK(this.source.getResourceAsStream("Units\\ItemData.slk"));
// final InputStream itemSkin = this.source.getResourceAsStream("Units\\ItemSkin.txt");
// if (itemSkin != null) {
// profile.readTXT(itemSkin, true);
// }
}
catch (final IOException e) {
throw new RuntimeException(e);

View File

@ -195,7 +195,7 @@ public final class War3ObjectDataChangeset {
this.kind = chid.asStringValue().charAt(0);
break;
default:
this.kind = 'a';
this.kind = this.expected;
}
}
return true;

View File

@ -1,7 +1,7 @@
package com.etheller.warsmash.util;
public class WarsmashConstants {
public static final int MAX_PLAYERS = 16;
public static final int MAX_PLAYERS = 28;
/*
* With version, we use 0 for RoC, 1 for TFT emulation, and probably 2+ or
* whatever for custom mods and other stuff
@ -39,4 +39,5 @@ public class WarsmashConstants {
public static final boolean ENABLE_MUSIC = true;
public static final boolean LOAD_UNITS_FROM_WORLDEDIT_DATA = false;
public static final boolean LOCAL_TEMP_TEST_ALL_PLAYERS_PLAYING = true;
public static final boolean CRASH_ON_INCOMPATIBLE_132_FEATURES = false;
}

View File

@ -55,6 +55,9 @@ public class EventObjectEmitterObject extends GenericObject implements EmitterOb
@Override
public Object call(final InputStream data) {
if (data == null) {
return new MappedData();
}
final StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(data, "utf-8"))) {
String line;

View File

@ -705,10 +705,11 @@ public class MdxComplexInstance extends ModelInstance {
public MdxComplexInstance setSequence(final int id) {
final MdxModel model = (MdxModel) this.model;
final int lastSequence = this.sequence;
this.sequence = id;
if (model.ok) {
final int lastSequence = this.sequence;
this.sequence = id;
final List<Sequence> sequences = model.sequences;
if ((id < 0) || (id > (sequences.size() - 1))) {
@ -789,6 +790,10 @@ public class MdxComplexInstance extends ModelInstance {
return this.model.bounds;
}
else {
if (((MdxModel) this.model).sequences.isEmpty()) {
System.err.println("Printing diagnostics for corrupted state MdxComplexInstance (about to crash)");
System.err.println("Model name: " + ((MdxModel) this.model).name);
}
final Bounds sequenceBounds = ((MdxModel) this.model).sequences.get(this.sequence).getBounds();
if (sequenceBounds.r == 0) {
return this.model.bounds;

View File

@ -244,6 +244,8 @@ public class War3MapViewer extends AbstractMdxModelViewer {
private GameTurnManager gameTurnManager;
private War3MapW3i lastLoadedMapInformation;
public War3MapViewer(final DataSource dataSource, final CanvasProvider canvas, final War3MapConfig mapConfig,
final GameTurnManager gameTurnManager) {
super(dataSource, canvas);
@ -451,6 +453,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.localPlayerIndex = localPlayerIndex;
this.mapMpq = war3Map;
this.lastLoadedMapInformation = w3iFile;
final PathSolver wc3PathSolver = this.wc3PathSolver;
@ -910,7 +913,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.walkableObjectsTree = new Quadtree<>(this.terrain.getEntireMap());
if (this.doodadsAndDestructiblesLoaded) {
this.loadDoodadsAndDestructibles(this.allObjectData);
this.loadDoodadsAndDestructibles(this.allObjectData, w3iFile);
}
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
@ -974,7 +977,7 @@ public class War3MapViewer extends AbstractMdxModelViewer {
*/
public void loadAfterUI() throws IOException {
if (this.unitsAndItemsLoaded) {
this.loadUnitsAndItems(this.allObjectData);
this.loadUnitsAndItems(this.allObjectData, this.lastLoadedMapInformation);
}
else {
throw new IllegalStateException("transcription of JS has not loaded a map and has no JS async promises");
@ -985,13 +988,14 @@ public class War3MapViewer extends AbstractMdxModelViewer {
this.terrain.initShadows();
}
private void loadDoodadsAndDestructibles(final Warcraft3MapObjectData modifications) throws IOException {
private void loadDoodadsAndDestructibles(final Warcraft3MapObjectData modifications, final War3MapW3i w3iFile)
throws IOException {
this.applyModificationFile(this.doodadsData, this.doodadMetaData, modifications.getDoodads(),
WorldEditorDataType.DOODADS);
this.applyModificationFile(this.doodadsData, this.destructableMetaData, modifications.getDestructibles(),
WorldEditorDataType.DESTRUCTIBLES);
final War3MapDoo doo = this.mapMpq.readDoodads();
final War3MapDoo doo = this.mapMpq.readDoodads(w3iFile);
for (final com.etheller.warsmash.parsers.w3x.doo.Doodad doodad : doo.getDoodads()) {
if ((doodad.getFlags() & 0x2) == 0) {
@ -1229,14 +1233,15 @@ public class War3MapViewer extends AbstractMdxModelViewer {
}
private void loadUnitsAndItems(final Warcraft3MapObjectData modifications) throws IOException {
private void loadUnitsAndItems(final Warcraft3MapObjectData modifications, final War3MapW3i mapInformation)
throws IOException {
final War3Map mpq = this.mapMpq;
this.unitsReady = false;
this.soundsetNameToSoundset = new HashMap<>();
if (this.dataSource.has("war3mapUnits.doo") && WarsmashConstants.LOAD_UNITS_FROM_WORLDEDIT_DATA) {
final War3MapUnitsDoo dooFile = mpq.readUnits();
final War3MapUnitsDoo dooFile = mpq.readUnits(mapInformation);
// Collect the units and items data.
for (final com.etheller.warsmash.parsers.w3x.unitsdoo.Unit unit : dooFile.getUnits()) {

View File

@ -281,6 +281,9 @@ public class PathingGrid {
public boolean isPathable(final float unitX, final float unitY, final MovementType pathingType,
final float collisionSize) {
if (collisionSize == 0f) {
if (!contains(unitX, unitY)) {
return false;
}
return pathingType.isPathable(getPathing(unitX, unitY));
}
for (int i = -1; i <= 1; i++) {

View File

@ -108,7 +108,7 @@ public class CUnit extends CWidget {
// which fields shouldn't be persisted if we do game state save later
private transient CUnitStateNotifier stateNotifier = new CUnitStateNotifier();
private transient List<StateListenerUpdate> stateListenersUpdates = new ArrayList<>();
private final float acquisitionRange;
private float acquisitionRange;
private transient static AutoAttackTargetFinderEnum autoAttackTargetFinderEnum = new AutoAttackTargetFinderEnum();
private transient CBehaviorMove moveBehavior;
@ -1221,13 +1221,20 @@ public class CUnit extends CWidget {
}
public boolean isMovementDisabled() {
return this.isBuilding();
return this.moveBehavior == null;
// TODO this used to directly return the state of whether our unit was a
// building. Will it be a problem that I changed it?
// I was trying to fix attack move on stationary units which was crashing
}
public float getAcquisitionRange() {
return this.acquisitionRange;
}
public void setAcquisitionRange(final float acquisitionRange) {
this.acquisitionRange = acquisitionRange;
}
public void heal(final CSimulation game, final int lifeToRegain) {
setLife(game, Math.min(getLife() + lifeToRegain, getMaximumLife()));
}
@ -1971,4 +1978,5 @@ public class CUnit extends CWidget {
}
return false;
}
}

View File

@ -80,6 +80,7 @@ public class CUnitType {
private final boolean canFlee;
private final int priority;
private final boolean revivesHeroes;
private final int pointValue;
public CUnitType(final String name, final String legacyName, final War3ID typeId, final int maxLife,
final float lifeRegen, final CRegenType lifeRegenType, final int manaInitial, final int manaMaximum,
@ -97,7 +98,7 @@ public class CUnitType {
final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence,
final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute,
final List<War3ID> heroAbilityList, final List<String> heroProperNames, final int properNamesCount,
final boolean canFlee, final int priority, final boolean revivesHeroes) {
final boolean canFlee, final int priority, final boolean revivesHeroes, final int pointValue) {
this.name = name;
this.legacyName = legacyName;
this.typeId = typeId;
@ -155,6 +156,7 @@ public class CUnitType {
this.canFlee = canFlee;
this.priority = priority;
this.revivesHeroes = revivesHeroes;
this.pointValue = pointValue;
}
public String getName() {
@ -384,4 +386,8 @@ public class CUnitType {
public boolean isRevivesHeroes() {
return this.revivesHeroes;
}
public int getPointValue() {
return this.pointValue;
}
}

View File

@ -46,7 +46,8 @@ public class CAbilityHero extends AbstractCAbility {
this.intelligence = new HeroStatValue(unitType.getStartingIntelligence(), unitType.getIntelligencePerLevel());
calculateDerivatedFields(game, unit);
final int nameIndex = game.getSeededRandom().nextInt(unitType.getProperNamesCount());
final int properNamesCount = unitType.getProperNamesCount();
final int nameIndex = properNamesCount > 0 ? game.getSeededRandom().nextInt(properNamesCount) : 0;
String properName;
final List<String> heroProperNames = unitType.getHeroProperNames();

View File

@ -177,6 +177,8 @@ public class CUnitData {
private static final War3ID CAN_FLEE = War3ID.fromString("ufle");
private static final War3ID PRIORITY = War3ID.fromString("upri");
private static final War3ID POINT_VALUE = War3ID.fromString("upoi");
private final CGameplayConstants gameplayConstants;
private final MutableObjectData unitData;
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
@ -324,7 +326,9 @@ public class CUnitData {
}
final String unitName = unitType.getFieldAsString(NAME, 0);
final float acquisitionRange = unitType.getFieldAsFloat(ACQUISITION_RANGE, 0);
final float minimumAttackRange = unitType.getFieldAsFloat(MINIMUM_ATTACK_RANGE, 0);
// note: uamn expected type int below, not exactly sure why that decision was
// made but I'll support it
final float minimumAttackRange = unitType.getFieldAsInteger(MINIMUM_ATTACK_RANGE, 0);
final EnumSet<CTargetType> targetedAs = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(TARGETED_AS, 0));
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
@ -468,6 +472,8 @@ public class CUnitData {
final int foodUsed = unitType.getFieldAsInteger(FOOD_USED, 0);
final int foodMade = unitType.getFieldAsInteger(FOOD_MADE, 0);
final int pointValue = unitType.getFieldAsInteger(POINT_VALUE, 0);
final boolean revivesHeroes = unitType.getFieldAsBoolean(REVIVES_HEROES, 0);
final String unitsTrainedString = unitType.getFieldAsString(UNITS_TRAINED, 0);
@ -567,7 +573,7 @@ public class CUnitData {
researchesAvailable, upgradesTo, unitRace, goldCost, lumberCost, foodUsed, foodMade, buildTime,
preventedPathingTypes, requiredPathingTypes, propWindow, turnRate, requirements, unitLevel, hero,
strength, strPlus, agility, agiPlus, intelligence, intPlus, primaryAttribute, heroAbilityList,
heroProperNames, properNamesCount, canFlee, priority, revivesHeroes);
heroProperNames, properNamesCount, canFlee, priority, revivesHeroes, pointValue);
this.unitIdToUnitType.put(typeId, unitTypeInstance);
this.jassLegacyNameToUnitId.put(legacyName, typeId);
}

View File

@ -29,7 +29,11 @@ public class OrderIdUtils {
}
public static int getOrderId(final String orderIdString) {
return stringToOrderId.get(orderIdString);
final Integer orderId = stringToOrderId.get(orderIdString.toLowerCase());
if (orderId == null) {
return 0;
}
return orderId;
}
public static String getStringFromOrderId(final Integer orderId) {

View File

@ -35,7 +35,6 @@ public class CPathfindingProcessor {
this.worldCollision = worldCollision;
this.nodes = new Node[pathingGrid.getHeight()][pathingGrid.getWidth()];
this.cornerNodes = new Node[pathingGrid.getHeight() + 1][pathingGrid.getWidth() + 1];
System.out.println("pathing size: ");
for (int i = 0; i < this.nodes.length; i++) {
for (int j = 0; j < this.nodes[i].length; j++) {
this.nodes[i][j] = new Node(new Point2D.Float(pathingGrid.getWorldX(j), pathingGrid.getWorldY(i)));

View File

@ -8,15 +8,18 @@ import com.etheller.interpreter.ast.debug.JassException;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.trigger.Trigger;
import com.etheller.interpreter.ast.util.CHandle;
import com.etheller.warsmash.parsers.jass.scope.CommonTriggerExecutionScope;
public class CTimerJass extends CTimer {
public class CTimerJass extends CTimer implements CHandle {
private JassFunction handlerFunc;
private final GlobalScope jassGlobalScope;
private final int handleId;
private final List<Trigger> eventTriggers = new ArrayList<>();
public CTimerJass(final GlobalScope jassGlobalScope) {
public CTimerJass(final GlobalScope jassGlobalScope, final int handleId) {
this.jassGlobalScope = jassGlobalScope;
this.handleId = handleId;
}
public void setHandlerFunc(final JassFunction handlerFunc) {
@ -27,7 +30,9 @@ public class CTimerJass extends CTimer {
public void onFire() {
final CommonTriggerExecutionScope handlerScope = CommonTriggerExecutionScope.expiringTimer(null, this);
try {
this.handlerFunc.call(Collections.emptyList(), this.jassGlobalScope, handlerScope);
if (this.handlerFunc != null) {
this.handlerFunc.call(Collections.emptyList(), this.jassGlobalScope, handlerScope);
}
}
catch (final Exception e) {
throw new JassException(this.jassGlobalScope, "Exception during jass time fire", e);
@ -47,4 +52,9 @@ public class CTimerJass extends CTimer {
public void removeEvent(final Trigger trigger) {
this.eventTriggers.remove(trigger);
}
@Override
public int getHandleId() {
return this.handleId;
}
}

View File

@ -36,6 +36,7 @@ import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
@ -168,6 +169,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandCardCommandL
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.CommandErrorListener;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.MultiSelectionIconListener;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.QueueIconListener;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog.CScriptDialog;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog.CScriptDialogButton;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog.CTimerDialog;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer.FilterMode;
@ -3834,4 +3837,43 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
public void displayTimedText(final float x, final float y, final float duration, final String message) {
showGameMessage(message, duration); // TODO x y
}
public CScriptDialog createScriptDialog(final GlobalScope globalScope) {
final SimpleFrame scriptDialog = (SimpleFrame) this.rootFrame.createFrame("ScriptDialog", this.rootFrame, 0, 0);
scriptDialog.addAnchor(new AnchorDefinition(FramePoint.TOP, 0, GameUI.convertY(this.uiViewport, -0.05f)));
scriptDialog.setVisible(false);
final StringFrame scriptDialogTextFrame = (StringFrame) this.rootFrame.getFrameByName("ScriptDialogText", 0);
scriptDialog.positionBounds(this.rootFrame, this.uiViewport);
return new CScriptDialog(globalScope, scriptDialog, scriptDialogTextFrame);
}
public CScriptDialogButton createScriptDialogButton(final CScriptDialog scriptDialog, final String text,
final char hotkey) {
// TODO use hotkey
final GlueTextButtonFrame scriptDialogButton = (GlueTextButtonFrame) this.rootFrame
.createFrame("ScriptDialogButton", scriptDialog.getScriptDialogFrame(), 0, 0);
scriptDialogButton.setHeight(GameUI.convertY(this.uiViewport, 0.03f));
final StringFrame scriptDialogTextFrame = (StringFrame) this.rootFrame.getFrameByName("ScriptDialogButtonText",
0);
this.rootFrame.setText(scriptDialogTextFrame, text);
scriptDialogButton.addSetPoint(new SetPoint(FramePoint.TOP, scriptDialog.getLastAddedComponent(),
FramePoint.BOTTOM, 0, GameUI.convertY(this.uiViewport, -0.005f)));
final CScriptDialogButton newButton = new CScriptDialogButton(scriptDialogButton, scriptDialogTextFrame);
scriptDialog.addButton(this.rootFrame, this.uiViewport, newButton);
return newButton;
}
public void destroyDialog(final CScriptDialog dialog) {
this.rootFrame.remove(dialog.getScriptDialogFrame());
}
public void clearDialog(final CScriptDialog dialog) {
destroyDialog(dialog);
final SimpleFrame scriptDialog = (SimpleFrame) this.rootFrame.createFrame("ScriptDialog", this.rootFrame, 0, 0);
scriptDialog.addAnchor(new AnchorDefinition(FramePoint.TOP, 0, GameUI.convertY(this.uiViewport, -0.05f)));
scriptDialog.setVisible(false);
final StringFrame scriptDialogTextFrame = (StringFrame) this.rootFrame.getFrameByName("ScriptDialogText", 0);
scriptDialog.positionBounds(this.rootFrame, this.uiViewport);
dialog.reset(scriptDialog, scriptDialogTextFrame);
}
}

View File

@ -0,0 +1,92 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.trigger.RemovableTriggerEvent;
import com.etheller.interpreter.ast.scope.trigger.Trigger;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.GlueTextButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.parsers.jass.scope.CommonTriggerExecutionScope;
public class CScriptDialog {
private final GlobalScope globalScope;
private SimpleFrame scriptDialogFrame;
private StringFrame scriptDialogTextFrame;
private UIFrame lastAddedComponent;
private final List<Trigger> eventTriggers = new ArrayList<>();
public CScriptDialog(final GlobalScope globalScope, final SimpleFrame scriptDialogFrame,
final StringFrame scriptDialogTextFrame) {
this.globalScope = globalScope;
this.scriptDialogFrame = scriptDialogFrame;
this.scriptDialogTextFrame = scriptDialogTextFrame;
this.lastAddedComponent = scriptDialogTextFrame;
}
public SimpleFrame getScriptDialogFrame() {
return this.scriptDialogFrame;
}
public StringFrame getScriptDialogTextFrame() {
return this.scriptDialogTextFrame;
}
public UIFrame getLastAddedComponent() {
return this.lastAddedComponent;
}
public void setTitle(final GameUI rootFrame, final String text) {
rootFrame.setText(this.scriptDialogTextFrame, text);
}
public void reset(final SimpleFrame scriptDialogFrame, final StringFrame scriptDialogTextFrame) {
this.scriptDialogFrame = scriptDialogFrame;
this.scriptDialogTextFrame = scriptDialogTextFrame;
this.lastAddedComponent = scriptDialogTextFrame;
}
public void setVisible(final boolean flag) {
this.scriptDialogFrame.setVisible(flag);
}
public RemovableTriggerEvent addEvent(final Trigger trigger) {
this.eventTriggers.add(trigger);
return new RemovableTriggerEvent() {
@Override
public void remove() {
CScriptDialog.this.eventTriggers.remove(trigger);
}
};
}
public void onButtonClick(final CScriptDialogButton cScriptDialogButton) {
this.scriptDialogFrame.setVisible(false);
for (final Trigger trigger : this.eventTriggers) {
final CommonTriggerExecutionScope scope = CommonTriggerExecutionScope.triggerDialogScope(trigger, this,
cScriptDialogButton);
if (trigger.evaluate(this.globalScope, scope)) {
trigger.execute(this.globalScope, scope);
}
}
}
public void addButton(final GameUI rootFrame, final Viewport uiViewport,
final CScriptDialogButton scriptDialogButton) {
final GlueTextButtonFrame buttonFrame = scriptDialogButton.getButtonFrame();
this.scriptDialogFrame.add(buttonFrame);
this.lastAddedComponent = buttonFrame;
buttonFrame.positionBounds(rootFrame, uiViewport);
this.scriptDialogFrame
.setHeight(((this.scriptDialogFrame.getAssignedHeight() + (buttonFrame.getFramePointY(FramePoint.TOP)))
- buttonFrame.getFramePointY(FramePoint.BOTTOM)) * 1.5f);
this.scriptDialogFrame.positionBounds(rootFrame, uiViewport);
scriptDialogButton.setupEvents(this);
}
}

View File

@ -0,0 +1,32 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui.dialog;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.frames.GlueTextButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
public class CScriptDialogButton {
private final GlueTextButtonFrame buttonFrame;
private final StringFrame buttonText;
public CScriptDialogButton(final GlueTextButtonFrame buttonFrame, final StringFrame buttonText) {
this.buttonFrame = buttonFrame;
this.buttonText = buttonText;
}
public GlueTextButtonFrame getButtonFrame() {
return this.buttonFrame;
}
public void setText(final GameUI rootFrame, final String text) {
rootFrame.setText(this.buttonText, text);
}
public void setupEvents(final CScriptDialog dialog) {
this.buttonFrame.setOnClick(new Runnable() {
@Override
public void run() {
dialog.onButtonClick(CScriptDialogButton.this);
}
});
}
}

View File

@ -523,6 +523,21 @@ public enum ArithmeticSigns implements ArithmeticSign {
}
private static boolean isEqual(final CodeJassValue left, final CodeJassValue right) {
return (left.getValue() == right.getValue());
if (left == null) {
if (right == null) {
return true;
}
else {
return false;
}
}
else {
if (right == null) {
return false;
}
else {
return (left.getValue() == right.getValue());
}
}
}
}

View File

@ -25,7 +25,7 @@ public class NativeJassFunction extends AbstractJassFunction {
if (this.implementation == null) {
System.err.println(
"Call to native function that was declared but had no native implementation: " + this.name);
return null;
return this.returnType.getNullValue();
// throw new UnsupportedOperationException(
// "Call to native function that was declared but had no native implementation: " + this.name);
}

View File

@ -32,11 +32,15 @@ public final class UserJassFunction extends AbstractJassFunction {
for (final JassStatement statement : this.statements) {
final JassValue returnValue = statement.execute(globalScope, localScope, triggerScope);
if (returnValue != null) {
if (returnValue.visit(JassTypeGettingValueVisitor.getInstance()) != this.returnType) {
if (!this.returnType.isAssignableFrom(returnValue.visit(JassTypeGettingValueVisitor.getInstance()))) {
if ((this.returnType == JassType.NOTHING)
&& (returnValue == JassReturnNothingStatement.RETURN_NOTHING_NOTICE)) {
return null;
}
else if ((this.returnType.isNullable())
&& (returnValue == JassReturnNothingStatement.RETURN_NOTHING_NOTICE)) {
return this.returnType.getNullValue();
}
else {
throw new RuntimeException("Invalid return type");
}

View File

@ -202,6 +202,10 @@ public final class GlobalScope {
final CLimitOp limitOp, final double doubleValue) {
final VariableEvent variableEvent = new VariableEvent(trigger, limitOp, doubleValue);
final GlobalScopeAssignable assignableGlobal = getAssignableGlobal(varName);
if (assignableGlobal == null) {
throw new IllegalArgumentException(
"registerVariableEvent failed to find var with name: \"" + varName + "\"");
}
assignableGlobal.add(variableEvent);
return new RemovableTriggerEvent() {
@Override

View File

@ -10,14 +10,14 @@ import com.etheller.interpreter.ast.value.JassValue;
public final class LocalScope {
private final Map<String, Assignable> locals = new HashMap<>();
public void createLocal(final String name, final JassType type) {
this.locals.put(name, new Assignable(type));
public Assignable createLocal(final String name, final JassType type) {
final Assignable assignable = new Assignable(type);
this.locals.put(name, assignable);
return assignable;
}
public void createLocal(final String name, final JassType type, final JassValue value) {
final Assignable assignable = new Assignable(type);
assignable.setValue(value);
this.locals.put(name, assignable);
createLocal(name, type).setValue(value);
}
public void setLocal(final String name, final JassValue value) {

View File

@ -65,7 +65,13 @@ public class Trigger {
action.call(Collections.emptyList(), globalScope, triggerScope);
}
catch (final Exception e) {
throw new JassException(globalScope, "Exception during Trigger action execute", e);
if (e.getMessage().startsWith("Needs to sleep")) {
// TODO not good design
e.printStackTrace();
}
else {
throw new JassException(globalScope, "Exception during Trigger action execute", e);
}
}
}
}

View File

@ -31,6 +31,7 @@ public class JassArrayedAssignmentStatement implements JassStatement {
variable = globalScope.getAssignableGlobal(this.identifier);
}
if (variable.getValue() == null) {
throw new RuntimeException("Unable to assign uninitialized array");
}
final ArrayJassValue arrayValue = variable.getValue().visit(ArrayJassValueVisitor.getInstance());

View File

@ -1,11 +1,15 @@
package com.etheller.interpreter.ast.statement;
import com.etheller.interpreter.ast.Assignable;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.value.ArrayJassType;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassType;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.ArrayTypeVisitor;
public class JassLocalStatement implements JassStatement {
private final String identifier;
@ -19,11 +23,15 @@ public class JassLocalStatement implements JassStatement {
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope,
final TriggerExecutionScope triggerScope) {
final Assignable local = localScope.createLocal(this.identifier, this.type);
if (this.type == JassType.INTEGER) {
localScope.createLocal(this.identifier, this.type, IntegerJassValue.ZERO);
local.setValue(IntegerJassValue.ZERO);
}
else {
localScope.createLocal(this.identifier, this.type);
final ArrayJassType arrayType = this.type.visit(ArrayTypeVisitor.getInstance());
if (arrayType != null) {
local.setValue(new ArrayJassValue(arrayType));
}
}
return null;
}

View File

@ -16,7 +16,11 @@ public class JassReturnStatement implements JassStatement {
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope,
final TriggerExecutionScope triggerScope) {
return this.expression.evaluate(globalScope, localScope, triggerScope);
final JassValue returnVal = this.expression.evaluate(globalScope, localScope, triggerScope);
if (returnVal == null) {
return JassReturnNothingStatement.RETURN_NOTHING_NOTICE;
}
return returnVal;
}
}

View File

@ -1,6 +1,8 @@
package com.etheller.interpreter.ast.util;
public class JassSettings {
public static final boolean LOG_FUNCTION_DEFINITIONS = false;
public static final int MAX_ARRAY_SIZE = 32768; // so dumb
public static boolean DEBUG = true;
public static boolean CONTINUE_EXECUTING_ON_ERROR = true;
}

View File

@ -2,10 +2,11 @@ package com.etheller.interpreter.ast.value;
import java.util.Arrays;
import com.etheller.interpreter.ast.util.JassSettings;
import com.etheller.interpreter.ast.value.visitor.JassTypeGettingValueVisitor;
public class ArrayJassValue implements JassValue {
private final JassValue[] data = new JassValue[8192]; // that's the array size in JASS
private final JassValue[] data = new JassValue[JassSettings.MAX_ARRAY_SIZE];
private final ArrayJassType type;
public ArrayJassValue(final ArrayJassType type) {
@ -43,8 +44,10 @@ public class ArrayJassValue implements JassValue {
"Attempted to set " + this.type.getName() + " to null in array at index " + index + "!");
}
}
if (value.visit(JassTypeGettingValueVisitor.getInstance()) != primitiveType) {
throw new IllegalStateException("Illegal type for assignment to " + primitiveType.getName() + " array");
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
if (!primitiveType.isAssignableFrom(valueType)) {
throw new IllegalStateException("Illegal type for assignment to " + primitiveType.getName() + " array: "
+ (valueType == null ? "null" : valueType.getName()));
}
this.data[index] = value;
}

View File

@ -3,16 +3,11 @@ package com.etheller.interpreter.ast.value;
public class CodeJassType extends PrimitiveJassType {
public CodeJassType(final String name) {
super(name);
super(name, new CodeJassValue(null));
}
@Override
public boolean isNullable() {
return true;
}
@Override
public JassValue getNullValue() {
return new CodeJassValue(null);
}
}

View File

@ -1,5 +1,7 @@
package com.etheller.interpreter.ast.value;
import com.etheller.interpreter.ast.statement.JassReturnNothingStatement;
public interface JassType {
<TYPE> TYPE visit(JassTypeVisitor<TYPE> visitor);
@ -11,10 +13,11 @@ public interface JassType {
JassValue getNullValue();
public static final PrimitiveJassType INTEGER = new PrimitiveJassType("integer");
public static final PrimitiveJassType INTEGER = new PrimitiveJassType("integer", IntegerJassValue.ZERO);
public static final PrimitiveJassType STRING = new StringJassType("string");
public static final PrimitiveJassType CODE = new CodeJassType("code");
public static final PrimitiveJassType REAL = new RealJassType("real");
public static final PrimitiveJassType BOOLEAN = new PrimitiveJassType("boolean");
public static final PrimitiveJassType NOTHING = new PrimitiveJassType("nothing");
public static final PrimitiveJassType REAL = new RealJassType("real", RealJassValue.ZERO);
public static final PrimitiveJassType BOOLEAN = new PrimitiveJassType("boolean", BooleanJassValue.FALSE);
public static final PrimitiveJassType NOTHING = new PrimitiveJassType("nothing",
JassReturnNothingStatement.RETURN_NOTHING_NOTICE);
}

View File

@ -2,9 +2,11 @@ package com.etheller.interpreter.ast.value;
public class PrimitiveJassType implements JassType {
private final String name;
private final JassValue nullValue;
public PrimitiveJassType(final String name) {
public PrimitiveJassType(final String name, final JassValue nullValue) {
this.name = name;
this.nullValue = nullValue;
}
@Override
@ -29,7 +31,7 @@ public class PrimitiveJassType implements JassType {
@Override
public JassValue getNullValue() {
return null;
return this.nullValue;
}
}

View File

@ -2,8 +2,8 @@ package com.etheller.interpreter.ast.value;
public class RealJassType extends PrimitiveJassType {
public RealJassType(final String name) {
super(name);
public RealJassType(final String name, final JassValue nullValue) {
super(name, nullValue);
}
@Override

View File

@ -3,16 +3,11 @@ package com.etheller.interpreter.ast.value;
public class StringJassType extends PrimitiveJassType {
public StringJassType(final String name) {
super(name);
super(name, new StringJassValue(null));
}
@Override
public boolean isNullable() {
return true;
}
@Override
public JassValue getNullValue() {
return new StringJassValue(null);
}
}

View File

@ -48,7 +48,10 @@ public class ArithmeticJassValueVisitor implements JassValueVisitor<JassValue> {
@Override
public JassValue accept(final CodeJassValue value) {
throw new UnsupportedOperationException("Cannot perform arithmetic on code");
if (this.rightHand == null) {
return this.sign.apply(value, null);
}
return this.rightHand.visit(ArithmeticLeftHandCodeJassValueVisitor.INSTANCE.reset(value, this.sign));
}
@Override

View File

@ -0,0 +1,60 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.expression.ArithmeticSign;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
import com.etheller.interpreter.ast.value.StringJassValue;
public class ArithmeticLeftHandCodeJassValueVisitor implements JassValueVisitor<JassValue> {
public static final ArithmeticLeftHandCodeJassValueVisitor INSTANCE = new ArithmeticLeftHandCodeJassValueVisitor();
private CodeJassValue leftHand;
private ArithmeticSign sign;
public ArithmeticLeftHandCodeJassValueVisitor reset(final CodeJassValue leftHand, final ArithmeticSign sign) {
this.leftHand = leftHand;
this.sign = sign;
return this;
}
@Override
public JassValue accept(final BooleanJassValue value) {
throw new UnsupportedOperationException("Invalid types for binary operator: code and boolean");
}
@Override
public JassValue accept(final IntegerJassValue value) {
throw new UnsupportedOperationException("Invalid types for binary operator: code and integer");
}
@Override
public JassValue accept(final RealJassValue value) {
throw new UnsupportedOperationException("Invalid types for binary operator: code and real");
}
@Override
public JassValue accept(final StringJassValue value) {
throw new UnsupportedOperationException("Invalid types for binary operator: code and string");
}
@Override
public JassValue accept(final CodeJassValue value) {
return this.sign.apply(this.leftHand, value);
}
@Override
public JassValue accept(final ArrayJassValue value) {
throw new UnsupportedOperationException("Invalid types for binary operator: code and array");
}
@Override
public JassValue accept(final HandleJassValue value) {
throw new UnsupportedOperationException("Invalid types for binary operator: code and handle");
}
}

View File

@ -0,0 +1,30 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassType;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.JassTypeVisitor;
import com.etheller.interpreter.ast.value.PrimitiveJassType;
public class ArrayTypeVisitor implements JassTypeVisitor<ArrayJassType> {
private static final ArrayTypeVisitor INSTANCE = new ArrayTypeVisitor();
public static ArrayTypeVisitor getInstance() {
return INSTANCE;
}
@Override
public ArrayJassType accept(final PrimitiveJassType primitiveType) {
return null;
}
@Override
public ArrayJassType accept(final ArrayJassType arrayType) {
return arrayType;
}
@Override
public ArrayJassType accept(final HandleJassType type) {
return null;
}
}

View File

@ -15,6 +15,7 @@ import com.etheller.interpreter.ast.function.UserJassFunction;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.TriggerExecutionScope;
import com.etheller.interpreter.ast.statement.JassStatement;
import com.etheller.interpreter.ast.util.JassSettings;
public class JassProgramVisitor extends JassBaseVisitor<Void> {
public static final TriggerExecutionScope EMPTY_TRIGGER_SCOPE = new TriggerExecutionScope(null);
@ -45,7 +46,9 @@ public class JassProgramVisitor extends JassBaseVisitor<Void> {
}
else if (ctx.nativeBlock() != null) {
final String text = ctx.nativeBlock().ID().getText();
System.out.println("Registering native: " + text);
if (JassSettings.LOG_FUNCTION_DEFINITIONS) {
System.out.println("Registering native: " + text);
}
this.jassNativeManager.registerNativeCode(ctx.getStart().getLine(), this.jassFileName, text,
this.jassParametersVisitor.visit(ctx.nativeBlock().paramList()),
this.jassTypeVisitor.visit(ctx.nativeBlock().type()), this.globals);
@ -84,7 +87,9 @@ public class JassProgramVisitor extends JassBaseVisitor<Void> {
this.jassTypeVisitor.visit(functionBlockContext.type()));
this.globals.defineFunction(ctx.getStart().getLine(), this.jassFileName,
functionBlockContext.ID().getText(), userJassFunction);
System.out.println("Defining jass user function: " + functionBlockContext.ID().getText());
if (JassSettings.LOG_FUNCTION_DEFINITIONS) {
System.out.println("Defining jass user function: " + functionBlockContext.ID().getText());
}
}
return null;
}