v0.4.1: reworked evil eyes
This commit is contained in:
parent
52fc2b1a7d
commit
093635c454
|
@ -31,11 +31,14 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Dewdrop;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfDisintegration;
|
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfDisintegration;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Grim;
|
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Grim;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Vampiric;
|
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Vampiric;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.EyeSprite;
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.EyeSprite;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||||
|
import com.watabou.utils.Bundle;
|
||||||
import com.watabou.utils.Random;
|
import com.watabou.utils.Random;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -53,12 +56,24 @@ public class Eye extends Mob {
|
||||||
maxLvl = 25;
|
maxLvl = 25;
|
||||||
|
|
||||||
flying = true;
|
flying = true;
|
||||||
|
|
||||||
|
HUNTING = new Hunting();
|
||||||
|
|
||||||
loot = new Dewdrop();
|
loot = new Dewdrop();
|
||||||
lootChance = 0.5f;
|
lootChance = 0.5f;
|
||||||
|
|
||||||
properties.add(Property.DEMONIC);
|
properties.add(Property.DEMONIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int damageRoll() {
|
||||||
|
return Random.NormalIntRange(20, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int attackSkill( Char target ) {
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int drRoll() {
|
public int drRoll() {
|
||||||
|
@ -66,65 +81,89 @@ public class Eye extends Mob {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Ballistica beam;
|
private Ballistica beam;
|
||||||
|
private int beamCooldown;
|
||||||
|
public boolean beamCharged;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canAttack( Char enemy ) {
|
protected boolean canAttack( Char enemy ) {
|
||||||
|
|
||||||
beam = new Ballistica( pos, enemy.pos, Ballistica.STOP_TERRAIN);
|
|
||||||
|
|
||||||
return beam.subPath(1, beam.dist).contains(enemy.pos);
|
if (beamCooldown == 0) {
|
||||||
|
Ballistica aim = new Ballistica(pos, enemy.pos, Ballistica.STOP_TERRAIN);
|
||||||
|
|
||||||
|
if (enemy.invisible == 0 && aim.subPath(1, aim.dist).contains(enemy.pos)){
|
||||||
|
beam = aim;
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
//if the beam is charged, it has to attack, will aim at previous location of hero.
|
||||||
|
return beamCharged;
|
||||||
|
} else
|
||||||
|
return super.canAttack(enemy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int attackSkill( Char target ) {
|
protected boolean act() {
|
||||||
return 30;
|
if (beamCooldown > 0)
|
||||||
}
|
beamCooldown--;
|
||||||
|
return super.act();
|
||||||
@Override
|
|
||||||
protected float attackDelay() {
|
|
||||||
return 1.6f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doAttack( Char enemy ) {
|
protected boolean doAttack( Char enemy ) {
|
||||||
|
|
||||||
spend( attackDelay() );
|
if (beamCooldown > 0) {
|
||||||
|
return super.doAttack(enemy);
|
||||||
boolean rayVisible = false;
|
} else if (!beamCharged){
|
||||||
|
((EyeSprite)sprite).charge( enemy.pos );
|
||||||
for (int i : beam.subPath(0, beam.dist)) {
|
spend( attackDelay()*2f );
|
||||||
if (Dungeon.visible[i]) {
|
beamCharged = true;
|
||||||
rayVisible = true;
|
return true;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
spend( attackDelay() );
|
||||||
|
|
||||||
|
if (Dungeon.visible[pos]) {
|
||||||
|
sprite.zap( beam.collisionPos );
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
deathGaze();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rayVisible) {
|
|
||||||
sprite.attack( beam.collisionPos );
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
attack( enemy );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void deathGaze(){
|
||||||
public boolean attack( Char enemy ) {
|
if (!beamCharged || beamCooldown > 0 || beam == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
beamCharged = false;
|
||||||
|
beamCooldown = Random.IntRange(3, 6);
|
||||||
|
|
||||||
|
boolean terrainAffected = false;
|
||||||
|
|
||||||
for (int pos : beam.subPath(1, beam.dist)) {
|
for (int pos : beam.subPath(1, beam.dist)) {
|
||||||
|
|
||||||
|
if (Level.flamable[pos]) {
|
||||||
|
|
||||||
|
Dungeon.level.destroy( pos );
|
||||||
|
GameScene.updateMap( pos );
|
||||||
|
terrainAffected = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Char ch = Actor.findChar( pos );
|
Char ch = Actor.findChar( pos );
|
||||||
if (ch == null) {
|
if (ch == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hit( this, ch, true )) {
|
if (hit( this, ch, true )) {
|
||||||
ch.damage( Random.NormalIntRange( 14, 20 ), this );
|
ch.damage( Random.NormalIntRange( 30, 40 ), this );
|
||||||
|
|
||||||
if (Dungeon.visible[pos]) {
|
if (Dungeon.visible[pos]) {
|
||||||
ch.sprite.flash();
|
ch.sprite.flash();
|
||||||
CellEmitter.center( pos ).burst( PurpleParticle.BURST, Random.IntRange( 1, 2 ) );
|
CellEmitter.center( pos ).burst( PurpleParticle.BURST, Random.IntRange( 1, 2 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ch.isAlive() && ch == Dungeon.hero) {
|
if (!ch.isAlive() && ch == Dungeon.hero) {
|
||||||
Dungeon.fail( getClass() );
|
Dungeon.fail( getClass() );
|
||||||
GLog.n( Messages.get(this, "deathgaze_kill") );
|
GLog.n( Messages.get(this, "deathgaze_kill") );
|
||||||
|
@ -133,10 +172,37 @@ public class Eye extends Mob {
|
||||||
ch.sprite.showStatus( CharSprite.NEUTRAL, ch.defenseVerb() );
|
ch.sprite.showStatus( CharSprite.NEUTRAL, ch.defenseVerb() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (terrainAffected) {
|
||||||
|
Dungeon.observe();
|
||||||
|
}
|
||||||
|
|
||||||
|
beam = null;
|
||||||
|
sprite.idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String BEAM_TARGET = "beamTarget";
|
||||||
|
private static final String BEAM_COOLDOWN = "beamCooldown";
|
||||||
|
private static final String BEAM_CHARGED = "beamCharged";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeInBundle(Bundle bundle) {
|
||||||
|
super.storeInBundle(bundle);
|
||||||
|
if (beam != null)
|
||||||
|
bundle.put( BEAM_TARGET, beam.collisionPos);
|
||||||
|
bundle.put( BEAM_COOLDOWN, beamCooldown );
|
||||||
|
bundle.put( BEAM_CHARGED, beamCharged );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreFromBundle(Bundle bundle) {
|
||||||
|
super.restoreFromBundle(bundle);
|
||||||
|
if (bundle.contains(BEAM_TARGET))
|
||||||
|
beam = new Ballistica(pos, bundle.getInt(BEAM_TARGET), Ballistica.STOP_TERRAIN);
|
||||||
|
beamCooldown = bundle.getInt(BEAM_COOLDOWN);
|
||||||
|
beamCharged = bundle.getBoolean(BEAM_CHARGED);
|
||||||
|
}
|
||||||
|
|
||||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<>();
|
private static final HashSet<Class<?>> RESISTANCES = new HashSet<>();
|
||||||
static {
|
static {
|
||||||
RESISTANCES.add( WandOfDisintegration.class );
|
RESISTANCES.add( WandOfDisintegration.class );
|
||||||
|
@ -158,4 +224,14 @@ public class Eye extends Mob {
|
||||||
public HashSet<Class<?>> immunities() {
|
public HashSet<Class<?>> immunities() {
|
||||||
return IMMUNITIES;
|
return IMMUNITIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class Hunting extends Mob.Hunting{
|
||||||
|
@Override
|
||||||
|
public boolean act(boolean enemyInFOV, boolean justAlerted) {
|
||||||
|
//always attack if the beam is charged, no exceptions
|
||||||
|
if (beamCharged)
|
||||||
|
enemyInFOV = true;
|
||||||
|
return super.act(enemyInFOV, justAlerted);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,17 @@ public class MagicMissile extends Emitter {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static final Emitter.Factory ATTRACTING = new Factory() {
|
||||||
|
@Override
|
||||||
|
public void emit( Emitter emitter, int index, float x, float y ) {
|
||||||
|
((MagicParticle)emitter.recycle( MagicParticle.class )).resetAttract( x, y );
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean lightMode() {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
public MagicParticle() {
|
public MagicParticle() {
|
||||||
super();
|
super();
|
||||||
|
@ -210,6 +221,17 @@ public class MagicMissile extends Emitter {
|
||||||
|
|
||||||
left = lifespan;
|
left = lifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resetAttract( float x, float y) {
|
||||||
|
revive();
|
||||||
|
|
||||||
|
//size = 8;
|
||||||
|
left = lifespan;
|
||||||
|
|
||||||
|
speed.polar( Random.Float( PointF.PI2 ), Random.Float( 16, 32 ) );
|
||||||
|
this.x = x - speed.x * lifespan;
|
||||||
|
this.y = y - speed.y * lifespan;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
|
|
|
@ -384,7 +384,7 @@ actors.mobs.elemental.desc=Wandering fire elementals are a byproduct of summonin
|
||||||
|
|
||||||
actors.mobs.eye.name=evil eye
|
actors.mobs.eye.name=evil eye
|
||||||
actors.mobs.eye.deathgaze_kill=The deathgaze killed you...
|
actors.mobs.eye.deathgaze_kill=The deathgaze killed you...
|
||||||
actors.mobs.eye.desc=One of this demon's other names is "orb of hatred", because when it sees an enemy, it uses its deathgaze recklessly, often ignoring its allies and wounding them.
|
actors.mobs.eye.desc=Evil Eyes are floating balls of pent up demonic energy. While they are capable of melee combat, their true strength comes from their magic.\n\nAfter building energy for a short time an Evil Eye will unleash a devastating beam of energy called the _deathgaze._ Anything within the Evil Eye's sights will take tremendous damage, wise adventurers will run for cover.
|
||||||
|
|
||||||
actors.mobs.fetidrat.name=fetid rat
|
actors.mobs.fetidrat.name=fetid rat
|
||||||
actors.mobs.fetidrat.desc=Something is clearly wrong with this rat. Its greasy black fur and rotting skin are very different from the healthy rats you've seen previously. It's pale green eyes make it seem especially menacing.\n\nThe rat carries a cloud of horrible stench with it, it's overpoweringly strong up close.\n\nDark ooze dribbles from the rat's mouth, it eats through the floor but seems to dissolve in water.
|
actors.mobs.fetidrat.desc=Something is clearly wrong with this rat. Its greasy black fur and rotting skin are very different from the healthy rats you've seen previously. It's pale green eyes make it seem especially menacing.\n\nThe rat carries a cloud of horrible stench with it, it's overpoweringly strong up close.\n\nDark ooze dribbles from the rat's mouth, it eats through the floor but seems to dissolve in water.
|
||||||
|
|
|
@ -23,12 +23,19 @@ package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap;
|
import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Eye;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
|
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
|
||||||
import com.watabou.noosa.TextureFilm;
|
import com.watabou.noosa.TextureFilm;
|
||||||
|
import com.watabou.noosa.particles.Emitter;
|
||||||
|
|
||||||
public class EyeSprite extends MobSprite {
|
public class EyeSprite extends MobSprite {
|
||||||
|
|
||||||
private int attackPos;
|
private int zapPos;
|
||||||
|
|
||||||
|
private Animation charging;
|
||||||
|
private Emitter chargeParticles;
|
||||||
|
|
||||||
public EyeSprite() {
|
public EyeSprite() {
|
||||||
super();
|
super();
|
||||||
|
@ -39,33 +46,70 @@ public class EyeSprite extends MobSprite {
|
||||||
|
|
||||||
idle = new Animation( 8, true );
|
idle = new Animation( 8, true );
|
||||||
idle.frames( frames, 0, 1, 2 );
|
idle.frames( frames, 0, 1, 2 );
|
||||||
|
|
||||||
|
charging = new Animation( 12, true);
|
||||||
|
charging.frames( frames, 3, 4 );
|
||||||
|
|
||||||
|
chargeParticles = centerEmitter();
|
||||||
|
chargeParticles.autoKill = false;
|
||||||
|
chargeParticles.pour(MagicMissile.MagicParticle.ATTRACTING, 0.05f);
|
||||||
|
chargeParticles.on = false;
|
||||||
|
|
||||||
run = new Animation( 12, true );
|
run = new Animation( 12, true );
|
||||||
run.frames( frames, 5, 6 );
|
run.frames( frames, 5, 6 );
|
||||||
|
|
||||||
attack = new Animation( 8, false );
|
attack = new Animation( 8, false );
|
||||||
attack.frames( frames, 4, 3 );
|
attack.frames( frames, 4, 3 );
|
||||||
|
zap = attack.clone();
|
||||||
|
|
||||||
die = new Animation( 8, false );
|
die = new Animation( 8, false );
|
||||||
die.frames( frames, 7, 8, 9 );
|
die.frames( frames, 7, 8, 9 );
|
||||||
|
|
||||||
play( idle );
|
play( idle );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attack( int pos ) {
|
public void link(Char ch) {
|
||||||
attackPos = pos;
|
super.link(ch);
|
||||||
super.attack( pos );
|
if (((Eye)ch).beamCharged) play(charging);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
super.update();
|
||||||
|
chargeParticles.pos(center());
|
||||||
|
chargeParticles.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void charge( int pos ){
|
||||||
|
turnTo(ch.pos, pos);
|
||||||
|
play(charging);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void play(Animation anim) {
|
||||||
|
chargeParticles.on = anim == charging;
|
||||||
|
super.play(anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zap( int pos ) {
|
||||||
|
zapPos = pos;
|
||||||
|
super.zap( pos );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete( Animation anim ) {
|
public void onComplete( Animation anim ) {
|
||||||
super.onComplete( anim );
|
super.onComplete( anim );
|
||||||
|
|
||||||
if (anim == attack) {
|
if (anim == zap) {
|
||||||
if (Dungeon.visible[ch.pos] || Dungeon.visible[attackPos]) {
|
if (Dungeon.visible[ch.pos] || Dungeon.visible[zapPos]) {
|
||||||
parent.add( new Beam.DeathRay( center(), DungeonTilemap.tileCenterToWorld( attackPos ) ) );
|
parent.add( new Beam.DeathRay( center(), DungeonTilemap.tileCenterToWorld( zapPos ) ) );
|
||||||
}
|
}
|
||||||
|
((Eye)ch).deathGaze();
|
||||||
|
ch.next();
|
||||||
|
} else if (anim == die){
|
||||||
|
chargeParticles.killAndErase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user