v0.8.0: redesigned cave spinners
This commit is contained in:
parent
1bc5845e77
commit
c68f27c774
|
@ -28,39 +28,59 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.WebParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
|
||||
public class Web extends Blob {
|
||||
|
||||
{
|
||||
//acts before the hero, to ensure terrain is adjusted correctly
|
||||
actPriority = HERO_PRIO+1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evolve() {
|
||||
|
||||
int cell;
|
||||
|
||||
Level l = Dungeon.level;
|
||||
for (int i = area.left; i < area.right; i++){
|
||||
for (int j = area.top; j < area.bottom; j++){
|
||||
cell = i + j*Dungeon.level.width();
|
||||
cell = i + j*l.width();
|
||||
off[cell] = cur[cell] > 0 ? cur[cell] - 1 : 0;
|
||||
|
||||
if (off[cell] > 0) {
|
||||
volume += off[cell];
|
||||
|
||||
volume += off[cell];
|
||||
|
||||
Char ch = Actor.findChar( cell );
|
||||
if (ch != null && !ch.isImmune(this.getClass())) {
|
||||
Buff.prolong( ch, Roots.class, TICK );
|
||||
}
|
||||
}
|
||||
l.solid[cell] = off[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//affects characters as they step on it. See Level.OccupyCell and Level.PressCell
|
||||
public static void affectChar( Char ch ){
|
||||
Buff.prolong( ch, Roots.class, 5f );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void use( BlobEmitter emitter ) {
|
||||
super.use( emitter );
|
||||
|
||||
emitter.pour( WebParticle.FACTORY, 0.4f );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(int cell) {
|
||||
super.clear(cell);
|
||||
Level l = Dungeon.level;
|
||||
l.solid[cell] = cur[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fullyClear() {
|
||||
super.fullyClear();
|
||||
Dungeon.level.buildFlagMaps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tileDesc() {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Web;
|
||||
|
@ -28,8 +29,10 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.MysteryMeat;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.SpinnerSprite;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Spinner extends Mob {
|
||||
|
@ -38,7 +41,7 @@ public class Spinner extends Mob {
|
|||
spriteClass = SpinnerSprite.class;
|
||||
|
||||
HP = HT = 50;
|
||||
defenseSkill = 14;
|
||||
defenseSkill = 17;
|
||||
|
||||
EXP = 9;
|
||||
maxLvl = 17;
|
||||
|
@ -56,21 +59,35 @@ public class Spinner extends Mob {
|
|||
|
||||
@Override
|
||||
public int attackSkill(Char target) {
|
||||
return 20;
|
||||
return 22;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drRoll() {
|
||||
return Random.NormalIntRange(0, 6);
|
||||
}
|
||||
|
||||
|
||||
private int webCoolDown = 0;
|
||||
private int lastEnemyPos = -1;
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
boolean result = super.act();
|
||||
|
||||
|
||||
webCoolDown--;
|
||||
if (shotWebVisually){
|
||||
result = shotWebVisually = false;
|
||||
} else {
|
||||
if (enemy != null && enemySeen) {
|
||||
lastEnemyPos = enemy.pos;
|
||||
} else {
|
||||
lastEnemyPos = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == FLEEING && buff( Terror.class ) == null &&
|
||||
enemy != null && enemySeen && enemy.buff( Poison.class ) == null) {
|
||||
state = HUNTING;
|
||||
state = HUNTING;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -80,20 +97,88 @@ public class Spinner extends Mob {
|
|||
damage = super.attackProc( enemy, damage );
|
||||
if (Random.Int(2) == 0) {
|
||||
Buff.affect(enemy, Poison.class).set(Random.Int(7, 9) );
|
||||
webCoolDown = 0;
|
||||
state = FLEEING;
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
private boolean shotWebVisually = false;
|
||||
|
||||
@Override
|
||||
public void move(int step) {
|
||||
int curWeb = Blob.volumeAt(pos, Web.class);
|
||||
if (state == FLEEING && curWeb < 5) {
|
||||
GameScene.add(Blob.seed(pos, Random.Int(5, 7) - curWeb, Web.class));
|
||||
if (enemySeen && webCoolDown <= 0 && lastEnemyPos != -1){
|
||||
if (webPos() != -1){
|
||||
if (sprite != null && (sprite.visible || enemy.sprite.visible)) {
|
||||
sprite.zap( webPos() );
|
||||
shotWebVisually = true;
|
||||
} else {
|
||||
shootWeb();
|
||||
}
|
||||
}
|
||||
}
|
||||
super.move(step);
|
||||
}
|
||||
|
||||
public int webPos(){
|
||||
|
||||
Ballistica b;
|
||||
//aims web in direction enemy is moving, or between self and enemy if they aren't moving
|
||||
if (lastEnemyPos == enemy.pos){
|
||||
b = new Ballistica( enemy.pos, pos, Ballistica.WONT_STOP );
|
||||
} else {
|
||||
b = new Ballistica( lastEnemyPos, enemy.pos, Ballistica.WONT_STOP );
|
||||
}
|
||||
|
||||
int collisionIndex = 0;
|
||||
for (int i = 0; i < b.path.size(); i++){
|
||||
if (b.path.get(i) == enemy.pos){
|
||||
collisionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int webPos = b.path.get( collisionIndex+1 );
|
||||
|
||||
if (Dungeon.level.passable[webPos]){
|
||||
return webPos;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void shootWeb(){
|
||||
int webPos = webPos();
|
||||
if (webPos != enemy.pos && webPos != -1){
|
||||
int i;
|
||||
for ( i = 0; i < PathFinder.CIRCLE8.length; i++){
|
||||
if ((enemy.pos + PathFinder.CIRCLE8[i]) == webPos){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//spread to the tile hero was moving towards and the two adjacent ones
|
||||
int leftPos = enemy.pos + PathFinder.CIRCLE8[left(i)];
|
||||
int rightPos = enemy.pos + PathFinder.CIRCLE8[right(i)];
|
||||
|
||||
if (Dungeon.level.passable[leftPos]) GameScene.add(Blob.seed(leftPos, 20, Web.class));
|
||||
if (Dungeon.level.passable[webPos]) GameScene.add(Blob.seed(webPos, 20, Web.class));
|
||||
if (Dungeon.level.passable[rightPos])GameScene.add(Blob.seed(rightPos, 20, Web.class));
|
||||
|
||||
webCoolDown = 10;
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
private int left(int direction){
|
||||
return direction == 0 ? 7 : direction-1;
|
||||
}
|
||||
|
||||
private int right(int direction){
|
||||
return direction == 7 ? 0 : direction+1;
|
||||
}
|
||||
|
||||
{
|
||||
resistances.add(Poison.class);
|
||||
|
|
|
@ -60,6 +60,6 @@ public class WebParticle extends PixelParticle {
|
|||
|
||||
float p = left / lifespan;
|
||||
am = p < 0.5f ? p : 1 - p;
|
||||
scale.y = 16 + p * 8;
|
||||
scale.y = 12 + p * 6;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.SmokeScreen;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Web;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.WellWater;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Awareness;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness;
|
||||
|
@ -37,6 +38,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicalSight;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Shadows;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
|
||||
|
@ -586,7 +588,14 @@ public abstract class Level implements Bundlable {
|
|||
SmokeScreen s = (SmokeScreen)blobs.get(SmokeScreen.class);
|
||||
if (s != null && s.volume > 0){
|
||||
for (int i=0; i < length(); i++) {
|
||||
losBlocking[i] = losBlocking[i] || s.cur[i] > 0;
|
||||
losBlocking[i] = losBlocking[i] || s.cur[i] > 0;
|
||||
}
|
||||
}
|
||||
|
||||
Web w = (Web) blobs.get(Web.class);
|
||||
if (w != null && w.volume > 0){
|
||||
for (int i=0; i < length(); i++) {
|
||||
solid[i] = solid[i] || w.cur[i] > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -770,6 +779,11 @@ public abstract class Level implements Bundlable {
|
|||
}
|
||||
|
||||
public void occupyCell( Char ch ){
|
||||
if (!ch.isImmune(Web.class) && Blob.volumeAt(ch.pos, Web.class) > 0){
|
||||
blobs.get(Web.class).clear(ch.pos);
|
||||
Web.affectChar( ch );
|
||||
}
|
||||
|
||||
if (!ch.flying){
|
||||
|
||||
if (pit[ch.pos]){
|
||||
|
@ -867,6 +881,10 @@ public abstract class Level implements Bundlable {
|
|||
if (plant != null) {
|
||||
plant.trigger();
|
||||
}
|
||||
|
||||
if (hard && Blob.volumeAt(cell, Web.class) > 0){
|
||||
blobs.get(Web.class).clear(cell);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFieldOfView( Char c, boolean[] fieldOfView ) {
|
||||
|
|
|
@ -23,8 +23,13 @@ package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
|||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Spinner;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
|
||||
import com.watabou.noosa.TextureFilm;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.watabou.utils.Callback;
|
||||
|
||||
//TODO improvements here
|
||||
public class SpinnerSprite extends MobSprite {
|
||||
|
||||
public SpinnerSprite() {
|
||||
|
@ -45,6 +50,8 @@ public class SpinnerSprite extends MobSprite {
|
|||
attack = new Animation( 12, false );
|
||||
attack.frames( frames, 0, 4, 5, 0 );
|
||||
|
||||
zap = attack.clone();
|
||||
|
||||
die = new Animation( 12, false );
|
||||
die.frames( frames, 6, 7, 8, 9 );
|
||||
|
||||
|
@ -57,6 +64,32 @@ public class SpinnerSprite extends MobSprite {
|
|||
if (parent != null) parent.sendToBack(this);
|
||||
renderShadow = false;
|
||||
}
|
||||
|
||||
public void zap( int cell ) {
|
||||
|
||||
turnTo( ch.pos , cell );
|
||||
play( zap );
|
||||
|
||||
MagicMissile.boltFromChar( parent,
|
||||
MagicMissile.MAGIC_MISSILE,
|
||||
this,
|
||||
cell,
|
||||
new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
((Spinner)ch).shootWeb();
|
||||
}
|
||||
} );
|
||||
Sample.INSTANCE.play( Assets.SND_MISS );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete( Animation anim ) {
|
||||
if (anim == zap) {
|
||||
play( run );
|
||||
}
|
||||
super.onComplete( anim );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int blood() {
|
||||
|
|
|
@ -39,7 +39,7 @@ actors.blobs.waterofhealth.desc=Power of health radiates from the water of this
|
|||
|
||||
actors.blobs.wateroftransmutation.desc=Power of change radiates from the water of this well. Throw an item into the well to turn it into something else.
|
||||
|
||||
actors.blobs.web.desc=Everything is covered with a thick web here.
|
||||
actors.blobs.web.desc=A thick web is covering everything here. Anything that touches or is thrown though the web will break it, but will also be stuck in place.
|
||||
|
||||
|
||||
|
||||
|
@ -596,7 +596,7 @@ actors.mobs.snake.name=sewer snake
|
|||
actors.mobs.snake.desc=These oversized serpents are capable of quickly slithering around blows, making them quite hard to hit. Magical attacks or surprise attacks are capable of catching them off-guard however.\n\nYou can perform a surprise attack by attacking while out of the snake's vision. One way is to let a snake chase you through a doorway and then _strike just as it moves into the door._
|
||||
|
||||
actors.mobs.spinner.name=cave spinner
|
||||
actors.mobs.spinner.desc=These greenish furry cave spiders try to avoid direct combat, preferring to wait in the distance while their victim, entangled in the spinner's excreted cobweb, slowly dies from their poisonous bite.
|
||||
actors.mobs.spinner.desc=These greenish furry cave spiders try to avoid direct combat. Instead they prefer to wait in the distance while their victim struggles in their excreted cobweb, slowly dieing from their poisonous bite. They are capable of shooting their webs great distances, and will try to block whatever path their prey is taking.
|
||||
|
||||
actors.mobs.statue.name=animated statue
|
||||
actors.mobs.statue.def_verb=blocked
|
||||
|
|
Loading…
Reference in New Issue
Block a user