From fe35b24b0db3cabe06530305c1f6675fd1436f21 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 15:53:07 +0200 Subject: [PATCH 01/10] Add interpreter support for unit natives --- .../jassinterpreter/mocks/UnitMock.java | 29 ++ .../providers/UnitProvider.java | 454 +++++++++++++++++- .../wurstscript/tests/InterpreterTests.java | 39 ++ 3 files changed, 521 insertions(+), 1 deletion(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java index 0c8adaa42..ec3fa4010 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java @@ -5,6 +5,8 @@ import de.peeeq.wurstscript.intermediatelang.IlConstHandle; import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; public class UnitMock { public IlConstHandle owner; @@ -13,8 +15,35 @@ public class UnitMock { public ILconstReal y; public ILconstReal face; public boolean removed; + public boolean hidden; + public boolean paused; + public boolean invulnerable; + public boolean pathing = true; + public boolean useFood = true; + public boolean selected; + public boolean suspendedXp; + public boolean sleeping; + public boolean sleepPermanent; + public ILconstReal acquireRange = ILconstReal.create(0); + public ILconstReal waygateX = ILconstReal.create(0); + public ILconstReal waygateY = ILconstReal.create(0); + public boolean waygateActive; + public ILconstReal moveSpeed = ILconstReal.create(0); + public ILconstReal flyHeight = ILconstReal.create(0); + public ILconstReal turnSpeed = ILconstReal.create(0); + public ILconstReal propWindow = ILconstReal.create(0); + public ILconstInt level = ILconstInt.create(1); + public ILconstInt heroXp = ILconstInt.create(0); + public ILconstInt heroStr = ILconstInt.create(0); + public ILconstInt heroAgi = ILconstInt.create(0); + public ILconstInt heroInt = ILconstInt.create(0); + public ILconstInt skillPoints = ILconstInt.create(0); + public ILconstInt resourceAmount = ILconstInt.create(0); public final HashMap states = new HashMap<>(); public final HashMap abilityLevels = new HashMap<>(); + public final Set permanentAbilities = new HashSet<>(); + public final Set unitTypes = new HashSet<>(); + public final java.util.ArrayList inventory = new java.util.ArrayList<>(); public ILconstInt currentOrder = ILconstInt.create(0); public UnitMock(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index a4a72a9f7..d2eb42324 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -2,6 +2,8 @@ import de.peeeq.wurstio.objectreader.ObjectHelper; import de.peeeq.wurstio.jassinterpreter.mocks.DestructableMock; +import de.peeeq.wurstio.jassinterpreter.mocks.ItemMock; +import de.peeeq.wurstio.jassinterpreter.mocks.LocationMock; import de.peeeq.wurstio.jassinterpreter.mocks.UnitMock; import de.peeeq.wurstscript.intermediatelang.ILconst; import de.peeeq.wurstscript.intermediatelang.ILconstBool; @@ -25,6 +27,28 @@ public IlConstHandle CreateUnit(IlConstHandle owner, ILconstInt unitid, ILconstR return new IlConstHandle(NameProvider.getRandomName("unit"), new UnitMock(owner, unitid, x, y, face)); } + public IlConstHandle CreateUnitByName(IlConstHandle owner, ILconstString unitname, ILconstReal x, ILconstReal y, ILconstReal face) { + return CreateUnit(owner, ILconstInt.create(ObjectHelper.objectIdStringToInt(unitname.getVal())), x, y, face); + } + + public IlConstHandle CreateUnitAtLoc(IlConstHandle owner, ILconstInt unitid, IlConstHandle location, ILconstReal face) { + LocationMock locationMock = locationOrNull(location); + return CreateUnit(owner, unitid, locationMock == null ? ILconstReal.create(0) : locationMock.x, + locationMock == null ? ILconstReal.create(0) : locationMock.y, face); + } + + public IlConstHandle CreateUnitAtLocByName(IlConstHandle owner, ILconstString unitname, IlConstHandle location, ILconstReal face) { + LocationMock locationMock = locationOrNull(location); + return CreateUnitByName(owner, unitname, locationMock == null ? ILconstReal.create(0) : locationMock.x, + locationMock == null ? ILconstReal.create(0) : locationMock.y, face); + } + + public IlConstHandle CreateCorpse(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { + IlConstHandle unit = CreateUnit(owner, unitid, x, y, face); + unitOrNull(unit).states.put("unitstate0", ILconstReal.create(0)); + return unit; + } + public ILconst GetOwningPlayer(IlConstHandle unit) { UnitMock unitMock = unitOrNull(unit); return unitMock == null ? ILconstNull.instance() : unitMock.owner; @@ -45,6 +69,12 @@ public ILconstReal GetUnitY(IlConstHandle unit) { return unitMock == null ? ILconstReal.create(0) : unitMock.y; } + public ILconst GetUnitLoc(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstNull.instance() + : new IlConstHandle(NameProvider.getRandomName("location"), new LocationMock(unitMock.x, unitMock.y)); + } + public void SetUnitX(IlConstHandle unit, ILconstReal x) { UnitMock unitMock = unitOrNull(unit); if (unitMock != null) { @@ -59,11 +89,40 @@ public void SetUnitY(IlConstHandle unit, ILconstReal y) { } } + public void SetUnitPosition(IlConstHandle unit, ILconstReal x, ILconstReal y) { + SetUnitX(unit, x); + SetUnitY(unit, y); + } + + public void SetUnitPositionLoc(IlConstHandle unit, IlConstHandle location) { + LocationMock locationMock = locationOrNull(location); + if (locationMock != null) SetUnitPosition(unit, locationMock.x, locationMock.y); + } + public ILconstReal GetUnitFacing(IlConstHandle unit) { UnitMock unitMock = unitOrNull(unit); return unitMock == null ? ILconstReal.create(0) : unitMock.face; } + public void SetUnitFacing(IlConstHandle unit, ILconstReal facingAngle) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.face = facingAngle; + } + + public void SetUnitFacingTimed(IlConstHandle unit, ILconstReal facingAngle, ILconstReal duration) { + SetUnitFacing(unit, facingAngle); + } + + public void ShowUnit(IlConstHandle unit, ILconstBool show) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.hidden = !show.getVal(); + } + + public ILconstBool IsUnitHidden(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitMock.hidden); + } + public ILconstString GetUnitName(IlConstHandle unit) { if (unit == null) { return ILconstString.fromText(""); @@ -92,6 +151,70 @@ public ILconstInt GetUnitBuildTime(ILconstInt unitid) { return ILconstInt.create(0); } + public ILconstReal GetUnitMoveSpeed(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.moveSpeed; + } + + public ILconstReal GetUnitDefaultMoveSpeed(IlConstHandle unit) { return GetUnitMoveSpeed(unit); } + + public void SetUnitMoveSpeed(IlConstHandle unit, ILconstReal newSpeed) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.moveSpeed = newSpeed; + } + + public ILconstReal GetUnitFlyHeight(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.flyHeight; + } + + public ILconstReal GetUnitDefaultFlyHeight(IlConstHandle unit) { return GetUnitFlyHeight(unit); } + + public void SetUnitFlyHeight(IlConstHandle unit, ILconstReal newHeight, ILconstReal rate) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.flyHeight = newHeight; + } + + public ILconstReal GetUnitTurnSpeed(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.turnSpeed; + } + + public ILconstReal GetUnitDefaultTurnSpeed(IlConstHandle unit) { return GetUnitTurnSpeed(unit); } + + public void SetUnitTurnSpeed(IlConstHandle unit, ILconstReal newTurnSpeed) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.turnSpeed = newTurnSpeed; + } + + public ILconstReal GetUnitPropWindow(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.propWindow; + } + + public ILconstReal GetUnitDefaultPropWindow(IlConstHandle unit) { return GetUnitPropWindow(unit); } + + public void SetUnitPropWindow(IlConstHandle unit, ILconstReal newPropWindowAngle) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.propWindow = newPropWindowAngle; + } + + public ILconstReal GetUnitAcquireRange(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.acquireRange; + } + + public ILconstReal GetUnitDefaultAcquireRange(IlConstHandle unit) { return GetUnitAcquireRange(unit); } + + public void SetUnitAcquireRange(IlConstHandle unit, ILconstReal newAcquireRange) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.acquireRange = newAcquireRange; + } + + public ILconstInt GetUnitFoodMade(IlConstHandle unit) { return ILconstInt.create(0); } + + public IlConstHandle GetUnitRace(IlConstHandle unit) { return new IlConstHandle("race0", new java.util.LinkedHashSet<>()); } + public ILconstInt BlzGetUnitIntegerField(IlConstHandle whichUnit, IlConstHandle whichField) { return ILconstInt.create(0); } @@ -101,7 +224,104 @@ public ILconstInt BlzGetUnitWeaponIntegerField(IlConstHandle whichUnit, IlConstH } public ILconstBool IsUnitType(IlConstHandle whichUnit, IlConstHandle whichUnitType) { - return ILconstBool.FALSE; + UnitMock unitMock = unitOrNull(whichUnit); + if (unitMock == null || whichUnitType == null) return ILconstBool.FALSE; + if ("unittype1".equals(whichUnitType.print())) { + return ILconstBool.instance(unitMock.states.get("unitstate0").getVal() <= 0); + } + return ILconstBool.instance(unitMock.unitTypes.contains(whichUnitType.print())); + } + + public ILconstBool IsUnit(IlConstHandle unit, IlConstHandle specifiedUnit) { + return ILconstBool.instance(unit != null && unit == specifiedUnit); + } + + public ILconstBool IsUnitOwnedByPlayer(IlConstHandle unit, IlConstHandle player) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitMock.owner == player); + } + + public ILconstBool IsUnitInForce(IlConstHandle unit, IlConstHandle force) { return ILconstBool.FALSE; } + + public ILconstBool IsUnitAlly(IlConstHandle unit, IlConstHandle player) { return IsUnitOwnedByPlayer(unit, player); } + + public ILconstBool IsUnitEnemy(IlConstHandle unit, IlConstHandle player) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitMock.owner != null && unitMock.owner != player); + } + + public ILconstBool IsUnitVisible(IlConstHandle unit, IlConstHandle player) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && !unitMock.hidden); + } + + public ILconstBool IsUnitDetected(IlConstHandle unit, IlConstHandle player) { return IsUnitVisible(unit, player); } + public ILconstBool IsUnitInvisible(IlConstHandle unit, IlConstHandle player) { return ILconstBool.FALSE; } + public ILconstBool IsUnitFogged(IlConstHandle unit, IlConstHandle player) { return ILconstBool.FALSE; } + public ILconstBool IsUnitMasked(IlConstHandle unit, IlConstHandle player) { return ILconstBool.FALSE; } + public ILconstBool IsUnitRace(IlConstHandle unit, IlConstHandle race) { return ILconstBool.FALSE; } + + public ILconstBool IsUnitInRange(IlConstHandle unit, IlConstHandle otherUnit, ILconstReal distance) { + UnitMock first = unitOrNull(unit), second = unitOrNull(otherUnit); + if (first == null || second == null) return ILconstBool.FALSE; + return ILconstBool.instance(Math.hypot(first.x.getVal() - second.x.getVal(), first.y.getVal() - second.y.getVal()) <= distance.getVal()); + } + + public ILconstBool IsUnitInRangeXY(IlConstHandle unit, ILconstReal x, ILconstReal y, ILconstReal distance) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock == null) return ILconstBool.FALSE; + return ILconstBool.instance(Math.hypot(unitMock.x.getVal() - x.getVal(), unitMock.y.getVal() - y.getVal()) <= distance.getVal()); + } + + public ILconstBool IsUnitInRangeLoc(IlConstHandle unit, IlConstHandle location, ILconstReal distance) { + LocationMock locationMock = locationOrNull(location); + return locationMock == null ? ILconstBool.FALSE : IsUnitInRangeXY(unit, locationMock.x, locationMock.y, distance); + } + + public ILconstBool IsUnitIllusion(IlConstHandle unit) { return ILconstBool.FALSE; } + public ILconstBool IsUnitInTransport(IlConstHandle unit, IlConstHandle transport) { return ILconstBool.FALSE; } + public ILconstBool IsUnitLoaded(IlConstHandle unit) { return ILconstBool.FALSE; } + public ILconstBool IsHeroUnitId(ILconstInt unitId) { return ILconstBool.FALSE; } + public ILconstBool IsUnitIdType(ILconstInt unitId, IlConstHandle unitType) { return ILconstBool.FALSE; } + + public ILconstBool UnitAddType(IlConstHandle unit, IlConstHandle unitType) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitType != null && unitMock.unitTypes.add(unitType.print())); + } + + public ILconstBool UnitRemoveType(IlConstHandle unit, IlConstHandle unitType) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitType != null && unitMock.unitTypes.remove(unitType.print())); + } + + public void PauseUnit(IlConstHandle unit, ILconstBool flag) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.paused = flag.getVal(); + } + + public ILconstBool IsUnitPaused(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitMock.paused); + } + + public void SetUnitInvulnerable(IlConstHandle unit, ILconstBool flag) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.invulnerable = flag.getVal(); + } + + public ILconstBool BlzIsUnitInvulnerable(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitMock.invulnerable); + } + + public void SetUnitPathing(IlConstHandle unit, ILconstBool flag) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.pathing = flag.getVal(); + } + + public void SetUnitOwner(IlConstHandle unit, IlConstHandle owner, ILconstBool changeColor) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.owner = owner; } public void RemoveUnit(IlConstHandle unit) { @@ -189,6 +409,113 @@ public ILconstInt SetUnitAbilityLevel(IlConstHandle unit, ILconstInt abilityId, return level; } + public ILconstBool UnitMakeAbilityPermanent(IlConstHandle unit, ILconstBool permanent, ILconstInt abilityId) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock == null || !unitMock.abilityLevels.containsKey(abilityId.getVal())) return ILconstBool.FALSE; + if (permanent.getVal()) unitMock.permanentAbilities.add(abilityId.getVal()); + else unitMock.permanentAbilities.remove(abilityId.getVal()); + return ILconstBool.TRUE; + } + + public ILconstInt IncUnitAbilityLevel(IlConstHandle unit, ILconstInt abilityId) { + return SetUnitAbilityLevel(unit, abilityId, ILconstInt.create(GetUnitAbilityLevel(unit, abilityId).getVal() + 1)); + } + + public ILconstInt DecUnitAbilityLevel(IlConstHandle unit, ILconstInt abilityId) { + return SetUnitAbilityLevel(unit, abilityId, ILconstInt.create(Math.max(0, GetUnitAbilityLevel(unit, abilityId).getVal() - 1))); + } + + public ILconstInt GetUnitLevel(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstInt.create(0) : unitMock.level; + } + + public ILconstInt GetHeroLevel(IlConstHandle unit) { return GetUnitLevel(unit); } + + public void SetHeroLevel(IlConstHandle unit, ILconstInt level, ILconstBool showEyeCandy) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.level = level; + } + + public ILconstInt GetHeroXP(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstInt.create(0) : unitMock.heroXp; + } + + public void SetHeroXP(IlConstHandle unit, ILconstInt xp, ILconstBool showEyeCandy) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.heroXp = xp; + } + + public void AddHeroXP(IlConstHandle unit, ILconstInt xp, ILconstBool showEyeCandy) { + SetHeroXP(unit, ILconstInt.create(GetHeroXP(unit).getVal() + xp.getVal()), showEyeCandy); + } + + public ILconstInt GetHeroStr(IlConstHandle unit, ILconstBool includeBonuses) { UnitMock m = unitOrNull(unit); return m == null ? ILconstInt.create(0) : m.heroStr; } + public ILconstInt GetHeroAgi(IlConstHandle unit, ILconstBool includeBonuses) { UnitMock m = unitOrNull(unit); return m == null ? ILconstInt.create(0) : m.heroAgi; } + public ILconstInt GetHeroInt(IlConstHandle unit, ILconstBool includeBonuses) { UnitMock m = unitOrNull(unit); return m == null ? ILconstInt.create(0) : m.heroInt; } + public void SetHeroStr(IlConstHandle unit, ILconstInt value, ILconstBool permanent) { UnitMock m = unitOrNull(unit); if (m != null) m.heroStr = value; } + public void SetHeroAgi(IlConstHandle unit, ILconstInt value, ILconstBool permanent) { UnitMock m = unitOrNull(unit); if (m != null) m.heroAgi = value; } + public void SetHeroInt(IlConstHandle unit, ILconstInt value, ILconstBool permanent) { UnitMock m = unitOrNull(unit); if (m != null) m.heroInt = value; } + + public ILconstInt GetHeroSkillPoints(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return m == null ? ILconstInt.create(0) : m.skillPoints; } + + public ILconstBool UnitModifySkillPoints(IlConstHandle unit, ILconstInt delta) { + UnitMock m = unitOrNull(unit); + if (m == null || m.skillPoints.getVal() + delta.getVal() < 0) return ILconstBool.FALSE; + m.skillPoints = ILconstInt.create(m.skillPoints.getVal() + delta.getVal()); + return ILconstBool.TRUE; + } + + public ILconstBool UnitStripHeroLevel(IlConstHandle unit, ILconstInt levels) { + UnitMock m = unitOrNull(unit); + if (m == null) return ILconstBool.FALSE; + m.level = ILconstInt.create(Math.max(1, m.level.getVal() - levels.getVal())); + return ILconstBool.TRUE; + } + + public ILconstString GetHeroProperName(IlConstHandle unit) { return GetUnitName(unit); } + public void SuspendHeroXP(IlConstHandle unit, ILconstBool flag) { UnitMock m = unitOrNull(unit); if (m != null) m.suspendedXp = flag.getVal(); } + public ILconstBool IsSuspendedXP(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.suspendedXp); } + public void SelectHeroSkill(IlConstHandle unit, ILconstInt abilityId) { UnitAddAbility(unit, abilityId); } + + public ILconstBool ReviveHero(IlConstHandle unit, ILconstReal x, ILconstReal y, ILconstBool doEyeCandy) { + UnitMock m = unitOrNull(unit); + if (m == null) return ILconstBool.FALSE; + m.x = x; m.y = y; m.states.put("unitstate0", ILconstReal.create(100)); + return ILconstBool.TRUE; + } + + public ILconstBool ReviveHeroLoc(IlConstHandle unit, IlConstHandle location, ILconstBool doEyeCandy) { + LocationMock m = locationOrNull(location); + return m == null ? ILconstBool.FALSE : ReviveHero(unit, m.x, m.y, doEyeCandy); + } + + public void SelectUnit(IlConstHandle unit, ILconstBool flag) { UnitMock m = unitOrNull(unit); if (m != null) m.selected = flag.getVal(); } + public void ClearSelection() { } + public ILconstBool IsUnitSelected(IlConstHandle unit, IlConstHandle player) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.selected); } + public void SetUnitColor(IlConstHandle unit, IlConstHandle color) { } + public void SetUnitScale(IlConstHandle unit, ILconstReal x, ILconstReal y, ILconstReal z) { } + public void SetUnitTimeScale(IlConstHandle unit, ILconstReal scale) { } + public void SetUnitBlendTime(IlConstHandle unit, ILconstReal time) { } + public void SetUnitVertexColor(IlConstHandle unit, ILconstInt red, ILconstInt green, ILconstInt blue, ILconstInt alpha) { } + public void QueueUnitAnimation(IlConstHandle unit, ILconstString animation) { } + public void SetUnitAnimation(IlConstHandle unit, ILconstString animation) { } + public void SetUnitAnimationByIndex(IlConstHandle unit, ILconstInt animation) { } + public void SetUnitAnimationWithRarity(IlConstHandle unit, ILconstString animation, IlConstHandle rarity) { } + public void AddUnitAnimationProperties(IlConstHandle unit, ILconstString properties, ILconstBool add) { } + public void SetUnitLookAt(IlConstHandle unit, ILconstString bone, IlConstHandle target, ILconstReal x, ILconstReal y, ILconstReal z) { } + public void ResetUnitLookAt(IlConstHandle unit) { } + public void SetUnitRescuable(IlConstHandle unit, IlConstHandle player, ILconstBool flag) { } + public void SetUnitRescueRange(IlConstHandle unit, ILconstReal range) { } + public void SetUnitCreepGuard(IlConstHandle unit, ILconstBool creepGuard) { } + public void SetUnitExploded(IlConstHandle unit, ILconstBool exploded) { if (exploded.getVal()) RemoveUnit(unit); } + public void UnitShareVision(IlConstHandle unit, IlConstHandle player, ILconstBool share) { } + public void UnitSuspendDecay(IlConstHandle unit, ILconstBool suspend) { } + public void UnitSetConstructionProgress(IlConstHandle unit, ILconstInt percentage) { } + public void UnitSetUpgradeProgress(IlConstHandle unit, ILconstInt percentage) { } + public void UnitSetUsesAltIcon(IlConstHandle unit, ILconstBool flag) { } + public ILconstBool IssueImmediateOrderById(IlConstHandle unit, ILconstInt orderId) { return issueOrder(unit, orderId); } @@ -201,15 +528,129 @@ public ILconstBool IssueTargetOrderById(IlConstHandle unit, ILconstInt orderId, return issueOrder(unit, orderId); } + public ILconstBool IssueImmediateOrder(IlConstHandle unit, ILconstString order) { return validUnit(unit); } + public ILconstBool IssuePointOrder(IlConstHandle unit, ILconstString order, ILconstReal x, ILconstReal y) { return validUnit(unit); } + public ILconstBool IssuePointOrderLoc(IlConstHandle unit, ILconstString order, IlConstHandle location) { return validUnit(unit); } + public ILconstBool IssueTargetOrder(IlConstHandle unit, ILconstString order, IlConstHandle target) { return validUnit(unit); } + public ILconstBool IssueBuildOrder(IlConstHandle unit, ILconstString unitToBuild, ILconstReal x, ILconstReal y) { return validUnit(unit); } + public ILconstBool IssueBuildOrderById(IlConstHandle unit, ILconstInt unitId, ILconstReal x, ILconstReal y) { return validUnit(unit); } + public ILconstBool IssuePointOrderByIdLoc(IlConstHandle unit, ILconstInt orderId, IlConstHandle location) { return issueOrder(unit, orderId); } + public ILconstBool IssueInstantPointOrder(IlConstHandle unit, ILconstString order, ILconstReal x, ILconstReal y, IlConstHandle target) { return validUnit(unit); } + public ILconstBool IssueInstantPointOrderById(IlConstHandle unit, ILconstInt orderId, ILconstReal x, ILconstReal y, IlConstHandle target) { return issueOrder(unit, orderId); } + public ILconstBool IssueInstantTargetOrder(IlConstHandle unit, ILconstString order, IlConstHandle target, IlConstHandle instantTarget) { return validUnit(unit); } + public ILconstBool IssueInstantTargetOrderById(IlConstHandle unit, ILconstInt orderId, IlConstHandle target, IlConstHandle instantTarget) { return issueOrder(unit, orderId); } + public ILconstBool IssueNeutralImmediateOrder(IlConstHandle player, IlConstHandle structure, ILconstString unitToBuild) { return validUnit(structure); } + public ILconstBool IssueNeutralImmediateOrderById(IlConstHandle player, IlConstHandle structure, ILconstInt unitId) { return validUnit(structure); } + public ILconstBool IssueNeutralPointOrder(IlConstHandle player, IlConstHandle structure, ILconstString unitToBuild, ILconstReal x, ILconstReal y) { return validUnit(structure); } + public ILconstBool IssueNeutralPointOrderById(IlConstHandle player, IlConstHandle structure, ILconstInt unitId, ILconstReal x, ILconstReal y) { return validUnit(structure); } + public ILconstBool IssueNeutralTargetOrder(IlConstHandle player, IlConstHandle structure, ILconstString unitToBuild, IlConstHandle target) { return validUnit(structure); } + public ILconstBool IssueNeutralTargetOrderById(IlConstHandle player, IlConstHandle structure, ILconstInt unitId, IlConstHandle target) { return validUnit(structure); } + public ILconstInt GetUnitCurrentOrder(IlConstHandle unit) { UnitMock unitMock = unitOrNull(unit); return unitMock == null ? ILconstInt.create(0) : unitMock.currentOrder; } + public void SetResourceAmount(IlConstHandle unit, ILconstInt amount) { UnitMock m = unitOrNull(unit); if (m != null) m.resourceAmount = amount; } + public void AddResourceAmount(IlConstHandle unit, ILconstInt amount) { SetResourceAmount(unit, ILconstInt.create(GetResourceAmount(unit).getVal() + amount.getVal())); } + public ILconstInt GetResourceAmount(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return m == null ? ILconstInt.create(0) : m.resourceAmount; } + public ILconstInt GetUnitFoodUsed(IlConstHandle unit) { return ILconstInt.create(0); } + public ILconstInt GetFoodMade(ILconstInt unitId) { return ILconstInt.create(0); } + public void SetUnitUseFood(IlConstHandle unit, ILconstBool useFood) { UnitMock m = unitOrNull(unit); if (m != null) m.useFood = useFood.getVal(); } + public ILconstInt GetUnitPointValue(IlConstHandle unit) { return ILconstInt.create(0); } + public ILconst GetUnitRallyPoint(IlConstHandle unit) { return ILconstNull.instance(); } + public ILconst GetUnitRallyUnit(IlConstHandle unit) { return ILconstNull.instance(); } + public ILconst GetUnitRallyDestructable(IlConstHandle unit) { return ILconstNull.instance(); } + + public ILconstBool UnitAddItem(IlConstHandle unit, IlConstHandle item) { + UnitMock m = unitOrNull(unit); + if (m == null || item == null || m.inventory.size() >= 6 || m.inventory.contains(item)) return ILconstBool.FALSE; + m.inventory.add(item); + return ILconstBool.TRUE; + } + + public IlConstHandle UnitAddItemById(IlConstHandle unit, ILconstInt itemId) { + UnitMock m = unitOrNull(unit); + if (m == null || m.inventory.size() >= 6) return null; + IlConstHandle item = new IlConstHandle(NameProvider.getRandomName("item"), new ItemMock(itemId, m.x, m.y)); + m.inventory.add(item); + return item; + } + + public ILconstBool UnitAddItemToSlotById(IlConstHandle unit, ILconstInt itemId, ILconstInt slot) { + UnitMock m = unitOrNull(unit); + if (m == null || slot.getVal() < 0 || slot.getVal() >= 6 || m.inventory.size() >= 6) return ILconstBool.FALSE; + while (m.inventory.size() <= slot.getVal()) m.inventory.add(null); + if (m.inventory.get(slot.getVal()) != null) return ILconstBool.FALSE; + m.inventory.set(slot.getVal(), new IlConstHandle(NameProvider.getRandomName("item"), new ItemMock(itemId, m.x, m.y))); + return ILconstBool.TRUE; + } + + public void UnitRemoveItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); if (m != null) m.inventory.remove(item); } + public IlConstHandle UnitRemoveItemFromSlot(IlConstHandle unit, ILconstInt slot) { + UnitMock m = unitOrNull(unit); + return m == null || slot.getVal() < 0 || slot.getVal() >= m.inventory.size() ? null : m.inventory.set(slot.getVal(), null); + } + public ILconstBool UnitHasItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.inventory.contains(item)); } + public ILconst UnitItemInSlot(IlConstHandle unit, ILconstInt slot) { + UnitMock m = unitOrNull(unit); + if (m == null || slot.getVal() < 0 || slot.getVal() >= m.inventory.size() || m.inventory.get(slot.getVal()) == null) return ILconstNull.instance(); + return m.inventory.get(slot.getVal()); + } + public ILconstInt UnitInventorySize(IlConstHandle unit) { return ILconstInt.create(6); } + public ILconstBool UnitDropItemPoint(IlConstHandle unit, IlConstHandle item, ILconstReal x, ILconstReal y) { return dropItem(unit, item); } + public ILconstBool UnitDropItemSlot(IlConstHandle unit, IlConstHandle item, ILconstInt slot) { return dropItem(unit, item); } + public ILconstBool UnitDropItemTarget(IlConstHandle unit, IlConstHandle item, IlConstHandle target) { return dropItem(unit, item); } + public ILconstBool UnitUseItem(IlConstHandle unit, IlConstHandle item) { return dropItem(unit, item); } + public ILconstBool UnitUseItemPoint(IlConstHandle unit, IlConstHandle item, ILconstReal x, ILconstReal y) { return dropItem(unit, item); } + public ILconstBool UnitUseItemTarget(IlConstHandle unit, IlConstHandle item, IlConstHandle target) { return dropItem(unit, item); } + + public void UnitAddSleep(IlConstHandle unit, ILconstBool add) { UnitMock m = unitOrNull(unit); if (m != null) m.sleeping = add.getVal(); } + public ILconstBool UnitCanSleep(IlConstHandle unit) { return validUnit(unit); } + public void UnitAddSleepPerm(IlConstHandle unit, ILconstBool add) { UnitMock m = unitOrNull(unit); if (m != null) m.sleepPermanent = add.getVal(); } + public ILconstBool UnitCanSleepPerm(IlConstHandle unit) { return validUnit(unit); } + public ILconstBool UnitIsSleeping(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.sleeping); } + public void UnitWakeUp(IlConstHandle unit) { UnitAddSleep(unit, ILconstBool.FALSE); } + public void UnitApplyTimedLife(IlConstHandle unit, ILconstInt buffId, ILconstReal duration) { } + public ILconstBool UnitIgnoreAlarm(IlConstHandle unit, ILconstBool flag) { return validUnit(unit); } + public ILconstBool UnitIgnoreAlarmToggled(IlConstHandle unit) { return ILconstBool.FALSE; } + public void UnitResetCooldown(IlConstHandle unit) { } + public void UnitPauseTimedLife(IlConstHandle unit, ILconstBool flag) { } + public void UnitRemoveBuffs(IlConstHandle unit, ILconstBool positive, ILconstBool negative) { } + public void UnitRemoveBuffsEx(IlConstHandle unit, ILconstBool positive, ILconstBool negative, ILconstBool magic, ILconstBool physical, ILconstBool timedLife, ILconstBool aura, ILconstBool autoDispel) { } + public ILconstBool UnitHasBuffsEx(IlConstHandle unit, ILconstBool positive, ILconstBool negative, ILconstBool magic, ILconstBool physical, ILconstBool timedLife, ILconstBool aura, ILconstBool autoDispel) { return ILconstBool.FALSE; } + public ILconstInt UnitCountBuffsEx(IlConstHandle unit, ILconstBool positive, ILconstBool negative, ILconstBool magic, ILconstBool physical, ILconstBool timedLife, ILconstBool aura, ILconstBool autoDispel) { return ILconstInt.create(0); } + public ILconstBool UnitDamagePoint(IlConstHandle unit, ILconstReal delay, ILconstReal radius, ILconstReal x, ILconstReal y, ILconstReal amount, ILconstBool attack, ILconstBool ranged, IlConstHandle attackType, IlConstHandle damageType, IlConstHandle weaponType) { return validUnit(unit); } + public ILconstBool UnitDamageTarget(IlConstHandle unit, IlConstHandle target, ILconstReal amount, ILconstBool attack, ILconstBool ranged, IlConstHandle attackType, IlConstHandle damageType, IlConstHandle weaponType) { + UnitMock m = unitOrNull(target); + if (unitOrNull(unit) == null || m == null) return ILconstBool.FALSE; + m.states.put("unitstate0", ILconstReal.create(Math.max(0, m.states.get("unitstate0").getVal() - amount.getVal()))); + return ILconstBool.TRUE; + } + public ILconstInt GetUnitUserData(IlConstHandle unit) { return unit == null ? ILconstInt.create(0) : userDataMap.getOrDefault(unit, ILconstInt.create(0)); } + public void AddItemToAllStock(ILconstInt itemId, ILconstInt currentStock, ILconstInt stockMax) { } + public void AddItemToStock(IlConstHandle unit, ILconstInt itemId, ILconstInt currentStock, ILconstInt stockMax) { } + public void AddUnitToAllStock(ILconstInt unitId, ILconstInt currentStock, ILconstInt stockMax) { } + public void AddUnitToStock(IlConstHandle unit, ILconstInt unitId, ILconstInt currentStock, ILconstInt stockMax) { } + public void RemoveItemFromAllStock(ILconstInt itemId) { } + public void RemoveItemFromStock(IlConstHandle unit, ILconstInt itemId) { } + public void RemoveUnitFromAllStock(ILconstInt unitId) { } + public void RemoveUnitFromStock(IlConstHandle unit, ILconstInt unitId) { } + public void SetAllItemTypeSlots(ILconstInt slots) { } + public void SetAllUnitTypeSlots(ILconstInt slots) { } + public void SetItemTypeSlots(IlConstHandle unit, ILconstInt slots) { } + public void SetUnitTypeSlots(IlConstHandle unit, ILconstInt slots) { } + + public ILconstReal WaygateGetDestinationX(IlConstHandle waygate) { UnitMock m = unitOrNull(waygate); return m == null ? ILconstReal.create(0) : m.waygateX; } + public ILconstReal WaygateGetDestinationY(IlConstHandle waygate) { UnitMock m = unitOrNull(waygate); return m == null ? ILconstReal.create(0) : m.waygateY; } + public void WaygateSetDestination(IlConstHandle waygate, ILconstReal x, ILconstReal y) { UnitMock m = unitOrNull(waygate); if (m != null) { m.waygateX = x; m.waygateY = y; } } + public void WaygateActivate(IlConstHandle waygate, ILconstBool activate) { UnitMock m = unitOrNull(waygate); if (m != null) m.waygateActive = activate.getVal(); } + public ILconstBool WaygateIsActive(IlConstHandle waygate) { UnitMock m = unitOrNull(waygate); return ILconstBool.instance(m != null && m.waygateActive); } + public void SetUnitUserData(IlConstHandle unit, ILconstInt userData) { if (unit == null) { return; @@ -226,6 +667,12 @@ private ILconstBool issueOrder(IlConstHandle unit, ILconstInt orderId) { return ILconstBool.TRUE; } + private ILconstBool validUnit(IlConstHandle unit) { return ILconstBool.instance(unitOrNull(unit) != null); } + private ILconstBool dropItem(IlConstHandle unit, IlConstHandle item) { + UnitMock m = unitOrNull(unit); + return ILconstBool.instance(m != null && m.inventory.remove(item)); + } + private UnitMock unitOrNull(IlConstHandle unit) { if (unit == null || !(unit.getObj() instanceof UnitMock)) { return null; @@ -233,6 +680,11 @@ private UnitMock unitOrNull(IlConstHandle unit) { return (UnitMock) unit.getObj(); } + private LocationMock locationOrNull(IlConstHandle location) { + if (location == null || !(location.getObj() instanceof LocationMock)) return null; + return (LocationMock) location.getObj(); + } + private DestructableMock destructableOrNull(IlConstHandle destructable) { if (destructable == null || !(destructable.getObj() instanceof DestructableMock)) { return null; diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index e9cc630c7..dab1d3374 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -137,6 +137,8 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"kill\")", " if not UnitAddAbility(u, 'Afoo')", " testFail(\"add ability\")", + " if not UnitMakeAbilityPermanent(u, true, 'Afoo')", + " testFail(\"make ability permanent\")", " if GetUnitAbilityLevel(u, 'Afoo') != 1", " testFail(\"ability default\")", " if SetUnitAbilityLevel(u, 'Afoo', 3) != 3", @@ -159,6 +161,43 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"target order\")", " if GetUnitCurrentOrder(u) != 852000", " testFail(\"target current\")", + " if IsUnitHidden(u)", + " testFail(\"hidden default\")", + " ShowUnit(u, false)", + " if not IsUnitHidden(u)", + " testFail(\"hide unit\")", + " ShowUnit(u, true)", + " if IsUnitHidden(u)", + " testFail(\"show unit\")", + " SetUnitPosition(u, 9.0, 10.0)", + " if not IsUnitInRangeXY(u, 9.0, 10.0, 0.0)", + " testFail(\"range\")", + " if not IsUnitOwnedByPlayer(u, Player(2))", + " testFail(\"owner predicate\")", + " SetUnitFacing(u, 180.0)", + " if GetUnitFacing(u) != 180.0", + " testFail(\"facing\")", + " SetUnitMoveSpeed(u, 280.0)", + " if GetUnitMoveSpeed(u) != 280.0", + " testFail(\"move speed\")", + " PauseUnit(u, true)", + " if not IsUnitPaused(u)", + " testFail(\"pause\")", + " SetUnitInvulnerable(u, true)", + " if not BlzIsUnitInvulnerable(u)", + " testFail(\"invulnerable\")", + " let testItem = CreateItem('Ifoo', 0.0, 0.0)", + " if not UnitAddItem(u, testItem) or not UnitHasItem(u, testItem)", + " testFail(\"inventory add\")", + " if UnitItemInSlot(u, 0) != testItem", + " testFail(\"inventory slot\")", + " UnitRemoveItem(u, testItem)", + " if UnitHasItem(u, testItem)", + " testFail(\"inventory remove\")", + " SetResourceAmount(u, 10)", + " AddResourceAmount(u, 5)", + " if GetResourceAmount(u) != 15", + " testFail(\"resource amount\")", " RemoveUnit(u)", " if GetUnitTypeId(u) != 'hfoo'", " testFail(\"removed handle\")", From 2327201f5c2d5cf854aa45e54501fa1fb86ca703 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 16:21:19 +0200 Subject: [PATCH 02/10] Address interpreter native review findings --- .../jassinterpreter/mocks/UnitMock.java | 13 ++++ .../providers/UnitProvider.java | 77 ++++++++++++++----- .../wurstscript/tests/InterpreterTests.java | 12 +++ 3 files changed, 84 insertions(+), 18 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java index ec3fa4010..283cc1b9a 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java @@ -6,9 +6,12 @@ import java.util.HashMap; import java.util.HashSet; +import java.util.Collections; import java.util.Set; +import java.util.WeakHashMap; public class UnitMock { + private static final Set instances = Collections.newSetFromMap(new WeakHashMap<>()); public IlConstHandle owner; public ILconstInt unitid; public ILconstReal x; @@ -25,13 +28,18 @@ public class UnitMock { public boolean sleeping; public boolean sleepPermanent; public ILconstReal acquireRange = ILconstReal.create(0); + public ILconstReal defaultAcquireRange = ILconstReal.create(0); public ILconstReal waygateX = ILconstReal.create(0); public ILconstReal waygateY = ILconstReal.create(0); public boolean waygateActive; public ILconstReal moveSpeed = ILconstReal.create(0); + public ILconstReal defaultMoveSpeed = ILconstReal.create(0); public ILconstReal flyHeight = ILconstReal.create(0); + public ILconstReal defaultFlyHeight = ILconstReal.create(0); public ILconstReal turnSpeed = ILconstReal.create(0); + public ILconstReal defaultTurnSpeed = ILconstReal.create(0); public ILconstReal propWindow = ILconstReal.create(0); + public ILconstReal defaultPropWindow = ILconstReal.create(0); public ILconstInt level = ILconstInt.create(1); public ILconstInt heroXp = ILconstInt.create(0); public ILconstInt heroStr = ILconstInt.create(0); @@ -47,6 +55,7 @@ public class UnitMock { public ILconstInt currentOrder = ILconstInt.create(0); public UnitMock(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { + instances.add(this); this.owner = owner; this.unitid = unitid; this.x = x; @@ -57,4 +66,8 @@ public UnitMock(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstRe states.put("unitstate2", ILconstReal.create(0)); states.put("unitstate3", ILconstReal.create(0)); } + + public static void clearSelection() { + for (UnitMock unit : instances) unit.selected = false; + } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index d2eb42324..2a40f18f5 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -24,7 +24,8 @@ public UnitProvider(AbstractInterpreter interpreter) { } public IlConstHandle CreateUnit(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { - return new IlConstHandle(NameProvider.getRandomName("unit"), new UnitMock(owner, unitid, x, y, face)); + UnitMock unitMock = new UnitMock(owner, unitid, x, y, face); + return new IlConstHandle(NameProvider.getRandomName("unit"), unitMock); } public IlConstHandle CreateUnitByName(IlConstHandle owner, ILconstString unitname, ILconstReal x, ILconstReal y, ILconstReal face) { @@ -156,7 +157,10 @@ public ILconstReal GetUnitMoveSpeed(IlConstHandle unit) { return unitMock == null ? ILconstReal.create(0) : unitMock.moveSpeed; } - public ILconstReal GetUnitDefaultMoveSpeed(IlConstHandle unit) { return GetUnitMoveSpeed(unit); } + public ILconstReal GetUnitDefaultMoveSpeed(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.defaultMoveSpeed; + } public void SetUnitMoveSpeed(IlConstHandle unit, ILconstReal newSpeed) { UnitMock unitMock = unitOrNull(unit); @@ -168,7 +172,10 @@ public ILconstReal GetUnitFlyHeight(IlConstHandle unit) { return unitMock == null ? ILconstReal.create(0) : unitMock.flyHeight; } - public ILconstReal GetUnitDefaultFlyHeight(IlConstHandle unit) { return GetUnitFlyHeight(unit); } + public ILconstReal GetUnitDefaultFlyHeight(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.defaultFlyHeight; + } public void SetUnitFlyHeight(IlConstHandle unit, ILconstReal newHeight, ILconstReal rate) { UnitMock unitMock = unitOrNull(unit); @@ -180,7 +187,10 @@ public ILconstReal GetUnitTurnSpeed(IlConstHandle unit) { return unitMock == null ? ILconstReal.create(0) : unitMock.turnSpeed; } - public ILconstReal GetUnitDefaultTurnSpeed(IlConstHandle unit) { return GetUnitTurnSpeed(unit); } + public ILconstReal GetUnitDefaultTurnSpeed(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.defaultTurnSpeed; + } public void SetUnitTurnSpeed(IlConstHandle unit, ILconstReal newTurnSpeed) { UnitMock unitMock = unitOrNull(unit); @@ -192,7 +202,10 @@ public ILconstReal GetUnitPropWindow(IlConstHandle unit) { return unitMock == null ? ILconstReal.create(0) : unitMock.propWindow; } - public ILconstReal GetUnitDefaultPropWindow(IlConstHandle unit) { return GetUnitPropWindow(unit); } + public ILconstReal GetUnitDefaultPropWindow(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.defaultPropWindow; + } public void SetUnitPropWindow(IlConstHandle unit, ILconstReal newPropWindowAngle) { UnitMock unitMock = unitOrNull(unit); @@ -204,7 +217,10 @@ public ILconstReal GetUnitAcquireRange(IlConstHandle unit) { return unitMock == null ? ILconstReal.create(0) : unitMock.acquireRange; } - public ILconstReal GetUnitDefaultAcquireRange(IlConstHandle unit) { return GetUnitAcquireRange(unit); } + public ILconstReal GetUnitDefaultAcquireRange(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? ILconstReal.create(0) : unitMock.defaultAcquireRange; + } public void SetUnitAcquireRange(IlConstHandle unit, ILconstReal newAcquireRange) { UnitMock unitMock = unitOrNull(unit); @@ -491,8 +507,14 @@ public ILconstBool ReviveHeroLoc(IlConstHandle unit, IlConstHandle location, ILc return m == null ? ILconstBool.FALSE : ReviveHero(unit, m.x, m.y, doEyeCandy); } - public void SelectUnit(IlConstHandle unit, ILconstBool flag) { UnitMock m = unitOrNull(unit); if (m != null) m.selected = flag.getVal(); } - public void ClearSelection() { } + public void SelectUnit(IlConstHandle unit, ILconstBool flag) { + UnitMock m = unitOrNull(unit); + if (m == null) return; + m.selected = flag.getVal(); + } + public void ClearSelection() { + UnitMock.clearSelection(); + } public ILconstBool IsUnitSelected(IlConstHandle unit, IlConstHandle player) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.selected); } public void SetUnitColor(IlConstHandle unit, IlConstHandle color) { } public void SetUnitScale(IlConstHandle unit, ILconstReal x, ILconstReal y, ILconstReal z) { } @@ -564,32 +586,39 @@ public ILconstInt GetUnitCurrentOrder(IlConstHandle unit) { public ILconstBool UnitAddItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); - if (m == null || item == null || m.inventory.size() >= 6 || m.inventory.contains(item)) return ILconstBool.FALSE; - m.inventory.add(item); + if (m == null || item == null || inventoryFull(m) || m.inventory.contains(item)) return ILconstBool.FALSE; + m.inventory.set(firstFreeSlot(m), item); return ILconstBool.TRUE; } - public IlConstHandle UnitAddItemById(IlConstHandle unit, ILconstInt itemId) { + public ILconst UnitAddItemById(IlConstHandle unit, ILconstInt itemId) { UnitMock m = unitOrNull(unit); - if (m == null || m.inventory.size() >= 6) return null; + if (m == null || inventoryFull(m)) return ILconstNull.instance(); IlConstHandle item = new IlConstHandle(NameProvider.getRandomName("item"), new ItemMock(itemId, m.x, m.y)); - m.inventory.add(item); + m.inventory.set(firstFreeSlot(m), item); return item; } public ILconstBool UnitAddItemToSlotById(IlConstHandle unit, ILconstInt itemId, ILconstInt slot) { UnitMock m = unitOrNull(unit); - if (m == null || slot.getVal() < 0 || slot.getVal() >= 6 || m.inventory.size() >= 6) return ILconstBool.FALSE; + if (m == null || slot.getVal() < 0 || slot.getVal() >= 6 || inventoryFull(m)) return ILconstBool.FALSE; while (m.inventory.size() <= slot.getVal()) m.inventory.add(null); if (m.inventory.get(slot.getVal()) != null) return ILconstBool.FALSE; m.inventory.set(slot.getVal(), new IlConstHandle(NameProvider.getRandomName("item"), new ItemMock(itemId, m.x, m.y))); return ILconstBool.TRUE; } - public void UnitRemoveItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); if (m != null) m.inventory.remove(item); } - public IlConstHandle UnitRemoveItemFromSlot(IlConstHandle unit, ILconstInt slot) { + public void UnitRemoveItem(IlConstHandle unit, IlConstHandle item) { + UnitMock m = unitOrNull(unit); + if (m != null) { + int index = m.inventory.indexOf(item); + if (index >= 0) m.inventory.set(index, null); + } + } + public ILconst UnitRemoveItemFromSlot(IlConstHandle unit, ILconstInt slot) { UnitMock m = unitOrNull(unit); - return m == null || slot.getVal() < 0 || slot.getVal() >= m.inventory.size() ? null : m.inventory.set(slot.getVal(), null); + return m == null || slot.getVal() < 0 || slot.getVal() >= m.inventory.size() || m.inventory.get(slot.getVal()) == null + ? ILconstNull.instance() : m.inventory.set(slot.getVal(), null); } public ILconstBool UnitHasItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.inventory.contains(item)); } public ILconst UnitItemInSlot(IlConstHandle unit, ILconstInt slot) { @@ -624,6 +653,7 @@ public void UnitRemoveBuffsEx(IlConstHandle unit, ILconstBool positive, ILconstB public ILconstBool UnitDamageTarget(IlConstHandle unit, IlConstHandle target, ILconstReal amount, ILconstBool attack, ILconstBool ranged, IlConstHandle attackType, IlConstHandle damageType, IlConstHandle weaponType) { UnitMock m = unitOrNull(target); if (unitOrNull(unit) == null || m == null) return ILconstBool.FALSE; + if (m.invulnerable) return ILconstBool.TRUE; m.states.put("unitstate0", ILconstReal.create(Math.max(0, m.states.get("unitstate0").getVal() - amount.getVal()))); return ILconstBool.TRUE; } @@ -668,9 +698,20 @@ private ILconstBool issueOrder(IlConstHandle unit, ILconstInt orderId) { } private ILconstBool validUnit(IlConstHandle unit) { return ILconstBool.instance(unitOrNull(unit) != null); } + private boolean inventoryFull(UnitMock unit) { return firstFreeSlot(unit) >= 6; } + private int firstFreeSlot(UnitMock unit) { + for (int i = 0; i < 6; i++) { + if (i >= unit.inventory.size() || unit.inventory.get(i) == null) return i; + } + return 6; + } private ILconstBool dropItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); - return ILconstBool.instance(m != null && m.inventory.remove(item)); + if (m == null) return ILconstBool.FALSE; + int index = m.inventory.indexOf(item); + if (index < 0) return ILconstBool.FALSE; + m.inventory.set(index, null); + return ILconstBool.TRUE; } private UnitMock unitOrNull(IlConstHandle unit) { diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index dab1d3374..acd6f2041 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -180,12 +180,20 @@ public void unitStateAbilityAndOrderNatives() { " SetUnitMoveSpeed(u, 280.0)", " if GetUnitMoveSpeed(u) != 280.0", " testFail(\"move speed\")", + " if GetUnitDefaultMoveSpeed(u) != 0.0", + " testFail(\"default move speed\")", " PauseUnit(u, true)", " if not IsUnitPaused(u)", " testFail(\"pause\")", " SetUnitInvulnerable(u, true)", " if not BlzIsUnitInvulnerable(u)", " testFail(\"invulnerable\")", + " SelectUnit(u, true)", + " ClearSelection()", + " if IsUnitSelected(u, GetLocalPlayer())", + " testFail(\"clear selection\")", + " if not UnitAddItemToSlotById(u, 'Ihi0', 5)", + " testFail(\"inventory high slot\")", " let testItem = CreateItem('Ifoo', 0.0, 0.0)", " if not UnitAddItem(u, testItem) or not UnitHasItem(u, testItem)", " testFail(\"inventory add\")", @@ -194,6 +202,10 @@ public void unitStateAbilityAndOrderNatives() { " UnitRemoveItem(u, testItem)", " if UnitHasItem(u, testItem)", " testFail(\"inventory remove\")", + " if not UnitAddItem(u, testItem)", + " testFail(\"inventory refill\")", + " UnitRemoveItem(u, testItem)", + " UnitRemoveItemFromSlot(u, 5)", " SetResourceAmount(u, 10)", " AddResourceAmount(u, 5)", " if GetResourceAmount(u) != 15", From 86f36e291eb1d4823cc3849818a8c3c08120b5f5 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 16:32:01 +0200 Subject: [PATCH 03/10] Fix interpreter unit registry and inventory growth --- .../jassinterpreter/mocks/UnitMock.java | 7 ------ .../providers/UnitProvider.java | 25 ++++++++++++++++--- .../wurstscript/tests/InterpreterTests.java | 4 +++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java index 283cc1b9a..ff98bde1a 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java @@ -6,12 +6,9 @@ import java.util.HashMap; import java.util.HashSet; -import java.util.Collections; import java.util.Set; -import java.util.WeakHashMap; public class UnitMock { - private static final Set instances = Collections.newSetFromMap(new WeakHashMap<>()); public IlConstHandle owner; public ILconstInt unitid; public ILconstReal x; @@ -55,7 +52,6 @@ public class UnitMock { public ILconstInt currentOrder = ILconstInt.create(0); public UnitMock(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { - instances.add(this); this.owner = owner; this.unitid = unitid; this.x = x; @@ -67,7 +63,4 @@ public UnitMock(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstRe states.put("unitstate3", ILconstReal.create(0)); } - public static void clearSelection() { - for (UnitMock unit : instances) unit.selected = false; - } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index 2a40f18f5..3f9a0ae7d 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -14,17 +14,29 @@ import de.peeeq.wurstscript.intermediatelang.IlConstHandle; import de.peeeq.wurstscript.intermediatelang.interpreter.AbstractInterpreter; +import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; public class UnitProvider extends Provider { + private static final Map> unitsByInterpreter = new WeakHashMap<>(); private final LinkedHashMap userDataMap = new LinkedHashMap<>(); + private final Set units; public UnitProvider(AbstractInterpreter interpreter) { super(interpreter); + synchronized (unitsByInterpreter) { + units = unitsByInterpreter.computeIfAbsent(interpreter, ignored -> + Collections.synchronizedSet(new LinkedHashSet<>())); + } } public IlConstHandle CreateUnit(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { UnitMock unitMock = new UnitMock(owner, unitid, x, y, face); + units.add(unitMock); return new IlConstHandle(NameProvider.getRandomName("unit"), unitMock); } @@ -513,7 +525,9 @@ public void SelectUnit(IlConstHandle unit, ILconstBool flag) { m.selected = flag.getVal(); } public void ClearSelection() { - UnitMock.clearSelection(); + synchronized (units) { + for (UnitMock unit : units) unit.selected = false; + } } public ILconstBool IsUnitSelected(IlConstHandle unit, IlConstHandle player) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.selected); } public void SetUnitColor(IlConstHandle unit, IlConstHandle color) { } @@ -587,7 +601,7 @@ public ILconstInt GetUnitCurrentOrder(IlConstHandle unit) { public ILconstBool UnitAddItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); if (m == null || item == null || inventoryFull(m) || m.inventory.contains(item)) return ILconstBool.FALSE; - m.inventory.set(firstFreeSlot(m), item); + putInFirstFreeSlot(m, item); return ILconstBool.TRUE; } @@ -595,7 +609,7 @@ public ILconst UnitAddItemById(IlConstHandle unit, ILconstInt itemId) { UnitMock m = unitOrNull(unit); if (m == null || inventoryFull(m)) return ILconstNull.instance(); IlConstHandle item = new IlConstHandle(NameProvider.getRandomName("item"), new ItemMock(itemId, m.x, m.y)); - m.inventory.set(firstFreeSlot(m), item); + putInFirstFreeSlot(m, item); return item; } @@ -705,6 +719,11 @@ private int firstFreeSlot(UnitMock unit) { } return 6; } + private void putInFirstFreeSlot(UnitMock unit, IlConstHandle item) { + int slot = firstFreeSlot(unit); + while (unit.inventory.size() <= slot) unit.inventory.add(null); + unit.inventory.set(slot, item); + } private ILconstBool dropItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); if (m == null) return ILconstBool.FALSE; diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index acd6f2041..5567a6320 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -192,6 +192,10 @@ public void unitStateAbilityAndOrderNatives() { " ClearSelection()", " if IsUnitSelected(u, GetLocalPlayer())", " testFail(\"clear selection\")", + " let emptyInventoryUnit = CreateUnit(GetLocalPlayer(), 'hfoo', 1.0, 1.0, 0.0)", + " let emptyInventoryItem = CreateItem('Iemp', 0.0, 0.0)", + " if not UnitAddItem(emptyInventoryUnit, emptyInventoryItem)", + " testFail(\"empty inventory add\")", " if not UnitAddItemToSlotById(u, 'Ihi0', 5)", " testFail(\"inventory high slot\")", " let testItem = CreateItem('Ifoo', 0.0, 0.0)", From e629acb0ccb0b091c87a5942c81bdb7594e9cd8a Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 16:51:28 +0200 Subject: [PATCH 04/10] Complete interpreter unit native semantics --- .../jassinterpreter/mocks/UnitMock.java | 3 +- .../providers/UnitProvider.java | 79 +++++++++++++++---- .../wurstscript/tests/InterpreterTests.java | 25 +++++- 3 files changed, 88 insertions(+), 19 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java index ff98bde1a..e963d4993 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java @@ -23,7 +23,8 @@ public class UnitMock { public boolean selected; public boolean suspendedXp; public boolean sleeping; - public boolean sleepPermanent; + public boolean canSleep = true; + public boolean canSleepPerm = true; public ILconstReal acquireRange = ILconstReal.create(0); public ILconstReal defaultAcquireRange = ILconstReal.create(0); public ILconstReal waygateX = ILconstReal.create(0); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index 3f9a0ae7d..715937e63 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -14,6 +14,7 @@ import de.peeeq.wurstscript.intermediatelang.IlConstHandle; import de.peeeq.wurstscript.intermediatelang.interpreter.AbstractInterpreter; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -564,10 +565,10 @@ public ILconstBool IssueTargetOrderById(IlConstHandle unit, ILconstInt orderId, return issueOrder(unit, orderId); } - public ILconstBool IssueImmediateOrder(IlConstHandle unit, ILconstString order) { return validUnit(unit); } - public ILconstBool IssuePointOrder(IlConstHandle unit, ILconstString order, ILconstReal x, ILconstReal y) { return validUnit(unit); } - public ILconstBool IssuePointOrderLoc(IlConstHandle unit, ILconstString order, IlConstHandle location) { return validUnit(unit); } - public ILconstBool IssueTargetOrder(IlConstHandle unit, ILconstString order, IlConstHandle target) { return validUnit(unit); } + public ILconstBool IssueImmediateOrder(IlConstHandle unit, ILconstString order) { return issueOrder(unit, orderId(order)); } + public ILconstBool IssuePointOrder(IlConstHandle unit, ILconstString order, ILconstReal x, ILconstReal y) { return issueOrder(unit, orderId(order)); } + public ILconstBool IssuePointOrderLoc(IlConstHandle unit, ILconstString order, IlConstHandle location) { return issueOrder(unit, orderId(order)); } + public ILconstBool IssueTargetOrder(IlConstHandle unit, ILconstString order, IlConstHandle target) { return issueOrder(unit, orderId(order)); } public ILconstBool IssueBuildOrder(IlConstHandle unit, ILconstString unitToBuild, ILconstReal x, ILconstReal y) { return validUnit(unit); } public ILconstBool IssueBuildOrderById(IlConstHandle unit, ILconstInt unitId, ILconstReal x, ILconstReal y) { return validUnit(unit); } public ILconstBool IssuePointOrderByIdLoc(IlConstHandle unit, ILconstInt orderId, IlConstHandle location) { return issueOrder(unit, orderId); } @@ -642,16 +643,16 @@ public ILconst UnitItemInSlot(IlConstHandle unit, ILconstInt slot) { } public ILconstInt UnitInventorySize(IlConstHandle unit) { return ILconstInt.create(6); } public ILconstBool UnitDropItemPoint(IlConstHandle unit, IlConstHandle item, ILconstReal x, ILconstReal y) { return dropItem(unit, item); } - public ILconstBool UnitDropItemSlot(IlConstHandle unit, IlConstHandle item, ILconstInt slot) { return dropItem(unit, item); } - public ILconstBool UnitDropItemTarget(IlConstHandle unit, IlConstHandle item, IlConstHandle target) { return dropItem(unit, item); } - public ILconstBool UnitUseItem(IlConstHandle unit, IlConstHandle item) { return dropItem(unit, item); } - public ILconstBool UnitUseItemPoint(IlConstHandle unit, IlConstHandle item, ILconstReal x, ILconstReal y) { return dropItem(unit, item); } - public ILconstBool UnitUseItemTarget(IlConstHandle unit, IlConstHandle item, IlConstHandle target) { return dropItem(unit, item); } - - public void UnitAddSleep(IlConstHandle unit, ILconstBool add) { UnitMock m = unitOrNull(unit); if (m != null) m.sleeping = add.getVal(); } - public ILconstBool UnitCanSleep(IlConstHandle unit) { return validUnit(unit); } - public void UnitAddSleepPerm(IlConstHandle unit, ILconstBool add) { UnitMock m = unitOrNull(unit); if (m != null) m.sleepPermanent = add.getVal(); } - public ILconstBool UnitCanSleepPerm(IlConstHandle unit) { return validUnit(unit); } + public ILconstBool UnitDropItemSlot(IlConstHandle unit, IlConstHandle item, ILconstInt slot) { return moveItemToSlot(unit, item, slot.getVal()); } + public ILconstBool UnitDropItemTarget(IlConstHandle unit, IlConstHandle item, IlConstHandle target) { return transferItem(unit, item, target); } + public ILconstBool UnitUseItem(IlConstHandle unit, IlConstHandle item) { return useItem(unit, item); } + public ILconstBool UnitUseItemPoint(IlConstHandle unit, IlConstHandle item, ILconstReal x, ILconstReal y) { return useItem(unit, item); } + public ILconstBool UnitUseItemTarget(IlConstHandle unit, IlConstHandle item, IlConstHandle target) { return useItem(unit, item); } + + public void UnitAddSleep(IlConstHandle unit, ILconstBool add) { UnitMock m = unitOrNull(unit); if (m != null) m.canSleep = add.getVal(); } + public ILconstBool UnitCanSleep(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.canSleep); } + public void UnitAddSleepPerm(IlConstHandle unit, ILconstBool add) { UnitMock m = unitOrNull(unit); if (m != null) m.canSleepPerm = add.getVal(); } + public ILconstBool UnitCanSleepPerm(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.canSleepPerm); } public ILconstBool UnitIsSleeping(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.sleeping); } public void UnitWakeUp(IlConstHandle unit) { UnitAddSleep(unit, ILconstBool.FALSE); } public void UnitApplyTimedLife(IlConstHandle unit, ILconstInt buffId, ILconstReal duration) { } @@ -663,12 +664,24 @@ public void UnitRemoveBuffs(IlConstHandle unit, ILconstBool positive, ILconstBoo public void UnitRemoveBuffsEx(IlConstHandle unit, ILconstBool positive, ILconstBool negative, ILconstBool magic, ILconstBool physical, ILconstBool timedLife, ILconstBool aura, ILconstBool autoDispel) { } public ILconstBool UnitHasBuffsEx(IlConstHandle unit, ILconstBool positive, ILconstBool negative, ILconstBool magic, ILconstBool physical, ILconstBool timedLife, ILconstBool aura, ILconstBool autoDispel) { return ILconstBool.FALSE; } public ILconstInt UnitCountBuffsEx(IlConstHandle unit, ILconstBool positive, ILconstBool negative, ILconstBool magic, ILconstBool physical, ILconstBool timedLife, ILconstBool aura, ILconstBool autoDispel) { return ILconstInt.create(0); } - public ILconstBool UnitDamagePoint(IlConstHandle unit, ILconstReal delay, ILconstReal radius, ILconstReal x, ILconstReal y, ILconstReal amount, ILconstBool attack, ILconstBool ranged, IlConstHandle attackType, IlConstHandle damageType, IlConstHandle weaponType) { return validUnit(unit); } + public ILconstBool UnitDamagePoint(IlConstHandle unit, ILconstReal delay, ILconstReal radius, ILconstReal x, ILconstReal y, ILconstReal amount, ILconstBool attack, ILconstBool ranged, IlConstHandle attackType, IlConstHandle damageType, IlConstHandle weaponType) { + if (unitOrNull(unit) == null) return ILconstBool.FALSE; + ArrayList targets; + synchronized (units) { + targets = new ArrayList<>(units); + } + double radiusValue = radius.getVal(); + for (UnitMock target : targets) { + double dx = target.x.getVal() - x.getVal(); + double dy = target.y.getVal() - y.getVal(); + if (dx * dx + dy * dy <= radiusValue * radiusValue) applyDamage(target, amount.getVal()); + } + return ILconstBool.TRUE; + } public ILconstBool UnitDamageTarget(IlConstHandle unit, IlConstHandle target, ILconstReal amount, ILconstBool attack, ILconstBool ranged, IlConstHandle attackType, IlConstHandle damageType, IlConstHandle weaponType) { UnitMock m = unitOrNull(target); if (unitOrNull(unit) == null || m == null) return ILconstBool.FALSE; - if (m.invulnerable) return ILconstBool.TRUE; - m.states.put("unitstate0", ILconstReal.create(Math.max(0, m.states.get("unitstate0").getVal() - amount.getVal()))); + applyDamage(m, amount.getVal()); return ILconstBool.TRUE; } @@ -712,6 +725,7 @@ private ILconstBool issueOrder(IlConstHandle unit, ILconstInt orderId) { } private ILconstBool validUnit(IlConstHandle unit) { return ILconstBool.instance(unitOrNull(unit) != null); } + private ILconstInt orderId(ILconstString order) { return ILconstInt.create(ObjectHelper.objectIdStringToInt(order.getVal())); } private boolean inventoryFull(UnitMock unit) { return firstFreeSlot(unit) >= 6; } private int firstFreeSlot(UnitMock unit) { for (int i = 0; i < 6; i++) { @@ -724,6 +738,37 @@ private void putInFirstFreeSlot(UnitMock unit, IlConstHandle item) { while (unit.inventory.size() <= slot) unit.inventory.add(null); unit.inventory.set(slot, item); } + private ILconstBool moveItemToSlot(IlConstHandle unit, IlConstHandle item, int slot) { + UnitMock source = unitOrNull(unit); + if (source == null || slot < 0 || slot >= 6) return ILconstBool.FALSE; + int sourceSlot = source.inventory.indexOf(item); + if (sourceSlot < 0 || sourceSlot == slot) return ILconstBool.instance(sourceSlot == slot); + while (source.inventory.size() <= slot) source.inventory.add(null); + if (source.inventory.get(slot) != null) return ILconstBool.FALSE; + source.inventory.set(sourceSlot, null); + source.inventory.set(slot, item); + return ILconstBool.TRUE; + } + private ILconstBool transferItem(IlConstHandle unit, IlConstHandle item, IlConstHandle target) { + UnitMock source = unitOrNull(unit); + UnitMock destination = unitOrNull(target); + if (source == null || destination == null || !source.inventory.contains(item)) return ILconstBool.FALSE; + if (source == destination) return ILconstBool.TRUE; + if (inventoryFull(destination) || destination.inventory.contains(item)) return ILconstBool.FALSE; + int sourceSlot = source.inventory.indexOf(item); + source.inventory.set(sourceSlot, null); + putInFirstFreeSlot(destination, item); + return ILconstBool.TRUE; + } + private ILconstBool useItem(IlConstHandle unit, IlConstHandle item) { + UnitMock m = unitOrNull(unit); + return ILconstBool.instance(m != null && m.inventory.contains(item)); + } + private void applyDamage(UnitMock target, double amount) { + if (!target.invulnerable) { + target.states.put("unitstate0", ILconstReal.create((float) Math.max(0, target.states.get("unitstate0").getVal() - amount))); + } + } private ILconstBool dropItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); if (m == null) return ILconstBool.FALSE; diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index 5567a6320..32cc62b43 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -161,6 +161,15 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"target order\")", " if GetUnitCurrentOrder(u) != 852000", " testFail(\"target current\")", + " if not IssueImmediateOrder(u, \"move\")", + " testFail(\"string order\")", + " if GetUnitCurrentOrder(u) != 'move'", + " testFail(\"string current\")", + " SetUnitState(target, UNIT_STATE_LIFE, 20.0)", + " if not UnitDamagePoint(u, 0.0, 1.0, 0.0, 0.0, 5.0, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)", + " testFail(\"point damage\")", + " if GetUnitState(target, UNIT_STATE_LIFE) != 15.0", + " testFail(\"point damage life\")", " if IsUnitHidden(u)", " testFail(\"hidden default\")", " ShowUnit(u, false)", @@ -192,6 +201,14 @@ public void unitStateAbilityAndOrderNatives() { " ClearSelection()", " if IsUnitSelected(u, GetLocalPlayer())", " testFail(\"clear selection\")", + " if not UnitCanSleep(u) or not UnitCanSleepPerm(u)", + " testFail(\"sleep default\")", + " UnitAddSleep(u, false)", + " UnitAddSleepPerm(u, false)", + " if UnitCanSleep(u) or UnitCanSleepPerm(u) or UnitIsSleeping(u)", + " testFail(\"sleep capability\")", + " UnitAddSleep(u, true)", + " UnitAddSleepPerm(u, true)", " let emptyInventoryUnit = CreateUnit(GetLocalPlayer(), 'hfoo', 1.0, 1.0, 0.0)", " let emptyInventoryItem = CreateItem('Iemp', 0.0, 0.0)", " if not UnitAddItem(emptyInventoryUnit, emptyInventoryItem)", @@ -208,7 +225,13 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"inventory remove\")", " if not UnitAddItem(u, testItem)", " testFail(\"inventory refill\")", - " UnitRemoveItem(u, testItem)", + " if not UnitDropItemSlot(u, testItem, 1) or UnitItemInSlot(u, 1) != testItem", + " testFail(\"inventory move\")", + " if not UnitDropItemTarget(u, testItem, target) or UnitHasItem(u, testItem) or not UnitHasItem(target, testItem)", + " testFail(\"inventory transfer\")", + " if not UnitUseItem(target, testItem) or not UnitHasItem(target, testItem)", + " testFail(\"inventory use\")", + " UnitRemoveItem(target, testItem)", " UnitRemoveItemFromSlot(u, 5)", " SetResourceAmount(u, 10)", " AddResourceAmount(u, 5)", From 8d741520a4f1ab0d2f6214526dbf374ce979b888 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 17:08:22 +0200 Subject: [PATCH 05/10] Finish unit native review fixes --- .../providers/UnitProvider.java | 41 +++++++++++++++++-- .../wurstscript/tests/InterpreterTests.java | 13 +++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index 715937e63..158c58d48 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -16,17 +16,33 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; public class UnitProvider extends Provider { + private static final Map ORDER_IDS = new HashMap<>(); private static final Map> unitsByInterpreter = new WeakHashMap<>(); private final LinkedHashMap userDataMap = new LinkedHashMap<>(); private final Set units; + static { + ORDER_IDS.put("smart", 851971); + ORDER_IDS.put("stop", 851972); + ORDER_IDS.put("attack", 851983); + ORDER_IDS.put("attackground", 851984); + ORDER_IDS.put("attackonce", 851985); + ORDER_IDS.put("move", 851986); + ORDER_IDS.put("moveitem", 851987); + ORDER_IDS.put("patrol", 851990); + ORDER_IDS.put("holdposition", 851993); + ORDER_IDS.put("build", 851994); + } + public UnitProvider(AbstractInterpreter interpreter) { super(interpreter); synchronized (unitsByInterpreter) { @@ -583,6 +599,14 @@ public ILconstBool IssueTargetOrderById(IlConstHandle unit, ILconstInt orderId, public ILconstBool IssueNeutralTargetOrder(IlConstHandle player, IlConstHandle structure, ILconstString unitToBuild, IlConstHandle target) { return validUnit(structure); } public ILconstBool IssueNeutralTargetOrderById(IlConstHandle player, IlConstHandle structure, ILconstInt unitId, IlConstHandle target) { return validUnit(structure); } + public ILconstInt OrderId(ILconstString order) { return orderId(order); } + public ILconstString OrderId2String(ILconstInt orderId) { + for (Map.Entry entry : ORDER_IDS.entrySet()) { + if (entry.getValue().equals(orderId.getVal())) return ILconstString.fromText(entry.getKey()); + } + return ILconstString.fromText(""); + } + public ILconstInt GetUnitCurrentOrder(IlConstHandle unit) { UnitMock unitMock = unitOrNull(unit); return unitMock == null ? ILconstInt.create(0) : unitMock.currentOrder; @@ -654,7 +678,7 @@ public ILconst UnitItemInSlot(IlConstHandle unit, ILconstInt slot) { public void UnitAddSleepPerm(IlConstHandle unit, ILconstBool add) { UnitMock m = unitOrNull(unit); if (m != null) m.canSleepPerm = add.getVal(); } public ILconstBool UnitCanSleepPerm(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.canSleepPerm); } public ILconstBool UnitIsSleeping(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.sleeping); } - public void UnitWakeUp(IlConstHandle unit) { UnitAddSleep(unit, ILconstBool.FALSE); } + public void UnitWakeUp(IlConstHandle unit) { UnitMock m = unitOrNull(unit); if (m != null) m.sleeping = false; } public void UnitApplyTimedLife(IlConstHandle unit, ILconstInt buffId, ILconstReal duration) { } public ILconstBool UnitIgnoreAlarm(IlConstHandle unit, ILconstBool flag) { return validUnit(unit); } public ILconstBool UnitIgnoreAlarmToggled(IlConstHandle unit) { return ILconstBool.FALSE; } @@ -679,9 +703,15 @@ public ILconstBool UnitDamagePoint(IlConstHandle unit, ILconstReal delay, ILcons return ILconstBool.TRUE; } public ILconstBool UnitDamageTarget(IlConstHandle unit, IlConstHandle target, ILconstReal amount, ILconstBool attack, ILconstBool ranged, IlConstHandle attackType, IlConstHandle damageType, IlConstHandle weaponType) { + if (unitOrNull(unit) == null) return ILconstBool.FALSE; UnitMock m = unitOrNull(target); - if (unitOrNull(unit) == null || m == null) return ILconstBool.FALSE; - applyDamage(m, amount.getVal()); + if (m != null) { + applyDamage(m, amount.getVal()); + return ILconstBool.TRUE; + } + DestructableMock destructable = destructableOrNull(target); + if (destructable == null) return ILconstBool.FALSE; + destructable.life = ILconstReal.create((float) Math.max(0, destructable.life.getVal() - amount.getVal())); return ILconstBool.TRUE; } @@ -725,7 +755,10 @@ private ILconstBool issueOrder(IlConstHandle unit, ILconstInt orderId) { } private ILconstBool validUnit(IlConstHandle unit) { return ILconstBool.instance(unitOrNull(unit) != null); } - private ILconstInt orderId(ILconstString order) { return ILconstInt.create(ObjectHelper.objectIdStringToInt(order.getVal())); } + private ILconstInt orderId(ILconstString order) { + Integer id = ORDER_IDS.get(order.getVal().toLowerCase(Locale.ROOT)); + return ILconstInt.create(id == null ? 0 : id); + } private boolean inventoryFull(UnitMock unit) { return firstFreeSlot(unit) >= 6; } private int firstFreeSlot(UnitMock unit) { for (int i = 0; i < 6; i++) { diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index 32cc62b43..fbef6dc2f 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -163,13 +163,21 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"target current\")", " if not IssueImmediateOrder(u, \"move\")", " testFail(\"string order\")", - " if GetUnitCurrentOrder(u) != 'move'", + " if GetUnitCurrentOrder(u) != 851986", " testFail(\"string current\")", + " if OrderId(\"move\") != 851986 or OrderId(\"attack\") != 851983 or OrderId2String(851986) != \"move\"", + " testFail(\"order conversion\")", " SetUnitState(target, UNIT_STATE_LIFE, 20.0)", " if not UnitDamagePoint(u, 0.0, 1.0, 0.0, 0.0, 5.0, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)", " testFail(\"point damage\")", " if GetUnitState(target, UNIT_STATE_LIFE) != 15.0", " testFail(\"point damage life\")", + " let d = CreateDestructable('B000', 0.0, 0.0, 0.0, 1.0, 0)", + " SetDestructableLife(d, 20.0)", + " if not UnitDamageTarget(u, d, 5.0, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)", + " testFail(\"destructable damage\")", + " if GetDestructableLife(d) != 15.0", + " testFail(\"destructable damage life\")", " if IsUnitHidden(u)", " testFail(\"hidden default\")", " ShowUnit(u, false)", @@ -209,6 +217,9 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"sleep capability\")", " UnitAddSleep(u, true)", " UnitAddSleepPerm(u, true)", + " UnitWakeUp(u)", + " if not UnitCanSleep(u) or not UnitCanSleepPerm(u) or UnitIsSleeping(u)", + " testFail(\"wake up\")", " let emptyInventoryUnit = CreateUnit(GetLocalPlayer(), 'hfoo', 1.0, 1.0, 0.0)", " let emptyInventoryItem = CreateItem('Iemp', 0.0, 0.0)", " if not UnitAddItem(emptyInventoryUnit, emptyInventoryItem)", From 4d20d35ccc56e08154c7eb1e097cdcb22f495854 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 17:28:59 +0200 Subject: [PATCH 06/10] Complete interpreter unit native coverage --- .../jassinterpreter/mocks/UnitMock.java | 4 +- .../providers/UnitProvider.java | 95 +++++++++++++++++-- .../wurstscript/tests/InterpreterTests.java | 11 ++- 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java index e963d4993..2513f9418 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java @@ -20,7 +20,8 @@ public class UnitMock { public boolean invulnerable; public boolean pathing = true; public boolean useFood = true; - public boolean selected; + public boolean exploded; + public final Set selectedPlayers = new HashSet<>(); public boolean suspendedXp; public boolean sleeping; public boolean canSleep = true; @@ -50,6 +51,7 @@ public class UnitMock { public final Set permanentAbilities = new HashSet<>(); public final Set unitTypes = new HashSet<>(); public final java.util.ArrayList inventory = new java.util.ArrayList<>(); + public final IlConstHandle race = new IlConstHandle("race0", new Object()); public ILconstInt currentOrder = ILconstInt.create(0); public UnitMock(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index 158c58d48..8806c4b44 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -4,6 +4,7 @@ import de.peeeq.wurstio.jassinterpreter.mocks.DestructableMock; import de.peeeq.wurstio.jassinterpreter.mocks.ItemMock; import de.peeeq.wurstio.jassinterpreter.mocks.LocationMock; +import de.peeeq.wurstio.jassinterpreter.mocks.PlayerMock; import de.peeeq.wurstio.jassinterpreter.mocks.UnitMock; import de.peeeq.wurstscript.intermediatelang.ILconst; import de.peeeq.wurstscript.intermediatelang.ILconstBool; @@ -16,7 +17,6 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Locale; @@ -25,7 +25,7 @@ import java.util.WeakHashMap; public class UnitProvider extends Provider { - private static final Map ORDER_IDS = new HashMap<>(); + private static final Map ORDER_IDS = new LinkedHashMap<>(); private static final Map> unitsByInterpreter = new WeakHashMap<>(); private final LinkedHashMap userDataMap = new LinkedHashMap<>(); private final Set units; @@ -33,6 +33,41 @@ public class UnitProvider extends Provider { static { ORDER_IDS.put("smart", 851971); ORDER_IDS.put("stop", 851972); + ORDER_IDS.put("cancel", 851976); + ORDER_IDS.put("resumeharvesting", 852017); + ORDER_IDS.put("harvest", 852018); + ORDER_IDS.put("returnresources", 852020); + ORDER_IDS.put("repair", 852024); + ORDER_IDS.put("repairon", 852025); + ORDER_IDS.put("repairoff", 852026); + ORDER_IDS.put("load", 852046); + ORDER_IDS.put("unload", 852048); + ORDER_IDS.put("unloadall", 852049); + ORDER_IDS.put("unloadallcorpses", 852051); + ORDER_IDS.put("defend", 852055); + ORDER_IDS.put("undefend", 852056); + ORDER_IDS.put("heal", 852063); + ORDER_IDS.put("healon", 852064); + ORDER_IDS.put("healoff", 852065); + ORDER_IDS.put("innerfire", 852066); + ORDER_IDS.put("innerfireon", 852067); + ORDER_IDS.put("innerfireoff", 852068); + ORDER_IDS.put("invisibility", 852069); + ORDER_IDS.put("holybolt", 852092); + ORDER_IDS.put("resurrection", 852094); + ORDER_IDS.put("thunderbolt", 852095); + ORDER_IDS.put("thunderclap", 852096); + ORDER_IDS.put("healingward", 852109); + ORDER_IDS.put("lightningshield", 852110); + ORDER_IDS.put("chainlightning", 852119); + ORDER_IDS.put("cyclone", 852144); + ORDER_IDS.put("detonate", 852145); + ORDER_IDS.put("flamingarrows", 852174); + ORDER_IDS.put("immolation", 852177); + ORDER_IDS.put("manaburn", 852179); + ORDER_IDS.put("firebolt", 852231); + ORDER_IDS.put("inferno", 852232); + ORDER_IDS.put("poisonarrows", 852255); ORDER_IDS.put("attack", 851983); ORDER_IDS.put("attackground", 851984); ORDER_IDS.put("attackonce", 851985); @@ -41,6 +76,22 @@ public class UnitProvider extends Provider { ORDER_IDS.put("patrol", 851990); ORDER_IDS.put("holdposition", 851993); ORDER_IDS.put("build", 851994); + ORDER_IDS.put("humanbuild", 851995); + ORDER_IDS.put("upgrade", 851997); + ORDER_IDS.put("magicdefense", 852478); + ORDER_IDS.put("magicleash", 852480); + ORDER_IDS.put("magicundefense", 852479); + ORDER_IDS.put("healingwave", 852501); + ORDER_IDS.put("hex", 852502); + ORDER_IDS.put("devourmagic", 852536); + ORDER_IDS.put("impale", 852555); + ORDER_IDS.put("locustswarm", 852556); + ORDER_IDS.put("howlofterror", 852588); + ORDER_IDS.put("channel", 852600); + ORDER_IDS.put("neutralspell", 852630); + ORDER_IDS.put("clusterrockets", 852652); + ORDER_IDS.put("chemicalrage", 852663); + ORDER_IDS.put("healingspray", 852664); } public UnitProvider(AbstractInterpreter interpreter) { @@ -258,7 +309,10 @@ public void SetUnitAcquireRange(IlConstHandle unit, ILconstReal newAcquireRange) public ILconstInt GetUnitFoodMade(IlConstHandle unit) { return ILconstInt.create(0); } - public IlConstHandle GetUnitRace(IlConstHandle unit) { return new IlConstHandle("race0", new java.util.LinkedHashSet<>()); } + public IlConstHandle GetUnitRace(IlConstHandle unit) { + UnitMock unitMock = unitOrNull(unit); + return unitMock == null ? new IlConstHandle("race0", new Object()) : unitMock.race; + } public ILconstInt BlzGetUnitIntegerField(IlConstHandle whichUnit, IlConstHandle whichField) { return ILconstInt.create(0); @@ -304,7 +358,10 @@ public ILconstBool IsUnitVisible(IlConstHandle unit, IlConstHandle player) { public ILconstBool IsUnitInvisible(IlConstHandle unit, IlConstHandle player) { return ILconstBool.FALSE; } public ILconstBool IsUnitFogged(IlConstHandle unit, IlConstHandle player) { return ILconstBool.FALSE; } public ILconstBool IsUnitMasked(IlConstHandle unit, IlConstHandle player) { return ILconstBool.FALSE; } - public ILconstBool IsUnitRace(IlConstHandle unit, IlConstHandle race) { return ILconstBool.FALSE; } + public ILconstBool IsUnitRace(IlConstHandle unit, IlConstHandle race) { + UnitMock unitMock = unitOrNull(unit); + return ILconstBool.instance(unitMock != null && unitMock.race == race); + } public ILconstBool IsUnitInRange(IlConstHandle unit, IlConstHandle otherUnit, ILconstReal distance) { UnitMock first = unitOrNull(unit), second = unitOrNull(otherUnit); @@ -539,14 +596,18 @@ public ILconstBool ReviveHeroLoc(IlConstHandle unit, IlConstHandle location, ILc public void SelectUnit(IlConstHandle unit, ILconstBool flag) { UnitMock m = unitOrNull(unit); if (m == null) return; - m.selected = flag.getVal(); + if (flag.getVal()) m.selectedPlayers.add(0); + else m.selectedPlayers.remove(0); } public void ClearSelection() { synchronized (units) { - for (UnitMock unit : units) unit.selected = false; + for (UnitMock unit : units) unit.selectedPlayers.remove(0); } } - public ILconstBool IsUnitSelected(IlConstHandle unit, IlConstHandle player) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.selected); } + public ILconstBool IsUnitSelected(IlConstHandle unit, IlConstHandle player) { + UnitMock m = unitOrNull(unit); + return ILconstBool.instance(m != null && m.selectedPlayers.contains(playerId(player))); + } public void SetUnitColor(IlConstHandle unit, IlConstHandle color) { } public void SetUnitScale(IlConstHandle unit, ILconstReal x, ILconstReal y, ILconstReal z) { } public void SetUnitTimeScale(IlConstHandle unit, ILconstReal scale) { } @@ -562,7 +623,10 @@ public void ResetUnitLookAt(IlConstHandle unit) { } public void SetUnitRescuable(IlConstHandle unit, IlConstHandle player, ILconstBool flag) { } public void SetUnitRescueRange(IlConstHandle unit, ILconstReal range) { } public void SetUnitCreepGuard(IlConstHandle unit, ILconstBool creepGuard) { } - public void SetUnitExploded(IlConstHandle unit, ILconstBool exploded) { if (exploded.getVal()) RemoveUnit(unit); } + public void SetUnitExploded(IlConstHandle unit, ILconstBool exploded) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock != null) unitMock.exploded = exploded.getVal(); + } public void UnitShareVision(IlConstHandle unit, IlConstHandle player, ILconstBool share) { } public void UnitSuspendDecay(IlConstHandle unit, ILconstBool suspend) { } public void UnitSetConstructionProgress(IlConstHandle unit, ILconstInt percentage) { } @@ -625,7 +689,7 @@ public ILconstInt GetUnitCurrentOrder(IlConstHandle unit) { public ILconstBool UnitAddItem(IlConstHandle unit, IlConstHandle item) { UnitMock m = unitOrNull(unit); - if (m == null || item == null || inventoryFull(m) || m.inventory.contains(item)) return ILconstBool.FALSE; + if (m == null || item == null || inventoryFull(m) || m.inventory.contains(item) || itemHeldByOtherUnit(m, item)) return ILconstBool.FALSE; putInFirstFreeSlot(m, item); return ILconstBool.TRUE; } @@ -747,7 +811,7 @@ public void SetUnitUserData(IlConstHandle unit, ILconstInt userData) { private ILconstBool issueOrder(IlConstHandle unit, ILconstInt orderId) { UnitMock unitMock = unitOrNull(unit); - if (unitMock == null) { + if (unitMock == null || orderId.getVal() == 0) { return ILconstBool.FALSE; } unitMock.currentOrder = orderId; @@ -759,6 +823,17 @@ private ILconstInt orderId(ILconstString order) { Integer id = ORDER_IDS.get(order.getVal().toLowerCase(Locale.ROOT)); return ILconstInt.create(id == null ? 0 : id); } + private int playerId(IlConstHandle player) { + return player != null && player.getObj() instanceof PlayerMock ? ((PlayerMock) player.getObj()).id.getVal() : -1; + } + private boolean itemHeldByOtherUnit(UnitMock destination, IlConstHandle item) { + synchronized (units) { + for (UnitMock unit : units) { + if (unit != destination && unit.inventory.contains(item)) return true; + } + } + return false; + } private boolean inventoryFull(UnitMock unit) { return firstFreeSlot(unit) >= 6; } private int firstFreeSlot(UnitMock unit) { for (int i = 0; i < 6; i++) { diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index fbef6dc2f..6292db8a4 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -165,7 +165,7 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"string order\")", " if GetUnitCurrentOrder(u) != 851986", " testFail(\"string current\")", - " if OrderId(\"move\") != 851986 or OrderId(\"attack\") != 851983 or OrderId2String(851986) != \"move\"", + " if OrderId(\"move\") != 851986 or OrderId(\"attack\") != 851983 or OrderId(\"thunderbolt\") != 852095 or OrderId(\"unknown-order\") != 0 or OrderId2String(851986) != \"move\"", " testFail(\"order conversion\")", " SetUnitState(target, UNIT_STATE_LIFE, 20.0)", " if not UnitDamagePoint(u, 0.0, 1.0, 0.0, 0.0, 5.0, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)", @@ -186,6 +186,11 @@ public void unitStateAbilityAndOrderNatives() { " ShowUnit(u, true)", " if IsUnitHidden(u)", " testFail(\"show unit\")", + " if not IsUnitRace(u, GetUnitRace(u))", + " testFail(\"race\")", + " SetUnitExploded(u, true)", + " if GetUnitTypeId(u) != 'hfoo'", + " testFail(\"exploded unit removed\")", " SetUnitPosition(u, 9.0, 10.0)", " if not IsUnitInRangeXY(u, 9.0, 10.0, 0.0)", " testFail(\"range\")", @@ -206,6 +211,8 @@ public void unitStateAbilityAndOrderNatives() { " if not BlzIsUnitInvulnerable(u)", " testFail(\"invulnerable\")", " SelectUnit(u, true)", + " if not IsUnitSelected(u, GetLocalPlayer()) or IsUnitSelected(u, Player(1))", + " testFail(\"selection player\")", " ClearSelection()", " if IsUnitSelected(u, GetLocalPlayer())", " testFail(\"clear selection\")", @@ -240,6 +247,8 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"inventory move\")", " if not UnitDropItemTarget(u, testItem, target) or UnitHasItem(u, testItem) or not UnitHasItem(target, testItem)", " testFail(\"inventory transfer\")", + " if UnitAddItem(emptyInventoryUnit, testItem)", + " testFail(\"duplicate item\")", " if not UnitUseItem(target, testItem) or not UnitHasItem(target, testItem)", " testFail(\"inventory use\")", " UnitRemoveItem(target, testItem)", From 08ed57c71f061b4d0c0c413f813aede50b299c68 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 17:50:28 +0200 Subject: [PATCH 07/10] Complete order and race native semantics --- .../jassinterpreter/mocks/UnitMock.java | 2 +- .../providers/ConversionProvider.java | 2 +- .../providers/UnitProvider.java | 18 +++++++++++++++--- .../wurstscript/tests/InterpreterTests.java | 7 +++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java index 2513f9418..f59017a6b 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/UnitMock.java @@ -51,7 +51,7 @@ public class UnitMock { public final Set permanentAbilities = new HashSet<>(); public final Set unitTypes = new HashSet<>(); public final java.util.ArrayList inventory = new java.util.ArrayList<>(); - public final IlConstHandle race = new IlConstHandle("race0", new Object()); + public IlConstHandle race; public ILconstInt currentOrder = ILconstInt.create(0); public UnitMock(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java index 994fff89f..dddf84258 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java @@ -20,7 +20,7 @@ public static IlConstHandle enumHandle(String typeName, int value) { } public IlConstHandle ConvertRace(ILconstInt i) { - return new IlConstHandle("race" + i, new LinkedHashSet<>()); + return enumHandle("race", i.getVal()); } public IlConstHandle ConvertAllianceType(ILconstInt i) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index 8806c4b44..e97d0766c 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -104,6 +104,7 @@ public UnitProvider(AbstractInterpreter interpreter) { public IlConstHandle CreateUnit(IlConstHandle owner, ILconstInt unitid, ILconstReal x, ILconstReal y, ILconstReal face) { UnitMock unitMock = new UnitMock(owner, unitid, x, y, face); + unitMock.race = ConversionProvider.enumHandle("race", unitRace(unitid)); units.add(unitMock); return new IlConstHandle(NameProvider.getRandomName("unit"), unitMock); } @@ -360,7 +361,8 @@ public ILconstBool IsUnitVisible(IlConstHandle unit, IlConstHandle player) { public ILconstBool IsUnitMasked(IlConstHandle unit, IlConstHandle player) { return ILconstBool.FALSE; } public ILconstBool IsUnitRace(IlConstHandle unit, IlConstHandle race) { UnitMock unitMock = unitOrNull(unit); - return ILconstBool.instance(unitMock != null && unitMock.race == race); + return ILconstBool.instance(unitMock != null && race != null + && (unitMock.race == race || unitMock.race.getObj().equals(race.getObj()))); } public ILconstBool IsUnitInRange(IlConstHandle unit, IlConstHandle otherUnit, ILconstReal distance) { @@ -652,9 +654,9 @@ public ILconstBool IssueTargetOrderById(IlConstHandle unit, ILconstInt orderId, public ILconstBool IssueBuildOrder(IlConstHandle unit, ILconstString unitToBuild, ILconstReal x, ILconstReal y) { return validUnit(unit); } public ILconstBool IssueBuildOrderById(IlConstHandle unit, ILconstInt unitId, ILconstReal x, ILconstReal y) { return validUnit(unit); } public ILconstBool IssuePointOrderByIdLoc(IlConstHandle unit, ILconstInt orderId, IlConstHandle location) { return issueOrder(unit, orderId); } - public ILconstBool IssueInstantPointOrder(IlConstHandle unit, ILconstString order, ILconstReal x, ILconstReal y, IlConstHandle target) { return validUnit(unit); } + public ILconstBool IssueInstantPointOrder(IlConstHandle unit, ILconstString order, ILconstReal x, ILconstReal y, IlConstHandle target) { return issueOrder(unit, orderId(order)); } public ILconstBool IssueInstantPointOrderById(IlConstHandle unit, ILconstInt orderId, ILconstReal x, ILconstReal y, IlConstHandle target) { return issueOrder(unit, orderId); } - public ILconstBool IssueInstantTargetOrder(IlConstHandle unit, ILconstString order, IlConstHandle target, IlConstHandle instantTarget) { return validUnit(unit); } + public ILconstBool IssueInstantTargetOrder(IlConstHandle unit, ILconstString order, IlConstHandle target, IlConstHandle instantTarget) { return issueOrder(unit, orderId(order)); } public ILconstBool IssueInstantTargetOrderById(IlConstHandle unit, ILconstInt orderId, IlConstHandle target, IlConstHandle instantTarget) { return issueOrder(unit, orderId); } public ILconstBool IssueNeutralImmediateOrder(IlConstHandle player, IlConstHandle structure, ILconstString unitToBuild) { return validUnit(structure); } public ILconstBool IssueNeutralImmediateOrderById(IlConstHandle player, IlConstHandle structure, ILconstInt unitId) { return validUnit(structure); } @@ -826,6 +828,16 @@ private ILconstInt orderId(ILconstString order) { private int playerId(IlConstHandle player) { return player != null && player.getObj() instanceof PlayerMock ? ((PlayerMock) player.getObj()).id.getVal() : -1; } + private int unitRace(ILconstInt unitid) { + String rawcode = ObjectHelper.objectIdIntToString(unitid.getVal()).toLowerCase(Locale.ROOT); + return switch (rawcode.charAt(0)) { + case 'h' -> 1; + case 'o' -> 2; + case 'u' -> 3; + case 'e' -> 4; + default -> 7; + }; + } private boolean itemHeldByOtherUnit(UnitMock destination, IlConstHandle item) { synchronized (units) { for (UnitMock unit : units) { diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index 6292db8a4..95ecd8e53 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -165,6 +165,10 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"string order\")", " if GetUnitCurrentOrder(u) != 851986", " testFail(\"string current\")", + " if not IssueInstantPointOrder(u, \"thunderbolt\", 1.0, 2.0, target) or GetUnitCurrentOrder(u) != 852095", + " testFail(\"instant string order\")", + " if IssueInstantTargetOrder(u, \"unknown-order\", target, target)", + " testFail(\"unknown instant order\")", " if OrderId(\"move\") != 851986 or OrderId(\"attack\") != 851983 or OrderId(\"thunderbolt\") != 852095 or OrderId(\"unknown-order\") != 0 or OrderId2String(851986) != \"move\"", " testFail(\"order conversion\")", " SetUnitState(target, UNIT_STATE_LIFE, 20.0)", @@ -188,6 +192,9 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"show unit\")", " if not IsUnitRace(u, GetUnitRace(u))", " testFail(\"race\")", + " let sameTypeUnit = CreateUnit(Player(2), 'hfoo', 0.0, 0.0, 0.0)", + " if not IsUnitRace(sameTypeUnit, GetUnitRace(u))", + " testFail(\"canonical race\")", " SetUnitExploded(u, true)", " if GetUnitTypeId(u) != 'hfoo'", " testFail(\"exploded unit removed\")", From 4da148417bf42a343264daa41460ab87371e743b Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 18:01:09 +0200 Subject: [PATCH 08/10] Cover remaining unit widget natives --- .../jassinterpreter/mocks/ItemMock.java | 1 + .../providers/UnitProvider.java | 31 ++++++++++++++++--- .../wurstscript/tests/InterpreterTests.java | 6 ++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/ItemMock.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/ItemMock.java index 564f655b0..306ee0a24 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/ItemMock.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/mocks/ItemMock.java @@ -8,6 +8,7 @@ public class ItemMock { public ILconstInt id; public ILconstReal x; public ILconstReal y; + public ILconstReal life = ILconstReal.create(100); private ILconstBool visible; public ItemMock(ILconstInt id, ILconstReal x, ILconstReal y) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index e97d0766c..c9dda46c4 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -33,6 +33,7 @@ public class UnitProvider extends Provider { static { ORDER_IDS.put("smart", 851971); ORDER_IDS.put("stop", 851972); + ORDER_IDS.put("setrally", 851980); ORDER_IDS.put("cancel", 851976); ORDER_IDS.put("resumeharvesting", 852017); ORDER_IDS.put("harvest", 852018); @@ -68,6 +69,10 @@ public class UnitProvider extends Provider { ORDER_IDS.put("firebolt", 852231); ORDER_IDS.put("inferno", 852232); ORDER_IDS.put("poisonarrows", 852255); + ORDER_IDS.put("blizzard", 852089); + ORDER_IDS.put("blink", 852525); + ORDER_IDS.put("flamestrike", 852488); + ORDER_IDS.put("entangleinstant", 852171); ORDER_IDS.put("attack", 851983); ORDER_IDS.put("attackground", 851984); ORDER_IDS.put("attackonce", 851985); @@ -385,7 +390,10 @@ public ILconstBool IsUnitInRangeLoc(IlConstHandle unit, IlConstHandle location, public ILconstBool IsUnitIllusion(IlConstHandle unit) { return ILconstBool.FALSE; } public ILconstBool IsUnitInTransport(IlConstHandle unit, IlConstHandle transport) { return ILconstBool.FALSE; } public ILconstBool IsUnitLoaded(IlConstHandle unit) { return ILconstBool.FALSE; } - public ILconstBool IsHeroUnitId(ILconstInt unitId) { return ILconstBool.FALSE; } + public ILconstBool IsHeroUnitId(ILconstInt unitId) { + String rawcode = ObjectHelper.objectIdIntToString(unitId.getVal()); + return ILconstBool.instance(!rawcode.isEmpty() && Character.isUpperCase(rawcode.charAt(0))); + } public ILconstBool IsUnitIdType(ILconstInt unitId, IlConstHandle unitType) { return ILconstBool.FALSE; } public ILconstBool UnitAddType(IlConstHandle unit, IlConstHandle unitType) { @@ -464,7 +472,9 @@ public ILconstReal GetWidgetLife(IlConstHandle widget) { return unitMock.states.getOrDefault("unitstate0", ILconstReal.create(0)); } DestructableMock destructableMock = destructableOrNull(widget); - return destructableMock == null ? ILconstReal.create(0) : destructableMock.life; + if (destructableMock != null) return destructableMock.life; + ItemMock itemMock = itemOrNull(widget); + return itemMock == null ? ILconstReal.create(0) : itemMock.life; } public void SetWidgetLife(IlConstHandle widget, ILconstReal newLife) { @@ -476,7 +486,10 @@ public void SetWidgetLife(IlConstHandle widget, ILconstReal newLife) { DestructableMock destructableMock = destructableOrNull(widget); if (destructableMock != null) { destructableMock.life = newLife; + return; } + ItemMock itemMock = itemOrNull(widget); + if (itemMock != null) itemMock.life = newLife; } public ILconstBool UnitAddAbility(IlConstHandle unit, ILconstInt abilityId) { @@ -776,8 +789,13 @@ public ILconstBool UnitDamageTarget(IlConstHandle unit, IlConstHandle target, IL return ILconstBool.TRUE; } DestructableMock destructable = destructableOrNull(target); - if (destructable == null) return ILconstBool.FALSE; - destructable.life = ILconstReal.create((float) Math.max(0, destructable.life.getVal() - amount.getVal())); + if (destructable != null) { + destructable.life = ILconstReal.create((float) Math.max(0, destructable.life.getVal() - amount.getVal())); + return ILconstBool.TRUE; + } + ItemMock item = itemOrNull(target); + if (item == null) return ILconstBool.FALSE; + item.life = ILconstReal.create((float) Math.max(0, item.life.getVal() - amount.getVal())); return ILconstBool.TRUE; } @@ -917,6 +935,11 @@ private DestructableMock destructableOrNull(IlConstHandle destructable) { return (DestructableMock) destructable.getObj(); } + private ItemMock itemOrNull(IlConstHandle item) { + if (item == null || !(item.getObj() instanceof ItemMock)) return null; + return (ItemMock) item.getObj(); + } + private String unitStateKey(IlConstHandle unitstate) { return unitstate == null ? "unitstate0" : unitstate.print(); } diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index 95ecd8e53..87323a4fd 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -116,6 +116,8 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"owner\")", " if GetUnitTypeId(u) != 'hfoo'", " testFail(\"type\")", + " if not IsHeroUnitId('Hpal') or IsHeroUnitId('hfoo')", + " testFail(\"hero id\")", " if GetUnitX(u) != 12.5", " testFail(\"x\")", " if GetUnitY(u) != -3.25", @@ -182,6 +184,10 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"destructable damage\")", " if GetDestructableLife(d) != 15.0", " testFail(\"destructable damage life\")", + " let damageItem = CreateItem('Idmg', 0.0, 0.0)", + " SetWidgetLife(damageItem, 20.0)", + " if not UnitDamageTarget(u, damageItem, 5.0, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) or GetWidgetLife(damageItem) != 15.0", + " testFail(\"item damage\")", " if IsUnitHidden(u)", " testFail(\"hidden default\")", " ShowUnit(u, false)", From 7a15c9c085ad8b9bacdfd41bb1c462f9f01ccc89 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 18:16:49 +0200 Subject: [PATCH 09/10] Complete hero unit interpreter coverage --- .../jassinterpreter/providers/UnitProvider.java | 12 ++++++++++-- .../tests/wurstscript/tests/InterpreterTests.java | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index c9dda46c4..24781cfd3 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -394,7 +394,9 @@ public ILconstBool IsHeroUnitId(ILconstInt unitId) { String rawcode = ObjectHelper.objectIdIntToString(unitId.getVal()); return ILconstBool.instance(!rawcode.isEmpty() && Character.isUpperCase(rawcode.charAt(0))); } - public ILconstBool IsUnitIdType(ILconstInt unitId, IlConstHandle unitType) { return ILconstBool.FALSE; } + public ILconstBool IsUnitIdType(ILconstInt unitId, IlConstHandle unitType) { + return IsHeroUnitId(unitId); + } public ILconstBool UnitAddType(IlConstHandle unit, IlConstHandle unitType) { UnitMock unitMock = unitOrNull(unit); @@ -594,7 +596,13 @@ public ILconstBool UnitStripHeroLevel(IlConstHandle unit, ILconstInt levels) { public ILconstString GetHeroProperName(IlConstHandle unit) { return GetUnitName(unit); } public void SuspendHeroXP(IlConstHandle unit, ILconstBool flag) { UnitMock m = unitOrNull(unit); if (m != null) m.suspendedXp = flag.getVal(); } public ILconstBool IsSuspendedXP(IlConstHandle unit) { UnitMock m = unitOrNull(unit); return ILconstBool.instance(m != null && m.suspendedXp); } - public void SelectHeroSkill(IlConstHandle unit, ILconstInt abilityId) { UnitAddAbility(unit, abilityId); } + public void SelectHeroSkill(IlConstHandle unit, ILconstInt abilityId) { + UnitMock m = unitOrNull(unit); + if (m == null || m.skillPoints.getVal() <= 0) return; + int level = m.abilityLevels.getOrDefault(abilityId.getVal(), ILconstInt.create(0)).getVal(); + m.abilityLevels.put(abilityId.getVal(), ILconstInt.create(level + 1)); + m.skillPoints = ILconstInt.create(m.skillPoints.getVal() - 1); + } public ILconstBool ReviveHero(IlConstHandle unit, ILconstReal x, ILconstReal y, ILconstBool doEyeCandy) { UnitMock m = unitOrNull(unit); diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java index 87323a4fd..8a6091cdb 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/InterpreterTests.java @@ -118,6 +118,8 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"type\")", " if not IsHeroUnitId('Hpal') or IsHeroUnitId('hfoo')", " testFail(\"hero id\")", + " if not IsUnitIdType('Hpal', UNIT_TYPE_HERO)", + " testFail(\"hero type\")", " if GetUnitX(u) != 12.5", " testFail(\"x\")", " if GetUnitY(u) != -3.25", @@ -151,6 +153,11 @@ public void unitStateAbilityAndOrderNatives() { " testFail(\"remove ability\")", " if GetUnitAbilityLevel(u, 'Afoo') != 0", " testFail(\"ability removed\")", + " UnitModifySkillPoints(u, 2)", + " SelectHeroSkill(u, 'Afoo')", + " SelectHeroSkill(u, 'Afoo')", + " if GetUnitAbilityLevel(u, 'Afoo') != 2 or GetHeroSkillPoints(u) != 0", + " testFail(\"hero skill\")", " if not IssueImmediateOrderById(u, 851971)", " testFail(\"immediate order\")", " if GetUnitCurrentOrder(u) != 851971", From 47573b8d3cd52f88ea843e731d298e6b3155ee11 Mon Sep 17 00:00:00 2001 From: Frotty Date: Wed, 2 Sep 2026 18:31:30 +0200 Subject: [PATCH 10/10] Finish hero interpreter native fixes --- .../jassinterpreter/providers/ConversionProvider.java | 2 +- .../jassinterpreter/providers/UnitProvider.java | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java index dddf84258..f0a14ac6f 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/ConversionProvider.java @@ -96,7 +96,7 @@ public IlConstHandle ConvertLimitOp(ILconstInt i) { } public IlConstHandle ConvertUnitType(ILconstInt i) { - return new IlConstHandle("unittype" + i, new LinkedHashSet<>()); + return enumHandle("unittype", i.getVal()); } public IlConstHandle ConvertGameSpeed(ILconstInt i) { diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java index 24781cfd3..3c81df862 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/jassinterpreter/providers/UnitProvider.java @@ -395,7 +395,7 @@ public ILconstBool IsHeroUnitId(ILconstInt unitId) { return ILconstBool.instance(!rawcode.isEmpty() && Character.isUpperCase(rawcode.charAt(0))); } public ILconstBool IsUnitIdType(ILconstInt unitId, IlConstHandle unitType) { - return IsHeroUnitId(unitId); + return ILconstBool.TRUE; } public ILconstBool UnitAddType(IlConstHandle unit, IlConstHandle unitType) { @@ -537,6 +537,8 @@ public ILconstBool UnitMakeAbilityPermanent(IlConstHandle unit, ILconstBool perm } public ILconstInt IncUnitAbilityLevel(IlConstHandle unit, ILconstInt abilityId) { + UnitMock unitMock = unitOrNull(unit); + if (unitMock == null || !unitMock.abilityLevels.containsKey(abilityId.getVal())) return ILconstInt.create(0); return SetUnitAbilityLevel(unit, abilityId, ILconstInt.create(GetUnitAbilityLevel(unit, abilityId).getVal() + 1)); } @@ -563,7 +565,12 @@ public ILconstInt GetHeroXP(IlConstHandle unit) { public void SetHeroXP(IlConstHandle unit, ILconstInt xp, ILconstBool showEyeCandy) { UnitMock unitMock = unitOrNull(unit); - if (unitMock != null) unitMock.heroXp = xp; + if (unitMock != null) { + int oldLevel = unitMock.level.getVal(); + unitMock.heroXp = xp; + unitMock.level = ILconstInt.create(Math.max(1, xp.getVal() / 1000 + 1)); + unitMock.skillPoints = ILconstInt.create(unitMock.skillPoints.getVal() + Math.max(0, unitMock.level.getVal() - oldLevel)); + } } public void AddHeroXP(IlConstHandle unit, ILconstInt xp, ILconstBool showEyeCandy) {