v0.8.0: New Minor Features:

- The game now flashes red when the hero is seriously injured, this replaces the old screen shake when injured effect
- Yog, ripper demons, and DM-300 are now less punishing to slower builds
- Yog's fist summons are now based on the levelgen seed
- velvet pouch can now hold goo blobs and metal shards
- wand of disintegration now breaks webs
-
This commit is contained in:
Evan Debenham 2020-03-26 14:57:25 -04:00
parent aa263b6f0a
commit 432c069691
7 changed files with 73 additions and 55 deletions

View File

@ -281,14 +281,6 @@ public abstract class Char extends Actor {
return true; return true;
} }
//TODO: consider revisiting this and shaking in more cases.
float shake = 0f;
if (enemy == Dungeon.hero)
shake = effectiveDamage / (enemy.HT / 4);
if (shake > 1f)
Camera.main.shake( GameMath.gate( 1, shake, 5), 0.3f );
enemy.damage( effectiveDamage, this ); enemy.damage( effectiveDamage, this );
if (buff(FireImbue.class) != null) if (buff(FireImbue.class) != null)

View File

@ -1045,7 +1045,18 @@ public class Hero extends Char {
dmg -= AntiMagic.drRoll(belongings.armor.buffedLvl()); dmg -= AntiMagic.drRoll(belongings.armor.buffedLvl());
} }
int preHP = HP + shielding();
super.damage( dmg, src ); super.damage( dmg, src );
int effectiveDamage = preHP - (HP + shielding());
//flash red when hit for 1/4 of your remaining HP or higher.
// Intensity increases the more injured the player is.
if (preHP > 0 && effectiveDamage >= preHP/4f){
//08%/11%/16%/33% intensity at
//75%/50%/25%/00% health
float divisor = 3 + 12*((HP + shielding()) / (float)(HT + shielding()));
GameScene.flash( (int)(0xFF/divisor) << 16 );
}
} }
public void checkVisibleMobs() { public void checkVisibleMobs() {

View File

@ -63,6 +63,7 @@ import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.Camera; import com.watabou.noosa.Camera;
import com.watabou.noosa.audio.Sample; import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Bundle; import com.watabou.utils.Bundle;
import com.watabou.utils.GameMath;
import com.watabou.utils.PathFinder; import com.watabou.utils.PathFinder;
import com.watabou.utils.Random; import com.watabou.utils.Random;
import com.watabou.utils.RectF; import com.watabou.utils.RectF;
@ -393,10 +394,11 @@ public class NewDM300 extends Mob {
pos++; pos++;
continue; continue;
} }
if (!Dungeon.level.solid[pos] && pos != safeCell && Random.Int(Dungeon.level.distance(rockCenter, pos)) == 0) {
GameScene.add(Blob.seed(pos, 1, FallingRocks.class));
}
//add rock cell to pos, if it is not solid, and isn't the safecell //add rock cell to pos, if it is not solid, and isn't the safecell
if (!Dungeon.level.solid[pos] && pos != safeCell && Random.Int(Dungeon.level.distance(rockCenter, pos)) == 0) {
//don't want to overly punish players with slow move or attack speed
GameScene.add(Blob.seed(pos, (int)GameMath.gate(TICK, (float)Math.ceil(target.cooldown()), 3*TICK), FallingRocks.class));
}
pos++; pos++;
} }
} }

View File

@ -37,6 +37,7 @@ import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.audio.Sample; import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Bundle; import com.watabou.utils.Bundle;
import com.watabou.utils.Callback; import com.watabou.utils.Callback;
import com.watabou.utils.GameMath;
import com.watabou.utils.PathFinder; import com.watabou.utils.PathFinder;
import com.watabou.utils.Random; import com.watabou.utils.Random;
@ -209,7 +210,8 @@ public class RipperDemon extends Mob {
if (b.collisionPos == targetPos){ if (b.collisionPos == targetPos){
//get ready to leap //get ready to leap
leapPos = targetPos; leapPos = targetPos;
spend(TICK); //don't want to overly punish players with slow move or attack speed
spend(GameMath.gate(TICK, enemy.cooldown(), 3*TICK));
if (Dungeon.level.heroFOV[pos]){ if (Dungeon.level.heroFOV[pos]){
GLog.w(Messages.get(RipperDemon.this, "leap")); GLog.w(Messages.get(RipperDemon.this, "leap"));
sprite.parent.addToBack(new TargetedCell(leapPos, 0xFF0000)); sprite.parent.addToBack(new TargetedCell(leapPos, 0xFF0000));

View File

@ -51,6 +51,7 @@ import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar; import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.utils.Bundle; import com.watabou.utils.Bundle;
import com.watabou.utils.GameMath;
import com.watabou.utils.PathFinder; import com.watabou.utils.PathFinder;
import com.watabou.utils.Random; import com.watabou.utils.Random;
import com.watabou.utils.Reflection; import com.watabou.utils.Reflection;
@ -87,10 +88,12 @@ public class YogDzewa extends Mob {
private ArrayList<Class> fistSummons = new ArrayList<>(); private ArrayList<Class> fistSummons = new ArrayList<>();
{ {
fistSummons.add(Random.Int(2) == 0 ? YogFist.Burning.class : YogFist.Soiled.class); Random.pushGenerator(Dungeon.seedCurDepth());
fistSummons.add(Random.Int(2) == 0 ? YogFist.Rotting.class : YogFist.Rusted.class); fistSummons.add(Random.Int(2) == 0 ? YogFist.Burning.class : YogFist.Soiled.class);
fistSummons.add(Random.Int(2) == 0 ? YogFist.Bright.class : YogFist.Dark.class); fistSummons.add(Random.Int(2) == 0 ? YogFist.Rotting.class : YogFist.Rusted.class);
Random.shuffle(fistSummons); fistSummons.add(Random.Int(2) == 0 ? YogFist.Bright.class : YogFist.Dark.class);
Random.shuffle(fistSummons);
Random.popGenerator();
} }
private static final int SUMMON_DECK_SIZE = 4; private static final int SUMMON_DECK_SIZE = 4;
@ -130,38 +133,41 @@ public class YogDzewa extends Mob {
boolean terrainAffected = false; boolean terrainAffected = false;
HashSet<Char> affected = new HashSet<>(); HashSet<Char> affected = new HashSet<>();
for (int i : targetedCells){ //delay fire on a rooted hero
Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP); if (!Dungeon.hero.rooted) {
//shoot beams for (int i : targetedCells) {
sprite.parent.add(new Beam.DeathRay(sprite.center(), DungeonTilemap.raisedTileCenterToWorld(b.collisionPos))); Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP);
for (int p : b.path){ //shoot beams
Char ch = Actor.findChar(p); sprite.parent.add(new Beam.DeathRay(sprite.center(), DungeonTilemap.raisedTileCenterToWorld(b.collisionPos)));
if (ch != null && ch.alignment != alignment){ for (int p : b.path) {
affected.add(ch); Char ch = Actor.findChar(p);
} if (ch != null && ch.alignment != alignment) {
if (Dungeon.level.flamable[p]){ affected.add(ch);
Dungeon.level.destroy( p ); }
GameScene.updateMap( p ); if (Dungeon.level.flamable[p]) {
terrainAffected = true; Dungeon.level.destroy(p);
GameScene.updateMap(p);
terrainAffected = true;
}
} }
} }
} if (terrainAffected) {
if (terrainAffected){ Dungeon.observe();
Dungeon.observe(); }
} for (Char ch : affected) {
for (Char ch : affected){ ch.damage(Random.NormalIntRange(20, 40), new Eye.DeathGaze());
ch.damage(Random.NormalIntRange(20, 40), new Eye.DeathGaze());
if (Dungeon.level.heroFOV[pos]) { if (Dungeon.level.heroFOV[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(Char.class, "kill", name()) ); GLog.n(Messages.get(Char.class, "kill", name()));
}
} }
targetedCells.clear();
} }
targetedCells.clear();
if (abilityCooldown <= 0){ if (abilityCooldown <= 0){
@ -200,18 +206,15 @@ public class YogDzewa extends Mob {
} }
} }
//wait extra time to let a crippled/rooted hero evade //don't want to overly punish players with slow move or attack speed
if (Dungeon.hero.buff(Cripple.class) != null){ spend(GameMath.gate(TICK, Dungeon.hero.cooldown(), 3*TICK));
spend(TICK);
} else if (Dungeon.hero.buff(Roots.class) != null){
spend(Dungeon.hero.buff(Roots.class).cooldown());
}
Dungeon.hero.interrupt(); Dungeon.hero.interrupt();
abilityCooldown += Random.NormalFloat(MIN_ABILITY_CD, MAX_ABILITY_CD); abilityCooldown += Random.NormalFloat(MIN_ABILITY_CD, MAX_ABILITY_CD);
abilityCooldown -= phase; abilityCooldown -= phase;
} else {
spend(TICK);
} }
while (summonCooldown <= 0){ while (summonCooldown <= 0){
@ -257,7 +260,6 @@ public class YogDzewa extends Mob {
summonCooldown = 3; summonCooldown = 3;
} }
spend(TICK);
return true; return true;
} }

View File

@ -22,6 +22,8 @@
package com.shatteredpixel.shatteredpixeldungeon.items.bags; package com.shatteredpixel.shatteredpixeldungeon.items.bags;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.quest.GooBlob;
import com.shatteredpixel.shatteredpixeldungeon.items.quest.MetalShard;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.Runestone; import com.shatteredpixel.shatteredpixeldungeon.items.stones.Runestone;
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant; import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
@ -36,7 +38,8 @@ public class VelvetPouch extends Bag {
@Override @Override
public boolean grab( Item item ) { public boolean grab( Item item ) {
return item instanceof Plant.Seed || item instanceof Runestone; return item instanceof Plant.Seed || item instanceof Runestone
|| item instanceof GooBlob || item instanceof MetalShard;
} }
@Override @Override

View File

@ -24,6 +24,8 @@ package com.shatteredpixel.shatteredpixeldungeon.items.wands;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Web;
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam; import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PurpleParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PurpleParticle;
@ -65,6 +67,8 @@ public class WandOfDisintegration extends DamageWand {
ArrayList<Char> chars = new ArrayList<>(); ArrayList<Char> chars = new ArrayList<>();
Blob web = Dungeon.level.blobs.get(Web.class);
int terrainPassed = 2, terrainBonus = 0; int terrainPassed = 2, terrainBonus = 0;
for (int c : beam.subPath(1, maxDistance)) { for (int c : beam.subPath(1, maxDistance)) {
@ -79,6 +83,11 @@ public class WandOfDisintegration extends DamageWand {
chars.add( ch ); chars.add( ch );
} }
if (Dungeon.level.solid[c]) {
terrainPassed++;
if (web != null) web.clear(c);
}
if (Dungeon.level.flamable[c]) { if (Dungeon.level.flamable[c]) {
Dungeon.level.destroy( c ); Dungeon.level.destroy( c );
@ -87,9 +96,6 @@ public class WandOfDisintegration extends DamageWand {
} }
if (Dungeon.level.solid[c])
terrainPassed++;
CellEmitter.center( c ).burst( PurpleParticle.BURST, Random.IntRange( 1, 2 ) ); CellEmitter.center( c ).burst( PurpleParticle.BURST, Random.IntRange( 1, 2 ) );
} }