2013-03-01 06:52:01 +01:00
package com.gmail.nossr50.runnables.skills ;
2012-03-18 21:59:35 +01:00
2019-01-15 07:11:58 +01:00
import com.gmail.nossr50.config.AdvancedConfig ;
2019-01-25 20:12:31 +01:00
import com.gmail.nossr50.datatypes.interactions.NotificationType ;
2020-02-29 00:43:32 +01:00
import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent ;
2019-01-24 01:01:30 +01:00
import com.gmail.nossr50.mcMMO ;
import com.gmail.nossr50.util.MobHealthbarUtils ;
2019-01-25 20:12:31 +01:00
import com.gmail.nossr50.util.player.NotificationManager ;
2019-01-15 07:11:58 +01:00
import com.gmail.nossr50.util.skills.CombatUtils ;
import com.gmail.nossr50.util.skills.ParticleEffectUtils ;
2019-01-22 00:14:01 +01:00
import com.gmail.nossr50.util.sounds.SoundManager ;
import com.gmail.nossr50.util.sounds.SoundType ;
2019-07-29 18:41:57 +02:00
import org.bukkit.Bukkit ;
2012-03-18 21:59:35 +01:00
import org.bukkit.entity.LivingEntity ;
import org.bukkit.entity.Player ;
2020-02-29 00:43:32 +01:00
import org.bukkit.event.entity.EntityDamageEvent ;
2019-03-24 06:57:44 +01:00
import org.bukkit.inventory.ItemStack ;
2013-03-20 08:11:16 +01:00
import org.bukkit.scheduler.BukkitRunnable ;
2020-12-01 22:08:33 +01:00
import org.jetbrains.annotations.NotNull ;
2012-03-18 21:59:35 +01:00
2019-01-15 07:11:58 +01:00
import java.util.HashMap ;
2019-01-25 20:12:31 +01:00
import java.util.Iterator ;
2019-01-15 07:11:58 +01:00
import java.util.Map ;
2019-01-25 20:12:31 +01:00
import java.util.Map.Entry ;
2012-03-18 21:59:35 +01:00
2013-03-20 08:11:16 +01:00
public class BleedTimerTask extends BukkitRunnable {
2020-12-01 22:08:33 +01:00
private static final @NotNull Map < LivingEntity , BleedContainer > bleedList = new HashMap < > ( ) ;
2019-08-12 03:31:46 +02:00
private static boolean isIterating = false ;
2012-03-18 21:59:35 +01:00
@Override
2019-01-26 02:14:10 +01:00
public void run ( ) {
2019-08-12 03:31:46 +02:00
isIterating = true ;
2019-01-25 20:12:31 +01:00
Iterator < Entry < LivingEntity , BleedContainer > > bleedIterator = bleedList . entrySet ( ) . iterator ( ) ;
2019-01-24 22:20:45 +01:00
2019-01-25 20:12:31 +01:00
while ( bleedIterator . hasNext ( ) ) {
Entry < LivingEntity , BleedContainer > containerEntry = bleedIterator . next ( ) ;
LivingEntity target = containerEntry . getKey ( ) ;
2019-03-24 06:57:44 +01:00
int toolTier = containerEntry . getValue ( ) . toolTier ;
2012-03-18 21:59:35 +01:00
2019-03-24 06:57:44 +01:00
// String debugMessage = "";
// debugMessage += ChatColor.GOLD + "Target ["+target.getName()+"]: " + ChatColor.RESET;
// debugMessage+="RemainingTicks=["+containerEntry.getValue().bleedTicks+"], ";
2019-01-25 20:12:31 +01:00
if ( containerEntry . getValue ( ) . bleedTicks < = 0 | | ! target . isValid ( ) ) {
2019-03-24 06:57:44 +01:00
if ( target instanceof Player )
{
NotificationManager . sendPlayerInformation ( ( Player ) target , NotificationType . SUBSKILL_MESSAGE , " Swords.Combat.Bleeding.Stopped " ) ;
}
2019-01-25 20:12:31 +01:00
bleedIterator . remove ( ) ;
2013-02-26 16:32:06 +01:00
continue ;
2012-03-21 03:51:02 +01:00
}
2019-03-24 06:57:44 +01:00
int armorCount = 0 ;
2014-10-11 12:18:31 +02:00
double damage ;
2013-02-27 13:49:56 +01:00
2019-01-24 01:01:30 +01:00
if ( target instanceof Player ) {
2019-01-22 00:14:01 +01:00
damage = AdvancedConfig . getInstance ( ) . getRuptureDamagePlayer ( ) ;
//Above Bleed Rank 3 deals 50% more damage
2019-03-24 06:57:44 +01:00
if ( containerEntry . getValue ( ) . toolTier > = 4 & & containerEntry . getValue ( ) . bleedRank > = 3 )
2019-01-22 00:14:01 +01:00
damage = damage * 1 . 5 ;
2019-01-24 01:01:30 +01:00
Player player = ( Player ) target ;
2012-04-28 06:14:19 +02:00
if ( ! player . isOnline ( ) ) {
continue ;
}
2012-03-18 21:59:35 +01:00
2019-03-24 06:57:44 +01:00
//Count Armor
2020-11-02 22:57:53 +01:00
for ( ItemStack armorPiece : ( ( Player ) target ) . getInventory ( ) . getArmorContents ( ) ) {
//We only want to count slots that contain armor.
if ( armorPiece ! = null ) {
armorCount + + ;
}
2019-03-24 06:57:44 +01:00
}
2019-01-25 20:12:31 +01:00
} else {
2019-01-22 00:14:01 +01:00
damage = AdvancedConfig . getInstance ( ) . getRuptureDamageMobs ( ) ;
2019-01-25 20:12:31 +01:00
2019-03-24 06:57:44 +01:00
// debugMessage+="BaseDMG=["+damage+"], ";
2019-01-25 20:12:31 +01:00
//Above Bleed Rank 3 deals 50% more damage
if ( containerEntry . getValue ( ) . bleedRank > = 3 )
2019-03-24 06:57:44 +01:00
{
2019-01-25 20:12:31 +01:00
damage = damage * 1 . 5 ;
2019-03-24 06:57:44 +01:00
}
// debugMessage+="Rank4Bonus=["+String.valueOf(containerEntry.getValue().bleedRank >= 3)+"], ";
2019-01-25 20:12:31 +01:00
2019-01-24 01:01:30 +01:00
MobHealthbarUtils . handleMobHealthbars ( target , damage , mcMMO . p ) ; //Update health bars
2012-03-18 21:59:35 +01:00
}
2019-01-24 01:01:30 +01:00
2019-03-24 06:57:44 +01:00
// debugMessage+="FullArmor=["+String.valueOf(armorCount > 3)+"], ";
if ( armorCount > 3 )
{
damage = damage * . 75 ;
}
// debugMessage+="AfterRankAndArmorChecks["+damage+"], ";
//Weapons below Diamond get damage cut in half
if ( toolTier < 4 )
damage = damage / 2 ;
2019-01-24 01:08:41 +01:00
2019-03-24 06:57:44 +01:00
// debugMessage+="AfterDiamondCheck=["+String.valueOf(damage)+"], ";
//Wood weapons get damage cut in half again
if ( toolTier < 2 )
damage = damage / 2 ;
// debugMessage+="AfterWoodenCheck=["+String.valueOf(damage)+"], ";
double victimHealth = target . getHealth ( ) ;
// debugMessage+="TargetHealthBeforeDMG=["+String.valueOf(target.getHealth())+"], ";
2020-02-29 00:43:32 +01:00
//Fire a fake event
FakeEntityDamageByEntityEvent fakeEntityDamageByEntityEvent = ( FakeEntityDamageByEntityEvent ) CombatUtils . sendEntityDamageEvent ( containerEntry . getValue ( ) . damageSource , target , EntityDamageEvent . DamageCause . CUSTOM , damage ) ;
Bukkit . getPluginManager ( ) . callEvent ( fakeEntityDamageByEntityEvent ) ;
2019-03-24 06:57:44 +01:00
CombatUtils . dealNoInvulnerabilityTickDamageRupture ( target , damage , containerEntry . getValue ( ) . damageSource , toolTier ) ;
double victimHealthAftermath = target . getHealth ( ) ;
// debugMessage+="TargetHealthAfterDMG=["+String.valueOf(target.getHealth())+"], ";
if ( victimHealthAftermath < = 0 | | victimHealth ! = victimHealthAftermath )
{
//Play Bleed Sound
SoundManager . worldSendSound ( target . getWorld ( ) , target . getLocation ( ) , SoundType . BLEED ) ;
ParticleEffectUtils . playBleedEffect ( target ) ;
}
2012-03-18 21:59:35 +01:00
2019-01-25 20:12:31 +01:00
//Lower Bleed Ticks
BleedContainer loweredBleedContainer = copyContainer ( containerEntry . getValue ( ) ) ;
loweredBleedContainer . bleedTicks - = 1 ;
2019-03-24 06:57:44 +01:00
// debugMessage+="RemainingTicks=["+loweredBleedContainer.bleedTicks+"]";
2019-01-25 20:12:31 +01:00
containerEntry . setValue ( loweredBleedContainer ) ;
2019-03-24 06:57:44 +01:00
// Bukkit.broadcastMessage(debugMessage);
2019-01-24 22:20:45 +01:00
}
2019-08-12 03:31:46 +02:00
isIterating = false ;
2019-01-24 22:20:45 +01:00
}
2020-12-01 22:08:33 +01:00
public static @NotNull BleedContainer copyContainer ( @NotNull BleedContainer container )
2019-01-25 20:12:31 +01:00
{
LivingEntity target = container . target ;
LivingEntity source = container . damageSource ;
int bleedTicks = container . bleedTicks ;
int bleedRank = container . bleedRank ;
2019-03-24 06:57:44 +01:00
int toolTier = container . toolTier ;
2019-01-24 22:20:45 +01:00
2020-07-13 20:39:03 +02:00
return new BleedContainer ( target , bleedTicks , bleedRank , toolTier , source ) ;
2019-01-24 01:01:30 +01:00
}
2012-04-28 06:14:19 +02:00
/ * *
* Instantly Bleed out a LivingEntity
2012-06-05 15:57:10 +02:00
*
2012-04-28 06:14:19 +02:00
* @param entity LivingEntity to bleed out
* /
2020-12-01 22:08:33 +01:00
public static void bleedOut ( @NotNull LivingEntity entity ) {
2019-01-25 20:12:31 +01:00
/ *
* Don ' t remove anything from the list outside of run ( )
* /
2012-04-28 06:14:19 +02:00
2013-02-26 16:32:06 +01:00
if ( bleedList . containsKey ( entity ) ) {
2019-01-25 20:12:31 +01:00
CombatUtils . dealNoInvulnerabilityTickDamage ( entity , bleedList . get ( entity ) . bleedTicks * 2 , bleedList . get ( entity ) . damageSource ) ;
2012-03-18 21:59:35 +01:00
}
}
/ * *
2012-03-21 03:51:02 +01:00
* Add a LivingEntity to the bleedList if it is not in it .
*
2012-03-18 21:59:35 +01:00
* @param entity LivingEntity to add
2020-12-01 22:08:33 +01:00
* @param attacker source of the bleed / rupture
2012-05-01 01:32:50 +02:00
* @param ticks Number of bleeding ticks
2012-03-18 21:59:35 +01:00
* /
2020-12-01 22:08:33 +01:00
public static void add ( @NotNull LivingEntity entity , @NotNull LivingEntity attacker , int ticks , int bleedRank , int toolTier ) {
2019-07-29 18:41:57 +02:00
if ( ! Bukkit . isPrimaryThread ( ) ) {
throw new IllegalStateException ( " Cannot add bleed task async! " ) ;
}
2020-12-01 22:08:33 +01:00
if ( isIterating ) {
//Used to throw an error here, but in reality all we are really doing is preventing concurrency issues from other plugins being naughty and its not really needed
//I'm not really a fan of silent errors, but I'm sick of seeing people using crazy enchantments come in and report this "bug"
return ;
}
// if (isIterating) throw new IllegalStateException("Cannot add task while iterating timers!");
2019-08-12 03:31:46 +02:00
2019-03-24 06:57:44 +01:00
if ( toolTier < 4 )
ticks = Math . max ( 1 , ( ticks / 3 ) ) ;
2020-08-19 04:47:15 +02:00
ticks + = 1 ;
2019-03-24 06:57:44 +01:00
BleedContainer newBleedContainer = new BleedContainer ( entity , ticks , bleedRank , toolTier , attacker ) ;
2019-01-25 20:12:31 +01:00
bleedList . put ( entity , newBleedContainer ) ;
2012-03-18 21:59:35 +01:00
}
2014-05-02 19:41:44 +02:00
2020-12-01 22:08:33 +01:00
public static boolean isBleedOperationAllowed ( ) {
return ! isIterating & & Bukkit . isPrimaryThread ( ) ;
}
public static boolean isBleeding ( @NotNull LivingEntity entity ) {
2014-05-02 19:41:44 +02:00
return bleedList . containsKey ( entity ) ;
}
2012-03-18 21:59:35 +01:00
}