v3.3.0: movement and glyph improvements:

- hero move speed is now calculated based on destination tile
- added particles when glyphs affect movespeed
This commit is contained in:
Evan Debenham
2025-10-10 14:04:23 -04:00
parent e3b0614afc
commit aa32a58dbd
7 changed files with 55 additions and 10 deletions

View File

@@ -88,16 +88,20 @@ public class Emitter extends Group {
}
public void start( Factory factory, float interval, int quantity ) {
//by default the delay is random, up to the interval
startDelayed( factory, interval, quantity, Random.Float(interval));
}
public void startDelayed( Factory factory, float interval, int quantity, float delay ) {
this.factory = factory;
this.lightMode = factory.lightMode();
this.interval = interval;
this.quantity = quantity;
count = 0;
time = Random.Float( interval );
time = interval - delay;
on = true;
started = true;
}

View File

@@ -3,7 +3,7 @@ items.armor.curses.antientropy.name=%s of anti-entropy
items.armor.curses.antientropy.desc=The Anti-entropy curse works against the forces of the universe, pulling energy into the wearer and away from their surroundings. This briefly sets the wearer on fire, but freezes everything around them!
items.armor.curses.bulk.name=%s of bulk
items.armor.curses.bulk.desc=Armor of bulk looks larger and more imposing, but doesn't actually have enhanced defense. Even worse, the added size makes moving through doorways very difficult.
items.armor.curses.bulk.desc=Armor of bulk looks larger and more imposing, but doesn't actually have enhanced defense. Even worse, the added size makes moving into doorways very difficult.
items.armor.curses.corrosion.name=%s of corrosion
items.armor.curses.corrosion.desc=Armor of corrosion is capable of bursting with corrosive fluid, coating everything in the area with sticky acidic ooze.

View File

@@ -1812,14 +1812,14 @@ public class Hero extends Char {
if (step != -1) {
float delay = 1 / speed();
float delay = 1;
if (buff(GreaterHaste.class) != null){
delay = 0;
}
if (Dungeon.level.pit[step] && !Dungeon.level.solid[step]
&& (!flying || buff(Levitation.class) != null && buff(Levitation.class).detachesWithinDelay(delay))){
&& (!flying || buff(Levitation.class) != null && buff(Levitation.class).detachesWithinDelay(delay / speed()))){
if (!Chasm.jumpConfirmed){
Chasm.heroJump(this);
interrupt();
@@ -1843,7 +1843,7 @@ public class Hero extends Char {
sprite.move(pos, step);
move(step);
spend( delay );
spend( delay / speed() );
search(false);

View File

@@ -70,6 +70,8 @@ public class Speck extends Image {
public static final int STORM = 117;
public static final int INFERNO = 118;
public static final int BLIZZARD = 119;
public static final int YELLOW_LIGHT= 120;
public static final int BLUE_LIGHT = 121;
private static final int SIZE = 7;
@@ -115,6 +117,8 @@ public class Speck extends Image {
switch (type) {
case DISCOVER:
case RED_LIGHT:
case YELLOW_LIGHT:
case BLUE_LIGHT:
frame( film.get( LIGHT ) );
break;
case EVOKE:
@@ -204,11 +208,30 @@ public class Speck extends Image {
case RED_LIGHT:
tint(0xFFCC0000);
angle = Random.Float( 360 );
angularSpeed = 90;
lifespan = 1f;
break;
case LIGHT:
angle = Random.Float( 360 );
angularSpeed = 90;
lifespan = 1f;
break;
case YELLOW_LIGHT:
tint(0xFFDDDD00);
angle = Random.Float( 360 );
angularSpeed = 90;
lifespan = 1f;
break;
case BLUE_LIGHT:
tint(0xFF00CCFF);
angle = Random.Float( 360 );
angularSpeed = 90;
lifespan = 1f;
break;
case DISCOVER:
angle = Random.Float( 360 );
@@ -420,6 +443,8 @@ public class Speck extends Image {
break;
case RED_LIGHT:
case YELLOW_LIGHT:
case BLUE_LIGHT:
case LIGHT:
am = scale.set( p < 0.2f ? p * 5f : (1 - p) * 1.25f ).x;
break;

View File

@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.armor.curses;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
@@ -43,6 +44,9 @@ public class Bulk extends Armor.Glyph {
(Dungeon.level.map[owner.pos] != Terrain.DOOR && Dungeon.level.map[owner.pos] != Terrain.OPEN_DOOR )) {
return 1;
} else {
if (owner.sprite != null){
owner.sprite.emitter().startDelayed(ShadowParticle.UP, 0.02f, 5, 0.05f);
}
return 1/3f * genericProcChanceMultiplier(owner);
}
}

View File

@@ -23,8 +23,10 @@ package com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.watabou.utils.Random;
public class Flow extends Armor.Glyph {
@@ -40,6 +42,10 @@ public class Flow extends Armor.Glyph {
if (level == -1 || !Dungeon.level.water[owner.pos]){
return 1;
} else {
if (owner.sprite != null){
int particles = 2 + (int) Random.Float(1+level/2f);
owner.sprite.emitter().startDelayed(Speck.factory(Speck.BLUE_LIGHT), 0.02f, particles, 0.05f);
}
return (2f + 0.5f*level) * genericProcChanceMultiplier(owner);
}
}

View File

@@ -24,9 +24,11 @@ package com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
public class Swiftness extends Armor.Glyph {
@@ -44,7 +46,7 @@ public class Swiftness extends Armor.Glyph {
}
boolean enemyNear = false;
//for each enemy, check if they are adjacent, or within 2 tiles and an adjacent cell is open
//for each enemy, check if they are adjacent, or within 2 tiles and an adjacent cell is open or a door
for (Char ch : Actor.chars()){
if ( Dungeon.level.distance(ch.pos, owner.pos) <= 2 && owner.alignment != ch.alignment && ch.alignment != Char.Alignment.NEUTRAL){
if (Dungeon.level.adjacent(ch.pos, owner.pos)){
@@ -52,7 +54,7 @@ public class Swiftness extends Armor.Glyph {
break;
} else {
for (int i : PathFinder.NEIGHBOURS8){
if (Dungeon.level.adjacent(owner.pos+i, ch.pos) && !Dungeon.level.solid[owner.pos+i]){
if (Dungeon.level.adjacent(owner.pos+i, ch.pos) && (!Dungeon.level.solid[owner.pos+i] || Dungeon.level.passable[owner.pos+i])){
enemyNear = true;
break;
}
@@ -63,6 +65,10 @@ public class Swiftness extends Armor.Glyph {
if (enemyNear){
return 1;
} else {
if (owner.sprite != null){
int particles = 1 + (int)Random.Float(1+level/5f);
owner.sprite.emitter().startDelayed(Speck.factory(Speck.YELLOW_LIGHT), 0.02f, particles, 0.05f);
}
return (1.2f + 0.04f * level) * genericProcChanceMultiplier(owner);
}
}