v2.2.0: more crystal enemy impl
This commit is contained in:
+62
-14
@@ -21,11 +21,17 @@
|
|||||||
|
|
||||||
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
||||||
|
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Healing;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.effects.Splash;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CrystalGuardianSprite;
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.CrystalGuardianSprite;
|
||||||
|
import com.watabou.noosa.audio.Sample;
|
||||||
import com.watabou.utils.Bundle;
|
import com.watabou.utils.Bundle;
|
||||||
import com.watabou.utils.PathFinder;
|
import com.watabou.utils.PathFinder;
|
||||||
import com.watabou.utils.Random;
|
import com.watabou.utils.Random;
|
||||||
@@ -33,11 +39,34 @@ import com.watabou.utils.Random;
|
|||||||
public class CrystalGuardian extends Mob{
|
public class CrystalGuardian extends Mob{
|
||||||
|
|
||||||
{
|
{
|
||||||
HP = HT = 1;
|
|
||||||
spriteClass = CrystalGuardianSprite.class;
|
spriteClass = CrystalGuardianSprite.class;
|
||||||
|
|
||||||
|
HP = HT = 100;
|
||||||
|
defenseSkill = 14;
|
||||||
|
|
||||||
|
EXP = 10;
|
||||||
|
maxLvl = -2;
|
||||||
|
|
||||||
SLEEPING = new Sleeping();
|
SLEEPING = new Sleeping();
|
||||||
state = SLEEPING;
|
state = SLEEPING;
|
||||||
|
|
||||||
|
properties.add(Property.INORGANIC);
|
||||||
|
properties.add(Property.MINIBOSS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int damageRoll() {
|
||||||
|
return Random.NormalIntRange( 10, 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int attackSkill( Char target ) {
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int drRoll() {
|
||||||
|
return super.drRoll() + Random.NormalIntRange(0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -45,6 +74,17 @@ public class CrystalGuardian extends Mob{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlive() {
|
||||||
|
if (HP <= 0){
|
||||||
|
HP = 1;
|
||||||
|
if (sprite != null) ((CrystalGuardianSprite)sprite).crumple();
|
||||||
|
spend(10f-cooldown());
|
||||||
|
Buff.affect(this, Healing.class).setHeal(100, 0, 10);
|
||||||
|
}
|
||||||
|
return super.isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
public CrystalGuardian(){
|
public CrystalGuardian(){
|
||||||
super();
|
super();
|
||||||
switch (Random.Int(3)){
|
switch (Random.Int(3)){
|
||||||
@@ -77,24 +117,32 @@ public class CrystalGuardian extends Mob{
|
|||||||
@Override
|
@Override
|
||||||
public void beckon(int cell) {
|
public void beckon(int cell) {
|
||||||
super.beckon(cell);
|
super.beckon(cell);
|
||||||
|
state = HUNTING;
|
||||||
|
}
|
||||||
|
|
||||||
//If we are still penned into our starting area, break out of it
|
@Override
|
||||||
PathFinder.buildDistanceMap(cell, Dungeon.level.passable);
|
public void move(int step, boolean travelling) {
|
||||||
if (PathFinder.distance[pos] == Integer.MAX_VALUE){
|
super.move(step, travelling);
|
||||||
boolean[] passable = Dungeon.level.passable.clone();
|
if (Dungeon.level.map[pos] == Terrain.MINE_CRYSTAL){
|
||||||
|
Level.set(pos, Terrain.EMPTY);
|
||||||
|
GameScene.updateMap(pos);
|
||||||
|
if (Dungeon.level.heroFOV[pos]){
|
||||||
|
Splash.at(pos, 0xFFFFFF, 5);
|
||||||
|
Sample.INSTANCE.play( Assets.Sounds.SHATTER );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean[] modifyPassable(boolean[] passable) {
|
||||||
|
//TODO maybe base this on passable instead of hunting?
|
||||||
|
// want to prevent one guardian randomly waking another though
|
||||||
|
if (state == HUNTING){
|
||||||
for (int i = 0; i < Dungeon.level.length(); i++){
|
for (int i = 0; i < Dungeon.level.length(); i++){
|
||||||
passable[i] = passable[i] || Dungeon.level.map[i] == Terrain.MINE_CRYSTAL;
|
passable[i] = passable[i] || Dungeon.level.map[i] == Terrain.MINE_CRYSTAL;
|
||||||
}
|
}
|
||||||
PathFinder.Path p = PathFinder.find(pos, cell, passable);
|
|
||||||
if (p != null) {
|
|
||||||
for (int i : p) {
|
|
||||||
if (Dungeon.level.map[i] == Terrain.MINE_CRYSTAL) {
|
|
||||||
Level.set(i, Terrain.EMPTY);
|
|
||||||
GameScene.updateMap(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return passable;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class Sleeping extends Mob.Sleeping{
|
protected class Sleeping extends Mob.Sleeping{
|
||||||
|
|||||||
+87
-1
@@ -21,17 +21,34 @@
|
|||||||
|
|
||||||
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
||||||
|
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AscensionChallenge;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CrystalWispSprite;
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.CrystalWispSprite;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||||
import com.watabou.utils.Bundle;
|
import com.watabou.utils.Bundle;
|
||||||
import com.watabou.utils.Random;
|
import com.watabou.utils.Random;
|
||||||
|
|
||||||
public class CrystalWisp extends Mob{
|
public class CrystalWisp extends Mob{
|
||||||
|
|
||||||
{
|
{
|
||||||
HP = HT = 1;
|
|
||||||
spriteClass = CrystalWispSprite.class;
|
spriteClass = CrystalWispSprite.class;
|
||||||
|
|
||||||
|
HP = HT = 35;
|
||||||
|
defenseSkill = 16;
|
||||||
|
|
||||||
|
EXP = 7;
|
||||||
|
maxLvl = -2;
|
||||||
|
|
||||||
|
flying = true;
|
||||||
|
|
||||||
|
properties.add(Property.INORGANIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CrystalWisp(){
|
public CrystalWisp(){
|
||||||
@@ -57,6 +74,75 @@ public class CrystalWisp extends Mob{
|
|||||||
return passable;
|
return passable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int damageRoll() {
|
||||||
|
return Random.NormalIntRange( 3, 10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int attackSkill( Char target ) {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int drRoll() {
|
||||||
|
return super.drRoll() + Random.NormalIntRange(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canAttack( Char enemy ) {
|
||||||
|
return super.canAttack(enemy)
|
||||||
|
|| new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean doAttack(Char enemy ) {
|
||||||
|
|
||||||
|
if (Dungeon.level.adjacent( pos, enemy.pos )
|
||||||
|
|| new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos != enemy.pos) {
|
||||||
|
|
||||||
|
return super.doAttack( enemy );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (sprite != null && (sprite.visible || enemy.sprite.visible)) {
|
||||||
|
sprite.zap( enemy.pos );
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
zap();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//used so resistances can differentiate between melee and magical attacks
|
||||||
|
public static class CrystalBolt{}
|
||||||
|
|
||||||
|
private void zap() {
|
||||||
|
spend( 1f );
|
||||||
|
|
||||||
|
Invisibility.dispel(this);
|
||||||
|
Char enemy = this.enemy;
|
||||||
|
if (hit( this, enemy, true )) {
|
||||||
|
|
||||||
|
int dmg = Random.NormalIntRange( 2, 8 );
|
||||||
|
dmg = Math.round(dmg * AscensionChallenge.statModifier(this));
|
||||||
|
enemy.damage( dmg, new CrystalBolt() );
|
||||||
|
|
||||||
|
if (!enemy.isAlive() && enemy == Dungeon.hero) {
|
||||||
|
Badges.validateDeathFromEnemyMagic();
|
||||||
|
Dungeon.fail( this );
|
||||||
|
GLog.n( Messages.get(this, "bolt_kill") );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enemy.sprite.showStatus( CharSprite.NEUTRAL, enemy.defenseVerb() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onZapComplete() {
|
||||||
|
zap();
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
public static final String SPRITE = "sprite";
|
public static final String SPRITE = "sprite";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+18
@@ -22,11 +22,15 @@
|
|||||||
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
||||||
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Healing;
|
||||||
import com.watabou.noosa.MovieClip;
|
import com.watabou.noosa.MovieClip;
|
||||||
import com.watabou.noosa.TextureFilm;
|
import com.watabou.noosa.TextureFilm;
|
||||||
|
|
||||||
public abstract class CrystalGuardianSprite extends MobSprite {
|
public abstract class CrystalGuardianSprite extends MobSprite {
|
||||||
|
|
||||||
|
private Animation crumple;
|
||||||
|
|
||||||
public CrystalGuardianSprite() {
|
public CrystalGuardianSprite() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -48,9 +52,23 @@ public abstract class CrystalGuardianSprite extends MobSprite {
|
|||||||
die = new MovieClip.Animation( 5, false );
|
die = new MovieClip.Animation( 5, false );
|
||||||
die.frames( frames, 11+c, 12+c, 13+c, 14+c, 15+c, 15+c );
|
die.frames( frames, 11+c, 12+c, 13+c, 14+c, 15+c, 15+c );
|
||||||
|
|
||||||
|
crumple = die.clone();
|
||||||
|
|
||||||
play( idle );
|
play( idle );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void crumple(){
|
||||||
|
play(crumple);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void link(Char ch) {
|
||||||
|
super.link(ch);
|
||||||
|
if (ch.buff(Healing.class) != null && ch.cooldown() > 0){
|
||||||
|
crumple();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract int texOffset();
|
protected abstract int texOffset();
|
||||||
|
|
||||||
public static class Blue extends CrystalGuardianSprite {
|
public static class Blue extends CrystalGuardianSprite {
|
||||||
|
|||||||
+20
@@ -22,6 +22,9 @@
|
|||||||
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
||||||
|
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalWisp;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
|
||||||
import com.watabou.noosa.TextureFilm;
|
import com.watabou.noosa.TextureFilm;
|
||||||
|
|
||||||
public abstract class CrystalWispSprite extends MobSprite {
|
public abstract class CrystalWispSprite extends MobSprite {
|
||||||
@@ -52,6 +55,23 @@ public abstract class CrystalWispSprite extends MobSprite {
|
|||||||
play( idle );
|
play( idle );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void zap( int cell ) {
|
||||||
|
|
||||||
|
super.zap( cell );
|
||||||
|
|
||||||
|
((CrystalWisp)ch).onZapComplete();
|
||||||
|
parent.add( new Beam.LightRay(center(), DungeonTilemap.raisedTileCenterToWorld(cell)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete( Animation anim ) {
|
||||||
|
if (anim == zap) {
|
||||||
|
idle();
|
||||||
|
}
|
||||||
|
super.onComplete( anim );
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract int texOffset();
|
protected abstract int texOffset();
|
||||||
|
|
||||||
public static class Blue extends CrystalWispSprite {
|
public static class Blue extends CrystalWispSprite {
|
||||||
|
|||||||
Reference in New Issue
Block a user