diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties
index 4846074cc..4fb71a069 100644
--- a/core/src/main/assets/messages/actors/actors.properties
+++ b/core/src/main/assets/messages/actors/actors.properties
@@ -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._
diff --git a/core/src/main/assets/sprites/crystal_guardian.png b/core/src/main/assets/sprites/crystal_guardian.png
new file mode 100644
index 000000000..204103269
Binary files /dev/null and b/core/src/main/assets/sprites/crystal_guardian.png differ
diff --git a/core/src/main/assets/sprites/crystal_spire.png b/core/src/main/assets/sprites/crystal_spire.png
new file mode 100644
index 000000000..fc1927ea3
Binary files /dev/null and b/core/src/main/assets/sprites/crystal_spire.png differ
diff --git a/core/src/main/assets/sprites/crystal_wisp.png b/core/src/main/assets/sprites/crystal_wisp.png
new file mode 100644
index 000000000..d276e7557
Binary files /dev/null and b/core/src/main/assets/sprites/crystal_wisp.png differ
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
index d0e0de3ae..dc750045b 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
@@ -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";
}
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
index a03a0c6ad..9fd298a5d 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
@@ -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]) {
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java
index 562236685..188875381 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java
@@ -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
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalGuardian.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalGuardian.java
new file mode 100644
index 000000000..082e89a45
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalGuardian.java
@@ -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
+ */
+
+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);
+ }
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalSpire.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalSpire.java
new file mode 100644
index 000000000..683c01a5f
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalSpire.java
@@ -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
+ */
+
+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);
+ }
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalWisp.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalWisp.java
new file mode 100644
index 000000000..99ef1f84d
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalWisp.java
@@ -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
+ */
+
+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);
+ }
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/MiningLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/MiningLevel.java
index 767228e95..a07abea03 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/MiningLevel.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/MiningLevel.java
@@ -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
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineGiantRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineGiantRoom.java
index e34931194..bddc2a300 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineGiantRoom.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineGiantRoom.java
@@ -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);
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineLargeRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineLargeRoom.java
index f249d1b00..9b80ca853 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineLargeRoom.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/MineLargeRoom.java
@@ -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);
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalGuardianSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalGuardianSprite.java
new file mode 100644
index 000000000..889e16c6e
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalGuardianSprite.java
@@ -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
+ */
+
+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;
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalSpireSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalSpireSprite.java
new file mode 100644
index 000000000..e05ebd33f
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalSpireSprite.java
@@ -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
+ */
+
+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;
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalWispSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalWispSprite.java
new file mode 100644
index 000000000..829a89c3a
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CrystalWispSprite.java
@@ -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
+ */
+
+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;
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/AttackIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/AttackIndicator.java
index 672bc0c53..81a9140ce 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/AttackIndicator.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/AttackIndicator.java
@@ -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();
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java
index 02c5de262..0496deb12 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java
@@ -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());
}
}
}