diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java index a719da483..141d92503 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java @@ -24,10 +24,14 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Corruption; import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; +import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.GhoulSprite; import com.watabou.utils.Bundle; +import com.watabou.utils.PathFinder; import com.watabou.utils.Random; import java.util.ArrayList; @@ -38,7 +42,7 @@ public class Ghoul extends Mob { { spriteClass = GhoulSprite.class; - HP = HT = 50; + HP = HT = 45; defenseSkill = 20; EXP = 5; @@ -72,19 +76,24 @@ public class Ghoul extends Mob { return 0.5f; } + private int timesDowned = 0; private int partnerID = -1; + private static final String PARTNER_ID = "partner_id"; + private static final String TIMES_DOWNED = "times_downed"; @Override public void storeInBundle( Bundle bundle ) { super.storeInBundle( bundle ); bundle.put( PARTNER_ID, partnerID ); + bundle.put( TIMES_DOWNED, timesDowned ); } @Override public void restoreFromBundle( Bundle bundle ) { super.restoreFromBundle( bundle ); partnerID = bundle.getInt( PARTNER_ID ); + timesDowned = bundle.getInt( TIMES_DOWNED ); } @Override @@ -122,7 +131,39 @@ public class Ghoul extends Mob { } return super.act(); } - + + @Override + public void die(Object cause) { + if (cause != Chasm.class && cause != GhoulLifeLink.class){ + Ghoul nearby = GhoulLifeLink.searchForHost(this); + if (nearby != null){ + Actor.remove(this); + Dungeon.level.mobs.remove( this ); + timesDowned++; + Buff.append(nearby, GhoulLifeLink.class).set(timesDowned*5, this); + ((GhoulSprite)sprite).crumple(); + } else { + super.die(cause); + } + } else { + super.die(cause); + } + } + + @Override + protected synchronized void onRemove() { + for (Buff buff : buffs()) { + //corruption is preserved + if (!(buff instanceof Corruption)) buff.detach(); + } + } + + @Override + protected void onAdd() { + spend(-cooldown()); + super.onAdd(); + } + private class Sleeping extends Mob.Sleeping { @Override public boolean act( boolean enemyInFOV, boolean justAlerted ) { @@ -207,4 +248,104 @@ public class Ghoul extends Mob { } } } + + public static class GhoulLifeLink extends Buff{ + + private Ghoul ghoul; + private int turnsToRevive; + + @Override + public boolean act() { + ghoul.sprite.visible = Dungeon.level.heroFOV[ghoul.pos]; + + if (!target.fieldOfView[ghoul.pos] && Dungeon.level.distance(ghoul.pos, target.pos) >= 4){ + detach(); + return true; + } + + turnsToRevive--; + if (turnsToRevive <= 0){ + ghoul.HP = Math.round(ghoul.HT/10f); + if (Actor.findChar( ghoul.pos ) != null) { + ArrayList candidates = new ArrayList<>(); + for (int n : PathFinder.NEIGHBOURS8) { + int cell = ghoul.pos + n; + if ((Dungeon.level.passable[cell] || Dungeon.level.avoid[cell]) && Actor.findChar( cell ) == null) { + candidates.add( cell ); + } + } + if (candidates.size() > 0) { + int newPos = Random.element( candidates ); + Actor.addDelayed( new Pushing( ghoul, ghoul.pos, newPos ), -1 ); + ghoul.pos = newPos; + + } else { + spend(TICK); + return true; + } + } + Actor.add(ghoul); + Dungeon.level.mobs.add(ghoul); + Dungeon.level.occupyCell( ghoul ); + super.detach(); + return true; + } + + spend(TICK); + return true; + } + + public void set(int turns, Ghoul ghoul){ + this.ghoul = ghoul; + turnsToRevive = turns; + } + + @Override + public void fx(boolean on) { + if (on && ghoul != null && ghoul.sprite == null){ + GameScene.addSprite(ghoul); + ((GhoulSprite)ghoul.sprite).crumple(); + } + } + + @Override + public void detach() { + super.detach(); + Ghoul newHost = searchForHost(ghoul); + if (newHost != null){ + newHost.add(this); + } else { + ghoul.die(this); + } + } + + private static final String GHOUL = "ghoul"; + private static final String LEFT = "left"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(GHOUL, ghoul); + bundle.put(LEFT, turnsToRevive); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + ghoul = (Ghoul) bundle.get(GHOUL); + turnsToRevive = bundle.getInt(LEFT); + } + + public static Ghoul searchForHost(Ghoul dieing){ + + for (Char ch : Actor.chars()){ + if (ch != dieing && ch instanceof Ghoul && ch.alignment == dieing.alignment){ + if (ch.fieldOfView[dieing.pos] || Dungeon.level.distance(ch.pos, dieing.pos) < 4){ + return (Ghoul) ch; + } + } + } + return null; + } + } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 7e3549f74..331b25841 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -760,6 +760,10 @@ public class GameScene extends PixelScene { Actor.add( mob ); scene.addMobSprite( mob ); } + + public static void addSprite( Mob mob ) { + scene.addMobSprite( mob ); + } public static void add( Mob mob, float delay ) { Dungeon.level.mobs.add( mob ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java index 794443e5d..04f8d5108 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java @@ -26,6 +26,8 @@ import com.watabou.noosa.TextureFilm; //TODO currently just a recolored monk sprite public class GhoulSprite extends MobSprite { + + private Animation crumple; public GhoulSprite() { super(); @@ -42,11 +44,22 @@ public class GhoulSprite extends MobSprite { attack = new Animation( 12, false ); attack.frames( frames, 3, 4, 3, 4 ); - + + crumple = new Animation( 15, false); + crumple.frames( frames, 1, 7, 8 ); + die = new Animation( 15, false ); - die.frames( frames, 1, 7, 8, 8, 9, 10 ); + die.frames( frames, 7, 8, 8, 9, 10 ); play( idle ); } + + public void crumple(){ + if (emo != null){ + emo.killAndErase(); + emo = null; + } + play(crumple); + } } 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 6a68c6bb2..06390f960 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 @@ -533,7 +533,7 @@ 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.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 weilding 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, attempting to overwhelm their opponent with greater numbers. +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 weilding 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._ actors.mobs.gnoll.name=gnoll scout actors.mobs.gnoll.desc=Gnolls are hyena-like humanoids. They dwell in sewers and dungeons, venturing up to raid the surface from time to time. Gnoll scouts are regular members of their pack, they are not as strong as brutes and not as intelligent as shamans.