diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bandit.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bandit.java index 6e0291244..c8d3d825f 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bandit.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bandit.java @@ -45,9 +45,9 @@ public class Bandit extends Thief { protected boolean steal( Hero hero ) { if (super.steal( hero )) { - Buff.prolong( enemy, Blindness.class, Random.Int( 5, 12 ) ); - Buff.affect( enemy, Poison.class ).set(Random.Int(5, 7) * Poison.durationFactor(enemy)); - Buff.prolong( enemy, Cripple.class, Cripple.DURATION ); + Buff.prolong( hero, Blindness.class, Random.Int( 5, 12 ) ); + Buff.affect( hero, Poison.class ).set(Random.Int(5, 7) * Poison.durationFactor(enemy)); + Buff.prolong( hero, Cripple.class, Cripple.DURATION ); Dungeon.observe(); return true; diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java index 5b1bee3af..939e6c917 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java @@ -47,7 +47,7 @@ import com.watabou.utils.Bundle; import com.watabou.utils.Random; public class Goo extends Mob { - +//todo: will need to manually recreate stuff from 1.7.5 here { name = "Goo"; HP = HT = 80; diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mimic.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mimic.java new file mode 100644 index 000000000..0451920d3 --- /dev/null +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mimic.java @@ -0,0 +1,181 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +import com.watabou.noosa.audio.Sample; +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; +import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.items.Gold; +import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.MimicSprite; +import com.watabou.utils.Bundle; +import com.watabou.utils.Random; + +public class Mimic extends Mob { + + private int level; + + { + name = "mimic"; + spriteClass = MimicSprite.class; + } + + public ArrayList items; + + private static final String LEVEL = "level"; + private static final String ITEMS = "items"; + + @Override + public void storeInBundle( Bundle bundle ) { + super.storeInBundle( bundle ); + bundle.put( ITEMS, items ); + bundle.put( LEVEL, level ); + } + + @SuppressWarnings("unchecked") + @Override + public void restoreFromBundle( Bundle bundle ) { + super.restoreFromBundle( bundle ); + items = new ArrayList( (Collection) bundle.getCollection( ITEMS ) ); + adjustStats( bundle.getInt( LEVEL ) ); + } + + @Override + public int damageRoll() { + return Random.NormalIntRange( HT / 10, HT / 4 ); + } + + @Override + public int attackSkill( Char target ) { + return 9 + level; + } + + @Override + public int attackProc( Char enemy, int damage ) { + if (enemy == Dungeon.hero && Random.Int( 3 ) == 0) { + Gold gold = new Gold( Random.Int( Dungeon.gold / 10, Dungeon.gold / 2 ) ); + if (gold.quantity() > 0) { + Dungeon.gold -= gold.quantity(); + Dungeon.level.drop( gold, Dungeon.hero.pos ).sprite.drop(); + } + } + return super.attackProc( enemy, damage ); + } + + public void adjustStats( int level ) { + this.level = level; + + HT = (3 + level) * 4; + EXP = 2 + 2 * (level - 1) / 5; + defenseSkill = attackSkill( null ) / 2; + + enemySeen = true; + } + + @Override + public void die( Object cause ) { + + super.die( cause ); + + if (items != null) { + for (Item item : items) { + Dungeon.level.drop( item, pos ).sprite.drop(); + } + } + } + + @Override + public boolean reset() { + state = WANDERING; + return true; + } + + @Override + public String description() { + return + "Mimics are magical creatures which can take any shape they wish. In dungeons they almost always " + + "choose a shape of a treasure chest, because they know how to beckon an adventurer."; + } + + public static Mimic spawnAt( int pos, List items ) { + Char ch = Actor.findChar( pos ); + if (ch != null) { + ArrayList candidates = new ArrayList(); + for (int n : Level.NEIGHBOURS8) { + int cell = pos + n; + if ((Level.passable[cell] || Level.avoid[cell]) && Actor.findChar( cell ) == null) { + candidates.add( cell ); + } + } + if (candidates.size() > 0) { + int newPos = Random.element( candidates ); + Actor.addDelayed( new Pushing( ch, ch.pos, newPos ), -1 ); + + ch.pos = newPos; + // FIXME + if (ch instanceof Mob) { + Dungeon.level.mobPress( (Mob)ch ); + } else { + Dungeon.level.press( newPos, ch ); + } + } else { + return null; + } + } + + Mimic m = new Mimic(); + m.items = new ArrayList( items ); + m.adjustStats( Dungeon.depth ); + m.HP = m.HT; + m.pos = pos; + m.state = m.HUNTING; + GameScene.add( m, 1 ); + + m.sprite.turnTo( pos, Dungeon.hero.pos ); + + if (Dungeon.visible[m.pos]) { + CellEmitter.get( pos ).burst( Speck.factory( Speck.STAR ), 10 ); + Sample.INSTANCE.play( Assets.SND_MIMIC ); + } + + return m; + } + + private static final HashSet> IMMUNITIES = new HashSet>(); + static { + IMMUNITIES.add( ScrollOfPsionicBlast.class ); + } + + @Override + public HashSet> immunities() { + return IMMUNITIES; + } +} diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index 54e64a7a3..19887b0c0 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -21,6 +21,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Badges; import com.shatteredpixel.shatteredpixeldungeon.Challenges; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; @@ -38,6 +39,7 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level.Feeling; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.shatteredpixel.shatteredpixeldungeon.utils.Utils; import com.watabou.utils.Bundle; import com.watabou.utils.Random; @@ -76,13 +78,6 @@ public abstract class Mob extends Char { public boolean hostile = true; public boolean ally = false; - // Unreachable target - public static final Mob DUMMY = new Mob() { - { - pos = -1; - } - }; - private static final String STATE = "state"; private static final String SEEN = "seen"; private static final String TARGET = "target"; @@ -157,16 +152,19 @@ public abstract class Mob extends Char { enemy = chooseEnemy(); - boolean enemyInFOV = enemy.isAlive() && Level.fieldOfView[enemy.pos] && enemy.invisible <= 0; + boolean enemyInFOV = enemy != null && enemy.isAlive() && Level.fieldOfView[enemy.pos] && enemy.invisible <= 0; return state.act( enemyInFOV, justAlerted ); } protected Char chooseEnemy() { - Terror terror = (Terror)buff( Terror.class ); + Terror terror = buff( Terror.class ); if (terror != null) { - return terror.source; + Char source = (Char)Actor.findById( terror.object ); + if (source != null) { + return source; + } } //resets target if: the target is dead, the target has been lost (wandering) @@ -257,7 +255,7 @@ public abstract class Mob extends Char { } protected boolean canAttack( Char enemy ) { - return Level.adjacent( pos, enemy.pos ) && !pacified; + return Level.adjacent( pos, enemy.pos ) && !isCharmedBy( enemy ); } protected boolean getCloser( int target ) { @@ -354,7 +352,11 @@ public abstract class Mob extends Char { } return damage; } - + + public void aggro( Char ch ) { + enemy = ch; + } + @Override public void damage( int dmg, Object src ) { @@ -516,7 +518,7 @@ public abstract class Mob extends Char { @Override public String status() { - return String.format( "This %s is sleeping", name ); + return Utils.format( "This %s is sleeping", name ); } } @@ -553,7 +555,7 @@ public abstract class Mob extends Char { @Override public String status() { - return String.format( "This %s is wandering", name ); + return Utils.format( "This %s is wandering", name ); } } @@ -592,7 +594,7 @@ public abstract class Mob extends Char { @Override public String status() { - return String.format( "This %s is hunting", name ); + return Utils.format( "This %s is hunting", name ); } } @@ -627,7 +629,7 @@ public abstract class Mob extends Char { @Override public String status() { - return String.format( "This %s is fleeing", name ); + return Utils.format( "This %s is fleeing", name ); } } @@ -644,7 +646,7 @@ public abstract class Mob extends Char { @Override public String status() { - return String.format( "This %s is passive", name ); + return Utils.format( "This %s is passive", name ); } } } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java index 5f11cb3ee..ad1ae9788 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Spinner.java @@ -68,10 +68,9 @@ public class Spinner extends Mob { protected boolean act() { boolean result = super.act(); - if (state == FLEEING && buff(Terror.class) == null && - enemySeen && enemy.buff(Poison.class) == null) { - - state = HUNTING; + if (state == FLEEING && buff( Terror.class ) == null && + enemy != null && enemySeen && enemy.buff( Poison.class ) == null) { + state = HUNTING; } return result; } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java index 4680a2c61..8a21ce898 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java @@ -121,6 +121,7 @@ public class Statue extends Mob { @Override public void beckon( int cell ) { + // Do nothing } @Override diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java index 3f926bae6..4882ce8f6 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java @@ -66,7 +66,7 @@ public class Succubus extends Mob { public int attackProc( Char enemy, int damage ) { if (Random.Int( 3 ) == 0) { - Buff.affect( enemy, Charm.class, Charm.durationFactor( enemy ) * Random.IntRange( 2, 5 ) ); + Buff.affect( enemy, Charm.class, Charm.durationFactor( enemy ) * Random.IntRange( 3, 7 ) ).object = id(); enemy.sprite.centerEmitter().start( Speck.factory( Speck.HEART ), 0.2f, 5 ); Sample.INSTANCE.play( Assets.SND_CHARMS ); }