diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java
index 8b7c00f6219..1c0a3c5bf24 100644
--- a/src/main/java/ch/njol/skript/Skript.java
+++ b/src/main/java/ch/njol/skript/Skript.java
@@ -543,6 +543,7 @@ public void onEnable() {
try {
getAddonInstance().loadClasses("ch.njol.skript",
"conditions", "effects", "events", "expressions", "entity", "sections", "structures");
+ getAddonInstance().loadClasses("org.skriptlang.skript", "elements");
} catch (final Exception e) {
exception(e, "Could not load required .class files: " + e.getLocalizedMessage());
setEnabled(false);
diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
index 25000a2390d..4137c96c73f 100644
--- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
+++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
@@ -52,6 +52,7 @@
import org.bukkit.enchantments.EnchantmentOffer;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Entity;
+import org.bukkit.entity.Firework;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Panda.Gene;
@@ -1365,14 +1366,14 @@ public String toVariableNameString(final CachedServerIcon o) {
}
}));
}
-
+
Classes.registerClass(new EnumClassInfo<>(FireworkEffect.Type.class, "fireworktype", "firework types")
.user("firework ?types?")
.name("Firework Type")
.description("The type of a fireworkeffect.")
.since("2.4")
.documentationId("FireworkType"));
-
+
Classes.registerClass(new ClassInfo<>(FireworkEffect.class, "fireworkeffect")
.user("firework ?effects?")
.name("Firework Effect")
@@ -1409,7 +1410,15 @@ public String toVariableNameString(FireworkEffect effect) {
return "firework effect " + effect.toString();
}
}));
-
+
+ Classes.registerClass(new ClassInfo<>(Firework.class, "firework")
+ .user("fireworks?")
+ .name("Firework")
+ .description("Firework entity")
+ .defaultExpression(new EventValueExpression<>(Firework.class))
+ .since("INSERT VERSION")
+ .changer(DefaultChangers.nonLivingEntityChanger));
+
Classes.registerClass(new EnumClassInfo<>(Difficulty.class, "difficulty", "difficulties")
.user("difficult(y|ies)")
.name("Difficulty")
diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
index 0c3175247b1..9d8a645419a 100644
--- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
+++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
@@ -40,14 +40,18 @@
import ch.njol.skript.util.Timespan;
import ch.njol.skript.util.slot.InventorySlot;
import ch.njol.skript.util.slot.Slot;
+
import com.destroystokyo.paper.event.block.AnvilDamagedEvent;
import com.destroystokyo.paper.event.entity.ProjectileCollideEvent;
import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
+import com.destroystokyo.paper.event.player.PlayerElytraBoostEvent;
+
import io.papermc.paper.event.entity.EntityMoveEvent;
-import io.papermc.paper.event.player.PlayerStopUsingItemEvent;
import io.papermc.paper.event.player.PlayerInventorySlotChangeEvent;
import io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent;
+import io.papermc.paper.event.player.PlayerStopUsingItemEvent;
import io.papermc.paper.event.player.PlayerTradeEvent;
+
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.FireworkEffect;
@@ -172,9 +176,6 @@
import org.bukkit.potion.PotionEffectType;
import org.eclipse.jdt.annotation.Nullable;
-/**
- * @author Peter Güttinger
- */
@SuppressWarnings("deprecation")
public final class BukkitEventValues {
@@ -1530,8 +1531,8 @@ public SpawnReason get(CreatureSpawnEvent e) {
EventValues.registerEventValue(FireworkExplodeEvent.class, Firework.class, new Getter() {
@Override
@Nullable
- public Firework get(FireworkExplodeEvent e) {
- return e.getEntity();
+ public Firework get(FireworkExplodeEvent event) {
+ return event.getEntity();
}
}, 0);
EventValues.registerEventValue(FireworkExplodeEvent.class, FireworkEffect.class, new Getter() {
@@ -1831,6 +1832,23 @@ public ItemStack get(InventoryMoveItemEvent event) {
}
}, EventValues.TIME_NOW);
+ if (Skript.classExists("com.destroystokyo.paper.event.player.PlayerElytraBoostEvent")) {
+ EventValues.registerEventValue(PlayerElytraBoostEvent.class, Firework.class, new Getter() {
+ @Override
+ @Nullable
+ public Firework get(PlayerElytraBoostEvent event) {
+ return event.getFirework();
+ }
+ }, EventValues.TIME_NOW);
+ EventValues.registerEventValue(PlayerElytraBoostEvent.class, ItemStack.class, new Getter() {
+ @Override
+ @Nullable
+ public ItemStack get(PlayerElytraBoostEvent event) {
+ return event.getItemStack();
+ }
+ }, EventValues.TIME_NOW);
+ }
+
}
}
diff --git a/src/main/java/ch/njol/skript/events/SimpleEvents.java b/src/main/java/ch/njol/skript/events/SimpleEvents.java
index 18679fcbbbf..d55294dc764 100644
--- a/src/main/java/ch/njol/skript/events/SimpleEvents.java
+++ b/src/main/java/ch/njol/skript/events/SimpleEvents.java
@@ -18,11 +18,24 @@
*/
package ch.njol.skript.events;
+import ch.njol.skript.Skript;
+import ch.njol.skript.SkriptEventHandler;
+import ch.njol.skript.lang.util.SimpleEvent;
+
import com.destroystokyo.paper.event.block.AnvilDamagedEvent;
+import com.destroystokyo.paper.event.entity.EntityJumpEvent;
+import com.destroystokyo.paper.event.entity.ProjectileCollideEvent;
+import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
+import com.destroystokyo.paper.event.player.PlayerElytraBoostEvent;
+import com.destroystokyo.paper.event.player.PlayerJumpEvent;
import com.destroystokyo.paper.event.player.PlayerReadyArrowEvent;
-import io.papermc.paper.event.player.PlayerStopUsingItemEvent;
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
+
import io.papermc.paper.event.player.PlayerDeepSleepEvent;
import io.papermc.paper.event.player.PlayerInventorySlotChangeEvent;
+import io.papermc.paper.event.player.PlayerStopUsingItemEvent;
+import io.papermc.paper.event.player.PlayerTradeEvent;
+
import org.bukkit.event.block.BlockCanBuildEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockFertilizeEvent;
@@ -35,9 +48,9 @@
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.LeavesDecayEvent;
import org.bukkit.event.block.SignChangeEvent;
+import org.bukkit.event.block.SpongeAbsorbEvent;
import org.bukkit.event.enchantment.EnchantItemEvent;
import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
-import org.bukkit.event.block.SpongeAbsorbEvent;
import org.bukkit.event.entity.AreaEffectCloudApplyEvent;
import org.bukkit.event.entity.CreeperPowerEvent;
import org.bukkit.event.entity.EntityBreakDoorEvent;
@@ -108,19 +121,6 @@
import org.spigotmc.event.entity.EntityDismountEvent;
import org.spigotmc.event.entity.EntityMountEvent;
-import com.destroystokyo.paper.event.entity.ProjectileCollideEvent;
-import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
-import com.destroystokyo.paper.event.player.PlayerJumpEvent;
-import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
-import com.destroystokyo.paper.event.entity.EntityJumpEvent;
-import io.papermc.paper.event.player.PlayerTradeEvent;
-import ch.njol.skript.Skript;
-import ch.njol.skript.SkriptEventHandler;
-import ch.njol.skript.lang.util.SimpleEvent;
-
-/**
- * @author Peter Güttinger
- */
public class SimpleEvents {
static {
Skript.registerEvent("Can Build Check", SimpleEvent.class, BlockCanBuildEvent.class, "[block] can build check")
@@ -741,6 +741,16 @@ public class SimpleEvents {
)
.since("2.7");
+ if (Skript.classExists("com.destroystokyo.paper.event.player.PlayerElytraBoostEvent"))
+ Skript.registerEvent("Elytra Boost", SimpleEvent.class, PlayerElytraBoostEvent.class, "[player] elytra boost [(with|by) [a] firework]")
+ .description("Called when a player boosts elytra flight with a firework.")
+ .examples(
+ "on player elytra boost:",
+ "\tsend \"You boosted an elytra with a level %max life of event-firework% firework!\" to player"
+ )
+ .requiredPlugins("Paper")
+ .since("INSERT VERSION");
+
}
}
diff --git a/src/main/java/org/skriptlang/skript/elements/fireworks/CondElytraBoostConsume.java b/src/main/java/org/skriptlang/skript/elements/fireworks/CondElytraBoostConsume.java
new file mode 100644
index 00000000000..4a2553112ff
--- /dev/null
+++ b/src/main/java/org/skriptlang/skript/elements/fireworks/CondElytraBoostConsume.java
@@ -0,0 +1,75 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package org.skriptlang.skript.elements.fireworks;
+
+import org.bukkit.event.Event;
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.destroystokyo.paper.event.player.PlayerElytraBoostEvent;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.doc.Description;
+import ch.njol.skript.doc.Examples;
+import ch.njol.skript.doc.Name;
+import ch.njol.skript.doc.RequiredPlugins;
+import ch.njol.skript.doc.Since;
+import ch.njol.skript.lang.Condition;
+import ch.njol.skript.lang.Expression;
+import ch.njol.skript.lang.SkriptParser.ParseResult;
+import ch.njol.util.Kleenean;
+
+@Name("Elytra Boost Will Consume")
+@Description("Checks if the firework will be consumed in an elytra boost event.")
+@Examples({
+ "on player elytra boost:",
+ "\twill consume firework",
+ "\tset to consume the firework"
+})
+@RequiredPlugins("Paper")
+@Since("INSERT VERSION")
+public class CondElytraBoostConsume extends Condition {
+
+ static {
+ if (Skript.classExists("com.destroystokyo.paper.event.player.PlayerElytraBoostEvent"))
+ Skript.registerCondition(CondElytraBoostConsume.class, "[event] (will [:not]|not:won't) consume [the] firework");
+ }
+
+ @Override
+ public boolean init(Expression>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
+ if (getParser().isCurrentEvent(PlayerElytraBoostEvent.class)) {
+ Skript.error("You can only use the 'will consume firework' condition in the 'on elytra boost' event!");
+ return false;
+ }
+ setNegated(parseResult.hasTag("not"));
+ return true;
+ }
+
+ @Override
+ public boolean check(Event event) {
+ if (!(event instanceof PlayerElytraBoostEvent))
+ return false;
+ return isNegated() && !((PlayerElytraBoostEvent) event).shouldConsume();
+ }
+
+ @Override
+ public String toString(@Nullable Event event, boolean debug) {
+ return "will " + (isNegated() ? " not " : "") + "consume the firework";
+ }
+
+}
diff --git a/src/main/java/org/skriptlang/skript/elements/fireworks/EffElytraBoostConsume.java b/src/main/java/org/skriptlang/skript/elements/fireworks/EffElytraBoostConsume.java
new file mode 100644
index 00000000000..db991ffaeff
--- /dev/null
+++ b/src/main/java/org/skriptlang/skript/elements/fireworks/EffElytraBoostConsume.java
@@ -0,0 +1,92 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package org.skriptlang.skript.elements.fireworks;
+
+import org.bukkit.event.Event;
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.destroystokyo.paper.event.player.PlayerElytraBoostEvent;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.doc.Description;
+import ch.njol.skript.doc.Examples;
+import ch.njol.skript.doc.Name;
+import ch.njol.skript.doc.RequiredPlugins;
+import ch.njol.skript.doc.Since;
+import ch.njol.skript.lang.Effect;
+import ch.njol.skript.lang.Expression;
+import ch.njol.skript.lang.SkriptParser.ParseResult;
+import ch.njol.util.Kleenean;
+
+@Name("Elytra Boost Consume")
+@Description("Change if the firework will be consumed in an elytra boost event.")
+@Examples({
+ "on player elytra boost:",
+ "\twill consume firework",
+ "\tset to consume the firework"
+})
+@RequiredPlugins("Paper")
+@Since("INSERT VERSION")
+public class EffElytraBoostConsume extends Effect {
+
+ static {
+ if (Skript.classExists("com.destroystokyo.paper.event.player.PlayerElytraBoostEvent"))
+ Skript.registerEffect(EffElytraBoostConsume.class, "[not:do not] consume firework", "set consum(e|ption of) firework to %boolean%");
+ }
+
+ @Nullable
+ private Expression expression;
+ private boolean consume;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean init(Expression>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
+ if (getParser().isCurrentEvent(PlayerElytraBoostEvent.class)) {
+ Skript.error("You can only use the 'consume firework' effect in the 'on elytra boost' event!");
+ return false;
+ }
+ if (matchedPattern == 1) {
+ expression = (Expression) exprs[0];
+ } else {
+ consume = !parseResult.hasTag("not");
+ }
+ return true;
+ }
+
+ @Override
+ protected void execute(Event event) {
+ if (!(event instanceof PlayerElytraBoostEvent))
+ return;
+ PlayerElytraBoostEvent elytraBoostEvent = (PlayerElytraBoostEvent) event;
+ if (expression != null) {
+ Boolean consume = expression.getSingle(event);
+ if (consume == null)
+ return;
+ elytraBoostEvent.setShouldConsume(consume);
+ } else {
+ elytraBoostEvent.setShouldConsume(consume);
+ }
+ }
+
+ @Override
+ public String toString(@Nullable Event event, boolean debug) {
+ return expression == null ? (consume ? "consume" : "do not consume") + " firework" : "set consume firework to " + expression.toString(event, debug);
+ }
+
+}
diff --git a/src/main/java/org/skriptlang/skript/elements/fireworks/ExprAttachedTo.java b/src/main/java/org/skriptlang/skript/elements/fireworks/ExprAttachedTo.java
new file mode 100644
index 00000000000..613c667098f
--- /dev/null
+++ b/src/main/java/org/skriptlang/skript/elements/fireworks/ExprAttachedTo.java
@@ -0,0 +1,101 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package org.skriptlang.skript.elements.fireworks;
+
+import org.bukkit.entity.Firework;
+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.Examples;
+import ch.njol.skript.doc.Name;
+import ch.njol.skript.doc.RequiredPlugins;
+import ch.njol.skript.doc.Since;
+import ch.njol.skript.expressions.base.SimplePropertyExpression;
+import ch.njol.util.coll.CollectionUtils;
+
+@Name("Firework Attached To")
+@Description("Returns the entity attached to the fireworks if any.")
+@Examples({
+ "on firework explode:",
+ "\tloop all players in radius 10 around event-location:",
+ "\t\tloop-player is not attached entity of event-firework",
+ "\t\tpush loop-player upwards at speed 2"
+})
+@RequiredPlugins("Spigot 1.19.4+ or Paper")
+@Since("INSERT VERSION")
+@SuppressWarnings("deprecation")
+public class ExprAttachedTo extends SimplePropertyExpression {
+
+ /**
+ * Developer note:
+ * Paper had a method called getBoostedEntity() in the Firework class since before 1.13.
+ * Spigot added the same method but called it getAttachedTo() in 1.19.
+ */
+ private static final boolean BOOSTED_ENTITY = Skript.methodExists(Firework.class, "getBoostedEntity");
+ private static final boolean RUNNING_1_19 = Skript.isRunningMinecraft(1, 19, 4);
+
+ static {
+ if (RUNNING_1_19 || BOOSTED_ENTITY)
+ registerDefault(ExprAttachedTo.class, LivingEntity.class, "(attached [to]|boost(ing|ed)) entity", "fireworks");
+ }
+
+ @Override
+ @Nullable
+ public LivingEntity convert(Firework firework) {
+ if (RUNNING_1_19)
+ return firework.getAttachedTo();
+ return firework.getBoostedEntity();
+ }
+
+ @Override
+ @Nullable
+ public Class>[] acceptChange(ChangeMode mode) {
+ if (!RUNNING_1_19)
+ Skript.error("You can only set/clear the 'attached entity' in 1.19+");
+ if (mode == ChangeMode.SET) {
+ return CollectionUtils.array(LivingEntity.class);
+ } else if (mode == ChangeMode.DELETE) {
+ return CollectionUtils.array();
+ }
+ return null;
+ }
+
+ @Override
+ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
+ assert RUNNING_1_19;
+ LivingEntity attach = mode == ChangeMode.DELETE ? null : (LivingEntity) delta[0];
+ for (Firework firework : getExpr().getArray(event))
+ firework.setAttachedTo(attach);
+ }
+
+ @Override
+ public Class extends LivingEntity> getReturnType() {
+ return LivingEntity.class;
+ }
+
+ @Override
+ protected String getPropertyName() {
+ return "firework attached entity";
+ }
+
+}
diff --git a/src/main/java/org/skriptlang/skript/elements/fireworks/ExprFireworkFlownTime.java b/src/main/java/org/skriptlang/skript/elements/fireworks/ExprFireworkFlownTime.java
new file mode 100644
index 00000000000..7cc8ca181bc
--- /dev/null
+++ b/src/main/java/org/skriptlang/skript/elements/fireworks/ExprFireworkFlownTime.java
@@ -0,0 +1,171 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package org.skriptlang.skript.elements.fireworks;
+
+import org.bukkit.entity.Firework;
+import org.bukkit.event.Event;
+import org.eclipse.jdt.annotation.Nullable;
+
+import ch.njol.skript.Skript;
+import ch.njol.skript.classes.Changer;
+import ch.njol.skript.classes.Changer.ChangeMode;
+import ch.njol.skript.doc.Description;
+import ch.njol.skript.doc.Examples;
+import ch.njol.skript.doc.Name;
+import ch.njol.skript.doc.Since;
+import ch.njol.skript.expressions.base.SimplePropertyExpression;
+import ch.njol.skript.lang.Expression;
+import ch.njol.skript.lang.SkriptParser.ParseResult;
+import ch.njol.skript.util.Timespan;
+import ch.njol.util.Kleenean;
+import ch.njol.util.coll.CollectionUtils;
+
+@Name("Firework Flown Time")
+@Description({
+ "How much time that the fireworks have been boosting the player in an elytra boost event.",
+ "Maximum is the same as time until detonation. Paper names them differently than Spigot."
+})
+@Examples({
+ "if the time until detonation is less than 5 seconds:",
+ "\tadd 2 seconds to time until detonation of event-firework"
+})
+@Since("INSERT VERSION")
+@SuppressWarnings("removal")
+public class ExprFireworkFlownTime extends SimplePropertyExpression {
+
+ private final static boolean PAPER = Skript.methodExists(Firework.class, "getTicksFlown");
+
+ /**
+ * Developer note:
+ * Spigot's methods are {@link Firework#getLife()} and {@link Firework#getMaxLife()} and were added in 1.19.
+ * Paper has had these methods since 1.18 but were named the following;
+ * {@link Firework#getTicksFlown()} and {@link Firework#getTicksToDetonate()} respectfully.
+ * Paper does not agree with Spigot's method naming, so they have Spigot's deprecated.
+ */
+ static {
+ registerDefault(ExprFireworkFlownTime.class, Timespan.class, "[firework] ([detonate:max[imum]] life[time]|flown time|detonate:time until detonat(e|ion))", "fireworks");
+ }
+
+ private boolean detonate;
+
+ @Override
+ public boolean init(Expression>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
+ detonate = parseResult.hasTag("detonate");
+ return super.init(exprs, matchedPattern, isDelayed, parseResult);
+ }
+
+ @Override
+ public Timespan convert(Firework firework) {
+ if (PAPER)
+ return Timespan.fromTicks_i(detonate ? firework.getTicksToDetonate() : firework.getTicksFlown());
+ return Timespan.fromTicks_i(detonate ? firework.getMaxLife() : firework.getLife());
+ }
+
+ @Nullable
+ @Override
+ public Class>[] acceptChange(Changer.ChangeMode mode) {
+ switch (mode) {
+ case ADD:
+ case DELETE:
+ case REMOVE:
+ case RESET:
+ case SET:
+ return CollectionUtils.array(Timespan.class);
+ case REMOVE_ALL:
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) {
+ long ticks = (mode == ChangeMode.DELETE || mode == ChangeMode.RESET) ? 0 : ((Timespan) delta[0]).getTicks_i();
+ switch (mode) {
+ case REMOVE:
+ ticks = -ticks;
+ case ADD:
+ for (Firework firework : getExpr().getArray(event)) {
+ long existing = convert(firework).getTicks_i();
+ if (detonate) {
+ if (PAPER) {
+ firework.setTicksToDetonate((int) Math.min(0, existing + ticks));
+ } else {
+ firework.setMaxLife((int) Math.min(0, existing + ticks));
+ }
+ } else {
+ if (PAPER) {
+ firework.setTicksFlown((int) Math.min(0, existing + ticks));
+ } else {
+ firework.setLife((int) Math.min(0, existing + ticks));
+ }
+ }
+ }
+ break;
+ case SET:
+ for (Firework firework : getExpr().getArray(event)) {
+ if (detonate) {
+ if (PAPER) {
+ firework.setTicksToDetonate((int) Math.min(0, ticks));
+ } else {
+ firework.setMaxLife((int) Math.min(0, ticks));
+ }
+ } else {
+ if (PAPER) {
+ firework.setTicksFlown((int) Math.min(0, ticks));
+ } else {
+ firework.setLife((int) Math.min(0, ticks));
+ }
+ }
+ }
+ break;
+ case DELETE:
+ case RESET:
+ for (Firework firework : getExpr().getArray(event)) {
+ if (detonate) {
+ if (PAPER) {
+ firework.setTicksToDetonate((int) 20 * firework.getFireworkMeta().getPower());
+ } else {
+ firework.setMaxLife((int) 20 * firework.getFireworkMeta().getPower());
+ }
+ } else {
+ if (PAPER) {
+ firework.setTicksFlown((int) 20 * firework.getFireworkMeta().getPower());
+ } else {
+ firework.setLife((int) 20 * firework.getFireworkMeta().getPower());
+ }
+ }
+ }
+ break;
+ case REMOVE_ALL:
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public Class getReturnType() {
+ return Timespan.class;
+ }
+
+ @Override
+ protected String getPropertyName() {
+ return "firework " + (detonate ? "max " : " ") + "lifetime";
+ }
+
+}
diff --git a/src/main/java/org/skriptlang/skript/elements/fireworks/package-info.java b/src/main/java/org/skriptlang/skript/elements/fireworks/package-info.java
new file mode 100644
index 00000000000..bafe89c93b7
--- /dev/null
+++ b/src/main/java/org/skriptlang/skript/elements/fireworks/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Skript is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD})
+package org.skriptlang.skript.elements.fireworks;
+
+import org.eclipse.jdt.annotation.DefaultLocation;
+import org.eclipse.jdt.annotation.NonNullByDefault;
diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang
index efd0651babf..4d854cb6fab 100644
--- a/src/main/resources/lang/default.lang
+++ b/src/main/resources/lang/default.lang
@@ -2059,6 +2059,7 @@ types:
quitreason: quit reason¦s @a
inventoryclosereason: inventory close reason¦s @an
transformreason: transform reason¦s @a
+ firework: firework¦s @a
# Skript
weathertype: weather type¦s @a