From 8e74837162537fb018751c57963b8aec3633d890 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 13 Feb 2020 23:25:35 -0500 Subject: [PATCH] v0.8.0: fully implemented new DK fight --- .../main/assets/custom_tiles/city_boss.png | Bin 6270 -> 6437 bytes .../actors/mobs/DwarfKing.java | 265 ++++++++++++++++-- .../actors/mobs/Ghoul.java | 20 +- .../levels/NewCityBossLevel.java | 10 +- .../messages/actors/actors.properties | 14 +- .../messages/items/items.properties | 2 +- .../messages/levels/levels.properties | 4 +- 7 files changed, 271 insertions(+), 44 deletions(-) diff --git a/core/src/main/assets/custom_tiles/city_boss.png b/core/src/main/assets/custom_tiles/city_boss.png index cf0abfd32aa574fdd2e335c0a0529caab6e2de06..5338ade52b833363f5fce88bd7e9aa1c04ce18ad 100644 GIT binary patch delta 5946 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 delta 5866 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 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java index e08eeb30a..211de82be 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java @@ -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 (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 (lifeLinkSubject()) { + } 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 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; + } + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java index 9559da13f..0c7699e52 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java @@ -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); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCityBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCityBossLevel.java index 190b5fad5..09f77132e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCityBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/NewCityBossLevel.java @@ -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) diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties index a3a18f3d7..010b127f9 100644 --- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties +++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties @@ -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. diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties index 60f29ee88..e97241873 100644 --- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties +++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties @@ -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. diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/levels/levels.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/levels/levels.properties index 8b8be2544..6309cb894 100644 --- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/levels/levels.properties +++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/levels/levels.properties @@ -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