v0.8.0: implemented ripper demons and demonic spawners

This commit is contained in:
Evan Debenham 2019-11-30 14:32:46 -05:00
parent ee6a1ce4fc
commit e487853fd2
13 changed files with 376 additions and 3 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

View File

@ -103,6 +103,8 @@ public class Assets {
public static final String SNAKE = "snake.png"; public static final String SNAKE = "snake.png";
public static final String NECRO = "necromancer.png"; public static final String NECRO = "necromancer.png";
public static final String GHOUL = "ghoul.png"; public static final String GHOUL = "ghoul.png";
public static final String RIPPER = "ripper.png";
public static final String SPAWNER = "spawner.png";
public static final String ITEMS = "items.png"; public static final String ITEMS = "items.png";
public static final String TERRAIN_FEATURES = "terrain_features.png"; public static final String TERRAIN_FEATURES = "terrain_features.png";

View File

@ -93,7 +93,7 @@ public class Dungeon {
NECRO_HP, NECRO_HP,
BAT_HP, BAT_HP,
WARLOCK_HP, WARLOCK_HP,
SCORPIO_HP, //Demon spawners are already limited in their spawnrate, no need to limit their health drops
//alchemy //alchemy
COOKING_HP, COOKING_HP,
BLANDFRUIT_SEED, BLANDFRUIT_SEED,

View File

@ -0,0 +1,102 @@
/*
* 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 <http://www.gnu.org/licenses/>
*/
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<Integer> 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);
}
}

View File

@ -52,7 +52,7 @@ public class Eye extends Mob {
viewDistance = Light.DISTANCE; viewDistance = Light.DISTANCE;
EXP = 13; EXP = 13;
maxLvl = 25; maxLvl = 26;
flying = true; flying = true;

View File

@ -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 <http://www.gnu.org/licenses/>
*/
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);
}
}

View File

@ -45,7 +45,7 @@ public class Scorpio extends Mob {
viewDistance = Light.DISTANCE; viewDistance = Light.DISTANCE;
EXP = 14; EXP = 14;
maxLvl = 25; maxLvl = 27;
loot = Generator.Category.POTION; loot = Generator.Category.POTION;
lootChance = 0.5f; lootChance = 0.5f;

View File

@ -26,6 +26,8 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Torch; import com.shatteredpixel.shatteredpixeldungeon.items.Torch;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.HallsPainter; import com.shatteredpixel.shatteredpixeldungeon.levels.painters.HallsPainter;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; 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.BlazingTrap;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.CorrosionTrap; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.CorrosionTrap;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.CursingTrap; 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.PointF;
import com.watabou.utils.Random; import com.watabou.utils.Random;
import java.util.ArrayList;
public class HallsLevel extends RegularLevel { public class HallsLevel extends RegularLevel {
{ {
@ -61,6 +65,18 @@ public class HallsLevel extends RegularLevel {
color2 = 0xa68521; color2 = 0xa68521;
} }
@Override
protected ArrayList<Room> initRooms() {
ArrayList<Room> rooms = super.initRooms();
rooms.add(new DemonSpawnerRoom());
if (Dungeon.depth == 24){
rooms.add(new DemonSpawnerRoom());
}
return rooms;
}
@Override @Override
protected int standardRooms() { protected int standardRooms() {
//8 to 10, average 8.67 //8 to 10, average 8.67

View File

@ -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 <http://www.gnu.org/licenses/>
*/
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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>
*/
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 );
}
}

View File

@ -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 <http://www.gnu.org/licenses/>
*/
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 );
}
}

View File

@ -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.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.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.name=DM-100
actors.mobs.dm100.zap_kill=The lightning bolt killed you... 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. 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.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.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.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. 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.