2011-07-18 22:06:02 +02:00
package com.massivecraft.factions.listeners ;
2011-02-06 13:36:11 +01:00
2014-04-04 20:55:21 +02:00
import com.massivecraft.factions.* ;
import com.massivecraft.factions.event.PowerLossEvent ;
import com.massivecraft.factions.struct.Relation ;
import com.massivecraft.factions.util.MiscUtil ;
2015-01-23 20:25:14 +01:00
import com.massivecraft.factions.zcore.util.TL ;
2012-12-19 13:18:56 +01:00
import org.bukkit.Bukkit ;
2011-08-02 03:22:16 +02:00
import org.bukkit.Location ;
New setting "handleExploitTNTWaterlog" (default false/disabled) which, if enabled, will cause TNT which explodes in liquid to actually destroy a single adjacent block in all 6 directions. This will only apply to blocks which can be destroyed by TNT normally, specifically anything other than air, bedrock, water, lava, obsidian, and enchanting tables. The destruction of these blocks will be handled as if they had been mined, dropping the appropriate item.
TNT in water/lava doesn't normally destroy any surrounding blocks, which is usually desired behavior. That's the reason this setting is disabled by default. However, it is available because it provides a method to get through waterwalls with enough persistence, and it makes cheap (non-obsidian) TNT cannons require minor maintenance between shots. Both are useful things for my server.
2012-03-19 17:18:40 +01:00
import org.bukkit.block.Block ;
2014-04-04 20:55:21 +02:00
import org.bukkit.entity.* ;
2013-04-23 15:52:39 +02:00
import org.bukkit.entity.minecart.ExplosiveMinecart ;
2012-01-28 11:37:55 +01:00
import org.bukkit.event.EventHandler ;
import org.bukkit.event.EventPriority ;
import org.bukkit.event.Listener ;
2014-04-04 20:55:21 +02:00
import org.bukkit.event.entity.* ;
2012-10-31 22:16:19 +01:00
import org.bukkit.event.hanging.HangingBreakByEntityEvent ;
import org.bukkit.event.hanging.HangingBreakEvent ;
2012-11-03 12:21:28 +01:00
import org.bukkit.event.hanging.HangingBreakEvent.RemoveCause ;
2012-10-31 22:16:19 +01:00
import org.bukkit.event.hanging.HangingPlaceEvent ;
2018-08-30 01:36:56 +02:00
import org.bukkit.event.player.PlayerInteractEntityEvent ;
2012-02-23 07:09:19 +01:00
import org.bukkit.potion.PotionEffect ;
import org.bukkit.potion.PotionEffectType ;
2014-04-06 00:00:33 +02:00
import org.bukkit.projectiles.ProjectileSource ;
2011-07-18 22:06:02 +02:00
2014-04-04 20:55:21 +02:00
import java.util.* ;
public class FactionsEntityListener implements Listener {
2014-08-05 17:17:27 +02:00
2019-12-02 19:55:38 +01:00
/ * *
* @author FactionsUUID Team
* /
2019-09-15 11:19:06 +02:00
private static final Set < PotionEffectType > badPotionEffects = new LinkedHashSet < > ( Arrays . asList ( PotionEffectType . BLINDNESS , PotionEffectType . CONFUSION , PotionEffectType . HARM , PotionEffectType . HUNGER , PotionEffectType . POISON , PotionEffectType . SLOW , PotionEffectType . SLOW_DIGGING , PotionEffectType . WEAKNESS , PotionEffectType . WITHER ) ) ;
2019-09-18 11:22:05 +02:00
2019-09-15 11:19:06 +02:00
@EventHandler ( priority = EventPriority . NORMAL )
public void onEntityDeath ( EntityDeathEvent event ) {
Entity entity = event . getEntity ( ) ;
if ( ! ( entity instanceof Player ) ) {
return ;
}
Player player = ( Player ) entity ;
FPlayer fplayer = FPlayers . getInstance ( ) . getByPlayer ( player ) ;
Faction faction = Board . getInstance ( ) . getFactionAt ( new FLocation ( player . getLocation ( ) ) ) ;
PowerLossEvent powerLossEvent = new PowerLossEvent ( faction , fplayer ) ;
// Check for no power loss conditions
if ( faction . isWarZone ( ) ) {
// war zones always override worldsNoPowerLoss either way, thus this layout
if ( ! Conf . warZonePowerLoss ) {
powerLossEvent . setMessage ( TL . PLAYER_POWER_NOLOSS_WARZONE . toString ( ) ) ;
powerLossEvent . setCancelled ( true ) ;
}
if ( Conf . worldsNoPowerLoss . contains ( player . getWorld ( ) . getName ( ) ) ) {
powerLossEvent . setMessage ( TL . PLAYER_POWER_LOSS_WARZONE . toString ( ) ) ;
}
} else if ( faction . isWilderness ( ) & & ! Conf . wildernessPowerLoss & & ! Conf . worldsNoWildernessProtection . contains ( player . getWorld ( ) . getName ( ) ) ) {
powerLossEvent . setMessage ( TL . PLAYER_POWER_NOLOSS_WILDERNESS . toString ( ) ) ;
powerLossEvent . setCancelled ( true ) ;
} else if ( Conf . worldsNoPowerLoss . contains ( player . getWorld ( ) . getName ( ) ) ) {
powerLossEvent . setMessage ( TL . PLAYER_POWER_NOLOSS_WORLD . toString ( ) ) ;
powerLossEvent . setCancelled ( true ) ;
} else if ( Conf . peacefulMembersDisablePowerLoss & & fplayer . hasFaction ( ) & & fplayer . getFaction ( ) . isPeaceful ( ) ) {
powerLossEvent . setMessage ( TL . PLAYER_POWER_NOLOSS_PEACEFUL . toString ( ) ) ;
powerLossEvent . setCancelled ( true ) ;
} else {
powerLossEvent . setMessage ( TL . PLAYER_POWER_NOW . toString ( ) ) ;
}
// call Event
Bukkit . getPluginManager ( ) . callEvent ( powerLossEvent ) ;
2019-11-01 19:15:18 +01:00
// Call player onDeath if the event is not cancelled and not using custom power
if ( ! powerLossEvent . isCancelled ( ) & & ! powerLossEvent . usingCustomPower ( ) ) {
2019-09-15 11:19:06 +02:00
fplayer . onDeath ( ) ;
2019-11-01 19:15:18 +01:00
} else if ( powerLossEvent . usingCustomPower ( ) & & ! powerLossEvent . isCancelled ( ) ) {
fplayer . alterPower ( - powerLossEvent . getCustomPowerLost ( ) ) ;
2019-09-15 11:19:06 +02:00
}
// Send the message from the powerLossEvent
final String msg = powerLossEvent . getMessage ( ) ;
if ( msg ! = null & & ! msg . isEmpty ( ) ) {
fplayer . msg ( msg , fplayer . getPowerRounded ( ) , fplayer . getPowerMaxRounded ( ) ) ;
}
}
/ * *
* Who can I hurt ? I can never hurt members or allies . I can always hurt enemies . I can hurt neutrals as long as
* they are outside their own territory .
* /
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
public void onEntityDamage ( EntityDamageEvent event ) {
if ( event instanceof EntityDamageByEntityEvent ) {
EntityDamageByEntityEvent sub = ( EntityDamageByEntityEvent ) event ;
2020-04-06 16:32:16 +02:00
if ( ! this . canDamagerHurtDamagee ( sub , true ) ) event . setCancelled ( true ) ;
2019-09-15 11:19:06 +02:00
2020-04-06 16:32:16 +02:00
// event is not cancelled by factions
2019-09-15 11:19:06 +02:00
Entity damagee = sub . getEntity ( ) ;
Entity damager = sub . getDamager ( ) ;
if ( damagee instanceof Player ) {
if ( damager instanceof Player ) {
FPlayer fdamager = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damager ) ;
FPlayer fdamagee = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damagee ) ;
if ( ( fdamagee . getRelationTo ( fdamager ) = = Relation . ALLY ) | |
( fdamagee . getRelationTo ( fdamager ) = = Relation . TRUCE ) | |
( fdamagee . getFaction ( ) = = fdamager . getFaction ( ) ) ) {
return ;
}
} else {
// this triggers if damagee is a player and damager is mob ( so like if a skeleton hits u )
if ( damager instanceof Projectile ) {
// this will trigger if the damager is a projectile
if ( ( ( Projectile ) damager ) . getShooter ( ) instanceof Player ) {
Player damagerPlayer = ( Player ) ( ( Projectile ) damager ) . getShooter ( ) ;
FPlayer fdamager = FPlayers . getInstance ( ) . getByPlayer ( damagerPlayer ) ;
FPlayer fdamagee = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damagee ) ;
Relation relation = fdamager . getRelationTo ( fdamagee ) ;
if ( relation = = Relation . ALLY | | relation = = Relation . TRUCE | |
fdamager . getFaction ( ) = = fdamagee . getFaction ( ) ) {
// this should disable the fly so
return ;
}
2020-04-06 16:32:16 +02:00
} else return ; // this should trigger if the attacker shootin the arrow is a mob
2019-08-24 19:18:50 +02:00
}
2019-09-15 11:19:06 +02:00
}
} else {
// Protect armor stands/item frames from being damaged in protected territories
2020-04-06 16:32:16 +02:00
if ( damagee . getType ( ) = = EntityType . ITEM_FRAME | | damagee . getType ( ) = = EntityType . ARMOR_STAND ) {
2019-09-15 11:19:06 +02:00
// Manage projectiles launched by players
if ( damager instanceof Projectile & & ( ( Projectile ) damager ) . getShooter ( ) instanceof Entity ) {
damager = ( Entity ) ( ( Projectile ) damager ) . getShooter ( ) ;
2019-08-24 19:18:50 +02:00
}
2019-09-15 11:19:06 +02:00
// Run the check for a player
2019-08-24 19:18:50 +02:00
if ( damager instanceof Player ) {
2020-04-06 16:32:16 +02:00
if ( ! FactionsBlockListener . playerCanBuildDestroyBlock ( ( Player ) damager , damagee . getLocation ( ) , " destroy " , false ) )
2019-09-15 11:19:06 +02:00
event . setCancelled ( true ) ;
2020-04-06 16:32:16 +02:00
2019-09-15 11:19:06 +02:00
} else {
// we don't want to let mobs/arrows destroy item frames/armor stands
// so we only have to run the check as if there had been an explosion at the damager location
2020-04-06 16:32:16 +02:00
if ( ! this . checkExplosionForBlock ( damager , damagee . getLocation ( ) . getBlock ( ) ) )
2019-09-15 11:19:06 +02:00
event . setCancelled ( true ) ;
2019-09-15 11:15:33 +02:00
}
2019-09-15 11:19:06 +02:00
// we don't need to go after
2019-09-15 11:14:14 +02:00
return ;
2019-09-15 11:19:06 +02:00
}
//this one should trigger if something other than a player takes damage
2020-04-06 16:32:16 +02:00
if ( damager instanceof Player ) return ;
2019-09-15 11:19:06 +02:00
}
if ( damagee ! = null & & damagee instanceof Player ) {
cancelFStuckTeleport ( ( Player ) damagee ) ;
cancelFFly ( ( Player ) damagee ) ;
FPlayer fplayer = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damagee ) ;
if ( fplayer . isInspectMode ( ) ) {
fplayer . setInspectMode ( false ) ;
fplayer . msg ( TL . COMMAND_INSPECT_DISABLED_MSG ) ;
}
}
if ( damager instanceof Player ) {
cancelFStuckTeleport ( ( Player ) damager ) ;
cancelFFly ( ( Player ) damager ) ;
FPlayer fplayer = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damager ) ;
if ( fplayer . isInspectMode ( ) ) {
fplayer . setInspectMode ( false ) ;
fplayer . msg ( TL . COMMAND_INSPECT_DISABLED_MSG ) ;
}
}
} else if ( Conf . safeZonePreventAllDamageToPlayers & & isPlayerInSafeZone ( event . getEntity ( ) ) ) {
// Players can not take any damage in a Safe Zone
event . setCancelled ( true ) ;
} else if ( event . getCause ( ) = = EntityDamageEvent . DamageCause . FALL & & event . getEntity ( ) instanceof Player ) {
Player player = ( Player ) event . getEntity ( ) ;
FPlayer fPlayer = FPlayers . getInstance ( ) . getByPlayer ( player ) ;
if ( fPlayer ! = null & & ! fPlayer . shouldTakeFallDamage ( ) ) {
event . setCancelled ( true ) ; // Falling after /f fly
}
}
// entity took generic damage?
Entity entity = event . getEntity ( ) ;
if ( entity instanceof Player ) {
Player player = ( Player ) entity ;
FPlayer me = FPlayers . getInstance ( ) . getByPlayer ( player ) ;
cancelFStuckTeleport ( player ) ;
if ( me . isWarmingUp ( ) ) {
me . clearWarmup ( ) ;
me . msg ( TL . WARMUPS_CANCELLED ) ;
}
}
}
2020-04-06 16:32:16 +02:00
2019-09-15 11:19:06 +02:00
private void cancelFFly ( Player player ) {
2019-11-21 14:50:51 +01:00
if ( player = = null ) return ;
2019-09-15 11:19:06 +02:00
FPlayer fPlayer = FPlayers . getInstance ( ) . getByPlayer ( player ) ;
2019-11-21 14:50:51 +01:00
if ( fPlayer . isFlying ( ) ) fPlayer . setFFlying ( false , true ) ;
2019-09-15 11:19:06 +02:00
}
public void cancelFStuckTeleport ( Player player ) {
2019-11-21 14:50:51 +01:00
if ( player = = null ) return ;
2019-09-15 11:19:06 +02:00
UUID uuid = player . getUniqueId ( ) ;
2019-11-21 14:50:51 +01:00
if ( FactionsPlugin . getInstance ( ) . getStuckMap ( ) . containsKey ( uuid ) )
2019-09-15 11:19:06 +02:00
FPlayers . getInstance ( ) . getByPlayer ( player ) . msg ( TL . COMMAND_STUCK_CANCELLED ) ;
2020-03-25 05:56:39 +01:00
FactionsPlugin . getInstance ( ) . getStuckMap ( ) . remove ( uuid ) ;
2019-09-15 11:19:06 +02:00
}
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
public void onEntityExplode ( EntityExplodeEvent event ) {
Entity boomer = event . getEntity ( ) ;
// Before we need to check the location where the block is placed
if ( ! this . checkExplosionForBlock ( boomer , event . getLocation ( ) . getBlock ( ) ) ) {
event . setCancelled ( true ) ;
return ;
}
// Loop the blocklist to run checks on each aimed block
// The block don't have to explode
event . blockList ( ) . removeIf ( block - > ! this . checkExplosionForBlock ( boomer , block ) ) ;
// Cancel the event if no block will explode
if ( ! event . blockList ( ) . isEmpty ( ) & & ( boomer instanceof TNTPrimed | | boomer instanceof ExplosiveMinecart ) & & Conf . handleExploitTNTWaterlog ) {
// TNT in water/lava doesn't normally destroy any surrounding blocks, which is usually desired behavior, but...
// this change below provides workaround for waterwalling providing perfect protection,
// and makes cheap (non-obsidian) TNT cannons require minor maintenance between shots
Block center = event . getLocation ( ) . getBlock ( ) ;
if ( center . isLiquid ( ) ) {
// a single surrounding block in all 6 directions is broken if the material is weak enough
List < Block > targets = new ArrayList < > ( ) ;
targets . add ( center . getRelative ( 0 , 0 , 1 ) ) ;
targets . add ( center . getRelative ( 0 , 0 , - 1 ) ) ;
targets . add ( center . getRelative ( 0 , 1 , 0 ) ) ;
targets . add ( center . getRelative ( 0 , - 1 , 0 ) ) ;
targets . add ( center . getRelative ( 1 , 0 , 0 ) ) ;
targets . add ( center . getRelative ( - 1 , 0 , 0 ) ) ;
for ( Block target : targets ) {
@SuppressWarnings ( " deprecation " )
int id = target . getType ( ) . getId ( ) ;
// ignore air, bedrock, water, lava, obsidian, enchanting table, etc.... too bad we can't get a blast resistance value through Bukkit yet
if ( id ! = 0 & & ( id < 7 | | id > 11 ) & & id ! = 90 & & id ! = 116 & & id ! = 119 & & id ! = 120 & & id ! = 130 ) {
target . breakNaturally ( ) ;
2019-09-15 11:15:33 +02:00
}
2019-09-15 11:19:06 +02:00
}
}
}
}
private boolean checkExplosionForBlock ( Entity boomer , Block block ) {
Faction faction = Board . getInstance ( ) . getFactionAt ( new FLocation ( block . getLocation ( ) ) ) ;
2019-11-21 14:50:51 +01:00
if ( faction . noExplosionsInTerritory ( ) | | ( faction . isPeaceful ( ) & & Conf . peacefulTerritoryDisableBoom ) )
2019-09-15 11:19:06 +02:00
return false ;
2020-03-25 05:56:39 +01:00
// faction is peaceful and has explosions set to disabled
2019-09-15 11:19:06 +02:00
boolean online = faction . hasPlayersOnline ( ) ;
if ( boomer instanceof Creeper & & ( ( faction . isWilderness ( ) & & Conf . wildernessBlockCreepers & & ! Conf . worldsNoWildernessProtection . contains ( block . getWorld ( ) . getName ( ) ) ) | |
( faction . isNormal ( ) & & ( online ? Conf . territoryBlockCreepers : Conf . territoryBlockCreepersWhenOffline ) ) | |
( faction . isWarZone ( ) & & Conf . warZoneBlockCreepers ) | |
faction . isSafeZone ( ) ) ) {
// creeper which needs prevention
return false ;
} else if (
// it's a bit crude just using fireball protection for Wither boss too, but I'd rather not add in a whole new set of xxxBlockWitherExplosion or whatever
( boomer instanceof Fireball | | boomer instanceof Wither ) & & ( faction . isWilderness ( ) & & Conf . wildernessBlockFireballs & & ! Conf . worldsNoWildernessProtection . contains ( block . getWorld ( ) . getName ( ) ) | | faction . isNormal ( ) & & ( online ? Conf . territoryBlockFireballs : Conf . territoryBlockFireballsWhenOffline ) | | faction . isWarZone ( ) & & Conf . warZoneBlockFireballs | | faction . isSafeZone ( ) ) ) {
// ghast fireball which needs prevention
return false ;
} else
return ( ! ( boomer instanceof TNTPrimed ) & & ! ( boomer instanceof ExplosiveMinecart ) ) | | ( ( ! faction . isWilderness ( ) | | ! Conf . wildernessBlockTNT | | Conf . worldsNoWildernessProtection . contains ( block . getWorld ( ) . getName ( ) ) ) & &
( ! faction . isNormal ( ) | | ( online ? ! Conf . territoryBlockTNT : ! Conf . territoryBlockTNTWhenOffline ) ) & &
( ! faction . isWarZone ( ) | | ! Conf . warZoneBlockTNT ) & &
( ! faction . isSafeZone ( ) | | ! Conf . safeZoneBlockTNT ) ) ;
// No condition retained, destroy the block!
}
// 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 , 0d ) ;
2019-11-21 14:50:51 +01:00
if ( ! this . canDamagerHurtDamagee ( sub , false ) ) event . setCancelled ( true ) ;
2019-09-15 11:19:06 +02:00
}
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
public void onPotionSplashEvent ( PotionSplashEvent event ) {
// 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 ;
}
}
2019-11-21 14:50:51 +01:00
if ( ! badjuju ) return ;
2019-09-15 11:19:06 +02:00
ProjectileSource thrower = event . getPotion ( ) . getShooter ( ) ;
2019-11-21 14:50:51 +01:00
if ( ! ( thrower instanceof Entity ) ) return ;
2019-09-15 11:19:06 +02:00
if ( thrower instanceof Player ) {
Player player = ( Player ) thrower ;
FPlayer fPlayer = FPlayers . getInstance ( ) . getByPlayer ( player ) ;
if ( badjuju & & fPlayer . getFaction ( ) . isPeaceful ( ) ) {
event . setCancelled ( true ) ;
return ;
}
}
// scan through affected entities to make sure they're all valid targets
for ( LivingEntity target : event . getAffectedEntities ( ) ) {
EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent ( ( Entity ) thrower , target , EntityDamageEvent . DamageCause . CUSTOM , 0 ) ;
2019-11-21 14:50:51 +01:00
if ( ! this . canDamagerHurtDamagee ( sub , true ) )
2019-09-15 11:19:06 +02:00
event . setIntensity ( target , 0 . 0 ) ; // affected entity list doesn't accept modification (so no iter.remove()), but this works
}
}
public boolean isPlayerInSafeZone ( Entity damagee ) {
2019-11-21 14:50:51 +01:00
if ( ! ( damagee instanceof Player ) ) return false ;
2019-09-15 11:19:06 +02:00
return Board . getInstance ( ) . getFactionAt ( new FLocation ( damagee . getLocation ( ) ) ) . isSafeZone ( ) ;
}
public boolean canDamagerHurtDamagee ( EntityDamageByEntityEvent sub ) {
return canDamagerHurtDamagee ( sub , true ) ;
}
public boolean canDamagerHurtDamagee ( EntityDamageByEntityEvent sub , boolean notify ) {
Entity damager = sub . getDamager ( ) ;
Entity damagee = sub . getEntity ( ) ;
2019-11-21 14:50:51 +01:00
if ( ! ( damagee instanceof Player ) ) return true ;
2019-09-15 11:19:06 +02:00
FPlayer defender = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damagee ) ;
2020-04-06 21:10:37 +02:00
FPlayer attacker = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damager ) ;
2019-09-15 11:19:06 +02:00
2019-11-21 14:50:51 +01:00
if ( defender = = null | | defender . getPlayer ( ) = = null ) return true ;
2020-04-06 21:10:37 +02:00
if ( attacker . getFaction ( ) = = defender . getFaction ( ) ) {
if ( attacker . hasFriendlyFire ( ) & & defender . hasFriendlyFire ( ) ) return true ;
if ( attacker . hasFriendlyFire ( ) & & ! defender . hasFriendlyFire ( ) ) {
attacker . msg ( TL . FRIENDLY_FIRE_OFF_ATTACKER , defender . getName ( ) ) ;
return false ;
} else if ( ! attacker . hasFriendlyFire ( ) & & defender . hasFriendlyFire ( ) ) {
attacker . msg ( TL . FRIENDLY_FIRE_YOU_MUST ) ;
return false ;
}
}
2019-09-15 11:19:06 +02:00
Location defenderLoc = defender . getPlayer ( ) . getLocation ( ) ;
Faction defLocFaction = Board . getInstance ( ) . getFactionAt ( new FLocation ( defenderLoc ) ) ;
2020-04-06 21:10:37 +02:00
2019-09-15 11:19:06 +02:00
// for damage caused by projectiles, getDamager() returns the projectile... what we need to know is the source
if ( damager instanceof Projectile ) {
Projectile projectile = ( Projectile ) damager ;
2019-11-21 14:50:51 +01:00
if ( ! ( projectile . getShooter ( ) instanceof Entity ) ) return true ;
2019-09-15 11:19:06 +02:00
damager = ( Entity ) projectile . getShooter ( ) ;
}
2019-11-21 14:50:51 +01:00
if ( damager = = damagee ) return true ; // ender pearl usage and other self-inflicted damage
2019-09-15 11:19:06 +02:00
2020-04-06 16:32:16 +02:00
// Players can not take attack damage in a SafeZone or peaceful territory depending on Conf options.
2019-09-15 11:19:06 +02:00
if ( defLocFaction . noPvPInTerritory ( ) ) {
if ( damager instanceof Player ) {
if ( notify ) {
attacker . msg ( TL . PLAYER_CANTHURT , ( defLocFaction . isSafeZone ( ) ? TL . REGION_SAFEZONE . toString ( ) : TL . REGION_PEACEFUL . toString ( ) ) ) ;
}
return false ;
}
return ! defLocFaction . noMonstersInTerritory ( ) ;
}
2019-11-21 14:50:51 +01:00
if ( ! ( damager instanceof Player ) ) return true ;
2020-04-06 21:10:37 +02:00
attacker = FPlayers . getInstance ( ) . getByPlayer ( ( Player ) damager ) ;
2019-09-15 11:19:06 +02:00
2019-11-21 14:50:51 +01:00
if ( attacker = = null | | attacker . getPlayer ( ) = = null ) return true ;
if ( Conf . playersWhoBypassAllProtection . contains ( attacker . getName ( ) ) ) return true ;
2019-09-15 11:19:06 +02:00
if ( attacker . hasLoginPvpDisabled ( ) ) {
2020-04-06 16:32:16 +02:00
if ( notify ) attacker . msg ( TL . PLAYER_PVP_LOGIN , Conf . noPVPDamageToOthersForXSecondsAfterLogin ) ;
2019-09-15 11:19:06 +02:00
return false ;
}
Faction locFaction = Board . getInstance ( ) . getFactionAt ( new FLocation ( attacker ) ) ;
// 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 . noPvPInTerritory ( ) ) {
2020-04-06 16:32:16 +02:00
if ( notify )
2019-09-15 11:19:06 +02:00
attacker . msg ( TL . PLAYER_CANTHURT , ( locFaction . isSafeZone ( ) ? TL . REGION_SAFEZONE . toString ( ) : TL . REGION_PEACEFUL . toString ( ) ) ) ;
return false ;
}
2019-11-21 14:50:51 +01:00
if ( locFaction . isWarZone ( ) & & Conf . warZoneFriendlyFire ) return true ;
if ( Conf . worldsIgnorePvP . contains ( defenderLoc . getWorld ( ) . getName ( ) ) ) return true ;
2019-09-15 11:19:06 +02:00
Faction defendFaction = defender . getFaction ( ) ;
Faction attackFaction = attacker . getFaction ( ) ;
if ( attackFaction . isWilderness ( ) & & Conf . disablePVPForFactionlessPlayers ) {
2020-04-06 16:32:16 +02:00
if ( notify ) attacker . msg ( TL . PLAYER_PVP_REQUIREFACTION ) ;
2019-09-15 11:19:06 +02:00
return false ;
} else if ( defendFaction . isWilderness ( ) ) {
if ( defLocFaction = = attackFaction & & Conf . enablePVPAgainstFactionlessInAttackersLand ) {
// Allow PVP vs. Factionless in attacker's faction territory
return true ;
} else if ( Conf . disablePVPForFactionlessPlayers ) {
2020-04-06 16:32:16 +02:00
if ( notify ) attacker . msg ( TL . PLAYER_PVP_FACTIONLESS ) ;
2019-09-15 11:19:06 +02:00
return false ;
}
}
2020-04-06 16:32:16 +02:00
if ( defendFaction . isPeaceful ( ) | | attackFaction . isPeaceful ( ) ) {
if ( notify ) attacker . msg ( TL . PLAYER_PVP_PEACEFUL ) ;
2019-09-15 11:19:06 +02:00
return false ;
}
Relation relation = defendFaction . getRelationTo ( attackFaction ) ;
// You can not hurt neutral factions
if ( Conf . disablePVPBetweenNeutralFactions & & relation . isNeutral ( ) ) {
2020-04-06 16:32:16 +02:00
if ( notify ) attacker . msg ( TL . PLAYER_PVP_NEUTRAL ) ;
2019-09-15 11:19:06 +02:00
return false ;
}
// Players without faction may be hurt anywhere
2019-11-21 14:50:51 +01:00
if ( ! defender . hasFaction ( ) ) return true ;
2019-09-15 11:19:06 +02:00
// You can never hurt faction members or allies
2020-04-06 16:32:16 +02:00
if ( relation . isMember ( ) | | relation . isAlly ( ) ) {
if ( notify ) attacker . msg ( TL . PLAYER_PVP_CANTHURT , defender . describeTo ( attacker ) ) ;
2019-09-15 11:19:06 +02:00
return false ;
}
boolean ownTerritory = defender . isInOwnTerritory ( ) ;
// You can not hurt neutrals in their own territory.
if ( ownTerritory & & relation . isNeutral ( ) ) {
if ( notify ) {
attacker . msg ( TL . PLAYER_PVP_NEUTRALFAIL , defender . describeTo ( attacker ) ) ;
defender . msg ( TL . PLAYER_PVP_TRIED , attacker . describeTo ( defender , true ) ) ;
}
return false ;
}
return true ;
}
2020-04-06 16:32:16 +02:00
2019-09-15 11:19:06 +02:00
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
public void onCreatureSpawn ( CreatureSpawnEvent event ) {
2019-11-21 14:50:51 +01:00
if ( event . getLocation ( ) = = null ) return ;
2019-09-15 11:19:06 +02:00
if ( Conf . safeZoneNerfedCreatureTypes . contains ( event . getEntityType ( ) ) & & Board . getInstance ( ) . getFactionAt ( new FLocation ( event . getLocation ( ) ) ) . noMonstersInTerritory ( ) ) {
event . setCancelled ( true ) ;
}
}
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
public void onEntityTarget ( EntityTargetEvent event ) {
// if there is a target
Entity target = event . getTarget ( ) ;
2019-11-21 14:50:51 +01:00
if ( target = = null ) return ;
2019-09-15 11:19:06 +02:00
// We are interested in blocking targeting for certain mobs:
2019-11-21 14:50:51 +01:00
if ( ! Conf . safeZoneNerfedCreatureTypes . contains ( MiscUtil . creatureTypeFromEntity ( event . getEntity ( ) ) ) ) return ;
2019-09-15 11:19:06 +02:00
// in case the target is in a safe zone.
if ( Board . getInstance ( ) . getFactionAt ( new FLocation ( target . getLocation ( ) ) ) . noMonstersInTerritory ( ) ) {
event . setCancelled ( true ) ;
}
}
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
public void onPaintingBreak ( HangingBreakEvent event ) {
if ( event . getCause ( ) = = RemoveCause . EXPLOSION ) {
Location loc = event . getEntity ( ) . getLocation ( ) ;
Faction faction = Board . getInstance ( ) . getFactionAt ( new FLocation ( loc ) ) ;
if ( faction . noExplosionsInTerritory ( ) ) {
// faction is peaceful and has explosions set to disabled
event . setCancelled ( true ) ;
return ;
}
boolean online = faction . hasPlayersOnline ( ) ;
if ( ( faction . isWilderness ( ) & & ! Conf . worldsNoWildernessProtection . contains ( loc . getWorld ( ) . getName ( ) ) & & ( Conf . wildernessBlockCreepers | | Conf . wildernessBlockFireballs | | Conf . wildernessBlockTNT ) ) | |
( faction . isNormal ( ) & & ( online ? ( Conf . territoryBlockCreepers | | Conf . territoryBlockFireballs | | Conf . territoryBlockTNT ) : ( Conf . territoryBlockCreepersWhenOffline | | Conf . territoryBlockFireballsWhenOffline | | Conf . territoryBlockTNTWhenOffline ) ) ) | |
( faction . isWarZone ( ) & & ( Conf . warZoneBlockCreepers | | Conf . warZoneBlockFireballs | | Conf . warZoneBlockTNT ) ) | |
faction . isSafeZone ( ) ) {
// explosion which needs prevention
event . setCancelled ( true ) ;
}
}
}
@EventHandler
public void onHangerBreak ( HangingBreakByEntityEvent e ) {
if ( ! ( e . getRemover ( ) instanceof Player ) ) return ;
Player p = ( Player ) e . getRemover ( ) ;
2020-04-06 16:32:16 +02:00
if ( e . getEntity ( ) . getType ( ) = = EntityType . PAINTING | | e . getEntity ( ) . getType ( ) = = EntityType . ITEM_FRAME ) {
2019-09-15 11:19:06 +02:00
if ( ! FactionsBlockListener . playerCanBuildDestroyBlock ( p , e . getEntity ( ) . getLocation ( ) , " destroy " , false ) ) {
e . setCancelled ( true ) ;
}
}
}
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
2020-04-06 16:32:16 +02:00
public void onPaintingPlace ( HangingPlaceEvent e ) {
if ( e . getPlayer ( ) = = null ) return ;
if ( e . getEntity ( ) . getType ( ) = = EntityType . PAINTING | | e . getEntity ( ) . getType ( ) = = EntityType . ITEM_FRAME ) {
if ( ! FactionsBlockListener . playerCanBuildDestroyBlock ( e . getPlayer ( ) , e . getBlock ( ) . getLocation ( ) , " build " , false ) ) {
e . setCancelled ( true ) ;
e . getPlayer ( ) . updateInventory ( ) ;
2019-09-15 11:19:06 +02:00
}
}
}
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
2020-04-06 16:32:16 +02:00
public void onEntityChangeBlock ( EntityChangeBlockEvent e ) {
Entity entity = e . getEntity ( ) ;
Location loc = e . getBlock ( ) . getLocation ( ) ;
2019-09-15 11:19:06 +02:00
// for now, only interested in Enderman and Wither boss tomfoolery
2020-04-06 16:32:16 +02:00
if ( entity . getType ( ) = = EntityType . ENDERMAN ) {
if ( stopEndermanBlockManipulation ( loc ) ) e . setCancelled ( true ) ;
} else if ( entity . getType ( ) = = EntityType . WITHER ) {
2019-09-15 11:19:06 +02:00
Faction faction = Board . getInstance ( ) . getFactionAt ( new FLocation ( loc ) ) ;
// it's a bit crude just using fireball protection, but I'd rather not add in a whole new set of xxxBlockWitherExplosion or whatever
if ( ( faction . isWilderness ( ) & & Conf . wildernessBlockFireballs & & ! Conf . worldsNoWildernessProtection . contains ( loc . getWorld ( ) . getName ( ) ) ) | |
( faction . isNormal ( ) & & ( faction . hasPlayersOnline ( ) ? Conf . territoryBlockFireballs : Conf . territoryBlockFireballsWhenOffline ) ) | |
( faction . isWarZone ( ) & & Conf . warZoneBlockFireballs ) | |
faction . isSafeZone ( ) ) {
2020-04-06 16:32:16 +02:00
e . setCancelled ( true ) ;
2019-09-15 11:19:06 +02:00
}
}
}
2020-04-06 16:32:16 +02:00
2019-12-24 15:19:43 +01:00
/ *
2019-09-15 11:19:06 +02:00
@EventHandler
public void onTravel ( PlayerPortalEvent event ) {
2019-11-21 14:50:51 +01:00
if ( ! FactionsPlugin . getInstance ( ) . getConfig ( ) . getBoolean ( " portals.limit " , false ) )
2019-09-15 11:19:06 +02:00
return ; // Don't do anything if they don't want us to.
2019-11-21 14:50:51 +01:00
2019-09-15 11:19:06 +02:00
TravelAgent agent = event . getPortalTravelAgent ( ) ;
// If they aren't able to find a portal, it'll try to create one.
if ( event . useTravelAgent ( ) & & agent . getCanCreatePortal ( ) & & agent . findPortal ( event . getTo ( ) ) = = null ) {
FLocation loc = new FLocation ( event . getTo ( ) ) ;
Faction faction = Board . getInstance ( ) . getFactionAt ( loc ) ;
if ( faction . isWilderness ( ) ) {
return ; // We don't care about wilderness.
} else if ( ! faction . isNormal ( ) & & ! event . getPlayer ( ) . isOp ( ) ) {
// Don't let non ops make portals in safezone or warzone.
event . setCancelled ( true ) ;
return ;
}
FPlayer fp = FPlayers . getInstance ( ) . getByPlayer ( event . getPlayer ( ) ) ;
String mininumRelation = FactionsPlugin . getInstance ( ) . getConfig ( ) . getString ( " portals.minimum-relation " , " MEMBER " ) ; // Defaults to Neutral if typed wrong.
if ( ! fp . getFaction ( ) . getRelationTo ( faction ) . isAtLeast ( Relation . fromString ( mininumRelation ) ) ) {
event . setCancelled ( true ) ;
}
}
}
2019-12-24 15:19:43 +01:00
* /
2019-09-15 11:19:06 +02:00
@EventHandler
public void onHit ( EntityDamageByEntityEvent e ) {
if ( e . getDamager ( ) instanceof Player ) {
if ( e . getEntity ( ) instanceof Player ) {
Player victim = ( Player ) e . getEntity ( ) ;
Player attacker = ( Player ) e . getDamager ( ) ;
FPlayer fvictim = FPlayers . getInstance ( ) . getByPlayer ( victim ) ;
FPlayer fattacker = FPlayers . getInstance ( ) . getByPlayer ( attacker ) ;
if ( fattacker . getRelationTo ( fvictim ) = = Relation . TRUCE ) {
fattacker . msg ( TL . PLAYER_PVP_CANTHURT , fvictim . describeTo ( fattacker ) ) ;
2019-09-15 11:15:33 +02:00
e . setCancelled ( true ) ;
2019-09-15 11:19:06 +02:00
}
}
}
}
@EventHandler
public void onBowHit ( EntityDamageByEntityEvent e ) {
if ( e . getDamager ( ) instanceof Projectile ) {
if ( e . getEntity ( ) instanceof Player ) {
Projectile arrow = ( ( Projectile ) e . getDamager ( ) ) ;
if ( arrow . getShooter ( ) instanceof Player ) {
Player damager = ( Player ) ( ( Projectile ) e . getDamager ( ) ) . getShooter ( ) ;
2019-08-24 19:18:50 +02:00
Player victim = ( Player ) e . getEntity ( ) ;
2019-09-15 11:19:06 +02:00
FPlayer fdamager = FPlayers . getInstance ( ) . getByPlayer ( damager ) ;
2019-08-24 19:18:50 +02:00
FPlayer fvictim = FPlayers . getInstance ( ) . getByPlayer ( victim ) ;
2020-03-25 05:56:39 +01:00
if ( damager = = victim ) return ;
if ( fdamager = = fvictim ) return ;
2019-09-15 11:19:06 +02:00
if ( fvictim . getRelationTo ( fdamager ) = = Relation . TRUCE ) {
fdamager . msg ( TL . PLAYER_PVP_CANTHURT , fvictim . describeTo ( fdamager ) ) ;
e . setCancelled ( true ) ;
2019-08-24 19:18:50 +02:00
}
2019-09-15 11:19:06 +02:00
if ( fvictim . getRelationTo ( fdamager ) = = Relation . ENEMY ) {
if ( fvictim . isFlying ( ) ) {
fvictim . setFFlying ( false , true ) ;
}
2019-08-24 19:18:50 +02:00
}
2019-09-15 11:19:06 +02:00
}
}
}
}
// For disabling interactions with item frames in another faction's territory
@EventHandler ( priority = EventPriority . NORMAL , ignoreCancelled = true )
public void onPlayerInteractEntity ( PlayerInteractEntityEvent event ) {
// only need to check for item frames
if ( event . getRightClicked ( ) = = null ) return ;
if ( ! event . getRightClicked ( ) . getType ( ) . equals ( EntityType . ITEM_FRAME ) ) return ;
if ( ! FactionsBlockListener . playerCanBuildDestroyBlock ( event . getPlayer ( ) , event . getRightClicked ( ) . getLocation ( ) , " build " , false ) ) {
event . setCancelled ( true ) ;
}
}
private boolean stopEndermanBlockManipulation ( Location loc ) {
2019-11-21 14:50:51 +01:00
if ( loc = = null ) return false ;
2019-09-15 11:19:06 +02:00
// quick check to see if all Enderman deny options are enabled; if so, no need to check location
if ( Conf . wildernessDenyEndermanBlocks & &
Conf . territoryDenyEndermanBlocks & &
Conf . territoryDenyEndermanBlocksWhenOffline & &
Conf . safeZoneDenyEndermanBlocks & &
2019-11-21 14:50:51 +01:00
Conf . warZoneDenyEndermanBlocks ) return true ;
2019-09-15 11:19:06 +02:00
FLocation fLoc = new FLocation ( loc ) ;
Faction claimFaction = Board . getInstance ( ) . getFactionAt ( fLoc ) ;
2019-11-21 14:50:51 +01:00
if ( claimFaction . isWilderness ( ) )
2019-09-15 11:19:06 +02:00
return Conf . wildernessDenyEndermanBlocks ;
2019-11-21 14:50:51 +01:00
else if ( claimFaction . isNormal ( ) )
2019-09-15 11:19:06 +02:00
return claimFaction . hasPlayersOnline ( ) ? Conf . territoryDenyEndermanBlocks : Conf . territoryDenyEndermanBlocksWhenOffline ;
2019-11-21 14:50:51 +01:00
else if ( claimFaction . isSafeZone ( ) )
2019-09-15 11:19:06 +02:00
return Conf . safeZoneDenyEndermanBlocks ;
2019-11-21 14:50:51 +01:00
else if ( claimFaction . isWarZone ( ) )
2019-09-15 11:19:06 +02:00
return Conf . warZoneDenyEndermanBlocks ;
return false ;
}
2018-11-19 08:34:29 +01:00
}