Skip to content

Commit

Permalink
Damage effect fixes (#4003)
Browse files Browse the repository at this point in the history
  • Loading branch information
TPGamesNL authored Jun 9, 2021
1 parent cd0a120 commit 9b39c45
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 125 deletions.
4 changes: 1 addition & 3 deletions src/main/java/ch/njol/skript/SkriptConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,7 @@ public EventPriority convert(final String s) {
}
}
});

public final static Option<Boolean> disableDamageCancelChecking = new Option<Boolean>("disable damage event cancellation checking", false);


public final static Option<Boolean> logPlayerCommands = new Option<Boolean>("log player commands", false);

/**
Expand Down
1 change: 0 additions & 1 deletion src/main/java/ch/njol/skript/aliases/ItemType.java
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,6 @@ public ItemType clone() {
* @see #removeFrom(ItemStack)
* @see #removeFrom(List...)
*/
@Nullable
public ItemStack getRandom() {
int numItems = types.size();
int index = random.nextInt(numItems);
Expand Down
61 changes: 26 additions & 35 deletions src/main/java/ch/njol/skript/bukkitutil/HealthUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,107 +18,98 @@
*/
package ch.njol.skript.bukkitutil;

import org.bukkit.Bukkit;
import ch.njol.util.Math2;
import org.bukkit.attribute.Attributable;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.Damageable;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;

import ch.njol.skript.SkriptConfig;
import ch.njol.util.Math2;

/**
* @author Peter Güttinger
*/
public class HealthUtils {

public abstract class HealthUtils {

private HealthUtils() {}

/** Get the health of an entity
/**
* Get the health of an entity
* @param e Entity to get health from
* @return The amount of hearts the entity has left
*/
public static double getHealth(final Damageable e) {
public static double getHealth(Damageable e) {
if (e.isDead())
return 0;
return e.getHealth() / 2;
}

/** Set the health of an entity
/**
* Set the health of an entity
* @param e Entity to set health for
* @param health The amount of hearts to set
*/
public static void setHealth(final Damageable e, final double health) {
public static void setHealth(Damageable e, double health) {
e.setHealth(Math2.fit(0, health, getMaxHealth(e)) * 2);
}

/** Get the max health an entity has
/**
* Get the max health an entity has
* @param e Entity to get max health from
* @return How many hearts the entity can have at most
*/
public static double getMaxHealth(final Damageable e) {
public static double getMaxHealth(Damageable e) {
AttributeInstance attributeInstance = ((Attributable) e).getAttribute(Attribute.GENERIC_MAX_HEALTH);
assert attributeInstance != null;
return attributeInstance.getValue() / 2;
}

/** Set the max health an entity can have
/**
* Set the max health an entity can have
* @param e Entity to set max health for
* @param health How many hearts the entity can have at most
*/
public static void setMaxHealth(final Damageable e, final double health) {
public static void setMaxHealth(Damageable e, double health) {
AttributeInstance attributeInstance = ((Attributable) e).getAttribute(Attribute.GENERIC_MAX_HEALTH);
assert attributeInstance != null;
attributeInstance.setBaseValue(health * 2);
}

/** Apply damage to an entity
/**
* Apply damage to an entity
* @param e Entity to apply damage to
* @param d Amount of hearts to damage
*/
public static void damage(final Damageable e, final double d) {
public static void damage(Damageable e, double d) {
if (d < 0) {
heal(e, -d);
return;
}
if (!SkriptConfig.disableDamageCancelChecking.value()) {
EntityDamageEvent event = new EntityDamageEvent(e, DamageCause.CUSTOM, d * 2);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return;
}
e.damage(d * 2);
}
/** Heal an entity

/**
* Heal an entity
* @param e Entity to heal
* @param h Amount of hearts to heal
*/
public static void heal(final Damageable e, final double h) {
public static void heal(Damageable e, double h) {
if (h < 0) {
damage(e, -h);
return;
}
setHealth(e, getHealth(e) + h);
}

public static double getDamage(final EntityDamageEvent e) {
public static double getDamage(EntityDamageEvent e) {
return e.getDamage() / 2;
}

public static double getFinalDamage(final EntityDamageEvent e) {
public static double getFinalDamage(EntityDamageEvent e) {
return e.getFinalDamage() / 2;
}

public static void setDamage(final EntityDamageEvent e, final double damage) {
public static void setDamage(EntityDamageEvent e, double damage) {
e.setDamage(damage * 2);
}

public static void setDamageCause(final Damageable e, final DamageCause cause) {
e.setLastDamageCause(new EntityDamageEvent(e, cause, 0)); // Use deprecated way too keep it compatible and create cleaner code
// Non-deprecated way is really, really bad
public static void setDamageCause(Damageable e, DamageCause cause) {
e.setLastDamageCause(new EntityDamageEvent(e, cause, 0));
}

}
101 changes: 49 additions & 52 deletions src/main/java/ch/njol/skript/effects/EffHealth.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@
*/
package ch.njol.skript.effects;

import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.bukkitutil.HealthUtils;
Expand All @@ -39,6 +33,10 @@
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import ch.njol.util.Math2;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;

/**
* @author Peter Güttinger
Expand All @@ -53,86 +51,85 @@ public class EffHealth extends Effect {

static {
Skript.registerEffect(EffHealth.class,
"damage %livingentities/itemtypes% by %number% [heart[s]][ with fake cause %-damagecause%]",
"heal %livingentities% [by %-number% [heart[s]]]",
"repair %itemtypes% [by %-number%]");
"damage %livingentities/itemtypes% by %number% [heart[s]] [with fake cause %-damagecause%]",
"heal %livingentities% [by %-number% [heart[s]]]",
"repair %itemtypes% [by %-number%]");
}

@SuppressWarnings("null")
@SuppressWarnings("NotNullFieldNotInitialized")
private Expression<?> damageables;
@Nullable
private Expression<Number> damage;
private boolean heal = false;
@Nullable
private Expression<DamageCause> damageCause;

@SuppressWarnings({"unchecked", "null"})
@Override
public boolean init(final Expression<?>[] vars, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) {
damageables = vars[0];
if (ItemStack.class.isAssignableFrom(damageables.getReturnType())) {
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
if (matchedPattern == 0 && exprs[2] != null)
Skript.warning("The fake damage cause extension of this effect has no functionality, " +
"and will be removed in the future");

damageables = exprs[0];
if (!LivingEntity.class.isAssignableFrom(damageables.getReturnType())) {
if (!ChangerUtils.acceptsChange(damageables, ChangeMode.SET, ItemType.class)) {
Skript.error(damageables + " cannot be changed, thus it cannot be damaged or repaired.");
return false;
}
}
damage = (Expression<Number>) vars[1];
heal = (matchedPattern >= 1);

if (vars.length >= 3) damageCause = (Expression<DamageCause>) vars[2];
damage = (Expression<Number>) exprs[1];
heal = matchedPattern >= 1;

return true;
}

@Override
public void execute(final Event e) {
public void execute(Event e) {
double damage = 0;
if (this.damage != null) {
final Number n = this.damage.getSingle(e);
if (n == null)
Number number = this.damage.getSingle(e);
if (number == null)
return;
damage = n.doubleValue();
damage = number.doubleValue();
}
Object[] arr = damageables.getArray(e);
if (arr.length > 0 && arr[0] instanceof ItemType) {
ItemType[] newarr = new ItemType[arr.length];
for (int i = 0; i < arr.length; i++) {
ItemStack is = ((ItemType) arr[i]).getRandom();
assert is != null;
Object[] array = damageables.getArray(e);
Object[] newArray = new Object[array.length];

boolean requiresChange = false;
for (int i = 0; i < array.length; i++) {
Object value = array[i];
if (value instanceof ItemType) {
ItemType itemType = (ItemType) value;
ItemStack itemStack = itemType.getRandom();

if (this.damage == null) {
ItemUtils.setDamage(is, 0);
ItemUtils.setDamage(itemStack, 0);
} else {
ItemUtils.setDamage(is, (int) Math2.fit(0, ItemUtils.getDamage(is) + (heal ? -damage : damage), is.getType().getMaxDurability()));
ItemUtils.setDamage(itemStack, (int) Math2.fit(0, ItemUtils.getDamage(itemStack) + (heal ? -damage : damage), itemStack.getType().getMaxDurability()));
}
newarr[i] = new ItemType(is);
}

// Set changed item back to source
// We KNOW this is supported, but have to check anyway to prepare SimpleExpression for change
damageables.acceptChange(ChangeMode.SET);
damageables.change(e, newarr, ChangeMode.SET);
} else {
for (final Object damageable : arr) {
LivingEntity entity = (LivingEntity) damageable;
assert entity != null;

newArray[i] = new ItemType(itemStack);
requiresChange = true;
} else {
LivingEntity livingEntity = (LivingEntity) value;
if (!heal) {
DamageCause cause = DamageCause.CUSTOM;
if (damageCause != null)
cause = damageCause.getSingle(e);
assert cause != null;
HealthUtils.setDamageCause(entity, cause);
HealthUtils.damage(entity, damage);
HealthUtils.damage(livingEntity, damage);
} else if (this.damage == null) {
HealthUtils.setHealth(entity, HealthUtils.getMaxHealth(entity));
HealthUtils.setHealth(livingEntity, HealthUtils.getMaxHealth(livingEntity));
} else {
HealthUtils.heal(entity, damage);
HealthUtils.heal(livingEntity, damage);
}

newArray[i] = livingEntity;
}
}

if (requiresChange)
damageables.change(e, newArray, ChangeMode.SET);
}

@Override
public String toString(final @Nullable Event e, final boolean debug) {
return (heal ? "heal " : "damage ") + damageables.toString(e, debug) + (damage != null ? " by " + damage.toString(e, debug) : "");
public String toString(@Nullable Event e, boolean debug) {
return (heal ? "heal" : "damage") + " " + damageables.toString(e, debug) + (damage != null ? " by " + damage.toString(e, debug) : "");
}

}
15 changes: 8 additions & 7 deletions src/main/java/ch/njol/skript/expressions/ExprAttacker.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@
@Since("1.3")
@Events({"damage", "death", "destroy"})
public class ExprAttacker extends SimpleExpression<Entity> {

static {
Skript.registerExpression(ExprAttacker.class, Entity.class, ExpressionType.SIMPLE, "[the] (attacker|damager)");
}

@Override
public boolean init(final Expression<?>[] vars, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) {
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
if (!getParser().isCurrentEvent(EntityDamageByEntityEvent.class, EntityDeathEvent.class, VehicleDamageEvent.class, VehicleDestroyEvent.class)) {
Skript.error("Cannot use 'attacker' outside of a damage/death/destroy event", ErrorQuality.SEMANTIC_ERROR);
return false;
Expand All @@ -68,19 +69,19 @@ public boolean init(final Expression<?>[] vars, final int matchedPattern, final
}

@Override
protected Entity[] get(final Event e) {
protected Entity[] get(Event e) {
return new Entity[] {getAttacker(e)};
}

@Nullable
private static Entity getAttacker(final @Nullable Event e) {
private static Entity getAttacker(@Nullable Event e) {
if (e == null)
return null;
if (e instanceof EntityDamageByEntityEvent) {
final EntityDamageByEntityEvent edbee = (EntityDamageByEntityEvent) e;
EntityDamageByEntityEvent edbee = (EntityDamageByEntityEvent) e;
if (edbee.getDamager() instanceof Projectile) {
final Projectile p = (Projectile) edbee.getDamager();
final Object o = p.getShooter();
Projectile p = (Projectile) edbee.getDamager();
Object o = p.getShooter();
if (o instanceof Entity)
return (Entity) o;
return null;
Expand All @@ -104,7 +105,7 @@ public Class<? extends Entity> getReturnType() {
}

@Override
public String toString(final @Nullable Event e, final boolean debug) {
public String toString(@Nullable Event e, boolean debug) {
if (e == null)
return "the attacker";
return Classes.getDebugMessage(getSingle(e));
Expand Down
Loading

0 comments on commit 9b39c45

Please sign in to comment.