Finished implementation of Sniper Skeletons.

This commit is contained in:
sigonasr2 2017-05-27 22:51:31 -05:00
parent ab164df286
commit f404d2fd73
23 changed files with 1468 additions and 57 deletions

Binary file not shown.

View File

@ -1,6 +1,6 @@
name: TwosideKeeper
main: sig.plugin.TwosideKeeper.TwosideKeeper
version: 3.10.16
version: 3.10.17
loadbefore: [aPlugin]
commands:
money:

View File

@ -32,6 +32,7 @@ import sig.plugin.TwosideKeeper.CustomDamage;
import sig.plugin.TwosideKeeper.EliteMonster;
import sig.plugin.TwosideKeeper.MonsterController;
import sig.plugin.TwosideKeeper.TwosideKeeper;
import sig.plugin.TwosideKeeper.HelperStructures.Channel;
import sig.plugin.TwosideKeeper.HelperStructures.LivingEntityDifficulty;
import sig.plugin.TwosideKeeper.HelperStructures.Loot;
import sig.plugin.TwosideKeeper.HelperStructures.MonsterDifficulty;
@ -276,12 +277,12 @@ public class EliteZombie extends EliteMonster{
}
}
if (!storingenergy) {
if (storingenergy_hit>0) {
storingenergy_hit/=1.04f;
/*if (storingenergy_hit>0) {
//storingenergy_hit/=1.04f;
if (storingenergy_hit<10) {
storingenergy_hit=0;
}
}
} */
if (l.getLocation().distanceSquared(m.getLocation())>8192 && !leaping && last_leap_time+20<TwosideKeeper.getServerTickTime()) {
//Lose the target.
targetlist.remove(l);
@ -401,6 +402,7 @@ public class EliteZombie extends EliteMonster{
for (int i=0;i<targetlist.size();i++) {
targetlist.get(i).sendMessage(ChatColor.GOLD+"The "+GenericFunctions.getDisplayName(m)+ChatColor.GOLD+" is absorbing energy!");
}
Channel.createNewChannel(m, "Storing Energy", 20);
m.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0f);
Bukkit.getScheduler().scheduleSyncDelayedTask(TwosideKeeper.plugin, new Runnable() {
public void run() {
@ -411,7 +413,7 @@ public class EliteZombie extends EliteMonster{
Player target = ChooseRandomTarget();
if (target!=null) {
if (last_storingenergy_health-m.getHealth()>0) {
storingenergy_hit=(last_storingenergy_health-m.getHealth())*500d;
storingenergy_hit=(last_storingenergy_health-m.getHealth());
for (int i=0;i<targetlist.size();i++) {
targetlist.get(i).sendMessage(ChatColor.GOLD+"The "+GenericFunctions.getDisplayName(m)+ChatColor.GOLD+"'s next hit is stronger!");
targetlist.get(i).sendMessage(ChatColor.DARK_RED+""+ChatColor.ITALIC+" \"DIE "+target.getName()+ChatColor.DARK_RED+"! DIEE!\"");
@ -604,7 +606,7 @@ public class EliteZombie extends EliteMonster{
GenericFunctions.logAndApplyPotionEffectToEntity(PotionEffectType.CONFUSION,20*4,0,p);
TwosideKeeper.log("Got hit for "+storingenergy_hit+" damage!", 2);
//GenericFunctions.removeNoDamageTick(p, m);
if (CustomDamage.ApplyDamage(storingenergy_hit, m, p, null, "Stored Energy", CustomDamage.IGNOREDODGE|CustomDamage.IGNORE_DAMAGE_TICK)) {
if (CustomDamage.ApplyDamage(storingenergy_hit, m, p, null, "Stored Energy", CustomDamage.TRUEDMG|CustomDamage.IGNOREDODGE|CustomDamage.IGNORE_DAMAGE_TICK)) {
//TwosideKeeperAPI.DealDamageToEntity(.CalculateDamageReduction(storingenergy_hit,p,m),p,m);
storingenergy_hit=0;
p.setVelocity(m.getLocation().getDirection().multiply(2.0f));

View File

@ -8,6 +8,7 @@ import org.bukkit.Color;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import sig.plugin.TwosideKeeper.HelperStructures.BuffTemplate;
import sig.plugin.TwosideKeeper.HelperStructures.Utils.TextUtils;
public class Buff {
@ -61,6 +62,28 @@ public class Buff {
this.displayTimer=false;
}
/**
* Creates a new Buff structure.
* @param displayName The name that will show up in the action bar for players if they have this buff.
* @param duration The amount of time in ticks the buff will remain active.
* @param amplifier The amplifier/level/stack amount of this buff.
* @param buffcolor The color of the particles this buff creates.
* @param icon An icon that appears for the buff in the action bar and status bar for monster name tags. This typically includes a chat color code as well to distinguish this buff's color.
* @param isGoodBuff Whether or not this is a good buff. Debuffs should have this set to false.
* @param permanentBuff Whether or not this buff cannot be removed. When set to true, the method buffCanBeRemoved() returns false, notifying the programmers that this buff should not be removed. This make the use of removeBuff() for this buff do absolutely nothing.
* @param displayTimer Whether or not to display the countdown timer even if the duration is greater than 10 seconds.
*/
public Buff(String displayName, long duration, int amplifier, Color buffcolor, String icon, boolean isGoodBuff, boolean permanentBuff, boolean displayTimer) {
this.displayName=displayName;
this.expireTime=TwosideKeeper.getServerTickTime()+duration;
this.level=amplifier;
this.col=buffcolor;
this.icon=icon;
this.isGoodBuff=isGoodBuff;
this.permanentBuff=permanentBuff;
this.displayTimer=displayTimer;
}
public static boolean hasBuffInHashMap(LivingEntity l, String name) {
if (l instanceof Player) {
Player p = (Player)l;
@ -72,6 +95,10 @@ public class Buff {
}
}
public static boolean hasBuff(LivingEntity l, BuffTemplate buff) {
return hasBuff(l,buff.getKeyName());
}
public static boolean hasBuff(LivingEntity l, String name) {
if (l instanceof Player) {
Player p = (Player)l;
@ -114,6 +141,17 @@ public class Buff {
}
}
/**
* Returns <b>null</b> if no buff found! Use <b>hasBuff()</b> to verify they have
* a buff beforehand.
*
* This version of the method uses a BuffTemplate, which allows you to use an already defined setup for
* a Buff's appearance and display.
*/
public static Buff getBuff(LivingEntity l, BuffTemplate buff) {
return getBuff(l,buff.getKeyName());
}
/**
* Returns <b>null</b> if no buff found! Use <b>hasBuff()</b> to verify they have
* a buff beforehand.
@ -150,6 +188,32 @@ public class Buff {
return displayTimer;
}
/**
* Attempts to add a buff to the target. This will not necessarily add the buff if the amplifier
* is weaker than what is currently applied, or the amplifier is the same but the duration is less.
* This follows the same rules established by all other buff mechanics added previously to the server.
*
* This version of the method uses a BuffTemplate, which allows you to use an already defined setup for
* a Buff's appearance and display.
*/
public static void addBuff(LivingEntity l, long duration, int amplifier, BuffTemplate buff, boolean stacking) {
addBuff(l,buff.getKeyName(),new Buff(
buff.getDisplayName(),
duration,
amplifier,
buff.getParticleColor(),
buff.getIcon(),
buff.isGoodBuff(),
buff.isPermanentBuff(),
buff.isDisplayTimer()
),stacking);
}
public static void addBuff(LivingEntity ent, int duration, int amplifier, BuffTemplate buff) {
addBuff(ent,duration,amplifier,buff,false);
}
public static void addBuff(LivingEntity l, String name, Buff buff) {
addBuff(l,name,buff,false);
}
@ -212,6 +276,10 @@ public class Buff {
}
}
}
public static void removeBuff(LivingEntity l, BuffTemplate buff) {
removeBuff(l,buff.getKeyName());
}
public static void removeBuff(LivingEntity l, String name) {
if (l instanceof Player) {
Player p = (Player)l;

View File

@ -6,6 +6,7 @@ import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Monster;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.TemporaryBlock;
import sig.plugin.TwosideKeeper.HelperStructures.Utils.SoundUtils;
public class ChargeZombie {
@ -152,6 +153,9 @@ public class ChargeZombie {
public static boolean ChanceToBreak(Block b) {
int blocktoughness = 0;
if (TemporaryBlock.isTemporaryBlock(b) || !aPlugin.API.isDestroyable(b)) {
return false;
}
switch (b.getType()) {
case BEDROCK: {
blocktoughness=999999;

View File

@ -61,6 +61,7 @@ import sig.plugin.TwosideKeeper.Events.PlayerDodgeEvent;
import sig.plugin.TwosideKeeper.HelperStructures.AdvancedTitle;
import sig.plugin.TwosideKeeper.HelperStructures.ArtifactAbility;
import sig.plugin.TwosideKeeper.HelperStructures.BowMode;
import sig.plugin.TwosideKeeper.HelperStructures.BuffTemplate;
import sig.plugin.TwosideKeeper.HelperStructures.Channel;
import sig.plugin.TwosideKeeper.HelperStructures.DamageStructure;
import sig.plugin.TwosideKeeper.HelperStructures.ItemSet;
@ -71,6 +72,8 @@ import sig.plugin.TwosideKeeper.HelperStructures.PlayerMode;
import sig.plugin.TwosideKeeper.HelperStructures.WorldShop;
import sig.plugin.TwosideKeeper.HelperStructures.Common.BaublePouch;
import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.EffectPool;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.TemporaryBlock;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.TemporaryBlockNode;
import sig.plugin.TwosideKeeper.HelperStructures.Utils.ArtifactUtils;
import sig.plugin.TwosideKeeper.HelperStructures.Utils.DebugUtils;
@ -84,6 +87,7 @@ import sig.plugin.TwosideKeeper.Monster.Dummy;
import sig.plugin.TwosideKeeper.Monster.HellfireGhast;
import sig.plugin.TwosideKeeper.Monster.HellfireSpider;
import sig.plugin.TwosideKeeper.Monster.Knight;
import sig.plugin.TwosideKeeper.Monster.SniperSkeleton;
public class CustomDamage {
@ -899,10 +903,42 @@ public class CustomDamage {
GenericFunctions.logAndApplyPotionEffectToEntity(type,GenericFunctions.getBasePotionDuration(pd)/8, (pd.isUpgraded())?1:0, target);
}
}
if (proj.hasMetadata("SNIPER_NORMAL") ||
proj.hasMetadata("SNIPER_POISON") ||
proj.hasMetadata("SNIPER_BLEED") ||
proj.hasMetadata("SNIPER_CRIPPLINGINFECTION")) {
if (proj.hasMetadata("SNIPER_POISON")) {
//Apply a stacking Poison.
Buff.addBuff(target, "Poison", new Buff("Poison",20*15,1,Color.YELLOW,ChatColor.YELLOW+"",false),true);
createPoisonPool(proj, target);
}
if (proj.hasMetadata("SNIPER_BLEED")) {
Buff.addBuff(target, "BLEEDING", new Buff("Bleed",20*15,1,Color.MAROON,ChatColor.DARK_RED+"",false),true);
createBloodPool(proj,target);
if (TwosideKeeper.custommonsters.containsKey(shooter.getUniqueId())) {
CustomMonster cm = TwosideKeeper.custommonsters.get(shooter.getUniqueId());
cm.bloodPoolSpawnedEvent(target);
}
}
if (proj.hasMetadata("SNIPER_CRIPPLINGINFECTION")) {
Buff.addBuff(target, 20*30, 1, BuffTemplate.INFECTION);
}
GenericFunctions.removeNoDamageTick(target, damager);
}
}
return damage;
}
private static void createBloodPool(Arrow proj, LivingEntity target) {
TemporaryBlock.createTemporaryBlockCircle(target.getLocation(), 1, Material.WOOL, (byte)14, 20*30, "BLOODPOOL");
new EffectPool(target.getLocation(),1,20*30,Color.fromRGB(255, 0, 0));
}
private static void createPoisonPool(Arrow proj, LivingEntity target) {
TemporaryBlock.createTemporaryBlockCircle(target.getLocation(), 1, Material.WOOL, (byte)4, 20*30, "POISONPOOL");
new EffectPool(target.getLocation(),1,20*30,Color.fromRGB(255, 255, 0));
}
private static double IncreaseDamageFromDarkSubmission(Player p, Entity damager, double damage) {
LivingEntity shooter = getDamagerEntity(damager);
double bonusdmg = 0;
@ -1876,12 +1912,26 @@ public class CustomDamage {
}
public static void addToCustomStructures(LivingEntity m) {
addHellfireSpiderToList(m);
addHellfireGhastToList(m);
addBlazeToList(m);
addWitherToList(m);
addKnighttoList(m);
removeStraySpiderMinions(m);
if (addHellfireSpiderToList(m)) {return;}
if (addHellfireGhastToList(m)) {return;}
if (addBlazeToList(m)) {return;}
if (addWitherToList(m)) {return;}
if (m instanceof Skeleton) {
if (Math.random()<=0.5) {
if (addKnighttoList(m)) {return;} else {
addSniperSkeletontoList(m);
}
} else {
if (addSniperSkeletontoList(m)) {return;} else {
addKnighttoList(m);
}
}
}
}
private static void removeStraySpiderMinions(LivingEntity m) {
@ -1891,51 +1941,76 @@ public class CustomDamage {
}
}
private static void addKnighttoList(LivingEntity m) {
public static boolean addSniperSkeletontoList(LivingEntity m) {
if (!TwosideKeeper.custommonsters.containsKey(m.getUniqueId()) &&
(SniperSkeleton.isSniperSkeleton(m) ||
(m instanceof Skeleton &&
SniperSkeleton.randomlyConvertAsSniperSkeleton(m)))) {
TwosideKeeper.custommonsters.put(m.getUniqueId(),new SniperSkeleton(m));
TwosideKeeper.log("Spawned a new "+LivingEntityStructure.getCustomLivingEntityName(m), 2);
TwosideKeeper.LAST_SPECIAL_SPAWN=TwosideKeeper.getServerTickTime();
return true;
}
return false;
}
private static boolean addKnighttoList(LivingEntity m) {
if (!TwosideKeeper.custommonsters.containsKey(m.getUniqueId()) &&
(Knight.isKnight(m) ||
(m instanceof Skeleton &&
Knight.randomlyConvertAsKnight(m)))) {
TwosideKeeper.custommonsters.put(m.getUniqueId(),new Knight(m));
TwosideKeeper.log("Spawned a new "+LivingEntityStructure.getCustomLivingEntityName(m), 0);
TwosideKeeper.log("Spawned a new "+LivingEntityStructure.getCustomLivingEntityName(m), 2);
TwosideKeeper.LAST_SPECIAL_SPAWN=TwosideKeeper.getServerTickTime();
return true;
}
return false;
}
private static void addWitherToList(LivingEntity m) {
private static boolean addWitherToList(LivingEntity m) {
if (!TwosideKeeper.custommonsters.containsKey(m.getUniqueId()) &&
m instanceof Wither) {
TwosideKeeper.custommonsters.put(m.getUniqueId(),new sig.plugin.TwosideKeeper.Monster.Wither((Monster)m));
return true;
}
return false;
}
static void addChargeZombieToList(LivingEntity m) {
static boolean addChargeZombieToList(LivingEntity m) {
if (!TwosideKeeper.chargezombies.containsKey(m.getUniqueId()) &&
MonsterController.isChargeZombie(m)) {
TwosideKeeper.chargezombies.put(m.getUniqueId(),new ChargeZombie((Monster)m));
return true;
}
return false;
}
static void addHellfireSpiderToList(LivingEntity m) {
static boolean addHellfireSpiderToList(LivingEntity m) {
if (!TwosideKeeper.custommonsters.containsKey(m.getUniqueId()) &&
MonsterController.isHellfireSpider(m)) {
TwosideKeeper.custommonsters.put(m.getUniqueId(),new HellfireSpider((Monster)m));
TwosideKeeper.log("Added Hellfire Spider.", 5);
return true;
}
return false;
}
static void addBlazeToList(LivingEntity m) {
static boolean addBlazeToList(LivingEntity m) {
if (!TwosideKeeper.custommonsters.containsKey(m.getUniqueId()) &&
m instanceof Blaze) {
TwosideKeeper.custommonsters.put(m.getUniqueId(),new sig.plugin.TwosideKeeper.Monster.Blaze((Monster)m));
return true;
}
return false;
}
static void addHellfireGhastToList(LivingEntity m) {
static boolean addHellfireGhastToList(LivingEntity m) {
if (!TwosideKeeper.custommonsters.containsKey(m.getUniqueId()) &&
MonsterController.isHellfireGhast(m)) {
TwosideKeeper.custommonsters.put(m.getUniqueId(),new HellfireGhast(m));
return true;
}
return false;
}
public static void addMonsterToTargetList(LivingEntity m,Player p) {
@ -2051,7 +2126,7 @@ public class CustomDamage {
if (isFlagSet(flags,IGNORE_DAMAGE_TICK)) {
GenericFunctions.removeNoDamageTick(target, damager);
}
if (isFlagSet(flags,IGNORE_DAMAGE_TICK) || (GenericFunctions.enoughTicksHavePassed(target, damager) && canHitMobDueToWeakness(damager) && !GenericFunctions.isSuppressed(getDamagerEntity(damager)) && !target.isDead())) {
if (isFlagSet(flags,IGNORE_DAMAGE_TICK) || (GenericFunctions.enoughTicksHavePassed(target, damager) && canHitMobDueToWeakness(damager) && (!GenericFunctions.isSuppressed(getDamagerEntity(damager)) || damager instanceof Projectile) && !target.isDead())) {
TwosideKeeper.log("Enough ticks have passed.", 5);
if (CanResistExplosionsWithExperienceSet(damager, target, reason)) {
@ -2200,6 +2275,10 @@ public class CustomDamage {
private static boolean PassesIframeCheck(LivingEntity target, Entity damager) {
if ((target instanceof Player) && isInIframe((Player)target)) {
return true;
} else
if (TwosideKeeper.custommonsters.containsKey(target.getUniqueId())) {
CustomMonster cm = TwosideKeeper.custommonsters.get(target.getUniqueId());
return cm.isInIframe();
}
return false;
}
@ -3238,19 +3317,33 @@ public class CustomDamage {
double mult = 0.0;
if (target!=null) {
if (target.hasPotionEffect(PotionEffectType.POISON)) {
mult += (GenericFunctions.getPotionEffectLevel(PotionEffectType.POISON, target)+1)*0.5;
mult += (GenericFunctions.getPotionEffectLevel(PotionEffectType.POISON, target)+1)*getPoisonMult(target);
}
/*if (target.hasPotionEffect(PotionEffectType.BLINDNESS)) {
mult += (GenericFunctions.getPotionEffectLevel(PotionEffectType.BLINDNESS, target)+1)*0.5;
}*/
if (Buff.hasBuff(target, "Poison")) {
mult += Buff.getBuff(target, "Poison").getAmplifier()*0.5;
mult += Buff.getBuff(target, "Poison").getAmplifier()*getPoisonMult(target);
}
}
TwosideKeeper.log("Mult is "+mult, 5);
return mult;
}
private static double getPoisonMult(LivingEntity target) {
double mult = 0.5;
if (!(target instanceof Player)) {
LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(target);
if (les.isElite || les.isLeader ||
MonsterController.getLivingEntityDifficulty(target)==LivingEntityDifficulty.T1_MINIBOSS ||
MonsterController.getLivingEntityDifficulty(target)==LivingEntityDifficulty.T2_MINIBOSS ||
MonsterController.getLivingEntityDifficulty(target)==LivingEntityDifficulty.T3_MINIBOSS) {
mult = 0.1;
}
}
return mult;
}
public static double calculateStrikerMultiplier(Entity damager, LivingEntity target) {
double mult=0.0;
if (damager instanceof Player) {

View File

@ -5,6 +5,8 @@ import java.io.File;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.inventivetalent.glow.GlowAPI.Color;
import sig.plugin.TwosideKeeper.Events.EntityChannelCastEvent;
import sig.plugin.TwosideKeeper.HelperStructures.Utils.Classes.MixedDamage;
@ -63,6 +65,10 @@ public class CustomMonster {
}
public boolean isImmuneToSuppression() {
return false;
}
public void cleanup() {
}
@ -75,7 +81,22 @@ public class CustomMonster {
}
public void runProjectileLaunchEvent(ProjectileLaunchEvent ev) {
}
public void onDeathEvent() {
}
public Color getGlowColor() {
return null;
}
public boolean isInIframe() {
return false;
}
public void bloodPoolSpawnedEvent(LivingEntity target) {
}
}

View File

@ -25,6 +25,7 @@ import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import org.inventivetalent.glow.GlowAPI;
import sig.plugin.TwosideKeeper.HelperStructures.Channel;
import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions;
import sig.plugin.TwosideKeeper.HelperStructures.Utils.SoundUtils;
@ -127,7 +128,7 @@ public class EliteMonster {
}
}
bar.setProgress(m.getHealth()/m.getMaxHealth());
bar.setTitle(GenericFunctions.getDisplayName(m) + ((m.getTarget()!=null && (m.getTarget() instanceof Player))?(ChatColor.DARK_AQUA+" "+arrow+" "+ChatColor.YELLOW+((Player)m.getTarget()).getName()):""));
bar.setTitle((Channel.isChanneling(m)?LivingEntityStructure.getChannelingBar(m):GenericFunctions.getDisplayName(m)) + ((m.getTarget()!=null && (m.getTarget() instanceof Player))?(ChatColor.DARK_AQUA+" "+arrow+" "+ChatColor.YELLOW+((Player)m.getTarget()).getName()):""));
if (!(m instanceof Wither || m instanceof EnderDragon)) {
displayHealthbarToNearbyPlayers();
}

View File

@ -75,7 +75,7 @@ public enum ArtifactAbility {
//Sword abilities
PROVOKE("Provoke","Your attacks provoke enemies for [VAL] seconds.",new double[]{0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1},
new double[]{3.0,2.9,2.8,2.7,2.6,2.5,2.4,2.3,2.2,2.1,2.0,1.9,1.8,1.7,1.6,1.5,1.4,1.3,1.2,1.1},10000,10,UpgradePath.SWORD,1),
new double[]{3.0,2.9,2.8,2.7,2.6,2.5,2.4,2.3,2.2,2.1,2.0,1.9,1.8,1.7,1.6,1.5,1.4,1.3,1.2,1.1},10000,10,UpgradePath.PROVOKE,1),
COMBO("Belligerent","[VAL]% more damage for each successive strike on a mob. Resets after 2 seconds of no combat.",new double[]{0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1},
new double[]{1.0,0.975,0.95,0.925,0.9,0.875,0.85,0.825,0.8,0.75,0.7,0.65,0.6,0.55,0.5},10000,40,UpgradePath.SWORD,1),
@ -441,6 +441,13 @@ public enum ArtifactAbility {
return true;
}
}break;
case PROVOKE:{
if ((item.getType().toString().contains("AXE") && !item.getType().toString().contains("PICKAXE"))
|| item.getType().toString().contains("SWORD")) {
//This is an item that can upgrade with Provoke.
return true;
}
}break;
case BASIC:{
if (!item.getType().toString().contains("HELMET") &&
!item.getType().toString().contains("CHESTPLATE") &&

View File

@ -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)
}

View File

@ -72,6 +72,7 @@ import sig.plugin.TwosideKeeper.Artifact;
import sig.plugin.TwosideKeeper.AwakenedArtifact;
import sig.plugin.TwosideKeeper.Buff;
import sig.plugin.TwosideKeeper.CustomDamage;
import sig.plugin.TwosideKeeper.CustomMonster;
import sig.plugin.TwosideKeeper.EliteMonster;
import sig.plugin.TwosideKeeper.MonsterController;
import sig.plugin.TwosideKeeper.LivingEntityStructure;
@ -4892,6 +4893,12 @@ public class GenericFunctions {
}
private static void SetupSuppression(Entity ent, int ticks) {
if (TwosideKeeper.custommonsters.containsKey(ent.getUniqueId())) {
CustomMonster cm = TwosideKeeper.custommonsters.get(ent.getUniqueId());
if (cm.isImmuneToSuppression()) {
return;
}
}
if (!TwosideKeeper.suppressed_entities.contains(ent)) {
TwosideKeeper.suppressed_entities.add(ent);
}
@ -4915,6 +4922,18 @@ public class GenericFunctions {
TwosideKeeper.log("Base Value: "+l.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue(), 5);
l.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0d);
l.setAI(false);
/*double prev_movespd = l.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue();
l.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0);
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{
if (l!=null && l.isValid()) {
l.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(prev_movespd);
}
}, 2);*/
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{
if (l!=null && l.isValid()) {
l.setVelocity(new Vector(0,0,0));
}
},1);
}
}

View File

@ -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());
}
}

View File

@ -23,9 +23,9 @@ public class ReplaceBlockTask implements Runnable{
}
public static void CleanupTemporaryBlock(TemporaryBlock tb) {
if (tb.getBlock()!=null &&
if (tb.getBlock()!=null /*&&
tb.getBlock().getType()==tb.getConvertedMaterial() &&
tb.getBlock().getData()==tb.getConvertedData()) {
tb.getBlock().getData()==tb.getConvertedData()*/) {
tb.getBlock().setType(tb.getOriginalMaterial());
tb.getBlock().setData(tb.getOriginalData());
}

View File

@ -127,32 +127,36 @@ public enum PlayerMode {
}
public static PlayerMode getPlayerMode(Player p) {
PlayerStructure pd = PlayerStructure.GetPlayerStructure(p);
if (needsUpdating(pd)) {
if (Check_isSlayer(p)) {
if (pd.lastmode!=PlayerMode.SLAYER) {pd.slayermodehp=p.getHealth();}
pd.lastmode=PlayerMode.SLAYER;
} else {
if (pd.lastmode==PlayerMode.SLAYER) {
GenericFunctions.removeStealth(p);
}
if (Check_isStriker(p)) {
pd.lastmode=PlayerMode.STRIKER;
} else
if (Check_isBarbarian(p)) {
pd.lastmode=PlayerMode.BARBARIAN;
} else
if (Check_isDefender(p)) {
pd.lastmode=PlayerMode.DEFENDER;
} else
if (Check_isRanger(p)) {
pd.lastmode=PlayerMode.RANGER;
if (p!=null && p.isValid() && p.isOnline()) {
PlayerStructure pd = PlayerStructure.GetPlayerStructure(p);
if (needsUpdating(pd)) {
if (Check_isSlayer(p)) {
if (pd.lastmode!=PlayerMode.SLAYER) {pd.slayermodehp=p.getHealth();}
pd.lastmode=PlayerMode.SLAYER;
} else {
pd.lastmode=PlayerMode.NORMAL;
if (pd.lastmode==PlayerMode.SLAYER) {
GenericFunctions.removeStealth(p);
}
if (Check_isStriker(p)) {
pd.lastmode=PlayerMode.STRIKER;
} else
if (Check_isBarbarian(p)) {
pd.lastmode=PlayerMode.BARBARIAN;
} else
if (Check_isDefender(p)) {
pd.lastmode=PlayerMode.DEFENDER;
} else
if (Check_isRanger(p)) {
pd.lastmode=PlayerMode.RANGER;
} else {
pd.lastmode=PlayerMode.NORMAL;
}
}
}
return pd.lastmode;
} else {
return PlayerMode.NORMAL;
}
return pd.lastmode;
}
public static boolean needsUpdating(PlayerStructure pd) {

View File

@ -247,6 +247,22 @@ public class Pronouns {
"got slammed into the earth by Darkness.",
};
}break;
case 20:{
pronouns = new String[]{
"was pierced to death.",
"took one to the face.",
"took an arrow to the knee.",
"took one too many arrows to the face.",
};
}break;
case 21:{
pronouns = new String[]{
"was barbequed!",
"was turned into fried chicken from a deadly Burning Plume.",
"could not avoid the Burning hell.",
"... wtfbbq",
};
}break;
}
return pronouns[(int)(Math.random()*pronouns.length)];
}

View File

@ -12,5 +12,6 @@ public enum UpgradePath {
SCYTHE, //Falls under the 'Weapon' and 'Tool' category.
FISHING_ROD, //Falls under the 'Weapon' category.
BASIC, //Every category that is not 'Armor'.
ALL //The base category.
ALL, //The base category.
PROVOKE
}

View File

@ -219,8 +219,12 @@ public class LivingEntityStructure {
if (GenericFunctions.isIsolatedTarget(m, p)) {
setGlow(p,GlowAPI.Color.WHITE);
} else
if (Knight.isKnight(m)) {
setGlow(p,GlowAPI.Color.AQUA);
if (TwosideKeeper.custommonsters.containsKey(m.getUniqueId()) &&
TwosideKeeper.custommonsters.get(m.getUniqueId()).getGlowColor()!=null) {
CustomMonster cm = TwosideKeeper.custommonsters.get(m.getUniqueId());
if (cm.getGlowColor()!=null) {
setGlow(p,cm.getGlowColor());
}
}
else {
//No glow.

View File

@ -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);
}
}
}

View File

@ -87,7 +87,7 @@ public class Knight extends CustomMonster{
long lastusedassassinate = TwosideKeeper.getServerTickTime();
final Spell DARKSLASH = new Spell("Dark Slash",new int[]{60,40,40},new int[]{400,300,200},new MixedDamage[]{MixedDamage.v(150),MixedDamage.v(300),MixedDamage.v(300,0.1)});
final Spell LINEDRIVE = new Spell("Line Drive",new int[]{20,10,10},new int[]{800,700,600},new MixedDamage[]{MixedDamage.v(200),MixedDamage.v(400),MixedDamage.v(400, 0.2)});
MixedDamage[] BASIC_ATTACK_DAMAGE = new MixedDamage[]{MixedDamage.v(200),MixedDamage.v(400),MixedDamage.v(400, 0.2)};
MixedDamage[] BASIC_ATTACK_DAMAGE = new MixedDamage[]{MixedDamage.v(50),MixedDamage.v(100),MixedDamage.v(200, 0.05)};
final Spell DARKCLEANSE = new Spell("Dark Cleanse",new int[]{200,240,300},new int[]{1500,1200,1200},new MixedDamage[]{MixedDamage.v(100),MixedDamage.v(300),MixedDamage.v(500, 0.3)});
long lastusedgrandslam = TwosideKeeper.getServerTickTime();
final static int[] GRANDSLAM_COOLDOWN = new int[]{900,700,600};
@ -101,6 +101,9 @@ public class Knight extends CustomMonster{
int randomness = 20;
boolean phaseii = false;
long silverfishtimer = 0;
long lastremoveddebufftime = 0;
final static int DEBUFFREMOVAL_COOLDOWN = 20*30;
List<LivingEntity> endermites = new ArrayList<LivingEntity>();
LivingEntity silverfish = null;
@ -126,6 +129,7 @@ public class Knight extends CustomMonster{
m.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.31f);
relinkToSpider();
m.setAI(false);
m.setRemoveWhenFarAway(false);
createBossHealthbar();
//GenericFunctions.setGlowing(m, Color.AQUA);
setupDarkSword();
@ -145,6 +149,55 @@ public class Knight extends CustomMonster{
increaseBarTextScroll();
performSpells();
performSilverfishNotification();
removeDebuffs();
updateAI();
removeIfTooOld();
}
public Color getGlowColor() {
return Color.AQUA;
}
private void removeIfTooOld() {
if (m.getTicksLived()>72000 && !startedfight) {
m.remove();
}
}
private void updateAI() {
if (!startedfight) {
m.setAI(false);
}
}
private void removeDebuffs() {
if (phaseii || lastremoveddebufftime+DEBUFFREMOVAL_COOLDOWN<=TwosideKeeper.getServerTickTime()) {
removeADebuff();
}
}
public boolean isImmuneToSuppression() {
return phaseii;
}
private void removeADebuff() {
for (PotionEffect pe : m.getActivePotionEffects()) {
if (GenericFunctions.isBadEffect(pe.getType())) {
GenericFunctions.logAndRemovePotionEffectFromEntity(pe.getType(), m);
return;
}
}
for (String s : Buff.getBuffData(m).keySet()) {
Buff b = Buff.getBuffData(m).get(s);
if (b.isDebuff()) {
/*TwosideKeeper.ScheduleRemoval(Buff.getBuffData(m), s);
return;*/
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{
Buff.removeBuff(m, s);
}, 1);
return;
}
}
}
private void performSilverfishNotification() {
@ -170,6 +223,7 @@ public class Knight extends CustomMonster{
public void onPlayerSlayEvent(Player p, String reason) {
if (reason.equalsIgnoreCase("Line Drive Knight")) {
changeAggroToRandomNewTarget();
LINEDRIVE.setLastCastedTime(0);
attemptSpellCast(LINEDRIVE);
SoundUtils.playGlobalSound(m.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 0.9f);
}
@ -422,13 +476,21 @@ public class Knight extends CustomMonster{
protected boolean attemptSpellCast(Spell spell) {
if (cooldownIsAvailable(spell.getLastCastedTime(),spell)) {
//Face target.
Channel.createNewChannel(m, spell.getName(), spell.getCastTimes()[getDifficultySlot()]);
Channel.createNewChannel(m, spell.getName(), (int)(spell.getCastTimes()[getDifficultySlot()]*getCastTimeMultiplier()));
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{FaceTarget(m);}, 5);
return true;
}
return false;
}
private double getCastTimeMultiplier() {
double mult = 1.0;
if (phaseii) {
mult=0.5;
}
return mult;
}
public MixedDamage getBasicAttackDamage() {
return BASIC_ATTACK_DAMAGE[getDifficultySlot()];
}

View File

@ -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
}
}

View File

@ -88,6 +88,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.SignChangeEvent;
@ -242,6 +243,7 @@ import sig.plugin.TwosideKeeper.HelperStructures.Common.RecipeCategory;
import sig.plugin.TwosideKeeper.HelperStructures.Common.RecipeLinker;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.DarkSlash;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.EarthWaveTask;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.EffectPool;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.HighlightCircle;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.LavaPlume;
import sig.plugin.TwosideKeeper.HelperStructures.Effects.ReplaceBlockTask;
@ -274,6 +276,7 @@ import sig.plugin.TwosideKeeper.Monster.Dummy;
import sig.plugin.TwosideKeeper.Monster.HellfireGhast;
import sig.plugin.TwosideKeeper.Monster.Knight;
import sig.plugin.TwosideKeeper.Monster.MonsterTemplate;
import sig.plugin.TwosideKeeper.Monster.SniperSkeleton;
public class TwosideKeeper extends JavaPlugin implements Listener {
@ -507,6 +510,7 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
public static HashMap<String,TemporaryBlock> temporaryblocks = new HashMap<String,TemporaryBlock>();
public static List<Channel> channels = new ArrayList<Channel>();
public static List<HighlightCircle> circles = new ArrayList<HighlightCircle>();
public static List<EffectPool> effectpools = new ArrayList<EffectPool>();
//public static stats StatCommand = new stats();
@ -908,6 +912,13 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
}
TwosideKeeper.HeartbeatLogger.AddEntry("Temporary Channel Handling", (int)(System.nanoTime()-time));time=System.nanoTime();
for (EffectPool ep : effectpools) {
if (!ep.runTick()) {
ScheduleRemoval(effectpools,ep);
}
}
TwosideKeeper.HeartbeatLogger.AddEntry("Effect Pool Handling", (int)(System.nanoTime()-time));time=System.nanoTime();
if ((int)(System.nanoTime()-totaltime)/1000000d>50) {
TwosideKeeper.log("WARNING! Structure Handling took longer than 1 tick! "+((int)(System.nanoTime()-totaltime)/1000000d)+"ms", 0);
}
@ -2026,6 +2037,15 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
m.setHealth(m.getMaxHealth()*0.3);
}, 100);*/
}break;
case "SNIPERSKELETON":{
LivingEntity m = MonsterController.convertLivingEntity((Skeleton)p.getWorld().spawnEntity(p.getLocation(),EntityType.SKELETON),
LivingEntityDifficulty.T1_MINIBOSS);
SniperSkeleton.randomlyConvertAsSniperSkeleton(m,true);
TwosideKeeper.custommonsters.put(m.getUniqueId(),new SniperSkeleton(m));
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{
m.setHealth(m.getMaxHealth()*0.3);
}, 20);
}break;
case "DAMAGETEST":{
LivingEntity m = MonsterController.convertLivingEntity((Skeleton)p.getWorld().spawnEntity(p.getLocation(),EntityType.SKELETON),
LivingEntityDifficulty.T1_MINIBOSS);
@ -2077,6 +2097,9 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
}, beamDuration);
}
}break;
case "EFFECTPOOL":{
new EffectPool(p.getLocation(),2,20*10,Color.fromRGB(255, 255, 0));
}break;
}
}
//LivingEntity m = MonsterController.convertMonster((Monster)p.getWorld().spawnEntity(p.getLocation(),EntityType.ZOMBIE), MonsterDifficulty.ELITE);
@ -4825,7 +4848,7 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
return Pronouns.ChoosePronoun(2)+" and died.";
}
case "FIRE_TICK":
case "FIRE": {
case "FIRE":{
if (Math.random()<0.5) {
return "could not handle the "+Pronouns.ChoosePronoun(3)+" flames.";
} else {
@ -4905,12 +4928,26 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
case "Grand Slam":{
return Pronouns.ChoosePronoun(19);
}
case "Piercing Arrow":{
return Pronouns.ChoosePronoun(20);
}
case "Burning Plume":{
return Pronouns.ChoosePronoun(21);
}
default:{
return "has died by "+pd.lasthitdesc;
}
}
}
@EventHandler(priority=EventPriority.LOW,ignoreCancelled = true)
public void onBurn(BlockBurnEvent ev) {
Block b = ev.getBlock();
if (TemporaryBlock.isTemporaryBlock(b)) {
ev.setCancelled(true);
}
}
@EventHandler(priority=EventPriority.LOW,ignoreCancelled = true)
public void onSignChange(SignChangeEvent ev) {
Player p = ev.getPlayer();
@ -6930,12 +6967,12 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
GenericFunctions.removeNoDamageTick((LivingEntity)ev.getEntity(), ev.getDamager());
CustomDamage.ApplyDamage(pd.vendetta_amt, ev.getDamager(), (LivingEntity)ev.getEntity(), null, "Vendetta");
pd.vendetta_amt=0.0;
GenericFunctions.sendActionBarMessage(p, ChatColor.YELLOW+"Vendetta: "+ChatColor.GREEN+Math.round(pd.vendetta_amt)+" dmg stored",true);
//GenericFunctions.sendActionBarMessage(p, ChatColor.YELLOW+"Vendetta: "+ChatColor.GREEN+Math.round(pd.vendetta_amt)+" dmg stored",true);
pd.customtitle.updateSideTitleStats(p);
ev.setCancelled(true);
} else {
if (weapon.getType()==Material.AIR && pd.weaponUsedForShooting!=null) {
TwosideKeeper.log("Using weapon "+pd.weaponUsedForShooting+" as a substitute", 0);
//TwosideKeeper.log("Using weapon "+pd.weaponUsedForShooting+" as a substitute", 0);
weapon=pd.weaponUsedForShooting.clone();
pd.weaponUsedForShooting=null;
}
@ -9144,7 +9181,15 @@ public class TwosideKeeper extends JavaPlugin implements Listener {
if (ev.getEntity() instanceof Projectile) {
Projectile arr = (Projectile)ev.getEntity();
if (arr.getShooter() instanceof Player) {
if (arr.getShooter() instanceof LivingEntity &&
custommonsters.containsKey(((LivingEntity)(arr.getShooter())).getUniqueId())) {
LivingEntity ent = (LivingEntity)(arr.getShooter());
CustomMonster cm = CustomMonster.getCustomMonster(ent);
cm.runProjectileLaunchEvent(ev);
}
if (arr.getShooter() instanceof Player &&
arr instanceof Arrow) {
Player p = (Player)(arr.getShooter());
PlayerStructure pd = PlayerStructure.GetPlayerStructure(p);
int slot = p.getInventory().getHeldItemSlot();

View File

@ -17,6 +17,7 @@ import org.bukkit.inventory.ItemStack;
import sig.plugin.TwosideKeeper.HelperStructures.ArtifactAbility;
import sig.plugin.TwosideKeeper.HelperStructures.ArtifactItem;
import sig.plugin.TwosideKeeper.HelperStructures.BuffTemplate;
import sig.plugin.TwosideKeeper.HelperStructures.Channel;
import sig.plugin.TwosideKeeper.HelperStructures.CubeType;
import sig.plugin.TwosideKeeper.HelperStructures.ItemSet;
@ -640,6 +641,9 @@ public final class TwosideKeeperAPI {
public static boolean isBuffActive(LivingEntity l, String buffname) {
return Buff.hasBuff(l,buffname);
}
public static boolean isBuffActive(LivingEntity l, BuffTemplate buff) {
return Buff.hasBuff(l,buff);
}
/**
* Outputs all buffs a particular LivingEntity has to the console.
*/
@ -649,6 +653,9 @@ public final class TwosideKeeperAPI {
public static Buff getBuff(LivingEntity l, String buffname) {
return Buff.getBuff(l, buffname);
}
public static Buff getBuff(LivingEntity l, BuffTemplate buff) {
return Buff.getBuff(l, buff);
}
/**
* Returns a HashMap containing ALL buffs, expired or not that have been
* applied to this LivingEntity. Try isBuffExpired() to check which ones are
@ -686,12 +693,33 @@ public final class TwosideKeeperAPI {
public static void addBuff(LivingEntity l, String name, Buff buff, boolean stacking) {
Buff.addBuff(l, name, buff, stacking);
}
/**
* Attempts to add a buff to the player's buff data structure, overwriting the buff if it contains
* the same name. Note that the buff will not be added if the amplifier of the buff is less than what
* is currently applied, or the amplifier is equal but the duration is less. A new Buff data structure
* has to be created and filled in when calling this (use <b>new Buff()</b>)<br><br>
*
* This version of the method uses a BuffTemplate, which allows you to use an already defined setup for
* a Buff's appearance and display.
*/
public static void addBuff(LivingEntity l, long duration, int amplifier, BuffTemplate buff, boolean stacking) {
Buff.addBuff(l, duration, amplifier, buff, stacking);
}
/**
* Removes a buff, if possible.
*/
public static void removeBuff(LivingEntity l, String name) {
Buff.removeBuff(l, name);
}
/**
* Removes a buff, if possible.
*
* This version of the method uses a BuffTemplate, which allows you to use an already defined setup for
* a Buff's appearance and display.
*/
public static void removeBuff(LivingEntity l, BuffTemplate buff) {
Buff.removeBuff(l, buff);
}
/**
* Returns whether or not a buff can be removed. (If it's not permanent)
*/

View File

@ -44,6 +44,7 @@ import sig.plugin.TwosideKeeper.Events.InventoryUpdateEvent;
import sig.plugin.TwosideKeeper.Events.InventoryUpdateEvent.UpdateReason;
import sig.plugin.TwosideKeeper.HelperStructures.ArtifactAbility;
import sig.plugin.TwosideKeeper.HelperStructures.BankSession;
import sig.plugin.TwosideKeeper.HelperStructures.BuffTemplate;
import sig.plugin.TwosideKeeper.HelperStructures.DamageStructure;
import sig.plugin.TwosideKeeper.HelperStructures.ItemSet;
import sig.plugin.TwosideKeeper.HelperStructures.MonsterDifficulty;
@ -411,6 +412,12 @@ final class runServerHeartbeat implements Runnable {
private void PerformPoisonTick(LivingEntity ent) {
if (ent instanceof Player) {
PlayerStructure pd = PlayerStructure.GetPlayerStructure((Player)ent);
if (TemporaryBlock.isInRangeOfSpecialBlock(ent.getLocation(), 5, "POISONPOOL")) {
Buff.addBuff(ent, 20*15, 1, BuffTemplate.POISON, true);
} else
if (TemporaryBlock.isInRangeOfSpecialBlock(ent.getLocation(), 5, "BLOODPOOL")) {
Buff.addBuff(ent, 20*15, 1, BuffTemplate.BLEEDING, true);
}
if (Buff.hasBuff(ent, "Poison") && pd.lastPoisonTick+getPoisonTickDelay(ent)<=TwosideKeeper.getServerTickTime()) {
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{
if (ent!=null && Buff.hasBuff(ent, "Poison")) {
@ -437,7 +444,7 @@ final class runServerHeartbeat implements Runnable {
//SoundUtils.playLocalSound((Player)ent, Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 1.0f, 1.0f);
//ent.getWorld().spawnParticle(Particle.LAVA, ent.getEyeLocation(), CustomDamage.GetHeartAmount(Buff.getBuff(ent, "SHRAPNEL").getAmplifier())*5);
Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{
if (ent!=null) {
if (ent!=null && ent.isValid() && Buff.hasBuff(ent, "BLEEDING")) {
CustomDamage.ApplyDamage((Buff.getBuff(ent, "BLEEDING").getAmplifier()), null, ent, null, "Bleeding", CustomDamage.IGNOREDODGE|CustomDamage.TRUEDMG|CustomDamage.IGNORE_DAMAGE_TICK);
}
}, 10); //Bleeding DOT is twice as fast.