v0.8.0: fully implemented new DK fight

This commit is contained in:
Evan Debenham 2020-02-13 23:25:35 -05:00
parent 499d2e1b2b
commit 8e74837162
7 changed files with 271 additions and 44 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -23,9 +23,11 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LifeLink;
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
@ -34,14 +36,19 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.ArmorKit;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.LloydsBeacon;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
import com.shatteredpixel.shatteredpixeldungeon.levels.NewCityBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.KingSprite;
import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.audio.Sample;
import com.watabou.noosa.particles.Emitter;
@ -55,13 +62,12 @@ import java.util.HashSet;
public class DwarfKing extends Mob {
//TODO decide on final stats, implement later phases
{
spriteClass = KingSprite.class;
HP = HT = 300;
EXP = 40;
defenseSkill = 25;
defenseSkill = 22;
properties.add(Property.BOSS);
properties.add(Property.UNDEAD);
@ -69,54 +75,160 @@ public class DwarfKing extends Mob {
@Override
public int damageRoll() {
return Random.NormalIntRange( 25, 40 );
return Random.NormalIntRange( 15, 30 );
}
@Override
public int attackSkill( Char target ) {
return 32;
return 28;
}
@Override
public int drRoll() {
return Random.NormalIntRange(0, 14);
return Random.NormalIntRange(0, 10);
}
private int phase = 1;
private int summonsMade = 0;
private float summonCooldown = 0;
private float abilityCooldown = 0;
private static final int MIN_COOLDOWN = 10;
private static final int MAX_COOLDOWN = 14;
private int lastAbility = 0;
private static final int NONE = 0;
private static final int LINK = 1;
private static final int TELE = 2;
private static final String PHASE = "phase";
private static final String SUMMONS_MADE = "summons_made";
private static final String SUMMON_CD = "summon_cd";
private static final String ABILITY_CD = "ability_cd";
private static final String LAST_ABILITY = "last_ability";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put( PHASE, phase );
bundle.put( SUMMONS_MADE, summonsMade );
bundle.put( SUMMON_CD, summonCooldown );
bundle.put( ABILITY_CD, abilityCooldown );
bundle.put( LAST_ABILITY, lastAbility );
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
phase = bundle.getInt( PHASE );
summonsMade = bundle.getInt( SUMMONS_MADE );
summonCooldown = bundle.getFloat( SUMMON_CD );
abilityCooldown = bundle.getFloat( ABILITY_CD );
lastAbility = bundle.getInt( LAST_ABILITY );
}
@Override
protected boolean act() {
if (buffs(Summoning.class).size() < 1) {
if (phase == 1) {
if (enemy != null
&& Dungeon.level.adjacent(pos, enemy.pos) && teleportSubject()){
if (summonCooldown <= 0 && summonSubject(3)){
summonsMade++;
summonCooldown += Random.NormalIntRange(MIN_COOLDOWN, MAX_COOLDOWN);
} else if (summonCooldown > 0){
summonCooldown--;
}
if (abilityCooldown <= 0){
if (lastAbility == NONE) {
//50/50 either ability
lastAbility = Random.Int(2) == 0 ? LINK : TELE;
} else if (lastAbility == LINK) {
//more likely to use tele
lastAbility = Random.Int(8) == 0 ? LINK : TELE;
} else {
//more likely to use link
lastAbility = Random.Int(8) != 0 ? LINK : TELE;
}
if (lastAbility == LINK && lifeLinkSubject()){
abilityCooldown += Random.NormalIntRange(MIN_COOLDOWN, MAX_COOLDOWN);
spend(TICK);
return true;
} else if (lifeLinkSubject()) {
} else if (teleportSubject()) {
lastAbility = TELE;
abilityCooldown += Random.NormalIntRange(MIN_COOLDOWN, MAX_COOLDOWN);
spend(TICK);
return true;
}
} else {
abilityCooldown--;
}
} else if (phase == 2){
if (summonsMade < 4){
if (summonsMade == 0){
sprite.centerEmitter().start( Speck.factory( Speck.SCREAM ), 0.4f, 2 );
Sample.INSTANCE.play( Assets.SND_CHALLENGE );
yell(Messages.get(this, "wave_1"));
}
summonSubject(3, Ghoul.class);
spend(3*TICK);
summonsMade++;
return true;
} else if (shielding() <= 200 && summonsMade < 8){
if (summonsMade == 4){
sprite.centerEmitter().start( Speck.factory( Speck.SCREAM ), 0.4f, 2 );
Sample.INSTANCE.play( Assets.SND_CHALLENGE );
yell(Messages.get(this, "wave_2"));
}
if (summonsMade == 7){
summonSubject(3, Random.Int(2) == 0 ? Monk.class : Warlock.class);
} else {
summonSubject(3, Ghoul.class);
}
summonsMade++;
spend(TICK);
return true;
} else if (shielding() <= 100 && summonsMade < 12) {
sprite.centerEmitter().start( Speck.factory( Speck.SCREAM ), 0.4f, 2 );
Sample.INSTANCE.play( Assets.SND_CHALLENGE );
yell(Messages.get(this, "wave_3"));
summonSubject(3, Warlock.class);
summonSubject(3, Monk.class);
summonSubject(3, Ghoul.class);
summonSubject(3, Ghoul.class);
summonsMade = 12;
spend(TICK);
return true;
} else {
summonSubject();
spend(TICK);
return true;
}
} else if (phase == 3 && buffs(Summoning.class).size() < 4){
if (summonSubject(3)) summonsMade++;
}
}
return super.act();
}
private boolean summonSubject(){
private boolean summonSubject( int delay ){
//4th summon is always a monk or warlock, otherwise ghoul
if (summonsMade % 4 == 3){
return summonSubject( delay, Random.Int(2) == 0 ? Monk.class : Warlock.class );
} else {
return summonSubject( delay, Ghoul.class );
}
}
private boolean summonSubject( int delay, Class<?extends Mob> type ){
Summoning s = new Summoning();
s.pos = ((NewCityBossLevel)Dungeon.level).getSummoningPos();
if (s.pos == -1) return false;
switch (Random.Int(6)){
default:
s.summon = Ghoul.class;
break;
case 0:
s.summon = Monk.class;
break;
case 1:
s.summon = Warlock.class;
break;
}
s.delay = 5;
s.summon = type;
s.delay = delay;
s.attachTo(this);
return true;
}
@ -200,7 +312,7 @@ public class DwarfKing extends Mob {
bestPos = enemy.pos;
for (int i : PathFinder.NEIGHBOURS8){
if (Actor.findChar(enemy.pos+i) == null
&& !Dungeon.level.solid[enemy.pos+1]
&& !Dungeon.level.solid[enemy.pos+i]
&& Dungeon.level.trueDistance(enemy.pos+i, pos) < bestDist){
bestPos = enemy.pos+i;
bestDist = Dungeon.level.trueDistance(enemy.pos+i, pos);
@ -229,16 +341,84 @@ public class DwarfKing extends Mob {
}
}
@Override
public void damage(int dmg, Object src) {
if (phase == 2 && !(src instanceof KingDamager)){
sprite.showStatus( CharSprite.POSITIVE, Messages.get(this, "immune") );
return;
} else if (phase == 3 && !(src instanceof Viscosity.DeferedDamage)){
Viscosity.DeferedDamage deferred = Buff.affect( this, Viscosity.DeferedDamage.class );
deferred.prolong( dmg );
sprite.showStatus( CharSprite.WARNING, Messages.get(Viscosity.class, "deferred", dmg) );
return;
}
int preHP = HP;
super.damage(dmg, src);
if (phase == 1) {
int dmgTaken = preHP - HP;
abilityCooldown -= dmgTaken/8f;
summonCooldown -= dmgTaken/8f;
if (HP <= 50) {
HP = 50;
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
ScrollOfTeleportation.appear(this, NewCityBossLevel.throne);
phase = 2;
summonsMade = 0;
sprite.idle();
Buff.affect(this, DKBarrior.class).setShield(HT);
for (Summoning s : buffs(Summoning.class)) {
s.detach();
}
for (Mob m : Dungeon.level.mobs.toArray(new Mob[0])) {
if (m instanceof Ghoul || m instanceof Monk || m instanceof Warlock) {
m.die(null);
}
}
}
} else if (phase == 2 && shielding() == 0) {
phase = 3;
summonsMade = 3; //opens with a monk/warlock
sprite.centerEmitter().start( Speck.factory( Speck.SCREAM ), 0.4f, 2 );
Sample.INSTANCE.play( Assets.SND_CHALLENGE );
yell( Messages.get(this, "enraged", Dungeon.hero.name()) );
} else if (phase == 3 && preHP > 20 && HP < 20){
yell( Messages.get(this, "losing") );
}
}
@Override
public boolean isAlive() {
return super.isAlive() || phase != 3;
}
@Override
public void die(Object cause) {
super.die(cause);
GameScene.bossSlain();
Dungeon.level.drop( new ArmorKit(), pos ).sprite.drop();
super.die( cause );
Badges.validateBossSlain();
super.die( cause );
Dungeon.level.unseal();
Badges.validateBossSlain();
for (Mob m : Dungeon.level.mobs.toArray(new Mob[0])){
if (m instanceof Ghoul || m instanceof Monk || m instanceof Warlock){
m.die(null);
}
}
LloydsBeacon beacon = Dungeon.hero.belongings.getItem(LloydsBeacon.class);
if (beacon != null) {
beacon.upgrade();
}
yell( Messages.get(this, "defeated") );
}
public static class Summoning extends Buff {
@ -292,9 +472,15 @@ public class DwarfKing extends Mob {
m.maxLvl = -2;
GameScene.add(m);
m.state = m.HUNTING;
if (((DwarfKing)target).phase == 2){
Buff.affect(m, KingDamager.class);
}
} else {
Char ch = Actor.findChar(pos);
ch.damage(Random.NormalIntRange(20, 40), summon);
if (((DwarfKing)target).phase == 2){
target.damage(target.HT/12, new KingDamager());
}
}
detach();
@ -343,4 +529,31 @@ public class DwarfKing extends Mob {
}
}
public static class KingDamager extends Buff {
@Override
public void detach() {
super.detach();
for (Mob m : Dungeon.level.mobs){
if (m instanceof DwarfKing){
m.damage(m.HT/12, this);
}
}
}
}
public static class DKBarrior extends Barrier{
@Override
public boolean act() {
incShield();
return super.act();
}
@Override
public int icon() {
return BuffIndicator.NONE;
}
}
}

View File

@ -146,19 +146,25 @@ public class Ghoul extends Mob {
timesDowned++;
Buff.append(nearby, GhoulLifeLink.class).set(timesDowned*5, this);
((GhoulSprite)sprite).crumple();
} else {
super.die(cause);
return;
}
} else {
super.die(cause);
}
Buff b = buff(Corruption.class);
if (b != null) b.detach();
b = buff(DwarfKing.KingDamager.class);
if (b != null) b.detach();
super.die(cause);
}
@Override
protected synchronized void onRemove() {
for (Buff buff : buffs()) {
//corruption is preserved
if (!(buff instanceof Corruption)) buff.detach();
//corruption and king damager are preserved when removed
//instead they are detached when the ghoul actually dies
if (!(buff instanceof Corruption) && !(buff instanceof DwarfKing.KingDamager))
buff.detach();
}
}
@ -291,6 +297,7 @@ public class Ghoul extends Mob {
Actor.add(ghoul);
Dungeon.level.mobs.add(ghoul);
Dungeon.level.occupyCell( ghoul );
ghoul.sprite.idle();
super.detach();
return true;
}
@ -318,6 +325,7 @@ public class Ghoul extends Mob {
Ghoul newHost = searchForHost(ghoul);
if (newHost != null){
attachTo(newHost);
spend(-cooldown());
} else {
ghoul.die(this);
}

View File

@ -66,10 +66,12 @@ public class NewCityBossLevel extends Level {
private static final int bottomDoor = 7 + (arena.bottom-1)*15;
private static final int topDoor = 7 + arena.top*15;
public static final int throne;
private static final int[] pedestals = new int[4];
static{
static {
Point c = arena.center();
throne = c.x + (c.y) * WIDTH;
pedestals[0] = c.x-3 + (c.y-3) * WIDTH;
pedestals[1] = c.x+3 + (c.y-3) * WIDTH;
pedestals[2] = c.x+3 + (c.y+3) * WIDTH;
@ -391,7 +393,7 @@ public class NewCityBossLevel extends Level {
//imp's pedestal
} else if (map[i] == Terrain.PEDESTAL) {
data[i] = 13*8 + 5;
data[i] = 12*8 + 5;
//skull piles
} else if (map[i] == Terrain.STATUE) {
@ -595,12 +597,14 @@ public class NewCityBossLevel extends Level {
shadowTop += tileW;
}
//lower part. Just need to handle statue tiles here
//lower part. Statues and DK's throne
for (int i = tileW*21; i < tileW * tileH; i++){
//Statues that need to face left instead of right
if (map[i] == Terrain.STATUE && i%tileW > 7){
data[i-tileW] = 14*8 + 4;
} else if (map[i] == Terrain.SIGN){
data[i-tileW] = 13*8 + 5;
}
//always no tile here (as the above statements are modifying previous tiles)

View File

@ -517,18 +517,20 @@ actors.mobs.newdm300.desc=The DM-300 is the largest and most powerful 'defense m
actors.mobs.newdm300.desc_supercharged=DM-300 is currently charged full of electrical energy, In this form DM-300 cannot be damaged and moves at double speed! Additionally, its drill now spins fast enough for it to _tunnel through solid rock,_ though it moves much more slowly when doing this.\n\nAttacking DM-300 directly is pointless while it is supercharged, but _something in the area must be providing it with this energy,_ destroying that may weaken it.
actors.mobs.newdm300$fallingrocks.desc=Loose rocks are tumbling down from the ceiling here, it looks like its about to collapse!
actors.mobs.dwarfking.name=Dwarf King
actors.mobs.dwarfking.name=King of Dwarves
actors.mobs.dwarfking.notice=How dare you! You have no idea what you're interfering with!
actors.mobs.dwarfking.lifelink_1=I need of your essence, slave!
actors.mobs.dwarfking.lifelink_2=Bleed for me, slave!
actors.mobs.dwarfking.teleport_1=Deal with them, slave!
actors.mobs.dwarfking.teleport_2=Keep them busy, slave!
actors.mobs.dwarfking.wave_1=Enough! Kill them my slaves!
actors.mobs.dwarfking.immune=IMMUNE
actors.mobs.dwarfking.wave_1=Enough! Arise my slaves!
actors.mobs.dwarfking.wave_2=More! Bleed for your king!
actors.mobs.dwarfking.wave_3=Useless! KILL THEM NOW!
actors.mobs.dwarfking.enraged=You cannot kill me %s, I AM IMMORTAL!
actors.mobs.dwarfking.dieing=No! You can't do this... you have no idea what lies below...
actors.mobs.dwarfking.dead=You've... Doomed us all...
actors.mobs.dwarfking.enraged=You cannot kill me %s. I. AM. IMMORTAL!
actors.mobs.dwarfking.losing=No! You can't do this... you have no idea what lies below...
actors.mobs.dwarfking.defeated=You've... Doomed us all...
actors.mobs.dwarfking.desc=Many years ago one of the highest wizards in the dwarven court uncovered secrets which gave him tremendous power over life and death. He soon put this power to use, subjugating and corrupting his peers, his king, and eventually every dwarven citizen. Now he is king, ruler over a legion of undead subjects.\n\nThe King of Dwarves is an aggressive foe, who will attempt to overwhelm his enemies with his horde of undead minions. Careful positioning is key to getting the upper hand against him.
actors.mobs.elemental$fire.name=fire elemental
actors.mobs.elemental$fire.desc=Elementals are chaotic creatures that are often created when powerful occult magic isn't properly controlled. Elementals have minimal intelligence, and are usually associated with a particular type of magic.\n\nFire elementals are a common type of elemental which deals damage with fiery magic. They will set their target ablaze with melee attacks, and can occasionally shoot bolts of fire as well.
@ -549,7 +551,7 @@ actors.mobs.fetidrat.name=fetid rat
actors.mobs.fetidrat.desc=Something is clearly wrong with this rat. Its greasy black fur and rotting skin are very different from the healthy rats you've seen previously. Its pale green eyes make it seem especially menacing.\n\nThe rat carries a cloud of horrible stench with it, it's overpoweringly strong up close.\n\nDark ooze dribbles from the rat's mouth, it eats through the floor but seems to dissolve in water.
actors.mobs.ghoul.name=dwarven ghoul
actors.mobs.ghoul.desc=As dwarven society slowly began to collapse, and the current king of the dwarves seized absolute power, those who were weak or who resisted him were not treated well. As the king grew more adept at weilding dark magic, he bent these dwarves to his will, and now they make up the footsoldiers of his army.\n\nGhouls are not especially strong on their own, but always travel in groups and are much harder to kill in large numbers. _When a ghoul is defeated, it will rise again after a few turns as long as another ghoul is nearby._
actors.mobs.ghoul.desc=As dwarven society slowly began to collapse, and the current king of the dwarves seized absolute power, those who were weak or who resisted him were not treated well. As the king grew more adept at wielding dark magic, he bent these dwarves to his will, and now they make up the footsoldiers of his army.\n\nGhouls are not especially strong on their own, but always travel in groups and are much harder to kill in large numbers. _When a ghoul is defeated, it will rise again after a few turns as long as another ghoul is nearby._
actors.mobs.gnoll.name=gnoll scout
actors.mobs.gnoll.desc=Gnolls are hyena-like humanoids. They dwell in sewers and dungeons, venturing up to raid the surface from time to time. Gnoll scouts are regular members of their pack, they are not as strong as brutes and not as intelligent as shamans.

View File

@ -67,7 +67,7 @@ items.armor.glyphs.viscosity.deferred=deferred %d
items.armor.glyphs.viscosity$defereddamage.name=Deferred damage
items.armor.glyphs.viscosity$defereddamage.ondeath=The deferred damage killed you...
items.armor.glyphs.viscosity$defereddamage.rankings_desc=Killed by deferred damage
items.armor.glyphs.viscosity$defereddamage.desc=While your armor's glyph has protected you from damage, it seems to be slowly paying you back for it.\n\nDamage is being dealt to you over time instead of immediately.\n\nDeferred damage remaining: %d.
items.armor.glyphs.viscosity$defereddamage.desc=Damage is being dealt slowly over time instead of immediately.\n\nDeferred damage remaining: %d.
items.armor.glyphs.viscosity.desc=This glyph is able to store damage dealt to the wearer, dealing it to them slowly rather than all at once.

View File

@ -137,9 +137,9 @@ levels.newcavesbosslevel.gate_desc_broken=The gate must have been connected to D
levels.newcavesbosslevel.water_desc=With all the electricity around here water might not always be safe...
levels.newcitybosslevel.throne_name=Throne
levels.newcitybosslevel.throne_desc=TODO
levels.newcitybosslevel.throne_desc=This impressively large throne is the seat of the dwarven empire, now taken over by a power-mad necromancer.\n\nThere seems to be some magical or mechanical parts to the throne, Dwarf King may have additional power when sitting on it.
levels.newcitybosslevel.summoning_name=Summoning pedestal
levels.newcitybosslevel.pedestal_desc=TODO
levels.newcitybosslevel.summoning_desc=This pedestal has a large opening in the center, which is practically radiating with dark energy.\n\nDwarf King uses these pedestals as focal points for his necromantic magic, and can summon minions to them. The pedestal must charge for a few turns before the minion appears, and the type of minion being summoned is telegraphed by the building magical power.
levels.caveslevel.grass_name=Fluorescent moss
levels.caveslevel.high_grass_name=Fluorescent mushrooms