v0.9.3: adjusted DM-300 for bosses challenge:

Baseline:
- No longer performs rockfall if target is already stunned
Challenge:
- HP up to 400 from 300
- Pylons are tougher and 3 are activated
- Abilities are stronger and used more often
- DM takes less time to supercharge and dig
- more exposed wires
This commit is contained in:
Evan Debenham 2021-04-20 21:25:20 -04:00
parent 17e312bc7d
commit 89095041cc
4 changed files with 66 additions and 31 deletions

View File

@ -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=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.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=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 rankings$record.something=Killed by Something

View File

@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges; import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
@ -79,7 +80,7 @@ public class NewDM300 extends Mob {
{ {
spriteClass = DM300Sprite.class; spriteClass = DM300Sprite.class;
HP = HT = 300; HP = HT = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 400 : 300;
EXP = 30; EXP = 30;
defenseSkill = 15; defenseSkill = 15;
@ -107,12 +108,12 @@ public class NewDM300 extends Mob {
public boolean supercharged = false; public boolean supercharged = false;
public boolean chargeAnnounced = 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 turnsSinceLastAbility = -1;
private int abilityCooldown = Random.NormalIntRange(MIN_COOLDOWN, MAX_COOLDOWN); 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 int lastAbility = 0;
private static final int NONE = 0; private static final int NONE = 0;
private static final int GAS = 1; private static final int GAS = 1;
@ -150,7 +151,7 @@ public class NewDM300 extends Mob {
if (turnsSinceLastAbility != -1){ if (turnsSinceLastAbility != -1){
BossHealthBar.assignBoss(this); 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; return true;
} }
//if we can't gas, then drop rocks //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; lastAbility = ROCKS;
turnsSinceLastAbility = 0; turnsSinceLastAbility = 0;
GLog.w(Messages.get(this, "rocks")); 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); 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)){ for (int i : trajectory.subPath(0, trajectory.dist)){
GameScene.add(Blob.seed(i, 20, ToxicGas.class)); GameScene.add(Blob.seed(i, 20*gasMulti, ToxicGas.class));
gasVented += 20; 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){ if (gasVented < 250*gasMulti){
int toVentAround = (int)Math.ceil((250 - gasVented)/8f); int toVentAround = (int)Math.ceil(((250*gasMulti) - gasVented)/8f);
for (int i : PathFinder.NEIGHBOURS8){ for (int i : PathFinder.NEIGHBOURS8){
GameScene.add(Blob.seed(pos+i, toVentAround, ToxicGas.class)); 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); 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){ if (HP < threshold){
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 @Override
public boolean isInvulnerable(Class effect) { public boolean isInvulnerable(Class effect) {
if (supercharged && !invulnWarned){ if (supercharged && !invulnWarned){
@ -471,7 +484,7 @@ public class NewDM300 extends Mob {
((NewCavesBossLevel)Dungeon.level).activatePylon(); ((NewCavesBossLevel)Dungeon.level).activatePylon();
pylonsActivated++; pylonsActivated++;
spend(3f); spend(Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 2f : 3f);
yell(Messages.get(this, "charging")); yell(Messages.get(this, "charging"));
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable")); sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable"));
((DM300Sprite)sprite).updateChargeState(true); ((DM300Sprite)sprite).updateChargeState(true);
@ -488,7 +501,7 @@ public class NewDM300 extends Mob {
supercharged = false; supercharged = false;
((DM300Sprite)sprite).updateChargeState(false); ((DM300Sprite)sprite).updateChargeState(false);
if (pylonsActivated < 2){ if (pylonsActivated < totalPylonsToActivate()){
yell(Messages.get(this, "charge_lost")); yell(Messages.get(this, "charge_lost"));
} else { } else {
yell(Messages.get(this, "pylons_destroyed")); yell(Messages.get(this, "pylons_destroyed"));
@ -498,7 +511,7 @@ public class NewDM300 extends Mob {
@Override @Override
public boolean isAlive() { public boolean isAlive() {
return HP > 0 || pylonsActivated < 2; return HP > 0 || pylonsActivated < totalPylonsToActivate();
} }
@Override @Override
@ -562,7 +575,7 @@ public class NewDM300 extends Mob {
} }
Dungeon.level.cleanWalls(); Dungeon.level.cleanWalls();
Dungeon.observe(); Dungeon.observe();
spend(3f); spend(Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 2f : 3f);
bestpos = pos; bestpos = pos;
for (int i : PathFinder.NEIGHBOURS8){ for (int i : PathFinder.NEIGHBOURS8){
@ -627,7 +640,7 @@ public class NewDM300 extends Mob {
Char ch = Actor.findChar(i); Char ch = Actor.findChar(i);
if (ch != null && !(ch instanceof NewDM300)){ if (ch != null && !(ch instanceof NewDM300)){
Buff.prolong( ch, Paralysis.class, 3 ); Buff.prolong( ch, Paralysis.class, Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 5 : 3 );
} }
} }

View File

@ -22,6 +22,7 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
@ -48,12 +49,14 @@ import com.watabou.utils.Bundle;
import com.watabou.utils.PathFinder; import com.watabou.utils.PathFinder;
import com.watabou.utils.Random; import com.watabou.utils.Random;
import java.util.ArrayList;
public class Pylon extends Mob { public class Pylon extends Mob {
{ {
spriteClass = PylonSprite.class; spriteClass = PylonSprite.class;
HP = HT = 50; HP = HT = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 80 : 50;
maxLvl = -2; maxLvl = -2;
@ -85,20 +88,38 @@ public class Pylon extends Mob {
return true; return true;
} }
int cell1 = pos + PathFinder.CIRCLE8[targetNeighbor]; ArrayList<Integer> shockCells = new ArrayList<>();
int cell2 = pos + PathFinder.CIRCLE8[(targetNeighbor+4)%8];
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(); sprite.flash();
if (Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[cell1] || Dungeon.level.heroFOV[cell2]) {
sprite.parent.add(new Lightning(DungeonTilemap.raisedTileCenterToWorld(cell1), boolean visible = Dungeon.level.heroFOV[pos];
DungeonTilemap.raisedTileCenterToWorld(cell2), null)); for (int cell : shockCells){
CellEmitter.get(cell1).burst(SparkParticle.FACTORY, 3); if (Dungeon.level.heroFOV[cell]){
CellEmitter.get(cell2).burst(SparkParticle.FACTORY, 3); 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 ); Sample.INSTANCE.play( Assets.Sounds.LIGHTNING );
} }
shockChar(Actor.findChar(cell1)); for (int cell : shockCells) {
shockChar(Actor.findChar(cell2)); shockChar(Actor.findChar(cell));
}
targetNeighbor = (targetNeighbor+1)%8; targetNeighbor = (targetNeighbor+1)%8;

View File

@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.levels;
import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones; import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; 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.blobs.Electricity;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.NewDM300; 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.actors.mobs.Pylon;
import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
@ -103,7 +103,7 @@ public class NewCavesBossLevel extends Level {
if (map[i] == Terrain.EMPTY) { if (map[i] == Terrain.EMPTY) {
if (patch[i - 14*width()]){ if (patch[i - 14*width()]){
map[i] = Terrain.WATER; 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; map[i] = Terrain.INACTIVE_TRAP;
} }
} }
@ -344,7 +344,8 @@ public class NewCavesBossLevel extends Level {
pylonsRemaining++; pylonsRemaining++;
} }
} }
if (pylonsRemaining > 2) { int finalPylonsRemaining = Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 1 : 2;
if (pylonsRemaining > finalPylonsRemaining) {
blobs.get(PylonEnergy.class).fullyClear(); blobs.get(PylonEnergy.class).fullyClear();
} }
} }