diff --git a/core/src/main/assets/messages/misc/misc.properties b/core/src/main/assets/messages/misc/misc.properties index 6b84482a8..1421b978b 100644 --- a/core/src/main/assets/messages/misc/misc.properties +++ b/core/src/main/assets/messages/misc/misc.properties @@ -86,6 +86,6 @@ challenges.no_scrolls_desc=A certain rune is harder to find. Unfortunately, it's challenges.champion_enemies=Hostile champions challenges.champion_enemies_desc=You're not the only one who can level up!\n\n- Regular enemies have a 1/8 chance to spawn with a special champion buff.\n- Champions wake up if they spawn asleep\n- The hero knows when a champion spawns\n- Champions are immune to corruption\n\nThere are six types of champion enemy:\n_Blazing (orange):_ +25% melee damage, ignites on hit, immune to fire, spreads flames on death\n_Projecting (purple):_ +25% melee damage, can attack anything they see\n_Antimagic (green):_ -25% damage taken, immune to magical effects\n_Giant (blue):_ -75% damage taken, +1 melee range, cannot move into tunnels\n_Blessed (yellow):_ +200% accuracy, +200% evasion\n_Growing (red):_ +20% accuracy, evasion, damage, and effective HP. Increases by 1% every 3 turns. challenges.stronger_bosses=Badder bosses -challenges.stronger_bosses_desc=TODO\n\n_Goo:_ +20% health\n_-_ Healing in water ramps up, to a max of 3/turn\n_-_ Pumps up in 1 turn instead of 2\n\n_Tengu:_ +25% health\n_-_ 1st phase traps are much deadlier\n_-_ 2nd phase abilities are more frequent +challenges.stronger_bosses_desc=TODO\n\n_Goo:_ +20% health\n_-_ Healing in water ramps up, to a max of 3/turn\n_-_ Pumps up in 1 turn instead of 2\n\n_Tengu:_ +25% health\n_-_ 1st phase traps are much deadlier\n_-_ 2nd phase abilities are more frequent\n\n_DM-300:_ +33% health\n_-_ Pylons are tougher and 3 activate\n_-_ Abilities are more powerful and frequent\n_-_ DM-300 is faster when supercharged\n_-_ Exposed wires are twice as common rankings$record.something=Killed by Something diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewDM300.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewDM300.java index 51c77cbd4..b7ad10387 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewDM300.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/NewDM300.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Badges; +import com.shatteredpixel.shatteredpixeldungeon.Challenges; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; @@ -79,7 +80,7 @@ public class NewDM300 extends Mob { { spriteClass = DM300Sprite.class; - HP = HT = 300; + HP = HT = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 400 : 300; EXP = 30; defenseSkill = 15; @@ -107,12 +108,12 @@ public class NewDM300 extends Mob { public boolean supercharged = false; public boolean chargeAnnounced = false; + private final int MIN_COOLDOWN = 5; + private final int MAX_COOLDOWN = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 7 : 9; + private int turnsSinceLastAbility = -1; private int abilityCooldown = Random.NormalIntRange(MIN_COOLDOWN, MAX_COOLDOWN); - private static final int MIN_COOLDOWN = 5; - private static final int MAX_COOLDOWN = 9; - private int lastAbility = 0; private static final int NONE = 0; private static final int GAS = 1; @@ -150,7 +151,7 @@ public class NewDM300 extends Mob { if (turnsSinceLastAbility != -1){ BossHealthBar.assignBoss(this); - if (!supercharged && pylonsActivated == 2) BossHealthBar.bleed(true); + if (!supercharged && pylonsActivated == totalPylonsToActivate()) BossHealthBar.bleed(true); } } @@ -216,7 +217,8 @@ public class NewDM300 extends Mob { return true; } //if we can't gas, then drop rocks - } else { + //unless enemy is already stunned, we don't want to stunlock them + } else if (enemy.paralysed <= 0) { lastAbility = ROCKS; turnsSinceLastAbility = 0; GLog.w(Messages.get(this, "rocks")); @@ -363,15 +365,17 @@ public class NewDM300 extends Mob { Ballistica trajectory = new Ballistica(pos, target.pos, Ballistica.STOP_TARGET); + int gasMulti = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 2 : 1; + for (int i : trajectory.subPath(0, trajectory.dist)){ - GameScene.add(Blob.seed(i, 20, ToxicGas.class)); - gasVented += 20; + GameScene.add(Blob.seed(i, 20*gasMulti, ToxicGas.class)); + gasVented += 20*gasMulti; } - GameScene.add(Blob.seed(trajectory.collisionPos, 100, ToxicGas.class)); + GameScene.add(Blob.seed(trajectory.collisionPos, 100*gasMulti, ToxicGas.class)); - if (gasVented < 250){ - int toVentAround = (int)Math.ceil((250 - gasVented)/8f); + if (gasVented < 250*gasMulti){ + int toVentAround = (int)Math.ceil(((250*gasMulti) - gasVented)/8f); for (int i : PathFinder.NEIGHBOURS8){ GameScene.add(Blob.seed(pos+i, toVentAround, ToxicGas.class)); } @@ -448,7 +452,12 @@ public class NewDM300 extends Mob { if (lock != null && !isImmune(src.getClass())) lock.addTime(dmgTaken*1.5f); } - int threshold = HT/3 * (2- pylonsActivated); + int threshold; + if (Dungeon.isChallenged(Challenges.STRONGER_BOSSES)){ + threshold = HT / 4 * (3 - pylonsActivated); + } else { + threshold = HT / 3 * (2 - pylonsActivated); + } if (HP < threshold){ HP = threshold; @@ -457,6 +466,10 @@ public class NewDM300 extends Mob { } + public int totalPylonsToActivate(){ + return Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 3 : 2; + } + @Override public boolean isInvulnerable(Class effect) { if (supercharged && !invulnWarned){ @@ -471,7 +484,7 @@ public class NewDM300 extends Mob { ((NewCavesBossLevel)Dungeon.level).activatePylon(); pylonsActivated++; - spend(3f); + spend(Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 2f : 3f); yell(Messages.get(this, "charging")); sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable")); ((DM300Sprite)sprite).updateChargeState(true); @@ -488,7 +501,7 @@ public class NewDM300 extends Mob { supercharged = false; ((DM300Sprite)sprite).updateChargeState(false); - if (pylonsActivated < 2){ + if (pylonsActivated < totalPylonsToActivate()){ yell(Messages.get(this, "charge_lost")); } else { yell(Messages.get(this, "pylons_destroyed")); @@ -498,7 +511,7 @@ public class NewDM300 extends Mob { @Override public boolean isAlive() { - return HP > 0 || pylonsActivated < 2; + return HP > 0 || pylonsActivated < totalPylonsToActivate(); } @Override @@ -562,7 +575,7 @@ public class NewDM300 extends Mob { } Dungeon.level.cleanWalls(); Dungeon.observe(); - spend(3f); + spend(Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 2f : 3f); bestpos = pos; for (int i : PathFinder.NEIGHBOURS8){ @@ -627,7 +640,7 @@ public class NewDM300 extends Mob { Char ch = Actor.findChar(i); if (ch != null && !(ch instanceof NewDM300)){ - Buff.prolong( ch, Paralysis.class, 3 ); + Buff.prolong( ch, Paralysis.class, Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 5 : 3 ); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Pylon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Pylon.java index fd233ffd4..4be14c69e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Pylon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Pylon.java @@ -22,6 +22,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Challenges; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; @@ -48,12 +49,14 @@ import com.watabou.utils.Bundle; import com.watabou.utils.PathFinder; import com.watabou.utils.Random; +import java.util.ArrayList; + public class Pylon extends Mob { { spriteClass = PylonSprite.class; - HP = HT = 50; + HP = HT = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 80 : 50; maxLvl = -2; @@ -85,20 +88,38 @@ public class Pylon extends Mob { return true; } - int cell1 = pos + PathFinder.CIRCLE8[targetNeighbor]; - int cell2 = pos + PathFinder.CIRCLE8[(targetNeighbor+4)%8]; + ArrayList shockCells = new ArrayList<>(); + + shockCells.add(pos + PathFinder.CIRCLE8[targetNeighbor]); + + if (Dungeon.isChallenged(Challenges.STRONGER_BOSSES)){ + shockCells.add(pos + PathFinder.CIRCLE8[(targetNeighbor+3)%8]); + shockCells.add(pos + PathFinder.CIRCLE8[(targetNeighbor+5)%8]); + } else { + shockCells.add(pos + PathFinder.CIRCLE8[(targetNeighbor+4)%8]); + } sprite.flash(); - if (Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[cell1] || Dungeon.level.heroFOV[cell2]) { - sprite.parent.add(new Lightning(DungeonTilemap.raisedTileCenterToWorld(cell1), - DungeonTilemap.raisedTileCenterToWorld(cell2), null)); - CellEmitter.get(cell1).burst(SparkParticle.FACTORY, 3); - CellEmitter.get(cell2).burst(SparkParticle.FACTORY, 3); + + boolean visible = Dungeon.level.heroFOV[pos]; + for (int cell : shockCells){ + if (Dungeon.level.heroFOV[cell]){ + visible = true; + } + } + + if (visible) { + for (int cell : shockCells){ + sprite.parent.add(new Lightning(sprite.center(), + DungeonTilemap.raisedTileCenterToWorld(cell), null)); + CellEmitter.get(cell).burst(SparkParticle.FACTORY, 3); + } Sample.INSTANCE.play( Assets.Sounds.LIGHTNING ); } - shockChar(Actor.findChar(cell1)); - shockChar(Actor.findChar(cell2)); + for (int cell : shockCells) { + shockChar(Actor.findChar(cell)); + } targetNeighbor = (targetNeighbor+1)%8; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCavesBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCavesBossLevel.java index 67aa543ba..2f60227bf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCavesBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCavesBossLevel.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Bones; +import com.shatteredpixel.shatteredpixeldungeon.Challenges; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; @@ -30,7 +31,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Electricity; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.NewDM300; -import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.OldDM300; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Pylon; import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; @@ -103,7 +103,7 @@ public class NewCavesBossLevel extends Level { if (map[i] == Terrain.EMPTY) { if (patch[i - 14*width()]){ map[i] = Terrain.WATER; - } else if (Random.Int(8) == 0){ + } else if (Random.Int(Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 4 : 8) == 0){ map[i] = Terrain.INACTIVE_TRAP; } } @@ -344,7 +344,8 @@ public class NewCavesBossLevel extends Level { pylonsRemaining++; } } - if (pylonsRemaining > 2) { + int finalPylonsRemaining = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 1 : 2; + if (pylonsRemaining > finalPylonsRemaining) { blobs.get(PylonEnergy.class).fullyClear(); } }