diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bestiary.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bestiary.java index 5660dd0ea..ed3a66991 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bestiary.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bestiary.java @@ -112,14 +112,16 @@ public class Bestiary { Bat.class, Brute.class, Brute.class, Shaman.random(), Shaman.random(), - Spinner.class, Spinner.class)); + Spinner.class, Spinner.class, + DM200.class)); case 14: case 15: //1x bat, 1x brute, 2x shaman, 2x spinner, 2x DM-300 return new ArrayList<>(Arrays.asList( Bat.class, Brute.class, Shaman.random(), Shaman.random(), - Spinner.class, Spinner.class)); + Spinner.class, Spinner.class, + DM200.class, DM200.class)); // City case 16: diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM200.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM200.java new file mode 100644 index 000000000..934de8a35 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM200.java @@ -0,0 +1,154 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 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.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob; +import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.DM200Sprite; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.utils.Bundle; +import com.watabou.utils.Random; + +public class DM200 extends Mob { + + { + spriteClass = DM200Sprite.class; + + HP = HT = 80; + defenseSkill = 8; + + EXP = 9; + maxLvl = 17; + + //TODO loot? + + properties.add(Property.INORGANIC); + properties.add(Property.LARGE); + + HUNTING = new Hunting(); + } + + @Override + public int damageRoll() { + return Random.NormalIntRange( 10, 30 ); + } + + @Override + public int attackSkill( Char target ) { + return 20; + } + + @Override + public int drRoll() { + return Random.NormalIntRange(0, 10); + } + + private int ventCooldown = 0; + + private static final String VENT_COOLDOWN = "vent_cooldown"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(VENT_COOLDOWN, ventCooldown); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + ventCooldown = bundle.getInt( VENT_COOLDOWN ); + } + + @Override + protected boolean act() { + ventCooldown--; + return super.act(); + } + + public void onZapComplete(){ + zap(); + next(); + } + + private void zap( ){ + spend( TICK ); + ventCooldown = 30; + + Ballistica trajectory = new Ballistica(pos, enemy.pos, Ballistica.STOP_TARGET); + + for (int i : trajectory.subPath(0, trajectory.dist)){ + GameScene.add(Blob.seed(i, 20, ToxicGas.class)); + } + + GLog.w(Messages.get(this, "vent")); + GameScene.add(Blob.seed(trajectory.collisionPos, 100, ToxicGas.class)); + + } + + private class Hunting extends Mob.Hunting{ + + @Override + public boolean act(boolean enemyInFOV, boolean justAlerted) { + if (!enemyInFOV || canAttack(enemy)) { + return super.act(enemyInFOV, justAlerted); + } else { + enemySeen = true; + target = enemy.pos; + + int oldPos = pos; + + if (ventCooldown <= 0 && Random.Int(100/distance(enemy)) == 0){ + if (sprite != null && (sprite.visible || enemy.sprite.visible)) { + sprite.zap( enemy.pos ); + return false; + } else { + zap(); + return true; + } + + } else if (getCloser( target )) { + spend( 1 / speed() ); + return moveSprite( oldPos, pos ); + + } else if (ventCooldown <= 0) { + if (sprite != null && (sprite.visible || enemy.sprite.visible)) { + sprite.zap( enemy.pos ); + return false; + } else { + zap(); + return true; + } + + } else { + spend( TICK ); + return true; + } + + } + } + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/MagicMissile.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/MagicMissile.java index 397857641..3a9219d79 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/MagicMissile.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/MagicMissile.java @@ -66,6 +66,7 @@ public class MagicMissile extends Emitter { public static final int SHAMAN_RED = 11; public static final int SHAMAN_BLUE = 12; public static final int SHAMAN_PURPLE = 13; + public static final int TOXIC_VENT = 14; public static final int FIRE_CONE = 100; public static final int FOLIAGE_CONE = 101; @@ -162,6 +163,10 @@ public class MagicMissile extends Emitter { size( 2 ); pour( ShamanParticle.PURPLE, 0.01f ); break; + case TOXIC_VENT: + size( 10 ); + pour( Speck.factory(Speck.TOXIC), 0.02f ); + break; case FIRE_CONE: size( 10 ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/DM200Sprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/DM200Sprite.java new file mode 100644 index 000000000..f3b88b0a7 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/DM200Sprite.java @@ -0,0 +1,78 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 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.mobs.DM200; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Shaman; +import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; +import com.watabou.noosa.TextureFilm; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Callback; + +//TODO currently just uses DM-300's sprite scaled to 80% +public class DM200Sprite extends MobSprite { + + public DM200Sprite () { + super(); + + texture( Assets.DM300 ); + + TextureFilm frames = new TextureFilm( texture, 22, 20 ); + + idle = new Animation( 10, true ); + idle.frames( frames, 0, 1 ); + + run = new Animation( 10, true ); + run.frames( frames, 2, 3 ); + + attack = new Animation( 15, false ); + attack.frames( frames, 4, 5, 6, 0 ); + + zap = attack.clone(); + + die = new Animation( 20, false ); + die.frames( frames, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 8 ); + + play( idle ); + scale.set( 0.8f ); + } + + public void zap( int cell ) { + + turnTo( ch.pos , cell ); + play( zap ); + + MagicMissile.boltFromChar( parent, + MagicMissile.TOXIC_VENT, + this, + cell, + new Callback() { + @Override + public void call() { + ((DM200)ch).onZapComplete(); + } + } ); + Sample.INSTANCE.play( Assets.SND_PUFF ); + } + +} 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 312e1a14d..43972a1a0 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 @@ -485,6 +485,10 @@ actors.mobs.dm100.name=DM-100 actors.mobs.dm100.zap_kill=The lightning bolt killed you... actors.mobs.dm100.desc=The DM-100 is an early model of dwarven 'defense machine' which was designed to protect dwarven miners in the caves below. Their electrical shocks proved too weak however, and so they were gifted to the human prison above. The warden initially deemed them too cruel to use, but as the prisoners became more unruly they became a necessity. +actors.mobs.dm200.name=DM-200 +actors.mobs.dm200.vent=The DM-200 fires a toxic jet of exhaust at you! +actors.mobs.dm200.desc=The DM-200 is the second generation of dwarven 'defense machine', which was designed to protect dwarven miners in the caves and city below. They are much larger and bulkier than their predecessors, and attack with devastating hydraulic fists.\n\nTheir increased size is also their primary weakness, as they are unable to fit into the narrow tunnels and doorways of the dungeon. The dwarves were able to compensate for the DM-200's lack of mobility by allowing them to vent their toxic exhaust fumes at distant enemies, or enemies they cannot reach. + actors.mobs.dm300.name=DM-300 actors.mobs.dm300.notice=Unauthorised personnel detected. actors.mobs.dm300.defeated=Mission failed. Shutting down.