From e487853fd2194c0d4d7a7394efadd0c8309ab3cd Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sat, 30 Nov 2019 14:32:46 -0500 Subject: [PATCH] v0.8.0: implemented ripper demons and demonic spawners --- core/src/main/assets/ripper.png | Bin 0 -> 536 bytes core/src/main/assets/spawner.png | Bin 0 -> 408 bytes .../shatteredpixeldungeon/Assets.java | 2 + .../shatteredpixeldungeon/Dungeon.java | 2 +- .../actors/mobs/DemonSpawner.java | 102 ++++++++++++++++++ .../actors/mobs/Eye.java | 2 +- .../actors/mobs/RipperDemon.java | 66 ++++++++++++ .../actors/mobs/Scorpio.java | 2 +- .../levels/HallsLevel.java | 16 +++ .../rooms/special/DemonSpawnerRoom.java | 74 +++++++++++++ .../sprites/RipperSprite.java | 55 ++++++++++ .../sprites/SpawnerSprite.java | 52 +++++++++ .../messages/actors/actors.properties | 6 ++ 13 files changed, 376 insertions(+), 3 deletions(-) create mode 100644 core/src/main/assets/ripper.png create mode 100644 core/src/main/assets/spawner.png create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DemonSpawner.java create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/RipperSprite.java create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SpawnerSprite.java diff --git a/core/src/main/assets/ripper.png b/core/src/main/assets/ripper.png new file mode 100644 index 0000000000000000000000000000000000000000..f557bd822e6f0d47a661ad3e586feb6121b6f589 GIT binary patch literal 536 zcmV+z0_XjSP)3Oca@q z+0H)HXcvAV)-tXs6RsBU6h9xcomB(WVr&_GcfD<};j;KS#0yQEpQ5wMLgUcbl8c^$ z36~W>_L6f1hbD8Bv&w23TS7A~S=Ty;R?rR*#1#%L*2g7O)*t#&OEqQaIndmPEb@8! z9MqB52*kMJfB`Aky>byGu$T{J+;|QwW8gNN-oP4bpckfzOw?c^@R1>fH|U9pcrBxD zL*I`qpzlvFVBdHB=9Os*Z+vJoypx-=T1HGPAP~vo=b}_FV#z}0^9x`i!(9M~488B~ z41|MOq?F>85(*2uP=-@R`EPX2!JXYe08$nZ-Z<+8w*V;WLx-~<1L%~ql%ZT`E;@Gw a{`CvFHZM={C^T9C0000hL8S%!tr0vzM#%mWp=O@;6oHq<`B>j@akS6pw8S|Eszh*{Jslx&Y#j#gzW7<1xU4| zKllNWSN{+Y@xK#5;ai- + */ + +package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; + +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; +import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.SpawnerSprite; +import com.watabou.utils.PathFinder; +import com.watabou.utils.Random; + +import java.util.ArrayList; + +public class DemonSpawner extends Mob { + + { + spriteClass = SpawnerSprite.class; + + HP = HT = 150; + defenseSkill = 0; + + EXP = 25; + maxLvl = 29; + + state = PASSIVE; + + loot = PotionOfHealing.class; + lootChance = 1f; + + properties.add(Property.IMMOVABLE); + properties.add(Property.MINIBOSS); + } + + @Override + public int drRoll() { + return Random.NormalIntRange(0, 12); + } + + private float spawnCooldown = 50; + + @Override + protected boolean act() { + spawnCooldown--; + if (spawnCooldown <= 0){ + ArrayList candidates = new ArrayList<>(); + for (int n : PathFinder.NEIGHBOURS8) { + if (!Dungeon.level.solid[pos+n] && Actor.findChar( pos+n ) == null) { + candidates.add( pos+n ); + } + } + + if (!candidates.isEmpty()) { + RipperDemon spawn = new RipperDemon(); + + spawn.pos = Random.element( candidates ); + spawn.state = spawn.HUNTING; + + Dungeon.level.occupyCell(spawn); + + GameScene.add( spawn ); + if (sprite.visible) { + Actor.addDelayed(new Pushing(spawn, pos, spawn.pos), -1); + } + + spawnCooldown += 50; + } + } + return super.act(); + } + + @Override + public void damage(int dmg, Object src) { + if (dmg >= 25){ + //takes 25/26/27/28/29/30/31/32/33/34/35 dmg + // at 25/27/30/34/39/45/52/60/69/79/90 incoming dmg + dmg = 24 + (int)(Math.sqrt(8*(dmg - 24) + 1) - 1)/2; + } + spawnCooldown -= dmg; + super.damage(dmg, src); + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java index aa0548700..e16d7cf7a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java @@ -52,7 +52,7 @@ public class Eye extends Mob { viewDistance = Light.DISTANCE; EXP = 13; - maxLvl = 25; + maxLvl = 26; flying = true; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java new file mode 100644 index 000000000..e362751f7 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java @@ -0,0 +1,66 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; + +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.sprites.RipperSprite; +import com.watabou.utils.Random; + +public class RipperDemon extends Mob { + + { + spriteClass = RipperSprite.class; + + HP = HT = 60; + defenseSkill = 22; + + EXP = 9; //for corrupting + maxLvl = -2; + + baseSpeed = 2f; + } + + @Override + public float spawningWeight() { + return 0; + } + + @Override + public int damageRoll() { + return Random.NormalIntRange( 20, 25 ); + } + + @Override + public int attackSkill( Char target ) { + return 35; + } + + @Override + protected float attackDelay() { + return super.attackDelay()*0.5f; + } + + @Override + public int drRoll() { + return Random.NormalIntRange(0, 4); + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java index 3e6eeb756..414df0cd5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java @@ -45,7 +45,7 @@ public class Scorpio extends Mob { viewDistance = Light.DISTANCE; EXP = 14; - maxLvl = 25; + maxLvl = 27; loot = Generator.Category.POTION; lootChance = 0.5f; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsLevel.java index bfc012ced..b60dfaf47 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/HallsLevel.java @@ -26,6 +26,8 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.items.Torch; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.HallsPainter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.DemonSpawnerRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.BlazingTrap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.CorrosionTrap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.CursingTrap; @@ -51,6 +53,8 @@ import com.watabou.noosa.particles.PixelParticle; import com.watabou.utils.PointF; import com.watabou.utils.Random; +import java.util.ArrayList; + public class HallsLevel extends RegularLevel { { @@ -60,6 +64,18 @@ public class HallsLevel extends RegularLevel { color1 = 0x801500; color2 = 0xa68521; } + + @Override + protected ArrayList initRooms() { + ArrayList rooms = super.initRooms(); + + rooms.add(new DemonSpawnerRoom()); + if (Dungeon.depth == 24){ + rooms.add(new DemonSpawnerRoom()); + } + + return rooms; + } @Override protected int standardRooms() { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java new file mode 100644 index 000000000..49e8d24bb --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/DemonSpawnerRoom.java @@ -0,0 +1,74 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special; + +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DemonSpawner; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.RipperDemon; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EntranceRoom; +import com.watabou.utils.Point; +import com.watabou.utils.Random; + +public class DemonSpawnerRoom extends SpecialRoom { + @Override + public void paint(Level level) { + + Painter.fill( level, this, Terrain.WALL ); + Painter.fill( level, this, 1, Terrain.EMPTY ); + + Point c = center(); + int cx = c.x; + int cy = c.y; + + Door door = entrance(); + door.set(Door.Type.UNLOCKED); + + DemonSpawner spawner = new DemonSpawner(); + spawner.pos = cx + cy * level.width(); + level.mobs.add( spawner ); + + int rippers = Random.IntRange(1, 2); + + for (int i = 0; i < rippers; i++){ + int pos; + do { + pos = level.pointToCell(random(1)); + } while (level.solid[pos] || level.findMob(pos) != null); + + RipperDemon ripper = new RipperDemon(); + ripper.pos = pos; + ripper.state = ripper.HUNTING; + level.mobs.add( ripper ); + } + + } + + @Override + public boolean connect(Room room) { + //cannot connect to entrance, otherwise works normally + if (room instanceof EntranceRoom) return false; + else return super.connect(room); + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/RipperSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/RipperSprite.java new file mode 100644 index 000000000..7e6a8a5e0 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/RipperSprite.java @@ -0,0 +1,55 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.sprites; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.watabou.noosa.TextureFilm; + +//TODO currently just a reskinned warlock sprite +public class RipperSprite extends MobSprite { + + public RipperSprite() { + super(); + + texture( Assets.RIPPER ); + + TextureFilm frames = new TextureFilm( texture, 12, 15 ); + + idle = new Animation( 2, true ); + idle.frames( frames, 0, 0, 0, 1, 0, 0, 1, 1 ); + + run = new Animation( 15, true ); + run.frames( frames, 0, 2, 3, 4 ); + + //TODO shoudl probably have 2 attack animations, like monks + attack = new Animation( 12, false ); + attack.frames( frames, 0, 5, 6 ); + + zap = attack.clone(); + + die = new Animation( 15, false ); + die.frames( frames, 0, 7, 8, 8, 9, 10 ); + + play( idle ); + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SpawnerSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SpawnerSprite.java new file mode 100644 index 000000000..80163e884 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SpawnerSprite.java @@ -0,0 +1,52 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.sprites; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.watabou.noosa.TextureFilm; + +public class SpawnerSprite extends MobSprite { + + //TODO just a recolored golem sprite atm + public SpawnerSprite() { + super(); + + texture( Assets.SPAWNER ); + + TextureFilm frames = new TextureFilm( texture, 16, 16 ); + + idle = new Animation( 4, true ); + idle.frames( frames, 0, 1 ); + + run = new Animation( 12, true ); + run.frames( frames, 2, 3, 4, 5 ); + + attack = new Animation( 10, false ); + attack.frames( frames, 6, 7, 8 ); + + die = new Animation( 15, false ); + die.frames( frames, 9, 10, 11, 12, 13 ); + + play( idle ); + } + +} 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 66915086f..2198175b9 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 @@ -470,6 +470,9 @@ actors.mobs.causticslime.desc=This slime seems to have been tainted by the dark actors.mobs.crab.name=sewer crab actors.mobs.crab.desc=These huge crabs are at the top of the food chain in the sewers. They are extremely fast and their thick carapace can withstand heavy blows. +actors.mobs.demonspawner.name=demon spawner +actors.mobs.demonspawner.desc=This twisting amalgam of dwarven flesh is responsible for creating ripper demons from dwarven body parts. Clearly the demons see no issue with using every resource they can against their enemies.\n\nWhile visually terrifying, demon spawners have no means of moving or directly defending themselves. Their considerable mass makes them hard to kill quickly however, and they will spawn ripper demons more quickly when they are under threat. + actors.mobs.dm100.name=DM-100 actors.mobs.dm100.zap_kill=The lightning bolt killed you... actors.mobs.dm100.desc=The DM-100 is an early model of dwarven 'defense machine' which was designed to protect dwarven miners in the caves below. Their electrical shocks proved too weak however, and so they were gifted to the human prison above. The warden initially deemed them too cruel to use, but as the prisoners became more unruly they became a necessity. @@ -572,6 +575,9 @@ actors.mobs.piranha.desc=These carnivorous fish are not natural inhabitants of u actors.mobs.rat.name=marsupial rat actors.mobs.rat.desc=Marsupial rats are aggressive but rather weak denizens of the sewers. They have a nasty bite, but are only life threatening in large numbers. +actors.mobs.ripperdemon.name=ripper demon +actors.mobs.ripperdemon.desc=These horrific creatures are the result of the many dwarven corpses in this region being put to use by demonic forces. Rippers are emaciated ghoulish creatures that resemble dwarves, but with broken bodies and long sharp claws made of bone.\n\nRipper demons are not particularly durable, but they are fast and dangerous. Killing them individually is not difficult, but they just seem to keep coming... + actors.mobs.rotheart.name=rot heart actors.mobs.rotheart.desc=A Rotberry's fruit is very unique. Instead of rotting away and providing nutrients, the fruit grows, hardens, and encompasses the seed. It provides protection for the internal organs which grow inside the fruit. This giant orb is referred to as the heart of an adult rotberry plant.