diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 51a495bdd..ff22b4b79 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -1595,9 +1595,11 @@ 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. actors.mobs.gnollexile.name=gnoll exile -actors.mobs.gnollexile.desc=Gnolls are sometimes exiled from their society for a variety of reasons. The unusual grey fur on this gnoll indicates it was probably kicked out for just not fitting in. Exiles have to be strong and smart to survive, this one looks like it knows how to use the spear its holding. -actors.mobs.gnollexile.desc_passive=_The gnoll exile isn't moving to attack._ It doesn't seem as aggressive as the other gnolls here, it probably doesn't want a fight. You could just let it pass, although it has a backpack that might be full of useful items... +actors.mobs.gnollexile.desc=This grey-furred gnoll has a large mark on its shoulder, denoting it as an exile. Gnolls are usually exiled from their society for ignoring orders or breaking laws. Exiles have to be strong and shrewd to survive, this one looks like it knows how to use the spear its holding. +actors.mobs.gnollexile.desc_passive=_The gnoll exile isn't moving to attack._ It doesn't seem as aggressive as the other gnolls here, and probably doesn't think that fighting you is worth it. You could just let it pass, but it has a backpack that might be full of useful items... actors.mobs.gnollexile.desc_aggro=_The gnoll exile looks around angrily._ It seems something has made it decide to fight after all. Watch out for that spear! +actors.mobs.gnollexile.seen_passive=The spear-wielding gnoll looks at you warily, but doesn't move to attack. +actors.mobs.gnollexile.seen_aggro=The spear-wielding gnoll moves to attack! actors.mobs.gnollgeomancer.name=gnoll geomancer actors.mobs.gnollgeomancer.warning=The geomancer begins to stir. Make sure you're ready before you continue! diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/GnollExile.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/GnollExile.java index 0daeb76fe..df43d65ce 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/GnollExile.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/GnollExile.java @@ -24,32 +24,52 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; -import com.shatteredpixel.shatteredpixeldungeon.items.Gold; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.items.Generator; +import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.GnollExileSprite; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.utils.BArray; import com.watabou.utils.PathFinder; +import com.watabou.utils.Random; + +import java.util.ArrayList; public class GnollExile extends Gnoll { + //has 2x HP, +50% other stats, and +1 reach vs. a regular gnoll scout + //in exchange, they do not aggro automatically, and drop extra loot + { spriteClass = GnollExileSprite.class; PASSIVE = new Passive(); + WANDERING = new Wandering(); state = PASSIVE; - loot = Gold.class; + defenseSkill = 6; + HP = HT = 24; + + loot = Generator.randomUsingDefaults(); lootChance = 1f; } - //TODO higher stats, more detailed behaviour, better loot + @Override + public int damageRoll() { + return Random.NormalIntRange( 1, 10 ); + } - //"the spear-wielding gnoll pauses and eyes you suspiciously, but doesn't move to attack" - //"After a moment the gnoll nods its head toward you and begins to move on" + @Override + public int attackSkill( Char target ) { + return 15; + } - // offer 1 ration to get all of its drops + @Override + public int drRoll() { + return super.drRoll() + Random.NormalIntRange(0, 3); + } - //has 1 extra reach from their spear @Override protected boolean canAttack( Char enemy ) { if (Dungeon.level.adjacent( pos, enemy.pos )){ @@ -72,6 +92,37 @@ public class GnollExile extends Gnoll { return super.canAttack(enemy); } + @Override + public void rollToDropLoot() { + super.rollToDropLoot(); + + if (Dungeon.hero.lvl > maxLvl + 2) return; + + //in addition to normal drop drop, also drops 1 or 2 random extras + ArrayList items = new ArrayList<>(); + items.add(Generator.randomUsingDefaults()); + if (Random.Int(2) == 0) items.add(Generator.randomUsingDefaults()); + + for (Item item : items){ + int ofs; + do { + ofs = PathFinder.NEIGHBOURS8[Random.Int(8)]; + } while (Dungeon.level.solid[pos + ofs] && !Dungeon.level.passable[pos + ofs]); + Dungeon.level.drop( item, pos + ofs ).sprite.drop( pos ); + } + + } + + @Override + public void beckon(int cell) { + if (state != PASSIVE) { + super.beckon(cell); + } else { + //still attracts if passive, but doesn't remove passive state + target = cell; + } + } + @Override public String description() { String desc = super.description(); @@ -83,14 +134,36 @@ public class GnollExile extends Gnoll { return desc; } - //while passive gnoll exiles wander around + //gnoll exiles wander around while passive private class Passive extends Mob.Wandering { + + private int seenNotifyCooldown = 0; + @Override public boolean act( boolean enemyInFOV, boolean justAlerted ) { + + for (Buff b : buffs()){ + if (b.type == Buff.buffType.NEGATIVE){ + //swap to aggro if we've been debuffed + state = WANDERING; + return true; + } + } + + if (fieldOfView[Dungeon.hero.pos] && Dungeon.level.heroFOV[pos]){ + if (seenNotifyCooldown <= 0){ + GLog.p(Messages.get(GnollExile.class, "seen_passive")); + } + seenNotifyCooldown = 10; + } else { + seenNotifyCooldown--; + } + if (enemyInFOV && justAlerted) { - //TODO pause if hero first enters fov? - + if (Dungeon.level.heroFOV[pos]) { + GLog.w(Messages.get(GnollExile.class, "seen_aggro")); + } return noticeEnemy(); } else { @@ -100,4 +173,14 @@ public class GnollExile extends Gnoll { } } } + + //standard wandering but with a warning that the exile is aggroed + private class Wandering extends Mob.Wandering { + @Override + protected boolean noticeEnemy() { + GLog.w(Messages.get(GnollExile.class, "seen_aggro")); + return super.noticeEnemy(); + } + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mimic.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mimic.java index 536f18974..4c5a9face 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mimic.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mimic.java @@ -241,7 +241,9 @@ public class Mimic extends Mob { @Override public void beckon( int cell ) { - // Do nothing + if (alignment != Alignment.NEUTRAL) { + super.beckon(cell); + } } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/MobSpawner.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/MobSpawner.java index a9253a16b..d20022549 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/MobSpawner.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/MobSpawner.java @@ -24,7 +24,6 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull; -import com.watabou.utils.DeviceCompat; import com.watabou.utils.Random; import java.util.ArrayList; @@ -248,7 +247,7 @@ public class MobSpawner extends Actor { Class cl = rotation.get(i); if (cl == Rat.class) { cl = Albino.class; - } else if (cl == Gnoll.class && DeviceCompat.isDebug()) { + } else if (cl == Gnoll.class) { cl = GnollExile.class; } else if (cl == Slime.class) { cl = CausticSlime.class; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java index 2c46803ae..3ecf70ead 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java @@ -143,7 +143,9 @@ public class Statue extends Mob { @Override public void beckon( int cell ) { - // Do nothing + if (state != PASSIVE){ + super.beckon(cell); + } } @Override