diff --git a/src/com/massivecraft/factions/listeners/FactionsEntityListener.java b/src/com/massivecraft/factions/listeners/FactionsEntityListener.java index 767de939..281938c1 100644 --- a/src/com/massivecraft/factions/listeners/FactionsEntityListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsEntityListener.java @@ -1,14 +1,19 @@ package com.massivecraft.factions.listeners; -import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.logging.Level; +import java.text.MessageFormat; +import java.util.Set; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Enderman; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.TNTPrimed; @@ -17,15 +22,19 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityCombustByEntityEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.ExplosionPrimeEvent; +import org.bukkit.event.entity.PotionSplashEvent; import org.bukkit.event.painting.PaintingBreakByEntityEvent; import org.bukkit.event.painting.PaintingBreakEvent; import org.bukkit.event.painting.PaintingPlaceEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import com.massivecraft.factions.Board; import com.massivecraft.factions.Conf; @@ -76,12 +85,12 @@ public class FactionsEntityListener implements Listener @EventHandler(priority = EventPriority.NORMAL) public void onEntityDamage(EntityDamageEvent event) { - if ( event.isCancelled()) return; + if (event.isCancelled()) return; if (event instanceof EntityDamageByEntityEvent) { EntityDamageByEntityEvent sub = (EntityDamageByEntityEvent)event; - if ( ! this.canDamagerHurtDamagee(sub)) + if ( ! this.canDamagerHurtDamagee(sub, true)) { event.setCancelled(true); } @@ -97,7 +106,7 @@ public class FactionsEntityListener implements Listener @EventHandler(priority = EventPriority.NORMAL) public void onEntityExplode(EntityExplodeEvent event) { - if ( event.isCancelled()) return; + if (event.isCancelled()) return; for (Block block : event.blockList()) { @@ -110,8 +119,63 @@ public class FactionsEntityListener implements Listener } } } - + + // mainly for flaming arrows; don't want allies or people in safe zones to be ignited even after damage event is cancelled + @EventHandler(priority = EventPriority.NORMAL) + public void onEntityCombustByEntity(EntityCombustByEntityEvent event) + { + if (event.isCancelled()) return; + + EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(event.getCombuster(), event.getEntity(), EntityDamageEvent.DamageCause.FIRE, 0); + if ( ! this.canDamagerHurtDamagee(sub, false)) + event.setCancelled(true); + sub = null; + } + + private static final Set badPotionEffects = new LinkedHashSet(Arrays.asList( + PotionEffectType.BLINDNESS, PotionEffectType.CONFUSION, PotionEffectType.HARM, PotionEffectType.HUNGER, + PotionEffectType.POISON, PotionEffectType.SLOW, PotionEffectType.SLOW_DIGGING, PotionEffectType.WEAKNESS + )); + + @EventHandler(priority = EventPriority.NORMAL) + public void onPotionSplashEvent(PotionSplashEvent event) + { + if (event.isCancelled()) return; + + // see if the potion has a harmful effect + boolean badjuju = false; + for (PotionEffect effect : event.getPotion().getEffects()) + { + if (badPotionEffects.contains(effect.getType())) + { + badjuju = true; + break; + } + } + if ( ! badjuju) return; + + Entity thrower = event.getEntity(); + if (thrower instanceof Projectile) + thrower = ((Projectile)thrower).getShooter(); + + // scan through affected entities to make sure they're all valid targets + Iterator iter = event.getAffectedEntities().iterator(); + while (iter.hasNext()) + { + LivingEntity target = iter.next(); + EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(thrower, target, EntityDamageEvent.DamageCause.CUSTOM, 0); + if ( ! this.canDamagerHurtDamagee(sub, true)) + event.setIntensity(target, 0.0); // affected entity list doesn't accept modification (iter.remove() is a no-go), but this works + sub = null; + } + } + public boolean canDamagerHurtDamagee(EntityDamageByEntityEvent sub) + { + return canDamagerHurtDamagee(sub, true); + } + + public boolean canDamagerHurtDamagee(EntityDamageByEntityEvent sub, boolean notify) { Entity damager = sub.getDamager(); Entity damagee = sub.getEntity(); @@ -141,8 +205,11 @@ public class FactionsEntityListener implements Listener { if (damager instanceof Player) { - FPlayer attacker = FPlayers.i.get((Player)damager); - attacker.msg("PVP is disabled in %s.", defLocFaction.describeTo(attacker)); + if (notify) + { + FPlayer attacker = FPlayers.i.get((Player)damager); + attacker.msg("PVP is disabled in %s.", defLocFaction.describeTo(attacker)); + } return false; } return defLocFaction.getFlag(FFlag.MONSTERS); @@ -158,7 +225,7 @@ public class FactionsEntityListener implements Listener if (attacker.hasLoginPvpDisabled()) { - attacker.msg("You can't hurt other players for " + Conf.noPVPDamageToOthersForXSecondsAfterLogin + " seconds after logging in."); + if (notify) attacker.msg("You can't hurt other players for " + Conf.noPVPDamageToOthersForXSecondsAfterLogin + " seconds after logging in."); return false; } @@ -167,7 +234,7 @@ public class FactionsEntityListener implements Listener // so we know from above that the defender isn't in a safezone... what about the attacker, sneaky dog that he might be? if (locFaction.getFlag(FFlag.PVP) == false) { - attacker.msg("PVP is disabled in %s.", locFaction.describeTo(attacker)); + if (notify) attacker.msg("PVP is disabled in %s.", locFaction.describeTo(attacker)); return false; } @@ -179,7 +246,7 @@ public class FactionsEntityListener implements Listener if (attackFaction.isNone() && Conf.disablePVPForFactionlessPlayers) { - attacker.msg("You can't hurt other players until you join a faction."); + if (notify) attacker.msg("You can't hurt other players until you join a faction."); return false; } else if (defendFaction.isNone()) @@ -191,7 +258,7 @@ public class FactionsEntityListener implements Listener } else if (Conf.disablePVPForFactionlessPlayers) { - attacker.msg("You can't hurt players who are not currently in a faction."); + if (notify) attacker.msg("You can't hurt players who are not currently in a faction."); return false; } } @@ -201,7 +268,7 @@ public class FactionsEntityListener implements Listener // Check the relation if (relation.isAtLeast(Conf.friendlyFireFromRel) && defLocFaction.getFlag(FFlag.FRIENDLYFIRE) == false) { - attacker.msg("You can't hurt %s.", relation.getDescPlayerMany()); + if (notify) attacker.msg("You can't hurt %s.", relation.getDescPlayerMany()); return false; } @@ -209,20 +276,26 @@ public class FactionsEntityListener implements Listener boolean ownTerritory = defender.isInOwnTerritory(); if (defender.hasFaction() && ownTerritory && relation == Rel.NEUTRAL) { - attacker.msg("You can't hurt %s in their own territory unless you declare them as an enemy.", defender.describeTo(attacker)); - defender.msg("%s tried to hurt you.", attacker.describeTo(defender, true)); + if (notify) + { + attacker.msg("You can't hurt %s in their own territory unless you declare them as an enemy.", defender.describeTo(attacker)); + defender.msg("%s tried to hurt you.", attacker.describeTo(defender, true)); + } return false; } // Damage will be dealt. However check if the damage should be reduced. - if (ownTerritory && Conf.territoryShieldFactor > 0) + if (damage > 0.0 && ownTerritory && Conf.territoryShieldFactor > 0) { int newDamage = (int)Math.ceil(damage * (1D - Conf.territoryShieldFactor)); sub.setDamage(newDamage); // Send message - String perc = MessageFormat.format("{0,number,#%}", (Conf.territoryShieldFactor)); // TODO does this display correctly?? - defender.msg("Enemy damage reduced by %s.", perc); + if (notify) + { + String perc = MessageFormat.format("{0,number,#%}", (Conf.territoryShieldFactor)); // TODO does this display correctly?? + defender.msg("Enemy damage reduced by %s.", perc); + } } return true;