v2.2.0: early incomplete implementations for crystal enemies

This commit is contained in:
Evan Debenham
2023-09-18 15:02:37 -04:00
parent 6c4c4be6f6
commit 4c86cba1cf
18 changed files with 592 additions and 12 deletions

View File

@@ -1111,11 +1111,20 @@ 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.crystalguardian.name=crystal guardian
actors.mobs.crystalguardian.desc=TODO
actors.mobs.crystalmimic.name=crystal mimic
actors.mobs.crystalmimic.ate=The mimic ate your %s!
actors.mobs.crystalmimic.escaped=The crystal mimic has escaped!
actors.mobs.crystalmimic.desc=Mimics are magical creatures which can take any shape they wish. In dungeons they almost always choose a shape of a treasure chest, in order to lure in unsuspecting adventurers.\n\nCrystal mimics are trickier than their regular cousins, and prefer to avoid conflict while stealing loot. They will attempt to sprint away once discovered, and have the ability to reposition enemies when they attack.
actors.mobs.crystalspire.name=crystal spire
actors.mobs.crystalspire.desc=TODO
actors.mobs.crystalwisp.name=crystal wisp
actors.mobs.crystalwisp.desc=TODO
actors.mobs.demonspawner.name=demon spawner
actors.mobs.demonspawner.on_death=The demonic energy here seems to lessen as the spawner dies.
actors.mobs.demonspawner.desc=This twisting amalgam of dwarven flesh is responsible for creating ripper demons from the dwarves that have died in this region. 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.\n\n_Demon spawners seem to be connected to some central source of demonic power. Killing them may weaken it._

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

View File

@@ -314,5 +314,8 @@ public class Assets {
public static final String NINJA_LOG= "sprites/ninja_log.png";
public static final String SPIRIT_HAWK= "sprites/spirit_hawk.png";
public static final String RED_SENTRY= "sprites/red_sentry.png";
public static final String CRYSTAL_WISP= "sprites/crystal_wisp.png";
public static final String CRYSTAL_GUARDIAN= "sprites/crystal_guardian.png";
public static final String CRYSTAL_SPIRE= "sprites/crystal_spire.png";
}
}

View File

@@ -987,6 +987,8 @@ public class Dungeon {
BArray.and( passable, Dungeon.level.openSpace, passable );
}
ch.modifyPassable(passable);
if (chars) {
for (Char c : Actor.chars()) {
if (vis[c.pos]) {

View File

@@ -1015,6 +1015,11 @@ public abstract class Char extends Actor {
public int distance( Char other ) {
return Dungeon.level.distance( pos, other.pos );
}
public boolean[] modifyPassable( boolean[] passable){
//do nothing by default, but some chars can pass over terrain that others can't
return passable;
}
public void onMotionComplete() {
//Does nothing by default

View File

@@ -0,0 +1,123 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2023 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.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.CrystalGuardianSprite;
import com.watabou.utils.Bundle;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
public class CrystalGuardian extends Mob{
{
HP = HT = 1;
spriteClass = CrystalGuardianSprite.class;
SLEEPING = new Sleeping();
state = SLEEPING;
}
public CrystalGuardian(){
super();
switch (Random.Int(3)){
case 0: default:
spriteClass = CrystalGuardianSprite.Blue.class;
break;
case 1:
spriteClass = CrystalGuardianSprite.Green.class;
break;
case 2:
spriteClass = CrystalGuardianSprite.Red.class;
break;
}
}
@Override
public float spawningWeight() {
return 0;
}
@Override
public float speed() {
if (Dungeon.level.openSpace[pos]) {
return super.speed();
} else {
return super.speed()/4f;
}
}
@Override
public void beckon(int cell) {
super.beckon(cell);
//If we are still penned into our starting area, break out of it
PathFinder.buildDistanceMap(cell, Dungeon.level.passable);
if (PathFinder.distance[pos] == Integer.MAX_VALUE){
boolean[] passable = Dungeon.level.passable.clone();
for (int i = 0; i < Dungeon.level.length(); i++){
passable[i] = passable[i] || Dungeon.level.map[i] == Terrain.MINE_CRYSTAL;
}
PathFinder.Path p = PathFinder.find(pos, cell, passable);
if (p != null) {
for (int i : p) {
if (Dungeon.level.map[i] == Terrain.MINE_CRYSTAL) {
Level.set(i, Terrain.EMPTY);
GameScene.updateMap(i);
}
}
}
}
}
protected class Sleeping extends Mob.Sleeping{
@Override
protected void awaken(boolean enemyInFOV) {
if (enemyInFOV){
//do not wake up if we see an enemy we can't actually reach
PathFinder.buildDistanceMap(enemy.pos, Dungeon.level.passable);
if (PathFinder.distance[pos] == Integer.MAX_VALUE){
return;
}
}
super.awaken(enemyInFOV);
}
}
public static final String SPRITE = "sprite";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(SPRITE, spriteClass);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
spriteClass = bundle.getClass(SPRITE);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2023 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.sprites.CrystalSpireSprite;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
public class CrystalSpire extends Mob {
{
HP = HT = 1;
spriteClass = CrystalSpireSprite.class;
state = PASSIVE;
}
public CrystalSpire(){
super();
switch (Random.Int(3)){
case 0: default:
spriteClass = CrystalSpireSprite.Blue.class;
break;
case 1:
spriteClass = CrystalSpireSprite.Green.class;
break;
case 2:
spriteClass = CrystalSpireSprite.Red.class;
break;
}
}
@Override
public float spawningWeight() {
return 0;
}
public static final String SPRITE = "sprite";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(SPRITE, spriteClass);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
spriteClass = bundle.getClass(SPRITE);
}
}

View File

@@ -0,0 +1,73 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2023 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.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.sprites.CrystalWispSprite;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
public class CrystalWisp extends Mob{
{
HP = HT = 1;
spriteClass = CrystalWispSprite.class;
}
public CrystalWisp(){
super();
switch (Random.Int(3)){
case 0: default:
spriteClass = CrystalWispSprite.Blue.class;
break;
case 1:
spriteClass = CrystalWispSprite.Green.class;
break;
case 2:
spriteClass = CrystalWispSprite.Red.class;
break;
}
}
@Override
public boolean[] modifyPassable(boolean[] passable) {
for (int i = 0; i < Dungeon.level.length(); i++){
passable[i] = passable[i] || Dungeon.level.map[i] == Terrain.MINE_CRYSTAL;
}
return passable;
}
public static final String SPRITE = "sprite";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(SPRITE, spriteClass);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
spriteClass = bundle.getClass(SPRITE);
}
}

View File

@@ -23,8 +23,9 @@ package com.shatteredpixel.shatteredpixeldungeon.levels;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bat;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalWisp;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
@@ -132,15 +133,12 @@ public class MiningLevel extends CavesLevel {
@Override
public Mob createMob() {
return null;
}
@Override
protected void createMobs() {
}
public Actor addRespawner() {
return null;
switch (Blacksmith.Quest.Type()){
default:
return new Bat();
case Blacksmith.Quest.CRYSTAL:
return new CrystalWisp();
}
}
@Override

View File

@@ -21,11 +21,13 @@
package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.quest;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalSpire;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
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.standard.CaveRoom;
import com.watabou.utils.Point;
public class MineGiantRoom extends CaveRoom {
@@ -49,6 +51,13 @@ public class MineGiantRoom extends CaveRoom {
for (int i = 0; i < (width()-8)*(height()-8)/3; i ++){
Painter.set(level, random(4), Terrain.MINE_CRYSTAL);
}
Point p = center();
CrystalSpire m = new CrystalSpire();
m.pos = level.pointToCell(p);
level.mobs.add(m);
Painter.set(level, p, Terrain.EMPTY);
} else {
Painter.fillEllipse(level, this, 3, Terrain.EMPTY);
}

View File

@@ -21,11 +21,13 @@
package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.quest;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalGuardian;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
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.standard.CaveRoom;
import com.watabou.utils.Point;
public class MineLargeRoom extends CaveRoom {
@@ -36,7 +38,6 @@ public class MineLargeRoom extends CaveRoom {
@Override
protected float fill() {
int scale = Math.min(width()*height(), 18*18);
return 0.55f;
}
@@ -51,6 +52,13 @@ public class MineLargeRoom extends CaveRoom {
for (int i = 0; i < (width()-8)*(height()-8)/5; i ++){
Painter.set(level, random(4), Terrain.MINE_CRYSTAL);
}
Point p = random(5);
CrystalGuardian m = new CrystalGuardian();
m.pos = level.pointToCell(p);
level.mobs.add(m);
Painter.set(level, p, Terrain.EMPTY);
} else {
Painter.fillEllipse(level, this, 3, Terrain.EMPTY);
}

View File

@@ -0,0 +1,89 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2023 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.MovieClip;
import com.watabou.noosa.TextureFilm;
public abstract class CrystalGuardianSprite extends MobSprite {
public CrystalGuardianSprite() {
super();
texture( Assets.Sprites.CRYSTAL_GUARDIAN );
TextureFilm frames = new TextureFilm( texture, 12, 15 );
int c = texOffset();
idle = new MovieClip.Animation( 2, true );
idle.frames( frames, 0+c, 0+c, 0+c, 0+c, 0+c, 1+c, 1+c );
run = new MovieClip.Animation( 15, true );
run.frames( frames, 2+c, 3+c, 4+c, 5+c, 6+c, 7+c );
attack = new MovieClip.Animation( 12, false );
attack.frames( frames, 8+c, 9+c, 10+c );
die = new MovieClip.Animation( 5, false );
die.frames( frames, 11+c, 12+c, 13+c, 14+c, 15+c, 15+c );
play( idle );
}
protected abstract int texOffset();
public static class Blue extends CrystalGuardianSprite {
@Override
protected int texOffset() {
return 0;
}
@Override
public int blood() {
return 0xFF8EE3FF;
}
}
public static class Green extends CrystalGuardianSprite {
@Override
protected int texOffset() {
return 21;
}
@Override
public int blood() {
return 0xFF85FFC8;
}
}
public static class Red extends CrystalGuardianSprite {
@Override
protected int texOffset() {
return 42;
}
@Override
public int blood() {
return 0xFFFFBB33;
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2023 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.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.watabou.noosa.TextureFilm;
public abstract class CrystalSpireSprite extends MobSprite {
{
perspectiveRaise = 7 / 16f; //7 pixels
}
public CrystalSpireSprite(){
texture( Assets.Sprites.CRYSTAL_SPIRE );
TextureFilm frames = new TextureFilm( texture, 30, 45 );
int c = texOffset();
idle = new Animation(1, true);
idle.frames( frames, 0+c );
run = idle.clone();
attack = idle.clone();
zap = idle.clone();
die = new Animation(1, false);
die.frames( frames, 0+c );
play(idle);
}
@Override
public void link(Char ch) {
super.link(ch);
renderShadow = false;
}
protected abstract int texOffset();
public static class Blue extends CrystalSpireSprite {
@Override
protected int texOffset() {
return 0;
}
@Override
public int blood() {
return 0xFF8EE3FF;
}
}
public static class Green extends CrystalSpireSprite {
@Override
protected int texOffset() {
return 1;
}
@Override
public int blood() {
return 0xFF85FFC8;
}
}
public static class Red extends CrystalSpireSprite {
@Override
protected int texOffset() {
return 2;
}
@Override
public int blood() {
return 0xFFFFBB33;
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2023 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 abstract class CrystalWispSprite extends MobSprite {
public CrystalWispSprite() {
super();
int c = texOffset();
texture( Assets.Sprites.CRYSTAL_WISP );
TextureFilm frames = new TextureFilm( texture, 12, 14 );
idle = new Animation( 4, true );
idle.frames( frames, c+0, c+1, c+0, c+2 );
run = new Animation( 12, true );
run.frames( frames, c+0, c+1, c+0, c+3 );
attack = new Animation( 15, false );
attack.frames( frames, c+4, c+5, c+6 );
zap = attack.clone();
die = new Animation( 15, false );
die.frames( frames, c+7, c+8, c+9, c+10, c+11, c+12, c+13, c+12 );
play( idle );
}
protected abstract int texOffset();
public static class Blue extends CrystalWispSprite {
@Override
protected int texOffset() {
return 0;
}
@Override
public int blood() {
return 0xFF8EE3FF;
}
}
public static class Green extends CrystalWispSprite {
@Override
protected int texOffset() {
return 14;
}
@Override
public int blood() {
return 0xFF85FFC8;
}
}
public static class Red extends CrystalWispSprite {
@Override
protected int texOffset() {
return 28;
}
@Override
public int blood() {
return 0xFFFFBB33;
}
}
}

View File

@@ -155,6 +155,11 @@ public class AttackIndicator extends Tag {
sprite.idle();
sprite.paused = true;
sprite.visible = bg.visible;
if (sprite.width() > 20 || sprite.height() > 20){
sprite.scale.set(PixelScene.align(20f/Math.max(sprite.width(), sprite.height())));
}
add( sprite );
layout();

View File

@@ -87,7 +87,7 @@ public class WndInfoMob extends WndTitledMessage {
buffs.setPos(name.right(), name.bottom() - BuffIndicator.SIZE_SMALL-2);
height = health.bottom();
height = Math.max(image.y + image.height(), health.bottom());
}
}
}