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 3a6ca2019..d7309fbb3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java @@ -77,6 +77,14 @@ public abstract class Char extends Actor { public boolean flying = false; public int invisible = 0; + //these are relative to the hero + public enum Alignment{ + ENEMY, + NEUTRAL, + ALLY + } + public Alignment alignment; + public int viewDistance = 8; protected boolean[] fieldOfView = null; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Corruption.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Corruption.java index dd6896b42..835752f8b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Corruption.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Corruption.java @@ -21,6 +21,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; @@ -32,7 +33,17 @@ public class Corruption extends Buff { } private float buildToDamage = 0f; - + + @Override + public boolean attachTo(Char target) { + if (super.attachTo(target)){ + target.alignment = Char.Alignment.ALLY; + return true; + } else { + return false; + } + } + @Override public boolean act() { buildToDamage += target.HT/200f; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index a037f438b..10ef5cc37 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -131,6 +131,8 @@ public class Hero extends Char { { actPriority = 0; //acts at priority 0, baseline for the rest of behaviour. + + alignment = Alignment.ALLY; } public static final int MAX_LEVEL = 30; @@ -988,7 +990,7 @@ public class Hero extends Char { Mob target = null; for (Mob m : Dungeon.level.mobs) { - if (fieldOfView[ m.pos ] && m.hostile) { + if (fieldOfView[ m.pos ] && m.alignment == Alignment.ENEMY) { visible.add(m); if (!visibleEnemies.contains( m )) { newMob = true; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java index ef6edfc44..d728e389c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java @@ -127,9 +127,13 @@ public class Bee extends Mob { //find all mobs near the pot HashSet enemies = new HashSet<>(); - for (Mob mob : Dungeon.level.mobs) - if (!(mob instanceof Bee) && Dungeon.level.distance(mob.pos, potPos) <= 3 && (mob.hostile || mob.ally)) + for (Mob mob : Dungeon.level.mobs) { + if (!(mob instanceof Bee) + && Dungeon.level.distance(mob.pos, potPos) <= 3 + && mob.alignment != Alignment.NEUTRAL) { enemies.add(mob); + } + } //pick one, if there are none, check if the hero is near the pot, go for them, otherwise go for nothing. if (enemies.size() > 0) return Random.element(enemies); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index c1ebf9b41..8f743a7f0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -62,6 +62,8 @@ public abstract class Mob extends Char { { name = Messages.get(this, "name"); actPriority = 2; //hero gets priority over mobs. + + alignment = Alignment.ENEMY; } private static final String TXT_DIED = "You hear something died in the distance"; @@ -92,9 +94,6 @@ public abstract class Mob extends Char { protected static final float TIME_TO_WAKE_UP = 1f; - public boolean hostile = true; - public boolean ally = false; - private static final String STATE = "state"; private static final String SEEN = "seen"; private static final String TARGET = "target"; @@ -194,8 +193,8 @@ public abstract class Mob extends Char { //we have no enemy, or the current one is dead if ( enemy == null || !enemy.isAlive() || state == WANDERING) newEnemy = true; - //We are corrupted, and current enemy is either the hero or another corrupted character. - else if (buff(Corruption.class) != null && (enemy == Dungeon.hero || enemy.buff(Corruption.class) != null)) + //We are an ally, and current enemy is another ally. + else if (alignment == Alignment.ALLY && enemy.alignment == Alignment.ALLY) newEnemy = true; //We are amoked and current enemy is the hero else if (buff( Amok.class ) != null && enemy == Dungeon.hero) @@ -205,47 +204,55 @@ public abstract class Mob extends Char { HashSet enemies = new HashSet<>(); - //if the mob is corrupted... - if ( buff(Corruption.class) != null) { - - //look for enemy mobs to attack, which are also not corrupted - for (Mob mob : Dungeon.level.mobs) - if (mob != this && fieldOfView[mob.pos] && mob.hostile && mob.buff(Corruption.class) == null) - enemies.add(mob); - if (enemies.size() > 0) return Random.element(enemies); - - //otherwise go for nothing - return null; - //if the mob is amoked... - } else if ( buff(Amok.class) != null) { - + if ( buff(Amok.class) != null) { //try to find an enemy mob to attack first. for (Mob mob : Dungeon.level.mobs) - if (mob != this && fieldOfView[mob.pos] && mob.hostile) + if (mob.alignment == Alignment.ENEMY && mob != this && fieldOfView[mob.pos]) enemies.add(mob); - if (enemies.size() > 0) return Random.element(enemies); - - //try to find ally mobs to attack second. - for (Mob mob : Dungeon.level.mobs) - if (mob != this && fieldOfView[mob.pos] && mob.ally) - enemies.add(mob); - if (enemies.size() > 0) return Random.element(enemies); - - //if there is nothing, go for the hero - else return Dungeon.hero; - - } else { - - //try to find ally mobs to attack. - for (Mob mob : Dungeon.level.mobs) - if (mob != this && fieldOfView[mob.pos] && mob.ally) - enemies.add(mob); - - //and add the hero to the list of targets. - enemies.add(Dungeon.hero); - //go after the closest enemy, preferring the hero if two are equidistant + if (enemies.isEmpty()) { + //try to find ally mobs to attack second. + for (Mob mob : Dungeon.level.mobs) + if (mob.alignment == Alignment.ALLY && mob != this && fieldOfView[mob.pos]) + enemies.add(mob); + + if (enemies.isEmpty()) { + //try to find the hero third + if (fieldOfView[Dungeon.hero.pos]) { + enemies.add(Dungeon.hero); + } + } + } + + //if the mob is an ally... + } else if ( alignment == Alignment.ALLY ) { + //look for hostile mobs that are not passive to attack + for (Mob mob : Dungeon.level.mobs) + if (mob.alignment == Alignment.ENEMY + && fieldOfView[mob.pos] + && mob.state != mob.PASSIVE) + enemies.add(mob); + + //if the mob is an enemy... + } else if (alignment == Alignment.ENEMY) { + //look for ally mobs to attack + for (Mob mob : Dungeon.level.mobs) + if (mob.alignment == Alignment.ALLY && fieldOfView[mob.pos]) + enemies.add(mob); + + //and look for the hero + if (fieldOfView[Dungeon.hero.pos]) { + enemies.add(Dungeon.hero); + } + + } + + //neutral character in particular do not choose enemies. + if (enemies.isEmpty()){ + return null; + } else { + //go after the closest potential enemy, preferring the hero if two are equidistant Char closest = null; for (Char curr : enemies){ if (closest == null @@ -255,7 +262,6 @@ public abstract class Mob extends Char { } } return closest; - } } else @@ -538,7 +544,7 @@ public abstract class Mob extends Char { if (Dungeon.hero.isAlive()) { - if (hostile) { + if (alignment == Alignment.ENEMY) { Statistics.enemiesSlain++; Badges.validateMonstersSlain(); Statistics.qualifiedForNoKilling = false; @@ -566,7 +572,7 @@ public abstract class Mob extends Char { Dungeon.level.drop( loot , pos ).sprite.drop(); } - if (hostile && Dungeon.hero.lvl <= maxLvl + 2){ + if (alignment == Alignment.ENEMY && Dungeon.hero.lvl <= maxLvl + 2){ int rolls = 1; if (properties.contains(Property.BOSS)) rolls = 15; else if (properties.contains(Property.MINIBOSS)) rolls = 5; @@ -723,18 +729,20 @@ public abstract class Mob extends Char { if (enemyInFOV) { target = enemy.pos; + } else if (enemy == null) { + state = WANDERING; + target = Dungeon.level.randomDestination(); + return true; } - + int oldPos = pos; if (target != -1 && getCloser( target )) { - + spend( 1 / speed() ); return moveSprite( oldPos, pos ); } else { - spend( TICK ); - if (!enemyInFOV) { sprite.showLost(); state = WANDERING; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java index 40ceb5142..b690b2d61 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java @@ -27,18 +27,16 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.VenomGas; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; -import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.MirrorSprite; import com.watabou.utils.Bundle; -import java.util.HashSet; - public class MirrorImage extends NPC { { spriteClass = MirrorSprite.class; + alignment = Alignment.ALLY; state = HUNTING; } @@ -93,32 +91,6 @@ public class MirrorImage extends NPC { return damage; } - protected Char chooseEnemy() { - - if (enemy == null || !enemy.isAlive()) { - HashSet enemies = new HashSet<>(); - for (Mob mob : Dungeon.level.mobs) { - if (mob.hostile - && fieldOfView[mob.pos] - && mob.state != mob.PASSIVE) { - enemies.add(mob); - } - } - - //go for closest enemy - Char closest = null; - for (Char curr : enemies){ - if (closest == null - || Dungeon.level.distance(pos, curr.pos) < Dungeon.level.distance(pos, closest.pos)){ - closest = curr; - } - } - return closest; - } - - return enemy; - } - @Override public CharSprite sprite() { CharSprite s = super.sprite(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/NPC.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/NPC.java index 7edd1eb2b..c4f20f701 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/NPC.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/NPC.java @@ -33,7 +33,7 @@ public abstract class NPC extends Mob { HP = HT = 1; EXP = 0; - hostile = false; + alignment = Alignment.NEUTRAL; state = PASSIVE; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java index 9aad07380..a0217a323 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java @@ -378,13 +378,11 @@ public class DriedRose extends Artifact { flying = true; - ally = true; + alignment = Alignment.ALLY; WANDERING = new Wandering(); - HUNTING = new Hunting(); - state = WANDERING; - enemy = null; + state = HUNTING; //after hero, but before mobs actPriority = 1; @@ -470,11 +468,12 @@ public class DriedRose extends Artifact { || !enemy.isAlive() || !Dungeon.level.mobs.contains(enemy) || Dungeon.level.distance(enemy.pos, Dungeon.hero.pos) > 8 + || enemy.alignment != Alignment.ENEMY || state == WANDERING) { HashSet enemies = new HashSet<>(); for (Mob mob : Dungeon.level.mobs) { - if (mob.hostile + if (mob.alignment == Alignment.ENEMY && fieldOfView[mob.pos] && Dungeon.level.distance(mob.pos, Dungeon.hero.pos) <= 8 && mob.state != mob.PASSIVE) { @@ -676,12 +675,14 @@ public class DriedRose extends Artifact { enemySeen = true; notice(); + alerted = true; state = HUNTING; target = enemy.pos; } else { enemySeen = false; + sprite.hideLost(); int oldPos = pos; //always move towards the hero when wandering @@ -701,40 +702,6 @@ public class DriedRose extends Artifact { } } - - private class Hunting extends Mob.Hunting { - - @Override - public boolean act( boolean enemyInFOV, boolean justAlerted ) { - - enemySeen = enemyInFOV; - if (enemyInFOV && !isCharmedBy( enemy ) && canAttack( enemy )) { - - return doAttack( enemy ); - - } else { - - if (enemyInFOV) { - target = enemy.pos; - } - - int oldPos = pos; - if (enemyInFOV && getCloser( target )) { - - spend( 1 / speed() ); - return moveSprite( oldPos, pos ); - - } else { - - //don't lose a turn due to the transition, immediately act instead - state = WANDERING; - return state.act( false, justAlerted ); - - } - } - } - - } //************************************************************************************ //This is a bunch strings & string arrays, used in all of the sad ghost's voice lines. diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/LloydsBeacon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/LloydsBeacon.java index 768b61b9a..55ac00d02 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/LloydsBeacon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/LloydsBeacon.java @@ -29,7 +29,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; -import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation; @@ -118,7 +117,7 @@ public class LloydsBeacon extends Artifact { for (int i = 0; i < PathFinder.NEIGHBOURS8.length; i++) { Char ch = Actor.findChar(hero.pos + PathFinder.NEIGHBOURS8[i]); - if (ch != null && !(ch instanceof Mob && !((Mob) ch).hostile)) { + if (ch != null && ch.alignment == Char.Alignment.ENEMY) { GLog.w( Messages.get(this, "creatures") ); return; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java index 53d67dc43..a8c24c642 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java @@ -23,12 +23,10 @@ package com.shatteredpixel.shatteredpixeldungeon.items.wands; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; -import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap; 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.Charm; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Corruption; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.effects.Beam; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; @@ -48,6 +46,7 @@ import com.shatteredpixel.shatteredpixeldungeon.plants.Plant; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.noosa.audio.Sample; import com.watabou.utils.Bundle; @@ -83,8 +82,8 @@ public class WandOfTransfusion extends Wand { processSoulMark(ch, chargesPerCast()); - //heals an ally, or charmed/corrupted enemy - if (((Mob) ch).ally || ch.buff(Charm.class) != null || ch.buff(Corruption.class) != null){ + //heals an ally, or a charmed enemy + if (ch.alignment == Char.Alignment.ALLY || ch.buff(Charm.class) != null){ int missingHP = ch.HT - ch.HP; //heals 30%+3%*lvl missing HP. diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java index 26bdd3b12..fc2f2bf84 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CavesBossLevel.java @@ -227,7 +227,7 @@ public class CavesBossLevel extends Level { for (Mob m : mobs){ //bring the first ally with you - if (m.ally){ + if (m.alignment == Char.Alignment.ALLY){ m.pos = Dungeon.hero.pos + (Random.Int(2) == 0 ? +1 : -1); m.sprite.place(m.pos); break; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java index f71979be7..86ff7efc1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/CityBossLevel.java @@ -198,7 +198,7 @@ public class CityBossLevel extends Level { for (Mob m : mobs){ //bring the first ally with you - if (m.ally){ + if (m.alignment == Char.Alignment.ALLY){ m.pos = Dungeon.hero.pos + (Random.Int(2) == 0 ? +1 : -1); m.sprite.place(m.pos); break; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java index 3af0d525e..fedaeeee6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java @@ -503,7 +503,7 @@ public abstract class Level implements Bundlable { protected boolean act() { int count = 0; for (Mob mob : mobs.toArray(new Mob[0])){ - if (mob.hostile) count++; + if (mob.alignment == Char.Alignment.ENEMY) count++; } if (count < nMobs()) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java index 42f019da6..5d80fa029 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/PrisonBossLevel.java @@ -287,7 +287,7 @@ public class PrisonBossLevel extends Level { for (Mob m : mobs){ //bring the first ally with you - if (m.ally){ + if (m.alignment == Char.Alignment.ALLY){ m.pos = 5 + 25 * 32; //they should immediately walk out of the door m.sprite.place(m.pos); break; @@ -340,7 +340,7 @@ public class PrisonBossLevel extends Level { //if any allies are left over, move them along the same way as the hero for (Mob m : mobs){ - if (m.ally) { + if (m.alignment == Char.Alignment.ALLY) { m.pos += 9 + 3 * 32; m.sprite().place(m.pos); } @@ -386,7 +386,7 @@ public class PrisonBossLevel extends Level { //remove all mobs, but preserve allies ArrayList allies = new ArrayList<>(); for(Mob m : mobs.toArray(new Mob[0])){ - if (m.ally){ + if (m.alignment == Char.Alignment.ALLY){ allies.add(m); mobs.remove(m); }