diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties
index de7489685..90be78731 100644
--- a/core/src/main/assets/messages/actors/actors.properties
+++ b/core/src/main/assets/messages/actors/actors.properties
@@ -1202,6 +1202,9 @@ actors.mobs.eye.desc=Evil Eyes are floating balls of pent up demonic energy. Whi
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.fungalspinner.name=fungal spinner
+actors.mobs.fungalspinner.desc=This cave spinner appears to be being controlled by a parasitic fungus. The fungus has also changed its abilities, replacing its web and venom sacks with fungal growth.\n\nThe fungal spinner will spit plant life at you instead of webs, spreading fungal vegetation and potentially rooting you. While it can't poison, the fungal spinner will gain substantial damage resistance if it is adjacent to any mushrooms.
+
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 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._
diff --git a/core/src/main/assets/sprites/fungal_spinner.png b/core/src/main/assets/sprites/fungal_spinner.png
new file mode 100644
index 000000000..99c8dbde1
Binary files /dev/null and b/core/src/main/assets/sprites/fungal_spinner.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 75e4c2111..44313bc45 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
@@ -321,5 +321,6 @@ public class Assets {
public static final String GNOLL_GUARD= "sprites/gnoll_guard.png";
public static final String GNOLL_SAPPER= "sprites/gnoll_sapper.png";
public static final String GNOLL_GEOMANCER = "sprites/gnoll_geomancer.png";
+ public static final String FUNGAL_SPINNER = "sprites/fungal_spinner.png";
}
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/FungalSpinner.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/FungalSpinner.java
new file mode 100644
index 000000000..3b85212ae
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/FungalSpinner.java
@@ -0,0 +1,74 @@
+/*
+ * 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.actors.Char;
+import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
+import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Regrowth;
+import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
+import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
+import com.shatteredpixel.shatteredpixeldungeon.sprites.FungalSpinnerSprite;
+import com.watabou.utils.PathFinder;
+
+public class FungalSpinner extends Spinner {
+
+ {
+ spriteClass = FungalSpinnerSprite.class;
+
+ HP = HT = 40;
+ defenseSkill = 16;
+
+ EXP = 7;
+ maxLvl = -2;
+ }
+
+ @Override
+ protected void applyWebToCell(int cell) {
+ GameScene.add(Blob.seed(cell, 40, Regrowth.class));
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ int grassCells = 0;
+ for (int i : PathFinder.NEIGHBOURS9) {
+ if (Dungeon.level.map[pos+i] == Terrain.FURROWED_GRASS
+ || Dungeon.level.map[pos+i] == Terrain.HIGH_GRASS){
+ grassCells++;
+ }
+ }
+ //first adjacent grass cell reduces damage taken by 30%, each one after reduces by another 10%
+ if (grassCells > 0) dmg = Math.round(dmg * (8-grassCells)/10f);
+
+ super.damage(dmg, src);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ return damage; //does not apply poison
+ }
+
+ {
+ immunities.add(Regrowth.class);
+ }
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java
index 49bf6ae56..bed6f13cc 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java
@@ -191,9 +191,9 @@ public class Spinner extends Mob {
int leftPos = enemy.pos + PathFinder.CIRCLE8[left(i)];
int rightPos = enemy.pos + PathFinder.CIRCLE8[right(i)];
- if (Dungeon.level.passable[leftPos]) GameScene.add(Blob.seed(leftPos, 20, Web.class));
- if (Dungeon.level.passable[webPos]) GameScene.add(Blob.seed(webPos, 20, Web.class));
- if (Dungeon.level.passable[rightPos])GameScene.add(Blob.seed(rightPos, 20, Web.class));
+ if (Dungeon.level.passable[leftPos]) applyWebToCell(leftPos);
+ if (Dungeon.level.passable[webPos]) applyWebToCell(webPos);
+ if (Dungeon.level.passable[rightPos])applyWebToCell(rightPos);
webCoolDown = 10;
@@ -203,6 +203,10 @@ public class Spinner extends Mob {
}
next();
}
+
+ protected void applyWebToCell(int cell){
+ GameScene.add(Blob.seed(cell, 20, Web.class));
+ }
private int left(int direction){
return direction == 0 ? 7 : direction-1;
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 5b67886e0..abca851b3 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/MiningLevel.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/MiningLevel.java
@@ -28,9 +28,9 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
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.FungalSpinner;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGuard;
-import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Spinner;
+import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
@@ -152,7 +152,7 @@ public class MiningLevel extends CavesLevel {
case Blacksmith.Quest.GNOLL:
return new GnollGuard();
case Blacksmith.Quest.FUNGI:
- return new Spinner();
+ return new FungalSpinner();
}
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/FungalSpinnerSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/FungalSpinnerSprite.java
new file mode 100644
index 000000000..06b74297b
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/FungalSpinnerSprite.java
@@ -0,0 +1,102 @@
+/*
+ * 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.shatteredpixel.shatteredpixeldungeon.actors.mobs.Spinner;
+import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
+import com.watabou.noosa.MovieClip;
+import com.watabou.noosa.TextureFilm;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Callback;
+
+public class FungalSpinnerSprite extends MobSprite {
+
+ public FungalSpinnerSprite() {
+ super();
+
+ perspectiveRaise = 0f;
+
+ texture( Assets.Sprites.FUNGAL_SPINNER );
+
+ TextureFilm frames = new TextureFilm( texture, 16, 16 );
+
+ idle = new MovieClip.Animation( 10, true );
+ idle.frames( frames, 0, 0, 0, 0, 0, 1, 0, 1 );
+
+ run = new MovieClip.Animation( 15, true );
+ run.frames( frames, 0, 2, 0, 3 );
+
+ attack = new MovieClip.Animation( 12, false );
+ attack.frames( frames, 0, 4, 5, 0 );
+
+ zap = attack.clone();
+
+ die = new MovieClip.Animation( 12, false );
+ die.frames( frames, 6, 7, 8, 9 );
+
+ play( idle );
+ }
+
+ @Override
+ public void link(Char ch) {
+ super.link(ch);
+ if (parent != null) {
+ parent.sendToBack(this);
+ if (aura != null){
+ parent.sendToBack(aura);
+ }
+ }
+ renderShadow = false;
+ }
+
+ public void zap( int cell ) {
+
+ super.zap( cell );
+
+ MagicMissile.boltFromChar( parent,
+ MagicMissile.FOLIAGE,
+ this,
+ cell,
+ new Callback() {
+ @Override
+ public void call() {
+ ((Spinner)ch).shootWeb();
+ }
+ } );
+ Sample.INSTANCE.play( Assets.Sounds.MISS );
+ }
+
+ @Override
+ public void onComplete( MovieClip.Animation anim ) {
+ if (anim == zap) {
+ play( run );
+ }
+ super.onComplete( anim );
+ }
+
+ @Override
+ public int blood() {
+ return 0xFF88CC44;
+ }
+}