parent
ab164df286
commit
f404d2fd73
Binary file not shown.
@ -0,0 +1,81 @@ |
|||||||
|
package sig.plugin.TwosideKeeper.HelperStructures; |
||||||
|
|
||||||
|
import org.bukkit.ChatColor; |
||||||
|
import org.bukkit.Color; |
||||||
|
|
||||||
|
import sig.plugin.TwosideKeeper.Buff; |
||||||
|
|
||||||
|
public enum BuffTemplate { |
||||||
|
POISON("Poison","Poison",Color.YELLOW,ChatColor.YELLOW+"☣",false), |
||||||
|
SHRAPNEL("SHRAPNEL","Shrapnel",Color.RED,ChatColor.RED+"❂",false), |
||||||
|
WINDCHARGES("WINDCHARGE","Wind",Color.GRAY,"๑",true), |
||||||
|
BLEEDING("BLEEDING","Bleed",Color.MAROON,ChatColor.DARK_RED+"☠",false), |
||||||
|
REGENERATION("REGENERATION","Regeneration",Color.GREEN,ChatColor.GREEN+""+ChatColor.BOLD+"✙",true), |
||||||
|
INFECTION("INFECTION","Infection",Color.GRAY,ChatColor.GRAY+"❧",false), |
||||||
|
CRIPPLE("CRIPPLE","Cripple",Color.WHITE,ChatColor.WHITE+"☹",false), |
||||||
|
DARKSUBMISSION("DARKSUBMISSION",ChatColor.GRAY+"Dark Submission"+ChatColor.RESET,Color.BLACK,ChatColor.BLACK+""+ChatColor.MAGIC+"☁"+ChatColor.RESET,false), |
||||||
|
CONFUSION("CONFUSION","Confusion",Color.PURPLE,ChatColor.DARK_PURPLE+"๑"+ChatColor.RESET,false), |
||||||
|
|
||||||
|
UNDYINGRAGE_COOLDOWN("COOLDOWN_UNDYING_RAGE","Undying Rage Cooldown",null,ChatColor.WHITE+"",true,true), |
||||||
|
UNSTOPPABLETEAM_COOLDOWN("Unstoppable Team Unavailable","Unstoppable Team Unavailable",null,ChatColor.WHITE+"",true,true), |
||||||
|
; |
||||||
|
|
||||||
|
String keyName; |
||||||
|
String displayName; |
||||||
|
Color col; |
||||||
|
String icon; |
||||||
|
boolean isGoodBuff; |
||||||
|
boolean permanentBuff; |
||||||
|
boolean displayTimer; |
||||||
|
|
||||||
|
public String getKeyName() { |
||||||
|
return keyName; |
||||||
|
} |
||||||
|
public String getDisplayName() { |
||||||
|
return displayName; |
||||||
|
} |
||||||
|
public Color getParticleColor() { |
||||||
|
return col; |
||||||
|
} |
||||||
|
public String getIcon() { |
||||||
|
return icon; |
||||||
|
} |
||||||
|
public boolean isGoodBuff() { |
||||||
|
return isGoodBuff; |
||||||
|
} |
||||||
|
public boolean isPermanentBuff() { |
||||||
|
return permanentBuff; |
||||||
|
} |
||||||
|
public boolean isDisplayTimer() { |
||||||
|
return displayTimer; |
||||||
|
} |
||||||
|
|
||||||
|
BuffTemplate(String keyName, String displayName, Color particleColor, String icon, boolean isGoodBuff) { |
||||||
|
this.keyName=keyName; |
||||||
|
this.displayName=displayName; |
||||||
|
this.col=particleColor; |
||||||
|
this.icon=icon; |
||||||
|
this.isGoodBuff=isGoodBuff; |
||||||
|
this.permanentBuff=false; |
||||||
|
this.displayTimer=false; |
||||||
|
} |
||||||
|
BuffTemplate(String keyName, String displayName, Color particleColor, String icon, boolean isGoodBuff, boolean isPermanentBuff) { |
||||||
|
this.keyName=keyName; |
||||||
|
this.displayName=displayName; |
||||||
|
this.col=particleColor; |
||||||
|
this.icon=icon; |
||||||
|
this.isGoodBuff=isGoodBuff; |
||||||
|
this.permanentBuff=isPermanentBuff; |
||||||
|
this.displayTimer=false; |
||||||
|
} |
||||||
|
BuffTemplate(String keyName, String displayName, Color particleColor, String icon, boolean isGoodBuff, boolean isPermanentBuff, boolean displayTimer) { |
||||||
|
this.keyName=keyName; |
||||||
|
this.displayName=displayName; |
||||||
|
this.col=particleColor; |
||||||
|
this.icon=icon; |
||||||
|
this.isGoodBuff=isGoodBuff; |
||||||
|
this.permanentBuff=isPermanentBuff; |
||||||
|
this.displayTimer=displayTimer; |
||||||
|
} |
||||||
|
//new Buff("Poison",20*20,Integer.parseInt(args[1]),Color.YELLOW,ChatColor.YELLOW+"☣",false)
|
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
package sig.plugin.TwosideKeeper.HelperStructures.Effects; |
||||||
|
|
||||||
|
import org.bukkit.Color; |
||||||
|
import org.bukkit.Location; |
||||||
|
|
||||||
|
import sig.plugin.TwosideKeeper.TwosideKeeper; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Utils.Classes.ColoredParticle; |
||||||
|
|
||||||
|
public class EffectPool { |
||||||
|
double radius = 1; |
||||||
|
Color col = null; |
||||||
|
Location loc = null; |
||||||
|
long expireTime=0; |
||||||
|
final int PARTICLE_DENSITY = 5; |
||||||
|
public EffectPool(Location loc, double radius, int duration, Color col) { |
||||||
|
this.loc=loc.clone(); |
||||||
|
this.radius=radius; |
||||||
|
this.col=col; |
||||||
|
this.expireTime=TwosideKeeper.getServerTickTime()+duration; |
||||||
|
TwosideKeeper.effectpools.add(this); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean runTick() { |
||||||
|
int density = (int)Math.pow(PARTICLE_DENSITY, radius); |
||||||
|
for (int i=0;i<density;i++) { |
||||||
|
Location particleloc = loc.clone().add( |
||||||
|
(Math.random()*(radius+1))-radius, |
||||||
|
0.66, |
||||||
|
(Math.random()*(radius+1))-radius |
||||||
|
); |
||||||
|
ColoredParticle.RED_DUST.send(particleloc, 50, col.getRed(), col.getGreen(), col.getBlue()); |
||||||
|
} |
||||||
|
return !(expireTime<=TwosideKeeper.getServerTickTime()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
package sig.plugin.TwosideKeeper.Monster; |
||||||
|
|
||||||
|
import org.bukkit.ChatColor; |
||||||
|
import org.bukkit.Color; |
||||||
|
import org.bukkit.Material; |
||||||
|
import org.bukkit.attribute.Attribute; |
||||||
|
import org.bukkit.entity.LivingEntity; |
||||||
|
|
||||||
|
import sig.plugin.TwosideKeeper.CustomMonster; |
||||||
|
import sig.plugin.TwosideKeeper.LivingEntityStructure; |
||||||
|
import sig.plugin.TwosideKeeper.TwosideKeeper; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Effects.EffectPool; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Effects.TemporaryBlock; |
||||||
|
|
||||||
|
public class Bloodmite extends CustomMonster{ |
||||||
|
|
||||||
|
long lastBloodPool=TwosideKeeper.getServerTickTime(); |
||||||
|
SniperSkeleton main; |
||||||
|
|
||||||
|
public Bloodmite(LivingEntity m) { |
||||||
|
super(m); |
||||||
|
LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); |
||||||
|
les.setCustomLivingEntityName(m, ChatColor.RED+"Bloodmite"); |
||||||
|
m.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.12f); |
||||||
|
} |
||||||
|
|
||||||
|
public void setMainEntity(SniperSkeleton ss) { |
||||||
|
main = ss; |
||||||
|
} |
||||||
|
|
||||||
|
public void runTick() { |
||||||
|
if (lastBloodPool+90<=TwosideKeeper.getServerTickTime()) { |
||||||
|
TemporaryBlock.createTemporaryBlockCircle(m.getLocation(), 1, Material.WOOL, (byte)14, 20*30, "BLOODPOOL"); |
||||||
|
new EffectPool(m.getLocation(),1,20*30,Color.fromRGB(255, 0, 0)); |
||||||
|
lastBloodPool=TwosideKeeper.getServerTickTime(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void cleanup() { |
||||||
|
if (main!=null) { |
||||||
|
main.bloodmites.remove(m); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,869 @@ |
|||||||
|
package sig.plugin.TwosideKeeper.Monster; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.text.DecimalFormat; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.bukkit.Bukkit; |
||||||
|
import org.bukkit.ChatColor; |
||||||
|
import org.bukkit.Location; |
||||||
|
import org.bukkit.Material; |
||||||
|
import org.bukkit.Particle; |
||||||
|
import org.bukkit.Sound; |
||||||
|
import org.bukkit.attribute.Attribute; |
||||||
|
import org.bukkit.block.Block; |
||||||
|
import org.bukkit.block.BlockFace; |
||||||
|
import org.bukkit.boss.BarColor; |
||||||
|
import org.bukkit.boss.BarFlag; |
||||||
|
import org.bukkit.boss.BarStyle; |
||||||
|
import org.bukkit.boss.BossBar; |
||||||
|
import org.bukkit.enchantments.Enchantment; |
||||||
|
import org.bukkit.entity.Arrow; |
||||||
|
import org.bukkit.entity.Endermite; |
||||||
|
import org.bukkit.entity.Entity; |
||||||
|
import org.bukkit.entity.EntityType; |
||||||
|
import org.bukkit.entity.LivingEntity; |
||||||
|
import org.bukkit.entity.Monster; |
||||||
|
import org.bukkit.entity.Player; |
||||||
|
import org.bukkit.entity.Projectile; |
||||||
|
import org.bukkit.entity.Skeleton; |
||||||
|
import org.bukkit.inventory.ItemStack; |
||||||
|
import org.bukkit.inventory.meta.LeatherArmorMeta; |
||||||
|
import org.bukkit.metadata.FixedMetadataValue; |
||||||
|
import org.bukkit.entity.Skeleton.SkeletonType; |
||||||
|
import org.bukkit.event.entity.ProjectileLaunchEvent; |
||||||
|
import org.bukkit.potion.PotionEffectType; |
||||||
|
import org.bukkit.util.Vector; |
||||||
|
import org.inventivetalent.glow.GlowAPI.Color; |
||||||
|
|
||||||
|
import sig.plugin.TwosideKeeper.Buff; |
||||||
|
import sig.plugin.TwosideKeeper.ChargeZombie; |
||||||
|
import sig.plugin.TwosideKeeper.CustomDamage; |
||||||
|
import sig.plugin.TwosideKeeper.CustomMonster; |
||||||
|
import sig.plugin.TwosideKeeper.LivingEntityStructure; |
||||||
|
import sig.plugin.TwosideKeeper.MonsterController; |
||||||
|
import sig.plugin.TwosideKeeper.TwosideKeeper; |
||||||
|
import sig.plugin.TwosideKeeper.Events.EntityChannelCastEvent; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.BuffTemplate; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Channel; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.LivingEntityDifficulty; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Spell; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Effects.HighlightCircle; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Utils.EntityUtils; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Utils.MovementUtils; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Utils.SoundUtils; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Utils.Classes.ColoredParticle; |
||||||
|
import sig.plugin.TwosideKeeper.HelperStructures.Utils.Classes.MixedDamage; |
||||||
|
|
||||||
|
public class SniperSkeleton extends CustomMonster{ |
||||||
|
|
||||||
|
BossBar healthbar; |
||||||
|
protected String arrow = "->"; |
||||||
|
int scroll=0; |
||||||
|
protected List<Player> participantlist = new ArrayList<Player>(); |
||||||
|
protected HashMap<String,Double> dpslist = new HashMap<String,Double>(); |
||||||
|
long lasthit; |
||||||
|
boolean startedfight=false; |
||||||
|
private long stuckTimer=0; |
||||||
|
private Location lastLoc = null; |
||||||
|
MixedDamage[] BASIC_ATTACK_DAMAGE = new MixedDamage[]{MixedDamage.v(30),MixedDamage.v(50),MixedDamage.v(130, 0.02)}; |
||||||
|
final Spell PIERCING_ARROW = new Spell("Piercing Arrow",new int[]{40,20,20},new int[]{240,200,160},new MixedDamage[]{MixedDamage.v(100,0.02),MixedDamage.v(140,0.04),MixedDamage.v(200,0.08)}); |
||||||
|
final Spell BURNING_PLUME = new Spell("Burning Plume",new int[]{50,40,30},new int[]{300,240,200},new MixedDamage[]{MixedDamage.v(200,0.06),MixedDamage.v(300,0.08),MixedDamage.v(500,0.15)}); |
||||||
|
final Spell CRIPPLING_INFECTION = new Spell("Crippling Infection",new int[]{30,20,20},new int[]{240,240,240}); |
||||||
|
final Spell SIPHON_BURST = new Spell("Siphon Burst",new int[]{80,60,40},new int[]{0,0,0},new MixedDamage[]{MixedDamage.v(10,0.06),MixedDamage.v(40,0.1),MixedDamage.v(70,0.15)}); |
||||||
|
final Spell ARROW_RAIN = new Spell("Arrow Rain",new int[]{160,160,160},new int[]{800,800,800},new MixedDamage[]{MixedDamage.v(100,0,5),MixedDamage.v(125,0.05,10),MixedDamage.v(150,0.10,20)}); |
||||||
|
final Spell MODE_SHIFT = new Spell("Mode Shift",new int[]{20,20,20},new int[]{120,120,120}); |
||||||
|
int randomness = 20; |
||||||
|
final Spell ENERGIZEDSHOTS = new Spell("Energized Shots",new int[]{60,40,40},new int[]{0,0,0}); |
||||||
|
boolean phaseii = false; |
||||||
|
ShotMode mode = ShotMode.NORMAL; |
||||||
|
|
||||||
|
long shotmodeExpireTime = 0; |
||||||
|
|
||||||
|
|
||||||
|
long lastUsedDodge=0; |
||||||
|
final static int[] DODGE_COOLDOWN = new int[]{80,60,40}; |
||||||
|
final int[] MODE_EXPIRE_TIME = new int[]{120,240,360}; |
||||||
|
final static double[] BLOODMITE_HEALTH = new double[]{180,650,1200}; |
||||||
|
|
||||||
|
List<LivingEntity> bloodmites = new ArrayList<LivingEntity>(); |
||||||
|
|
||||||
|
public SniperSkeleton(LivingEntity m) { |
||||||
|
super(m); |
||||||
|
LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); |
||||||
|
les.setCustomLivingEntityName(m, ChatColor.GOLD+"Sniper Skeleton"); |
||||||
|
LivingEntityDifficulty led = MonsterController.getLivingEntityDifficulty(m); |
||||||
|
switch (led) { |
||||||
|
case T1_MINIBOSS:{ |
||||||
|
m.setMaxHealth(16000); |
||||||
|
}break; |
||||||
|
case T2_MINIBOSS:{ |
||||||
|
m.setMaxHealth(41000); |
||||||
|
}break; |
||||||
|
case T3_MINIBOSS:{ |
||||||
|
m.setMaxHealth(108000); |
||||||
|
}break; |
||||||
|
} |
||||||
|
m.setHealth(m.getMaxHealth()); |
||||||
|
m.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.3625f); |
||||||
|
m.setAI(false); |
||||||
|
m.setRemoveWhenFarAway(false); |
||||||
|
createBossHealthbar(); |
||||||
|
setupBow(); |
||||||
|
GenericFunctions.logAndRemovePotionEffectFromEntity(PotionEffectType.INVISIBILITY, m); |
||||||
|
} |
||||||
|
|
||||||
|
private void setupBow() { |
||||||
|
ItemStack bow = new ItemStack(Material.BOW); |
||||||
|
bow.addUnsafeEnchantment(Enchantment.ARROW_DAMAGE, 10); |
||||||
|
bow.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 10); |
||||||
|
bow.addUnsafeEnchantment(Enchantment.ARROW_KNOCKBACK, 1); |
||||||
|
bow.addUnsafeEnchantment(Enchantment.ARROW_FIRE, 10); |
||||||
|
m.getEquipment().setItemInMainHand(bow); |
||||||
|
m.getEquipment().setItemInMainHandDropChance(0.2f); |
||||||
|
} |
||||||
|
|
||||||
|
private void createBossHealthbar() { |
||||||
|
healthbar = Bukkit.getServer().createBossBar(GenericFunctions.getDisplayName(m), BarColor.WHITE, BarStyle.SEGMENTED_10, BarFlag.CREATE_FOG); |
||||||
|
healthbar.setProgress(m.getHealth()/m.getMaxHealth()); |
||||||
|
} |
||||||
|
|
||||||
|
public void runTick() { |
||||||
|
updateHealthbarForNearbyPlayers(); |
||||||
|
updateTargetIfLost(); |
||||||
|
regenerateHealthAndResetBossIfIdle(); |
||||||
|
keepHealthbarUpdated(); |
||||||
|
unstuckIfStuck(); |
||||||
|
increaseBarTextScroll(); |
||||||
|
performSpells(); |
||||||
|
updateAI(); |
||||||
|
removeIfTooOld(); |
||||||
|
giveHatProtectionAndFireResist(); |
||||||
|
setModeBackToNormal(); |
||||||
|
} |
||||||
|
|
||||||
|
private void setModeBackToNormal() { |
||||||
|
if (mode!=ShotMode.NORMAL && |
||||||
|
shotmodeExpireTime<=TwosideKeeper.getServerTickTime()) { |
||||||
|
mode=ShotMode.NORMAL; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void runProjectileLaunchEvent(ProjectileLaunchEvent ev) { |
||||||
|
Projectile proj = ev.getEntity(); |
||||||
|
proj.setMetadata("SNIPER_"+mode.name(), new FixedMetadataValue(TwosideKeeper.plugin,true)); |
||||||
|
} |
||||||
|
|
||||||
|
private void giveHatProtectionAndFireResist() { |
||||||
|
ItemStack helm = new ItemStack(Material.LEATHER_HELMET); |
||||||
|
LeatherArmorMeta meta = (LeatherArmorMeta)(helm.getItemMeta()); |
||||||
|
meta.setColor(org.bukkit.Color.fromRGB(255,255,0)); |
||||||
|
helm.setItemMeta(meta); |
||||||
|
m.getEquipment().setHelmet(helm); |
||||||
|
} |
||||||
|
|
||||||
|
public Color getGlowColor() { |
||||||
|
if (isInIframe()) { |
||||||
|
return Color.WHITE; |
||||||
|
} else { |
||||||
|
switch (mode) { |
||||||
|
case NORMAL: return Color.AQUA; |
||||||
|
case POISON: return Color.YELLOW; |
||||||
|
case BLEED: return Color.RED; |
||||||
|
default: return Color.AQUA; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void removeIfTooOld() { |
||||||
|
if (m.getTicksLived()>72000 && !startedfight) { |
||||||
|
m.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void updateAI() { |
||||||
|
if (!startedfight) { |
||||||
|
m.setAI(false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isImmuneToSuppression() { |
||||||
|
return phaseii; |
||||||
|
} |
||||||
|
|
||||||
|
public void runChannelCastEvent(EntityChannelCastEvent ev) { |
||||||
|
switch (ev.getAbilityName()) { |
||||||
|
case "Piercing Arrow":{ |
||||||
|
final int NUMBER_OF_PARTICLES=40; |
||||||
|
final int RANGE = 20; |
||||||
|
Location baseloc = m.getEyeLocation().clone(); |
||||||
|
SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ARROW_SHOOT, 1.0f, 1.6f); |
||||||
|
for (int i=0;i<NUMBER_OF_PARTICLES;i++) { |
||||||
|
baseloc.add(baseloc.getDirection().multiply((double)RANGE/NUMBER_OF_PARTICLES)); |
||||||
|
aPlugin.API.displayEndRodParticle(baseloc, 0, 0, 0, 0, 1); |
||||||
|
MixedDamage dmg = PIERCING_ARROW.getDamageValues()[getDifficultySlot()]; |
||||||
|
GenericFunctions.DealDamageToNearbyPlayers(baseloc, dmg.getDmgComponent(), 1, false, true, 0, m, "Piercing Arrow", false, false); |
||||||
|
if (dmg.getTruePctDmgComponent()>0) {GenericFunctions.DealDamageToNearbyPlayers(baseloc, dmg.getTruePctDmgComponent(), 1, false, true, 0, m, "Piercing Arrow", false, true);} |
||||||
|
if (dmg.getTrueDmgComponent()>0) {GenericFunctions.DealDamageToNearbyPlayers(baseloc, dmg.getTrueDmgComponent(), 1, false, true, 0, m, "Piercing Arrow", true, false);} |
||||||
|
} |
||||||
|
PIERCING_ARROW.setLastCastedTime(TwosideKeeper.getServerTickTime()); |
||||||
|
}break; |
||||||
|
case "Mode Shift":{ |
||||||
|
if (mode!=ShotMode.NORMAL) { |
||||||
|
mode=ShotMode.NORMAL; |
||||||
|
} else { |
||||||
|
if (Math.random()<=0.5) { |
||||||
|
mode=ShotMode.POISON; |
||||||
|
} else { |
||||||
|
mode=ShotMode.BLEED; |
||||||
|
} |
||||||
|
} |
||||||
|
MODE_SHIFT.setLastCastedTime(TwosideKeeper.getServerTickTime()); |
||||||
|
shotmodeExpireTime = TwosideKeeper.getServerTickTime()+MODE_EXPIRE_TIME[getDifficultySlot()]; |
||||||
|
}break; |
||||||
|
case "Burning Plume":{ |
||||||
|
final int RANGE = 12; |
||||||
|
final int PARTICLE_AMT = 100; |
||||||
|
BlockFace facingdir = EntityUtils.getFacingDirection(m); |
||||||
|
Location startingloc = m.getLocation().add(new Vector(facingdir.getModX(),0,facingdir.getModZ())); |
||||||
|
List<Location> firestarters = new ArrayList<Location>(); |
||||||
|
int[] size = new int[]{1,3,3}; |
||||||
|
for (int i=-size[getDifficultySlot()];i<=size[getDifficultySlot()];i++) { |
||||||
|
BlockFace[] newdir = MovementUtils.get90DegreeDirections(facingdir); |
||||||
|
if (i<0) { |
||||||
|
Location newloc = m.getLocation().add(new Vector(newdir[1].getModX()*Math.abs(i),0,newdir[1].getModZ()*Math.abs(i))); |
||||||
|
firestarters.add(newloc); |
||||||
|
} else |
||||||
|
if (i>0){ |
||||||
|
Location newloc = m.getLocation().add(new Vector(newdir[0].getModX()*Math.abs(i),0,newdir[0].getModZ()*Math.abs(i))); |
||||||
|
firestarters.add(newloc); |
||||||
|
} |
||||||
|
} |
||||||
|
firestarters.add(startingloc); |
||||||
|
Location centerloc = startingloc.clone(); |
||||||
|
for (int i=0;i<RANGE;i++) { |
||||||
|
final int amt = i; |
||||||
|
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()-> { |
||||||
|
for (Location l : firestarters) { |
||||||
|
Block b = findFireBlock(l); |
||||||
|
//TwosideKeeper.log("Fire starter: "+l+". Block chosen: "+b, 0);
|
||||||
|
if (b!=null) { |
||||||
|
b.setType(Material.FIRE); |
||||||
|
} |
||||||
|
l.add(new Vector(facingdir.getModX(),0,facingdir.getModZ())); |
||||||
|
|
||||||
|
for (int j=0;j<PARTICLE_AMT;j++) { |
||||||
|
ColoredParticle.RED_DUST.send(l.clone().add(facingdir.getModX()/2, -10+((double)20/PARTICLE_AMT)*j, facingdir.getModZ()/2), 50, 255, 128, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
MixedDamage dmg = BURNING_PLUME.getDamageValues()[getDifficultySlot()]; |
||||||
|
Location dmgloc = centerloc.clone().add(new Vector(facingdir.getModX()*amt,0,facingdir.getModZ()*amt)); |
||||||
|
List<Player> players = GenericFunctions.DealDamageToNearbyPlayers(dmgloc, dmg.getDmgComponent(), size[getDifficultySlot()], false, true, 0, m, "Burning Plume", false, false); |
||||||
|
if (dmg.getTruePctDmgComponent()>0) {GenericFunctions.DealDamageToNearbyPlayers(dmgloc, dmg.getTruePctDmgComponent(), size[getDifficultySlot()], false, true, 0, m, "Burning Plume", false, true);} |
||||||
|
if (dmg.getTrueDmgComponent()>0) {GenericFunctions.DealDamageToNearbyPlayers(dmgloc, dmg.getTrueDmgComponent(), size[getDifficultySlot()], false, true, 0, m, "Burning Plume", true, false);} |
||||||
|
for (Player p : players) { |
||||||
|
p.setFireTicks(p.getFireTicks()+(20*10)); |
||||||
|
} |
||||||
|
SoundUtils.playGlobalSound(dmgloc, Sound.BLOCK_FURNACE_FIRE_CRACKLE, 1.0f, 1.0f); |
||||||
|
}, (3*i)+3); |
||||||
|
} |
||||||
|
BURNING_PLUME.setLastCastedTime(TwosideKeeper.getServerTickTime()); |
||||||
|
}break; |
||||||
|
case "Crippling Infection":{ |
||||||
|
BlockFace facingdir = EntityUtils.getFacingDirection(m); |
||||||
|
Location newloc = m.getLocation().add(facingdir.getModX(),0,facingdir.getModZ()); |
||||||
|
double dist = newloc.distance(m.getLocation()); |
||||||
|
//Arrow a = m.launchProjectile(Arrow.class);
|
||||||
|
List<Vector> speeds = new ArrayList<Vector>(); |
||||||
|
for (BlockFace bf : MovementUtils.get45DegreeDirections(facingdir)) { |
||||||
|
speeds.add(new Vector(bf.getModX(),0,bf.getModZ()).multiply(dist)); |
||||||
|
} |
||||||
|
for (BlockFace bf : MovementUtils.get90DegreeDirections(facingdir)) { |
||||||
|
speeds.add(new Vector(bf.getModX(),0,bf.getModZ()).multiply(dist)); |
||||||
|
} |
||||||
|
for (int i=0;i<speeds.size();i++) { |
||||||
|
Arrow a = m.launchProjectile(Arrow.class); |
||||||
|
a.setVelocity(speeds.get(i)); |
||||||
|
a.setMetadata("SNIPER_CRIPPLINGINFECTION", new FixedMetadataValue(TwosideKeeper.plugin,true)); |
||||||
|
} |
||||||
|
Arrow a = m.launchProjectile(Arrow.class); |
||||||
|
a.setMetadata("SNIPER_CRIPPLINGINFECTION", new FixedMetadataValue(TwosideKeeper.plugin,true)); |
||||||
|
CRIPPLING_INFECTION.setLastCastedTime(TwosideKeeper.getServerTickTime()); |
||||||
|
}break; |
||||||
|
case "Siphon Burst":{ |
||||||
|
removeDebuffsAndApplySiphonDamage(); |
||||||
|
}break; |
||||||
|
case "Arrow Rain":{ |
||||||
|
ARROW_RAIN.setLastCastedTime(TwosideKeeper.getServerTickTime()); |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void removeDebuffsAndApplySiphonDamage() { |
||||||
|
MixedDamage dmg = SIPHON_BURST.getDamageValues()[getDifficultySlot()]; |
||||||
|
for (Player p : participantlist) { |
||||||
|
int stackamt = 0; |
||||||
|
if (Buff.hasBuff(p, BuffTemplate.BLEEDING)) { |
||||||
|
stackamt += Buff.getBuff(p, BuffTemplate.BLEEDING).getAmplifier(); |
||||||
|
Buff.removeBuff(p, BuffTemplate.BLEEDING); |
||||||
|
} |
||||||
|
if (Buff.hasBuff(p, BuffTemplate.INFECTION)) { |
||||||
|
stackamt += Buff.getBuff(p, BuffTemplate.INFECTION).getAmplifier(); |
||||||
|
Buff.removeBuff(p, BuffTemplate.INFECTION); |
||||||
|
} |
||||||
|
if (Buff.hasBuff(p, BuffTemplate.POISON)) { |
||||||
|
stackamt += Buff.getBuff(p, BuffTemplate.POISON).getAmplifier(); |
||||||
|
Buff.removeBuff(p, BuffTemplate.POISON); |
||||||
|
} |
||||||
|
CustomDamage.ApplyDamage(stackamt*dmg.getDmgComponent(), m, p, null, "Siphon Burst", CustomDamage.IGNORE_DAMAGE_TICK|CustomDamage.IGNOREDODGE); |
||||||
|
if (dmg.getTruePctDmgComponent()>0) {CustomDamage.ApplyDamage(p.getMaxHealth()*(stackamt*dmg.getTruePctDmgComponent()), m, p, null, "Siphon Burst", CustomDamage.TRUEDMG|CustomDamage.IGNORE_DAMAGE_TICK|CustomDamage.IGNOREDODGE);} |
||||||
|
if (dmg.getTrueDmgComponent()>0) {CustomDamage.ApplyDamage((stackamt*dmg.getTrueDmgComponent()), m, p, null, "Siphon Burst", CustomDamage.TRUEDMG|CustomDamage.IGNORE_DAMAGE_TICK|CustomDamage.IGNOREDODGE);} |
||||||
|
SoundUtils.playGlobalSound(p.getLocation(),Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 1.0f, 1.0f); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Block findFireBlock(Location l) { |
||||||
|
int diffy = 0; |
||||||
|
while (diffy<=5) { |
||||||
|
Block testb = l.getBlock().getRelative(0, diffy, 0); |
||||||
|
if (testb.getType()==Material.AIR && |
||||||
|
testb.getRelative(0, -1, 0).getType().isSolid()) { |
||||||
|
return testb; |
||||||
|
} |
||||||
|
if (diffy<=0) { |
||||||
|
diffy--; |
||||||
|
if (diffy<-5) { |
||||||
|
diffy=1; |
||||||
|
} |
||||||
|
} else { |
||||||
|
diffy++; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public void bloodPoolSpawnedEvent(LivingEntity target) { |
||||||
|
Endermite bloodmite = (Endermite)target.getWorld().spawnEntity(target.getLocation(), EntityType.ENDERMITE); |
||||||
|
Bloodmite bm = new Bloodmite(bloodmite); |
||||||
|
bm.setMainEntity(this); |
||||||
|
bm.GetMonster().setMaxHealth(BLOODMITE_HEALTH[getDifficultySlot()]); |
||||||
|
bm.GetMonster().setHealth(bm.GetMonster().getMaxHealth()); |
||||||
|
bloodmite.setTarget(pickRandomTarget()); |
||||||
|
TwosideKeeper.custommonsters.put(bloodmite.getUniqueId(), bm); |
||||||
|
bloodmites.add(bloodmite); |
||||||
|
} |
||||||
|
|
||||||
|
private void announceMessageToParticipants(String msg) { |
||||||
|
for (Player p : participantlist) { |
||||||
|
p.sendMessage(msg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean attemptSpellCast(Spell spell) { |
||||||
|
if (cooldownIsAvailable(spell.getLastCastedTime(),spell)) { |
||||||
|
//Face target.
|
||||||
|
Channel.createNewChannel(m, spell.getName(), (int)(spell.getCastTimes()[getDifficultySlot()])); |
||||||
|
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{FaceTarget(m);}, 5); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public void cleanup() { |
||||||
|
healthbar.removeAll(); |
||||||
|
for (LivingEntity ent : bloodmites) { |
||||||
|
if (ent!=null && ent.isValid()) { |
||||||
|
ent.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public MixedDamage getBasicAttackDamage() { |
||||||
|
return BASIC_ATTACK_DAMAGE[getDifficultySlot()]; |
||||||
|
} |
||||||
|
|
||||||
|
private void FaceTarget(LivingEntity m) { |
||||||
|
if (((Monster)m).getTarget()!=null) { |
||||||
|
Location loc = m.getLocation(); |
||||||
|
loc.setDirection(MovementUtils.pointTowardsLocation(loc, ((Monster)m).getTarget().getLocation())); |
||||||
|
m.teleport(loc); |
||||||
|
} |
||||||
|
} |
||||||
|
private boolean cooldownIsAvailable(long spell_timer, Spell spell) { |
||||||
|
return spell_timer+spell.getCooldowns()[getDifficultySlot()]<=TwosideKeeper.getServerTickTime(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isInIframe() { |
||||||
|
return m.hasPotionEffect(PotionEffectType.INVISIBILITY); |
||||||
|
} |
||||||
|
|
||||||
|
private void performDodge() { |
||||||
|
if (lastUsedDodge+DODGE_COOLDOWN[getDifficultySlot()]<=TwosideKeeper.getServerTickTime()) { |
||||||
|
SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_DONKEY_CHEST, 1.0f, 1.0f); |
||||||
|
GenericFunctions.logAndApplyPotionEffectToEntity(PotionEffectType.INVISIBILITY, 20, 0, m, true); |
||||||
|
if (distanceToTarget()<9) { |
||||||
|
m.setVelocity(m.getLocation().getDirection().multiply(-0.4f)); |
||||||
|
} |
||||||
|
lastUsedDodge=TwosideKeeper.getServerTickTime(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private double distanceToTarget() { |
||||||
|
Monster me = (Monster)m; |
||||||
|
if (me.getTarget()!=null && me.getTarget().getWorld().equals(m.getWorld())) { |
||||||
|
return m.getLocation().distanceSquared(me.getTarget().getLocation()); |
||||||
|
} else { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void performSpells() { |
||||||
|
final Runnable[] actions = new Runnable[]{ |
||||||
|
()->{performDodge();}, |
||||||
|
()->{attemptSpellCast(PIERCING_ARROW);}, |
||||||
|
()->{attemptSpellCast(MODE_SHIFT);}, |
||||||
|
()->{attemptSpellCast(BURNING_PLUME);}, |
||||||
|
()->{attemptSpellCast(CRIPPLING_INFECTION);}, |
||||||
|
}; |
||||||
|
final Runnable[] actions2 = new Runnable[]{ |
||||||
|
()->{attemptSpellCast(MODE_SHIFT);}, |
||||||
|
()->{attemptSpellCast(CRIPPLING_INFECTION);}, |
||||||
|
()->{if (meetsConditionsForSiphon()) { |
||||||
|
attemptSpellCast(SIPHON_BURST); |
||||||
|
}}, |
||||||
|
()->{if (attemptSpellCast(ARROW_RAIN)) { |
||||||
|
runArrowRain();}}, |
||||||
|
}; |
||||||
|
if (canCastSpells()) { |
||||||
|
if (phaseii) { |
||||||
|
for (Runnable r : actions2) { |
||||||
|
if (Math.random()<=1d/actions2.length) { |
||||||
|
Bukkit.getScheduler().runTask(TwosideKeeper.plugin, r); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
performSpellFromFirstPhase(actions); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!phaseii && m.getHealth()<=m.getMaxHealth()/2 && startedfight) { |
||||||
|
if (attemptSpellCast(ENERGIZEDSHOTS)) { |
||||||
|
phaseii=true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void runArrowRain() { |
||||||
|
new HighlightCircle(m.getLocation(),8,20,ARROW_RAIN.getCastTimes()[getDifficultySlot()]); |
||||||
|
for (int i=0;i<200;i++) { |
||||||
|
int randomTickTime=(int)(Math.random()*ARROW_RAIN.getCastTimes()[getDifficultySlot()]); |
||||||
|
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, |
||||||
|
()->{ |
||||||
|
Arrow a = m.launchProjectile(Arrow.class); |
||||||
|
BlockFace facingdir = EntityUtils.getFacingDirection(m); |
||||||
|
Location newloc = m.getLocation().add(facingdir.getModX(),1,facingdir.getModZ()); |
||||||
|
double dist = newloc.distance(m.getLocation()); |
||||||
|
a.setVelocity(new Vector(Math.random()*2-1,0.1,Math.random()*2-1).multiply(dist)); |
||||||
|
switch ((int)(Math.random()*3)) { |
||||||
|
case 0:{ |
||||||
|
a.setMetadata("SNIPER_POISON", new FixedMetadataValue(TwosideKeeper.plugin,true)); |
||||||
|
}break; |
||||||
|
case 1:{ |
||||||
|
a.setMetadata("SNIPER_BLEED", new FixedMetadataValue(TwosideKeeper.plugin,true)); |
||||||
|
}break; |
||||||
|
case 2:{ |
||||||
|
a.setMetadata("SNIPER_CRIPPLINGINFECTION", new FixedMetadataValue(TwosideKeeper.plugin,true)); |
||||||
|
}break; |
||||||
|
} |
||||||
|
for (int j=0;j<5;j++) |
||||||
|
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, |
||||||
|
()->{ |
||||||
|
a.getWorld().spawnParticle(Particle.CRIT, a.getLocation(), 3); |
||||||
|
},j*1); |
||||||
|
}, randomTickTime); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean meetsConditionsForSiphon() { |
||||||
|
int debufflevels = 0; |
||||||
|
for (Player p : participantlist) { |
||||||
|
if (Buff.hasBuff(p, "BLEEDING")) { |
||||||
|
debufflevels++; |
||||||
|
} |
||||||
|
if (Buff.hasBuff(p, "INFECTION")) { |
||||||
|
debufflevels++; |
||||||
|
} |
||||||
|
if (Buff.hasBuff(p, "Poison")) { |
||||||
|
debufflevels++; |
||||||
|
} |
||||||
|
if (debufflevels>=2) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private void performSpellFromFirstPhase(final Runnable[] actions) { |
||||||
|
for (Runnable r : actions) { |
||||||
|
if (Math.random()<=1d/actions.length) { |
||||||
|
Bukkit.getScheduler().runTask(TwosideKeeper.plugin, r); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static double getDamageReduction() { |
||||||
|
return 0.0; |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean randomlyConvertAsSniperSkeleton(LivingEntity m) { |
||||||
|
return randomlyConvertAsSniperSkeleton(m,false); |
||||||
|
} |
||||||
|
|
||||||
|
private Player setAggroOnRandomTarget() { |
||||||
|
Player p = pickRandomTarget(); |
||||||
|
setAggro((Monster)m,p); |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
public LivingEntityDifficulty getDifficulty() { |
||||||
|
return MonsterController.getLivingEntityDifficulty(m); |
||||||
|
} |
||||||
|
|
||||||
|
public int getDifficultySlot() { |
||||||
|
switch (getDifficulty()) { |
||||||
|
case T1_MINIBOSS:{ |
||||||
|
return 0; |
||||||
|
} |
||||||
|
case T2_MINIBOSS:{ |
||||||
|
return 1; |
||||||
|
} |
||||||
|
case T3_MINIBOSS:{ |
||||||
|
return 2; |
||||||
|
} |
||||||
|
default:{ |
||||||
|
TwosideKeeper.log("WARNING! Could not get proper difficulty slot for Difficulty "+getDifficulty()+". Defaulting to slot 0.", 1); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Player changeAggroToRandomNewTarget() { |
||||||
|
if (Math.random()<=0.5) { |
||||||
|
Monster me = (Monster)m; |
||||||
|
Player newtarget = pickRandomTarget(); |
||||||
|
setAggro(me, newtarget); |
||||||
|
return newtarget; |
||||||
|
} else { |
||||||
|
Monster me = (Monster)m; |
||||||
|
return (Player)me.getTarget(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void setAggro(Monster me, Player newtarget) { |
||||||
|
if (newtarget!=null) { |
||||||
|
me.setTarget(newtarget); |
||||||
|
LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); |
||||||
|
les.SetTarget(me.getTarget()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Player pickRandomTarget() { |
||||||
|
updateTargetList(); |
||||||
|
if (participantlist.size()>0) { |
||||||
|
for (Player p : participantlist) { |
||||||
|
if (Math.random()<=1d/participantlist.size() && |
||||||
|
!p.isDead() && p.isValid()) { |
||||||
|
return p; |
||||||
|
} |
||||||
|
} |
||||||
|
return participantlist.get(0); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void updateTargetList() { |
||||||
|
for (int i=0;i<participantlist.size();i++) { |
||||||
|
Player p = participantlist.get(i); |
||||||
|
if (p==null || !p.isValid() || p.isDead() || |
||||||
|
p.getLocation().distanceSquared(m.getLocation())>2500) { |
||||||
|
participantlist.remove(i--); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean canCastSpells() { |
||||||
|
return Math.random()<=1/8d && !Buff.hasBuff(m, "SILENCE") && startedfight && !Channel.isChanneling(m) && !m.hasPotionEffect(PotionEffectType.INVISIBILITY); |
||||||
|
} |
||||||
|
|
||||||
|
private void unstuckIfStuck() { |
||||||
|
if (!startedfight) { |
||||||
|
ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); |
||||||
|
} else |
||||||
|
if (startedfight) { |
||||||
|
lastLoc = m.getLocation().clone(); |
||||||
|
if (lastLoc!=null && lastLoc.distance(m.getLocation())<=0.4) { |
||||||
|
stuckTimer++; |
||||||
|
//TwosideKeeper.log("Stuck. "+stuckTimer, 0);
|
||||||
|
ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); |
||||||
|
} else { |
||||||
|
stuckTimer=0; |
||||||
|
} |
||||||
|
if (!Channel.isChanneling(m) && stuckTimer>5) { |
||||||
|
//Teleport randomly.
|
||||||
|
double numb = Math.random(); |
||||||
|
if (numb<=0.33) { |
||||||
|
Location newloc = m.getLocation().add(Math.random()*10-5,0,0); |
||||||
|
if (!newloc.getBlock().getType().isSolid() && |
||||||
|
!newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { |
||||||
|
SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); |
||||||
|
m.teleport(newloc); |
||||||
|
} |
||||||
|
} else |
||||||
|
if (numb<=0.5) { |
||||||
|
Location newloc = m.getLocation().add(0,0,Math.random()*10-5); |
||||||
|
if (!newloc.getBlock().getType().isSolid() && |
||||||
|
!newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { |
||||||
|
SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); |
||||||
|
m.teleport(newloc); |
||||||
|
} |
||||||
|
} |
||||||
|
stuckTimer=0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void keepHealthbarUpdated() { |
||||||
|
healthbar.setProgress(m.getHealth()/m.getMaxHealth()); |
||||||
|
Monster me = (Monster)m; |
||||||
|
String healthbarfooter = ((me.getTarget()!=null && (me.getTarget() instanceof Player))?(ChatColor.DARK_AQUA+" "+arrow+" "+ChatColor.YELLOW+((Player)me.getTarget()).getName()):""); |
||||||
|
if (Channel.isChanneling(m)) { |
||||||
|
healthbar.setTitle(LivingEntityStructure.getChannelingBar(m)+healthbarfooter); |
||||||
|
} else { |
||||||
|
healthbar.setTitle(GenericFunctions.getDisplayName(m)+healthbarfooter); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void regenerateHealthAndResetBossIfIdle() { |
||||||
|
if (lasthit+20*15<=TwosideKeeper.getServerTickTime()) { |
||||||
|
GenericFunctions.HealEntity(m, m.getMaxHealth()*0.01); |
||||||
|
if (startedfight) { |
||||||
|
healthbar.setColor(BarColor.GREEN); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (startedfight) { |
||||||
|
healthbar.setColor(BarColor.BLUE); |
||||||
|
} |
||||||
|
} |
||||||
|
if (participantlist.size()==0 && startedfight) { |
||||||
|
startedfight=false; |
||||||
|
m.setAI(false); |
||||||
|
m.setHealth(m.getMaxHealth()); |
||||||
|
announceFailedTakedown(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void updateTargetIfLost() { |
||||||
|
Monster mm = (Monster)m; |
||||||
|
LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); |
||||||
|
if (mm.getTarget()==null || !mm.getTarget().isValid() || |
||||||
|
les.GetTarget()==null || !mm.getTarget().isValid() || |
||||||
|
((mm.getTarget().getLocation().distanceSquared(mm.getLocation())>2500 || |
||||||
|
les.GetTarget().getLocation().distanceSquared(mm.getLocation())>2500 |
||||||
|
))) { |
||||||
|
//See if there's another participant in the list. Choose randomly.
|
||||||
|
while (participantlist.size()>0) { |
||||||
|
Player p = participantlist.get((int)(Math.random()*participantlist.size())); |
||||||
|
if (p!=null && p.isValid() && !p.isDead() && |
||||||
|
(p.getLocation().distanceSquared(mm.getLocation())<=2500)) { |
||||||
|
mm.setTarget(p); |
||||||
|
les.SetTarget(p); |
||||||
|
break; |
||||||
|
} else { |
||||||
|
participantlist.remove(p); |
||||||
|
} |
||||||
|
} |
||||||
|
if (participantlist.size()==0 && startedfight) { |
||||||
|
//This fight has failed.
|
||||||
|
announceFailedTakedown(); |
||||||
|
startedfight=false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void announceFailedTakedown() { |
||||||
|
if (dpslist.size()>0 && !m.isDead()) { |
||||||
|
phaseii=false; |
||||||
|
Bukkit.getServer().broadcastMessage(GenericFunctions.getDisplayName(m)+" Takedown Failed..."); |
||||||
|
Bukkit.getServer().broadcastMessage(ChatColor.YELLOW+"DPS Breakdown:"); |
||||||
|
Bukkit.getServer().broadcastMessage(generateDPSReport()); |
||||||
|
aPlugin.API.discordSendRaw(GenericFunctions.getDisplayName(m)+" Takedown Failed...\n\n"+ChatColor.YELLOW+"DPS Breakdown:"+"\n```\n"+generateDPSReport()+"\n```"); |
||||||
|
dpslist.clear(); |
||||||
|
healthbar.setColor(BarColor.WHITE); |
||||||
|
|
||||||
|
for (LivingEntity ent : bloodmites) { |
||||||
|
if (ent!=null && ent.isValid()) { |
||||||
|
ent.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void announceSuccessfulTakedown() { |
||||||
|
if (dpslist.size()>0 && !m.isDead()) { |
||||||
|
phaseii=false; |
||||||
|
Bukkit.getServer().broadcastMessage(GenericFunctions.getDisplayName(m)+" Takedown Failed..."); |
||||||
|
Bukkit.getServer().broadcastMessage(ChatColor.YELLOW+"DPS Breakdown:"); |
||||||
|
Bukkit.getServer().broadcastMessage(generateDPSReport()); |
||||||
|
aPlugin.API.discordSendRaw(GenericFunctions.getDisplayName(m)+" Takedown Failed...\n\n"+ChatColor.YELLOW+"DPS Breakdown:"+"\n```\n"+generateDPSReport()+"\n```"); |
||||||
|
dpslist.clear(); |
||||||
|
healthbar.setColor(BarColor.WHITE); |
||||||
|
|
||||||
|
for (LivingEntity ent : bloodmites) { |
||||||
|
if (ent!=null && ent.isValid()) { |
||||||
|
ent.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String generateDPSReport() { |
||||||
|
//Sorts a list of players by DPS contribution.
|
||||||
|
List<Double> sorted_dmg = new ArrayList<Double>(); |
||||||
|
List<String> sorted_pl = new ArrayList<String>(); |
||||||
|
double totaldmg = 0; |
||||||
|
for (String pl : dpslist.keySet()) { |
||||||
|
double dmg = dpslist.get(pl); |
||||||
|
int slot = 0; |
||||||
|
totaldmg+=dmg; |
||||||
|
for (int i=0;i<sorted_dmg.size();i++) { |
||||||
|
if (dmg>sorted_dmg.get(i)) { |
||||||
|
break; |
||||||
|
} else { |
||||||
|
slot++; |
||||||
|
} |
||||||
|
} |
||||||
|
sorted_pl.add(slot,pl); |
||||||
|
sorted_dmg.add(slot,dmg); |
||||||
|
} |
||||||
|
StringBuilder finalstr = new StringBuilder(); |
||||||
|
DecimalFormat df = new DecimalFormat("0.00"); |
||||||
|
for (int i=0;i<sorted_pl.size();i++) { |
||||||
|
if (finalstr.length()!=0) { |
||||||
|
finalstr.append("\n"); |
||||||
|
} |
||||||
|
finalstr.append(sorted_pl.get(i)+": "+df.format(sorted_dmg.get(i))+" dmg ("+df.format((sorted_dmg.get(i)/totaldmg)*100)+"%)"); |
||||||
|
} |
||||||
|
return finalstr.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public void onHitEvent(LivingEntity damager, double damage) { |
||||||
|
addTarget(damager,damage); |
||||||
|
Bukkit.getScheduler().scheduleSyncDelayedTask(TwosideKeeper.plugin, ()->{ |
||||||
|
m.setVelocity(m.getVelocity().multiply(0.33)); |
||||||
|
}, 1); |
||||||
|
healthbar.setProgress(m.getHealth()/m.getMaxHealth()); |
||||||
|
lasthit=TwosideKeeper.getServerTickTime(); |
||||||
|
if (!startedfight) { |
||||||
|
startedfight=true; |
||||||
|
healthbar.setColor(BarColor.BLUE); |
||||||
|
} |
||||||
|
m.setAI(true); |
||||||
|
} |
||||||
|
|
||||||
|
private void addTarget(LivingEntity damager, double dmg) { |
||||||
|
if (damager instanceof Player) { |
||||||
|
Player p = (Player)damager; |
||||||
|
addParticipant(p); |
||||||
|
if (!dpslist.containsKey(p.getName())) { |
||||||
|
dpslist.put(p.getName(), dmg); |
||||||
|
} else { |
||||||
|
dpslist.put(p.getName(), dpslist.get(p.getName())+dmg); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void addParticipant(Player p) { |
||||||
|
if (!participantlist.contains(p)) { |
||||||
|
participantlist.add(p); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void updateHealthbarForNearbyPlayers() { |
||||||
|
for (Player p : healthbar.getPlayers()) { |
||||||
|
if (p.getWorld().equals(m.getWorld()) && p.getLocation().distanceSquared(m.getLocation())>2500) { |
||||||
|
healthbar.removePlayer(p); |
||||||
|
} |
||||||
|
} |
||||||
|
for (Entity e : m.getNearbyEntities(50, 50, 50)) { |
||||||
|
if (e instanceof Player) { |
||||||
|
Player p = (Player)e; |
||||||
|
healthbar.addPlayer(p); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean randomlyConvertAsSniperSkeleton(LivingEntity m, boolean force) { |
||||||
|
if ((TwosideKeeper.MINIBOSSES_ACTIVATED && |
||||||
|
TwosideKeeper.LAST_SPECIAL_SPAWN+(6000/Math.max(Bukkit.getOnlinePlayers().size(),1))<=TwosideKeeper.getServerTickTime() && |
||||||
|
Math.random()<=0.01) || force) { |
||||||
|
Skeleton s = (Skeleton)m; |
||||||
|
s.setSkeletonType(SkeletonType.NORMAL); |
||||||
|
//Determine distance from Twoside for Difficulty.
|
||||||
|
Location compareloc = TwosideKeeper.TWOSIDE_LOCATION; |
||||||
|
if (!compareloc.getWorld().equals(s.getWorld())) { |
||||||
|
compareloc = new Location(s.getWorld(),0,0,0); |
||||||
|
} |
||||||
|
double chancer = compareloc.distanceSquared(m.getLocation()); |
||||||
|
if (Math.random()*chancer<4000000) { |
||||||
|
MonsterController.convertLivingEntity(m, LivingEntityDifficulty.T1_MINIBOSS); |
||||||
|
} else |
||||||
|
if (Math.random()*chancer<25000000) { |
||||||
|
MonsterController.convertLivingEntity(m, LivingEntityDifficulty.T2_MINIBOSS); |
||||||
|
} else { |
||||||
|
MonsterController.convertLivingEntity(m, LivingEntityDifficulty.T3_MINIBOSS); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean isSniperSkeleton(LivingEntity m) { |
||||||
|
return m instanceof Skeleton && |
||||||
|
((Skeleton)m).getSkeletonType()==SkeletonType.NORMAL && |
||||||
|
( |
||||||
|
MonsterController.getLivingEntityDifficulty(m)==LivingEntityDifficulty.T1_MINIBOSS || |
||||||
|
MonsterController.getLivingEntityDifficulty(m)==LivingEntityDifficulty.T2_MINIBOSS || |
||||||
|
MonsterController.getLivingEntityDifficulty(m)==LivingEntityDifficulty.T3_MINIBOSS |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
protected void increaseBarTextScroll() { |
||||||
|
scroll++; |
||||||
|
switch (scroll%22) { |
||||||
|
case 11:{ |
||||||
|
arrow=" -"; |
||||||
|
}break; |
||||||
|
case 12:{ |
||||||
|
arrow=" "; |
||||||
|
}break; |
||||||
|
case 13:{ |
||||||
|
arrow="> "; |
||||||
|
}break; |
||||||
|
case 14:{ |
||||||
|
arrow="->"; |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
enum ShotMode { |
||||||
|
NORMAL, |
||||||
|
POISON, |
||||||
|
BLEED |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue