Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fire PotionSplashEvent #945

Merged
merged 10 commits into from
Jun 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/main/java/net/glowstone/entity/GlowAreaEffectCloud.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import net.glowstone.entity.meta.MetadataMap;
import net.glowstone.net.message.play.entity.EntityMetadataMessage;
import net.glowstone.net.message.play.entity.SpawnObjectMessage;
import net.glowstone.util.EntityUtils;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
Expand Down Expand Up @@ -48,7 +49,9 @@ public void pulse() {
if (entity instanceof LivingEntity
&& temporaryImmunities.getOrDefault(entity, Long.MIN_VALUE) <= currentTick
&& location.distanceSquared(entity.getLocation()) < radius * radius) {
((LivingEntity) entity).addPotionEffects(customEffects.values());
customEffects.values().forEach(
effect -> EntityUtils.applyPotionEffectWithIntensity(
effect, (LivingEntity) entity, 0.5, 0.25));
temporaryImmunities.put((LivingEntity) entity,
currentTick + reapplicationDelay);
}
Expand Down
10 changes: 2 additions & 8 deletions src/main/java/net/glowstone/entity/GlowPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
import net.glowstone.scoreboard.GlowScoreboard;
import net.glowstone.scoreboard.GlowTeam;
import net.glowstone.util.Convert;
import net.glowstone.util.EntityUtils;
import net.glowstone.util.InventoryUtil;
import net.glowstone.util.Position;
import net.glowstone.util.StatisticMap;
Expand Down Expand Up @@ -158,7 +159,6 @@
import org.bukkit.entity.Villager;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
Expand Down Expand Up @@ -840,13 +840,7 @@ public void pulse() {
if (getHealth() < getMaxHealth() && !isDead()) {
if (foodLevel >= 18 && ticksLived % 80 == 0
|| world.getDifficulty() == Difficulty.PEACEFUL) {

EntityRegainHealthEvent event1
= new EntityRegainHealthEvent(this, 1f, RegainReason.SATIATED);
EventFactory.getInstance().callEvent(event1);
if (!event1.isCancelled()) {
setHealth(getHealth() + 1);
}
EntityUtils.heal(this, 1, EntityRegainHealthEvent.RegainReason.SATIATED);
exhaustion = Math.min(exhaustion + 3.0f, 40.0f);

saturation -= 3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;

public class GlowLingeringPotion extends GlowSplashPotion implements LingeringPotion {
public GlowLingeringPotion(Location location) {
Expand Down Expand Up @@ -39,13 +38,6 @@ private void createEffectCloud() {
cloud.setColor(potionMeta.getColor());
cloud.setBasePotionData(potionMeta.getBasePotionData());
for (PotionEffect effect : getEffects()) {
// Cloud effects have only 1/4 the usual duration
PotionEffectType type = effect.getType();
if (!type.isInstant()) {
effect = new PotionEffect(effect.getType(), effect.getDuration() / 4,
effect.getAmplifier());
}
// TODO: else effect is 1/2 the usual
cloud.addCustomEffect(effect, true);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import net.glowstone.EventFactory;
import net.glowstone.net.message.play.entity.SpawnObjectMessage;
import net.glowstone.util.EntityUtils;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.SplashPotion;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;

public class GlowSplashPotion extends GlowProjectile implements SplashPotion {
private static final double MAX_VERTICAL_DISTANCE = 2.125;
private static final double MAX_DISTANCE_SQUARED = 16.0;
private static final double MAX_DISTANCE = 4.0;
private static final double MAX_DISTANCE_SQUARED = MAX_DISTANCE * MAX_DISTANCE;
@Getter
@Setter
private ItemStack item;
Expand All @@ -41,13 +47,29 @@ private void applyEffects() {
return;
}
double y = location.getY();
for (LivingEntity entity : world.getLivingEntities()) {
Location entityLocation = entity.getLocation();
double verticalOffset = entityLocation.getY() - y;
if (verticalOffset <= MAX_VERTICAL_DISTANCE
&& verticalOffset >= -MAX_VERTICAL_DISTANCE
&& entityLocation.distanceSquared(location) < MAX_DISTANCE_SQUARED) {
entity.addPotionEffects(effects);
Map<LivingEntity, Double> affectedIntensities = new HashMap<>();
world.getNearbyEntities(location, MAX_DISTANCE, MAX_VERTICAL_DISTANCE, MAX_DISTANCE)
.stream()
.filter(LivingEntity.class::isInstance)
.forEach(entity -> {
Location entityLoc = entity.getLocation();
double distFractionSquared = entityLoc.distanceSquared(location)
/ MAX_DISTANCE_SQUARED;
if (distFractionSquared < 1) {
// intensity is 1 - (distance / max distance)
affectedIntensities.put((LivingEntity) entity,
1 - Math.sqrt(distFractionSquared));
}
});
PotionSplashEvent event = EventFactory.getInstance().callEvent(
new PotionSplashEvent(this, affectedIntensities));
if (!event.isCancelled()) {
for (LivingEntity splashed : event.getAffectedEntities()) {
for (PotionEffect effect : effects) {
double intensity = event.getIntensity(splashed);
EntityUtils.applyPotionEffectWithIntensity(
effect, splashed, intensity, intensity);
}
}
}
remove();
Expand Down
81 changes: 81 additions & 0 deletions src/main/java/net/glowstone/util/EntityUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package net.glowstone.util;

import net.glowstone.EventFactory;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;

/**
* Utility methods for dealing with entities.
*/
public class EntityUtils {
/**
* Heals an entity by a specific amount.
*
* @param target the entity to heal
* @param amount the amount of health to regain
* @param reason the reason supplied to the {@link EntityRegainHealthEvent}
*/
public static void heal(LivingEntity target, double amount,
EntityRegainHealthEvent.RegainReason reason) {
if (target.isDead()) {
return; // too late!
}
final double maxHealth = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
final double currentHealth = target.getHealth();
if (currentHealth >= maxHealth) {
return;
}
EntityRegainHealthEvent event = new EntityRegainHealthEvent(target, amount, reason);
EventFactory.getInstance().callEvent(event);
if (!event.isCancelled()) {
target.setHealth(Math.min(maxHealth, currentHealth + event.getAmount()));
}
}

/**
* Applies a potion effect with an intensity ranging from 0.0 for no effect to 1.0 for full
* effect.
*
* @param effect the effect
* @param target the target to apply the effect to
* @param instantIntensity the intensity multiplier if the effect is instantaneous
* @param durationIntensity the duration multiplier if the effect has a duration
*/
public static void applyPotionEffectWithIntensity(
PotionEffect effect, LivingEntity target, double instantIntensity,
double durationIntensity) {
PotionEffectType type = effect.getType();
final int baseAmplifier = effect.getAmplifier();
if (type.equals(PotionEffectType.HEAL)) {
heal(target, (2 << baseAmplifier) * instantIntensity,
EntityRegainHealthEvent.RegainReason.MAGIC);
} else if (type.equals(PotionEffectType.HARM)) {
target.damage((3 << baseAmplifier) * instantIntensity,
EntityDamageEvent.DamageCause.MAGIC);
} else if (type.isInstant()) {
// Custom instant potion effect: can't partially apply, so scale amplifier down instead
// (but never reduce it to zero)
target.addPotionEffect((instantIntensity >= 1.0 || baseAmplifier <= 1)
? effect
: new PotionEffect(
type,
0,
Math.max(1, (int) (baseAmplifier * instantIntensity + 0.5)),
effect.isAmbient(),
effect.hasParticles(),
effect.getColor()));
} else {
target.addPotionEffect(durationIntensity >= 1.0 ? effect : new PotionEffect(
type,
(int) (effect.getDuration() * durationIntensity),
baseAmplifier,
effect.isAmbient(),
effect.hasParticles(),
effect.getColor()));
}
}
}