From db09a3c7b7e65226cd89d64a2c28cae90e48c046 Mon Sep 17 00:00:00 2001 From: CJH3139 Date: Thu, 16 Apr 2026 22:45:38 -0700 Subject: [PATCH 1/2] Add ExprFuseTicks --- .../skript/expressions/ExprFuseTicks.java | 87 +++++++++++++++++++ .../skript/bukkit/entity/EntityModule.java | 4 +- .../syntaxes/expressions/ExprFuseTicks.sk | 25 ++++++ 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ch/njol/skript/expressions/ExprFuseTicks.java create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk diff --git a/src/main/java/ch/njol/skript/expressions/ExprFuseTicks.java b/src/main/java/ch/njol/skript/expressions/ExprFuseTicks.java new file mode 100644 index 00000000000..e40927215d4 --- /dev/null +++ b/src/main/java/ch/njol/skript/expressions/ExprFuseTicks.java @@ -0,0 +1,87 @@ +package ch.njol.skript.expressions; + +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.Math2; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.entity.Creeper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Fuse Ticks") +@Description("The fuse ticks of a creeper or primed TNT. This is how many ticks remain before the entity explodes.") +@Example(""" + on spawn of a creeper: + set the fuse ticks of the event-entity to 100 + """) +@Example(""" + on spawn of primed tnt: + set fuse ticks of event-entity to 200 + """) +@Since("INSERT VERSION") +public class ExprFuseTicks extends SimplePropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder(ExprFuseTicks.class, Number.class, "fuse tick[s]", "entities", false).build() + ); + } + + @Override + public @Nullable Number convert(Entity entity) { + if (entity instanceof Creeper creeper) + return creeper.getMaxFuseTicks(); + else if (entity instanceof TNTPrimed tnt) + return tnt.getFuseTicks(); + return null; + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, DELETE, ADD, REMOVE -> CollectionUtils.array(Number.class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + int value = delta != null ? Math2.fit(0, ((Number) delta[0]).intValue(), Integer.MAX_VALUE) : 0; + for (Entity entity : getExpr().getArray(event)) { + if (entity instanceof Creeper creeper) { + creeper.setMaxFuseTicks(Math2.fit(0, switch (mode) { + case SET, DELETE -> value; + case ADD -> creeper.getMaxFuseTicks() + value; + case REMOVE -> creeper.getMaxFuseTicks() - value; + default -> throw new IllegalArgumentException("Unexpected mode: " + mode); + }, Integer.MAX_VALUE)); + } else if (entity instanceof TNTPrimed tnt) { + tnt.setFuseTicks(Math2.fit(0, switch (mode) { + case SET, DELETE -> value; + case ADD -> tnt.getFuseTicks() + value; + case REMOVE -> tnt.getFuseTicks() - value; + default -> throw new IllegalArgumentException("Unexpected mode: " + mode); + }, Integer.MAX_VALUE)); + } + } + } + + @Override + public Class getReturnType() { + return Number.class; + } + + @Override + protected String getPropertyName() { + return "fuse ticks"; + } + +} \ No newline at end of file diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java b/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java index 5e07c604ed6..ff7a427a99e 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java @@ -2,6 +2,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.entity.SimpleEntityData; +import ch.njol.skript.expressions.ExprFuseTicks; import org.bukkit.entity.AbstractNautilus; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.HierarchicalAddonModule; @@ -38,7 +39,8 @@ protected void loadSelf(SkriptAddon addon) { } register(addon, - ExprDeathMessage::register + ExprDeathMessage::register, + ExprFuseTicks::register ); } diff --git a/src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk b/src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk new file mode 100644 index 00000000000..a852ae94c9d --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk @@ -0,0 +1,25 @@ +test "creeper fuse ticks": + spawn a creeper at test-location: + assert fuse ticks of entity is 30 with "fuse ticks of a creeper should be 30 by default" + set fuse ticks of entity to 100 + assert fuse ticks of entity is 100 with "fuse ticks of creeper should be 100 after setting to 100" + add 50 to fuse ticks of entity + assert fuse ticks of entity is 150 with "fuse ticks of creeper should be 150 after adding 50" + remove 200 from fuse ticks of entity + assert fuse ticks of entity is 0 with "fuse ticks of creeper should be capped at 0 minimum" + delete fuse ticks of entity + assert fuse ticks of entity is 0 with "fuse ticks of creeper should be 0 after deletion" + delete entity + +test "primed tnt fuse ticks": + spawn a primed tnt at test-location: + assert fuse ticks of entity is 80 with "fuse ticks of primed tnt should be 80 by default" + set fuse ticks of entity to 200 + assert fuse ticks of entity is 200 with "fuse ticks of primed tnt should be 200 after setting to 200" + add 50 to fuse ticks of entity + assert fuse ticks of entity is 250 with "fuse ticks of primed tnt should be 250 after adding 50" + remove 300 from fuse ticks of entity + assert fuse ticks of entity is 0 with "fuse ticks of primed tnt should be capped at 0 minimum" + delete fuse ticks of entity + assert fuse ticks of entity is 0 with "fuse ticks of primed tnt should be 0 after deletion" + delete entity \ No newline at end of file From 6f196ab5e74b9e808f018525c76ad7d3597193ec Mon Sep 17 00:00:00 2001 From: CJH3139 Date: Fri, 17 Apr 2026 00:09:41 -0700 Subject: [PATCH 2/2] Change ExprFuseTicks to ExprFuseDuration --- .../expressions/ExprCreeperMaxFuseTicks.java | 84 ------------------- ...prFuseTicks.java => ExprFuseDuration.java} | 43 +++++----- .../skript/bukkit/entity/EntityModule.java | 4 +- .../syntaxes/expressions/ExprFuseDuration.sk | 25 ++++++ .../syntaxes/expressions/ExprFuseTicks.sk | 25 ------ 5 files changed, 50 insertions(+), 131 deletions(-) delete mode 100644 src/main/java/ch/njol/skript/expressions/ExprCreeperMaxFuseTicks.java rename src/main/java/ch/njol/skript/expressions/{ExprFuseTicks.java => ExprFuseDuration.java} (56%) create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprFuseDuration.sk delete mode 100644 src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk diff --git a/src/main/java/ch/njol/skript/expressions/ExprCreeperMaxFuseTicks.java b/src/main/java/ch/njol/skript/expressions/ExprCreeperMaxFuseTicks.java deleted file mode 100644 index a14766b6341..00000000000 --- a/src/main/java/ch/njol/skript/expressions/ExprCreeperMaxFuseTicks.java +++ /dev/null @@ -1,84 +0,0 @@ -package ch.njol.skript.expressions; - -import org.bukkit.entity.Creeper; -import org.bukkit.entity.LivingEntity; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - -import ch.njol.skript.Skript; -import ch.njol.skript.classes.Changer.ChangeMode; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Example; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.util.coll.CollectionUtils; - -@Name("Creeper Max Fuse Ticks") -@Description("The max fuse ticks that a creeper has.") -@Example("set target entity's max fuse ticks to 20 #1 second") -@Since("2.5") -public class ExprCreeperMaxFuseTicks extends SimplePropertyExpression { - - static { - if(Skript.methodExists(LivingEntity.class, "getMaxFuseTicks")) - register(ExprCreeperMaxFuseTicks.class, Long.class, "[creeper] max[imum] fuse tick[s]", "livingentities"); - } - - @Override - public Long convert(LivingEntity e) { - return e instanceof Creeper ? (long) ((Creeper) e).getMaxFuseTicks() : 0; - } - - @Override - @Nullable - public Class[] acceptChange(final ChangeMode mode) { - if (mode == ChangeMode.REMOVE_ALL) - return null; - return CollectionUtils.array(Number.class); - } - - @Override - public void change(final Event e, final @Nullable Object[] delta, final ChangeMode mode) { - int d = delta == null ? 0 : ((Number) delta[0]).intValue(); - for (LivingEntity le : getExpr().getArray(e)) { - if (le instanceof Creeper) { - Creeper c = (Creeper) le; - switch (mode) { - case ADD: - int r1 = c.getMaxFuseTicks() + d; - if (r1 < 0) r1 = 0; - c.setMaxFuseTicks(r1); - break; - case SET: - c.setMaxFuseTicks(d); - break; - case DELETE: - c.setMaxFuseTicks(0); - break; - case RESET: - c.setMaxFuseTicks(30); //Seems to be the same for powered creepers? - break; - case REMOVE: - int r2 = c.getMaxFuseTicks() - d; - if (r2 < 0) r2 = 0; - c.setMaxFuseTicks(r2); - break; - case REMOVE_ALL: - assert false; - } - } - } - } - - @Override - public Class getReturnType() { - return Long.class; - } - - @Override - protected String getPropertyName() { - return "creeper max fuse ticks"; - } - -} diff --git a/src/main/java/ch/njol/skript/expressions/ExprFuseTicks.java b/src/main/java/ch/njol/skript/expressions/ExprFuseDuration.java similarity index 56% rename from src/main/java/ch/njol/skript/expressions/ExprFuseTicks.java rename to src/main/java/ch/njol/skript/expressions/ExprFuseDuration.java index e40927215d4..87ac2710539 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFuseTicks.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFuseDuration.java @@ -6,6 +6,7 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.Timespan; import ch.njol.util.Math2; import ch.njol.util.coll.CollectionUtils; import org.bukkit.entity.Creeper; @@ -15,59 +16,61 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.registration.SyntaxRegistry; -@Name("Fuse Ticks") -@Description("The fuse ticks of a creeper or primed TNT. This is how many ticks remain before the entity explodes.") +@Name("Fuse Duration") +@Description("The fuse duration of a creeper or primed TNT. For creepers, this is the total fuse duration before explosion. For primed TNT, this is the remaining time before explosion.") @Example(""" on spawn of a creeper: - set the fuse ticks of the event-entity to 100 + set the fuse duration of the event-entity to 5 seconds """) @Example(""" on spawn of primed tnt: - set fuse ticks of event-entity to 200 + set fuse duration of event-entity to 10 seconds """) @Since("INSERT VERSION") -public class ExprFuseTicks extends SimplePropertyExpression { +public class ExprFuseDuration extends SimplePropertyExpression { public static void register(SyntaxRegistry registry) { registry.register( SyntaxRegistry.EXPRESSION, - infoBuilder(ExprFuseTicks.class, Number.class, "fuse tick[s]", "entities", false).build() + infoBuilder(ExprFuseDuration.class, Timespan.class, "fuse (duration|time)", "entities", false).build() ); } @Override - public @Nullable Number convert(Entity entity) { + public @Nullable Timespan convert(Entity entity) { if (entity instanceof Creeper creeper) - return creeper.getMaxFuseTicks(); + return new Timespan(Timespan.TimePeriod.TICK, creeper.getMaxFuseTicks()); else if (entity instanceof TNTPrimed tnt) - return tnt.getFuseTicks(); + return new Timespan(Timespan.TimePeriod.TICK, tnt.getFuseTicks()); return null; } @Override public Class @Nullable [] acceptChange(ChangeMode mode) { return switch (mode) { - case SET, DELETE, ADD, REMOVE -> CollectionUtils.array(Number.class); + case SET, DELETE, ADD, REMOVE -> CollectionUtils.array(Timespan.class); default -> null; }; } @Override public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { - int value = delta != null ? Math2.fit(0, ((Number) delta[0]).intValue(), Integer.MAX_VALUE) : 0; + int ticks = delta != null && delta[0] instanceof Timespan ts + ? (int) Math2.fit(0, ts.get(Timespan.TimePeriod.TICK), Integer.MAX_VALUE) + : 0; for (Entity entity : getExpr().getArray(event)) { if (entity instanceof Creeper creeper) { creeper.setMaxFuseTicks(Math2.fit(0, switch (mode) { - case SET, DELETE -> value; - case ADD -> creeper.getMaxFuseTicks() + value; - case REMOVE -> creeper.getMaxFuseTicks() - value; + case SET, DELETE -> ticks; + case ADD -> creeper.getMaxFuseTicks() + ticks; + case REMOVE -> creeper.getMaxFuseTicks() - ticks; default -> throw new IllegalArgumentException("Unexpected mode: " + mode); }, Integer.MAX_VALUE)); } else if (entity instanceof TNTPrimed tnt) { tnt.setFuseTicks(Math2.fit(0, switch (mode) { - case SET, DELETE -> value; - case ADD -> tnt.getFuseTicks() + value; - case REMOVE -> tnt.getFuseTicks() - value; + case SET, DELETE -> ticks; + case ADD -> tnt.getFuseTicks() + ticks; + case REMOVE -> tnt.getFuseTicks() - ticks; default -> throw new IllegalArgumentException("Unexpected mode: " + mode); }, Integer.MAX_VALUE)); } @@ -75,13 +78,13 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { } @Override - public Class getReturnType() { - return Number.class; + public Class getReturnType() { + return Timespan.class; } @Override protected String getPropertyName() { - return "fuse ticks"; + return "fuse duration"; } } \ No newline at end of file diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java b/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java index ff7a427a99e..e5721c2f0f1 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java @@ -2,7 +2,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.entity.SimpleEntityData; -import ch.njol.skript.expressions.ExprFuseTicks; +import ch.njol.skript.expressions.ExprFuseDuration; import org.bukkit.entity.AbstractNautilus; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.HierarchicalAddonModule; @@ -40,7 +40,7 @@ protected void loadSelf(SkriptAddon addon) { register(addon, ExprDeathMessage::register, - ExprFuseTicks::register + ExprFuseDuration::register ); } diff --git a/src/test/skript/tests/syntaxes/expressions/ExprFuseDuration.sk b/src/test/skript/tests/syntaxes/expressions/ExprFuseDuration.sk new file mode 100644 index 00000000000..b5b101f2401 --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprFuseDuration.sk @@ -0,0 +1,25 @@ +test "creeper fuse duration": + spawn a creeper at test-location: + assert fuse duration of entity is 1.5 seconds with "fuse duration of a creeper should be 1.5 seconds by default" + set fuse duration of entity to 5 seconds + assert fuse duration of entity is 5 seconds with "fuse duration of creeper should be 5 seconds after setting to 5 seconds" + add 2.5 seconds to fuse duration of entity + assert fuse duration of entity is 7.5 seconds with "fuse duration of creeper should be 7.5 seconds after adding 2.5 seconds" + remove 10 seconds from fuse duration of entity + assert fuse duration of entity is 0 seconds with "fuse duration of creeper should be capped at 0 minimum" + delete fuse duration of entity + assert fuse duration of entity is 0 seconds with "fuse duration of creeper should be 0 seconds after deletion" + delete entity + +test "primed tnt fuse duration": + spawn a primed tnt at test-location: + assert fuse duration of entity is 4 seconds with "fuse duration of primed tnt should be 4 seconds by default" + set fuse duration of entity to 10 seconds + assert fuse duration of entity is 10 seconds with "fuse duration of primed tnt should be 10 seconds after setting to 10 seconds" + add 2.5 seconds to fuse duration of entity + assert fuse duration of entity is 12.5 seconds with "fuse duration of primed tnt should be 12.5 seconds after adding 2.5 seconds" + remove 15 seconds from fuse duration of entity + assert fuse duration of entity is 0 seconds with "fuse duration of primed tnt should be capped at 0 minimum" + delete fuse duration of entity + assert fuse duration of entity is 0 seconds with "fuse duration of primed tnt should be 0 seconds after deletion" + delete entity \ No newline at end of file diff --git a/src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk b/src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk deleted file mode 100644 index a852ae94c9d..00000000000 --- a/src/test/skript/tests/syntaxes/expressions/ExprFuseTicks.sk +++ /dev/null @@ -1,25 +0,0 @@ -test "creeper fuse ticks": - spawn a creeper at test-location: - assert fuse ticks of entity is 30 with "fuse ticks of a creeper should be 30 by default" - set fuse ticks of entity to 100 - assert fuse ticks of entity is 100 with "fuse ticks of creeper should be 100 after setting to 100" - add 50 to fuse ticks of entity - assert fuse ticks of entity is 150 with "fuse ticks of creeper should be 150 after adding 50" - remove 200 from fuse ticks of entity - assert fuse ticks of entity is 0 with "fuse ticks of creeper should be capped at 0 minimum" - delete fuse ticks of entity - assert fuse ticks of entity is 0 with "fuse ticks of creeper should be 0 after deletion" - delete entity - -test "primed tnt fuse ticks": - spawn a primed tnt at test-location: - assert fuse ticks of entity is 80 with "fuse ticks of primed tnt should be 80 by default" - set fuse ticks of entity to 200 - assert fuse ticks of entity is 200 with "fuse ticks of primed tnt should be 200 after setting to 200" - add 50 to fuse ticks of entity - assert fuse ticks of entity is 250 with "fuse ticks of primed tnt should be 250 after adding 50" - remove 300 from fuse ticks of entity - assert fuse ticks of entity is 0 with "fuse ticks of primed tnt should be capped at 0 minimum" - delete fuse ticks of entity - assert fuse ticks of entity is 0 with "fuse ticks of primed tnt should be 0 after deletion" - delete entity \ No newline at end of file