Moved canCombatDamageHappen logic to the main listener.

This commit is contained in:
Olof Larsson 2013-04-18 21:00:46 +02:00
parent f70cc283db
commit 18da8c1250
2 changed files with 169 additions and 184 deletions

View File

@ -1,5 +1,6 @@
package com.massivecraft.factions.listeners; package com.massivecraft.factions.listeners;
import java.text.MessageFormat;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
@ -9,7 +10,9 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Enderman; import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Wither; import org.bukkit.entity.Wither;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -26,10 +29,13 @@ import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent; 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.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.hanging.HangingPlaceEvent; import org.bukkit.event.hanging.HangingPlaceEvent;
@ -78,6 +84,169 @@ public class FactionsListenerMain implements Listener
Bukkit.getPluginManager().registerEvents(this, Factions.get()); Bukkit.getPluginManager().registerEvents(this, Factions.get());
} }
// -------------------------------------------- //
// CAN COMBAT DAMAGE HAPPEN
// -------------------------------------------- //
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void canCombatDamageHappen(EntityDamageEvent event)
{
// TODO: Can't we just listen to the class type the sub is of?
if (!(event instanceof EntityDamageByEntityEvent)) return;
EntityDamageByEntityEvent sub = (EntityDamageByEntityEvent)event;
if (this.canCombatDamageHappen(sub, true)) return;
event.setCancelled(true);
}
// 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, ignoreCancelled = true)
public void canCombatDamageHappen(EntityCombustByEntityEvent event)
{
EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(event.getCombuster(), event.getEntity(), EntityDamageEvent.DamageCause.FIRE, 0);
if (this.canCombatDamageHappen(sub, false)) return;
event.setCancelled(true);
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void canCombatDamageHappen(PotionSplashEvent event)
{
// If a harmful potion is splashing ...
if (!MUtil.isHarmfulPotion(event.getPotion())) return;
Entity thrower = event.getPotion().getShooter();
// ... scan through affected entities to make sure they're all valid targets.
for (LivingEntity affectedEntity : event.getAffectedEntities())
{
EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(thrower, affectedEntity, EntityDamageEvent.DamageCause.CUSTOM, 0);
if (this.canCombatDamageHappen(sub, true)) continue;
// affected entity list doesn't accept modification (iter.remove() is a no-go), but this works
event.setIntensity(affectedEntity, 0.0);
}
}
public boolean canCombatDamageHappen(EntityDamageByEntityEvent event, boolean notify)
{
// If the defender is a player ...
Entity edefender = event.getEntity();
if (!(edefender instanceof Player)) return true;
Player defender = (Player)edefender;
FPlayer fdefender = FPlayerColl.get().get(edefender);
// ... and the attacker is someone else ...
Entity eattacker = event.getDamager();
if (eattacker instanceof Projectile)
{
eattacker = ((Projectile)eattacker).getShooter();
}
if (eattacker.equals(edefender)) return true;
// ... gather defender PS and faction information ...
PS defenderPs = PS.valueOf(defender);
Faction defenderPsFaction = BoardColl.get().getFactionAt(defenderPs);
// ... PVP flag may cause a damage block ...
if (defenderPsFaction.getFlag(FFlag.PVP) == false)
{
if (eattacker instanceof Player)
{
if (notify)
{
FPlayer attacker = FPlayerColl.get().get((Player)eattacker);
attacker.msg("<i>PVP is disabled in %s.", defenderPsFaction.describeTo(attacker));
}
return false;
}
return defenderPsFaction.getFlag(FFlag.MONSTERS);
}
// ... and if the attacker is a player ...
if (!(eattacker instanceof Player)) return true;
Player attacker = (Player)eattacker;
FPlayer fattacker = FPlayerColl.get().get(attacker);
// ... does this player bypass all protection? ...
if (ConfServer.playersWhoBypassAllProtection.contains(attacker.getName())) return true;
// ... gather attacker PS and faction information ...
PS attackerPs = PS.valueOf(attacker);
Faction attackerPsFaction = BoardColl.get().getFactionAt(attackerPs);
// ... PVP flag may cause a damage block ...
// (just checking the defender as above isn't enough. What about the attacker? It could be in a no-pvp area)
// NOTE: This check is probably not that important but we could keep it anyways.
if (attackerPsFaction.getFlag(FFlag.PVP) == false)
{
if (notify) fattacker.msg("<i>PVP is disabled in %s.", attackerPsFaction.describeTo(fattacker));
return false;
}
// ... are PVP rules completely ignored in this world? ...
if (ConfServer.worldsIgnorePvP.contains(defenderPs.getWorld())) return true;
Faction defendFaction = fdefender.getFaction();
Faction attackFaction = fattacker.getFaction();
if (attackFaction.isNone() && ConfServer.disablePVPForFactionlessPlayers)
{
if (notify) fattacker.msg("<i>You can't hurt other players until you join a faction.");
return false;
}
else if (defendFaction.isNone())
{
if (defenderPsFaction == attackFaction && ConfServer.enablePVPAgainstFactionlessInAttackersLand)
{
// Allow PVP vs. Factionless in attacker's faction territory
return true;
}
else if (ConfServer.disablePVPForFactionlessPlayers)
{
if (notify) fattacker.msg("<i>You can't hurt players who are not currently in a faction.");
return false;
}
}
Rel relation = defendFaction.getRelationTo(attackFaction);
// Check the relation
if (fdefender.hasFaction() && relation.isAtLeast(ConfServer.friendlyFireFromRel) && defenderPsFaction.getFlag(FFlag.FRIENDLYFIRE) == false)
{
if (notify) fattacker.msg("<i>You can't hurt %s<i>.", relation.getDescPlayerMany());
return false;
}
// You can not hurt neutrals in their own territory.
boolean ownTerritory = fdefender.isInOwnTerritory();
if (fdefender.hasFaction() && ownTerritory && relation == Rel.NEUTRAL)
{
if (notify)
{
fattacker.msg("<i>You can't hurt %s<i> in their own territory unless you declare them as an enemy.", fdefender.describeTo(fattacker));
fdefender.msg("%s<i> tried to hurt you.", fattacker.describeTo(fdefender, true));
}
return false;
}
// Damage will be dealt. However check if the damage should be reduced.
int damage = event.getDamage();
if (damage > 0.0 && fdefender.hasFaction() && ownTerritory && ConfServer.territoryShieldFactor > 0)
{
int newDamage = (int)Math.ceil(damage * (1D - ConfServer.territoryShieldFactor));
event.setDamage(newDamage);
// Send message
if (notify)
{
String perc = MessageFormat.format("{0,number,#%}", (ConfServer.territoryShieldFactor)); // TODO does this display correctly??
fdefender.msg("<i>Enemy damage reduced by <rose>%s<i>.", perc);
}
}
return true;
}
// -------------------------------------------- // // -------------------------------------------- //
// REMOVE PLAYER DATA WHEN BANNED // REMOVE PLAYER DATA WHEN BANNED
// -------------------------------------------- // // -------------------------------------------- //

View File

@ -1,21 +1,11 @@
package com.massivecraft.factions.listeners; package com.massivecraft.factions.listeners;
import java.text.MessageFormat;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import com.massivecraft.factions.BoardColl; import com.massivecraft.factions.BoardColl;
import com.massivecraft.factions.ConfServer; import com.massivecraft.factions.ConfServer;
@ -23,10 +13,8 @@ import com.massivecraft.factions.FFlag;
import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.FPlayer;
import com.massivecraft.factions.FPlayerColl; import com.massivecraft.factions.FPlayerColl;
import com.massivecraft.factions.Faction; import com.massivecraft.factions.Faction;
import com.massivecraft.factions.Rel;
import com.massivecraft.factions.event.PowerLossEvent; import com.massivecraft.factions.event.PowerLossEvent;
import com.massivecraft.mcore.ps.PS; import com.massivecraft.mcore.ps.PS;
import com.massivecraft.mcore.util.MUtil;
public class TodoFactionsEntityListener implements Listener public class TodoFactionsEntityListener implements Listener
@ -83,179 +71,7 @@ public class TodoFactionsEntityListener implements Listener
} }
} }
// -------------------------------------------- //
// PVP STUFF??
// -------------------------------------------- //
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onEntityDamage(EntityDamageEvent event)
{
// TODO: Can't we just listen to the class type the sub is of?
if (!(event instanceof EntityDamageByEntityEvent)) return;
EntityDamageByEntityEvent sub = (EntityDamageByEntityEvent)event;
if ( ! this.canDamagerHurtDamagee(sub, true))
{
event.setCancelled(true);
}
}
// 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, ignoreCancelled = true)
public void onEntityCombustByEntity(EntityCombustByEntityEvent event)
{
EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(event.getCombuster(), event.getEntity(), EntityDamageEvent.DamageCause.FIRE, 0);
if ( ! this.canDamagerHurtDamagee(sub, false))
{
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPotionSplashEvent(PotionSplashEvent event)
{
// If a harmful potion is splashing ...
if (!MUtil.isHarmfulPotion(event.getPotion())) return;
Entity thrower = event.getPotion().getShooter();
// scan through affected entities to make sure they're all valid targets
for (LivingEntity affectedEntity : event.getAffectedEntities())
{
EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(thrower, affectedEntity, EntityDamageEvent.DamageCause.CUSTOM, 0);
if (this.canDamagerHurtDamagee(sub, true)) continue;
// affected entity list doesn't accept modification (iter.remove() is a no-go), but this works
event.setIntensity(affectedEntity, 0.0);
}
}
public boolean canDamagerHurtDamagee(EntityDamageByEntityEvent sub)
{
return canDamagerHurtDamagee(sub, true);
}
public boolean canDamagerHurtDamagee(EntityDamageByEntityEvent sub, boolean notify)
{
Entity damager = sub.getDamager();
Entity damagee = sub.getEntity();
int damage = sub.getDamage();
if ( ! (damagee instanceof Player)) return true;
FPlayer defender = FPlayerColl.get().get(damagee);
if (defender == null || defender.getPlayer() == null)
return true;
Location defenderLoc = defender.getPlayer().getLocation();
Faction defLocFaction = BoardColl.get().getFactionAt(PS.valueOf(defenderLoc));
// for damage caused by projectiles, getDamager() returns the projectile... what we need to know is the source
if (damager instanceof Projectile)
damager = ((Projectile)damager).getShooter();
if (damager == damagee) // ender pearl usage and other self-inflicted damage
return true;
// Players can not take attack damage in a SafeZone, or possibly peaceful territory
if (defLocFaction.getFlag(FFlag.PVP) == false)
{
if (damager instanceof Player)
{
if (notify)
{
FPlayer attacker = FPlayerColl.get().get((Player)damager);
attacker.msg("<i>PVP is disabled in %s.", defLocFaction.describeTo(attacker));
}
return false;
}
return defLocFaction.getFlag(FFlag.MONSTERS);
}
if ( ! (damager instanceof Player))
return true;
FPlayer attacker = FPlayerColl.get().get((Player)damager);
if (attacker == null || attacker.getPlayer() == null)
return true;
if (ConfServer.playersWhoBypassAllProtection.contains(attacker.getName())) return true;
Faction locFaction = BoardColl.get().getFactionAt(PS.valueOf(damager));
// 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)
{
if (notify) attacker.msg("<i>PVP is disabled in %s.", locFaction.describeTo(attacker));
return false;
}
if (ConfServer.worldsIgnorePvP.contains(defenderLoc.getWorld().getName()))
return true;
Faction defendFaction = defender.getFaction();
Faction attackFaction = attacker.getFaction();
if (attackFaction.isNone() && ConfServer.disablePVPForFactionlessPlayers)
{
if (notify) attacker.msg("<i>You can't hurt other players until you join a faction.");
return false;
}
else if (defendFaction.isNone())
{
if (defLocFaction == attackFaction && ConfServer.enablePVPAgainstFactionlessInAttackersLand)
{
// Allow PVP vs. Factionless in attacker's faction territory
return true;
}
else if (ConfServer.disablePVPForFactionlessPlayers)
{
if (notify) attacker.msg("<i>You can't hurt players who are not currently in a faction.");
return false;
}
}
Rel relation = defendFaction.getRelationTo(attackFaction);
// Check the relation
if (defender.hasFaction() && relation.isAtLeast(ConfServer.friendlyFireFromRel) && defLocFaction.getFlag(FFlag.FRIENDLYFIRE) == false)
{
if (notify) attacker.msg("<i>You can't hurt %s<i>.", relation.getDescPlayerMany());
return false;
}
// You can not hurt neutrals in their own territory.
boolean ownTerritory = defender.isInOwnTerritory();
if (defender.hasFaction() && ownTerritory && relation == Rel.NEUTRAL)
{
if (notify)
{
attacker.msg("<i>You can't hurt %s<i> in their own territory unless you declare them as an enemy.", defender.describeTo(attacker));
defender.msg("%s<i> tried to hurt you.", attacker.describeTo(defender, true));
}
return false;
}
// Damage will be dealt. However check if the damage should be reduced.
if (damage > 0.0 && defender.hasFaction() && ownTerritory && ConfServer.territoryShieldFactor > 0)
{
int newDamage = (int)Math.ceil(damage * (1D - ConfServer.territoryShieldFactor));
sub.setDamage(newDamage);
// Send message
if (notify)
{
String perc = MessageFormat.format("{0,number,#%}", (ConfServer.territoryShieldFactor)); // TODO does this display correctly??
defender.msg("<i>Enemy damage reduced by <rose>%s<i>.", perc);
}
}
return true;
}