v0.8.2c: big refactor to cursed wand effects, fixes various minor bugs

This commit is contained in:
Evan Debenham 2020-08-23 16:45:20 -04:00
parent 0a6127b843
commit 076b26302c
3 changed files with 181 additions and 243 deletions

View File

@ -44,7 +44,6 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ElementalSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ElementalSprite;
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.Random; import com.watabou.utils.Random;
import java.util.ArrayList; import java.util.ArrayList;
@ -305,22 +304,12 @@ public abstract class Elemental extends Mob {
@Override @Override
protected void meleeProc( Char enemy, int damage ) { protected void meleeProc( Char enemy, int damage ) {
CursedWand.cursedZap( null, this, new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT ), new Callback() { CursedWand.cursedEffect(null, this, enemy);
@Override
public void call() {
next();
}
} );
} }
@Override @Override
protected void rangedProc( Char enemy ) { protected void rangedProc( Char enemy ) {
CursedWand.cursedZap( null, this, new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT ), new Callback() { CursedWand.cursedEffect(null, this, enemy);
@Override
public void call() {
next();
}
} );
} }
} }

View File

@ -22,6 +22,7 @@
package com.shatteredpixel.shatteredpixeldungeon.items.wands; package com.shatteredpixel.shatteredpixeldungeon.items.wands;
import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
@ -69,6 +70,7 @@ import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.watabou.noosa.Game; import com.watabou.noosa.Game;
import com.watabou.noosa.audio.Sample; import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Callback; import com.watabou.utils.Callback;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random; import com.watabou.utils.Random;
import java.io.IOException; import java.io.IOException;
@ -78,152 +80,126 @@ import java.util.ArrayList;
public class CursedWand { public class CursedWand {
private static float COMMON_CHANCE = 0.6f; private static float COMMON_CHANCE = 0.6f;
private static float UNCOMMON_CHANCE = 0.3f; private static float UNCOMMON_CHANCE = 10.3f;
private static float RARE_CHANCE = 0.09f; private static float RARE_CHANCE = 0.09f;
private static float VERY_RARE_CHANCE = 0.01f; private static float VERY_RARE_CHANCE = 0.01f;
public static void cursedZap(final Item origin, final Char user, final Ballistica bolt, final Callback afterZap){ public static void cursedZap(final Item origin, final Char user, final Ballistica bolt, final Callback afterZap){
cursedFX(user, bolt, new Callback() {
@Override
public void call() {
if (cursedEffect(origin, user, bolt.collisionPos)){
if (afterZap != null) afterZap.call();
}
}
});
}
public static boolean cursedEffect(final Item origin, final Char user, final Char target){
return cursedEffect(origin, user, target.pos);
}
public static boolean cursedEffect(final Item origin, final Char user, final int targetPos){
switch (Random.chances(new float[]{COMMON_CHANCE, UNCOMMON_CHANCE, RARE_CHANCE, VERY_RARE_CHANCE})){ switch (Random.chances(new float[]{COMMON_CHANCE, UNCOMMON_CHANCE, RARE_CHANCE, VERY_RARE_CHANCE})){
case 0: case 0: default:
default: return commonEffect(origin, user, targetPos);
commonEffect(origin, user, bolt, afterZap);
break;
case 1: case 1:
uncommonEffect(origin, user, bolt, afterZap); return uncommonEffect(origin, user, targetPos);
break;
case 2: case 2:
rareEffect(origin, user, bolt, afterZap); return rareEffect(origin, user, targetPos);
break;
case 3: case 3:
veryRareEffect(origin, user, bolt, afterZap); return veryRareEffect(origin, user, targetPos);
break;
} }
} }
private static void commonEffect(final Item origin, final Char user, final Ballistica bolt, final Callback afterZap){ private static boolean commonEffect(final Item origin, final Char user, final int targetPos){
switch(Random.Int(4)){ switch(Random.Int(4)){
//anti-entropy //anti-entropy
case 0: case 0: default:
cursedFX(user, bolt, new Callback() { Char target = Actor.findChar(targetPos);
public void call() { if (Random.Int(2) == 0) {
Char target = Actor.findChar(bolt.collisionPos); if (target != null) Buff.affect(target, Burning.class).reignite(target);
switch (Random.Int(2)){
case 0:
if (target != null)
Buff.affect(target, Burning.class).reignite(target);
Buff.affect(user, Frost.class, Frost.DURATION); Buff.affect(user, Frost.class, Frost.DURATION);
break; } else {
case 1:
Buff.affect(user, Burning.class).reignite(user); Buff.affect(user, Burning.class).reignite(user);
if (target != null) if (target != null) Buff.affect(target, Frost.class, Frost.DURATION);
Buff.affect(target, Frost.class, Frost.DURATION);
break;
} }
afterZap.call(); return true;
}
});
break;
//spawns some regrowth //spawns some regrowth
case 1: case 1:
cursedFX(user, bolt, new Callback() { GameScene.add( Blob.seed(targetPos, 30, Regrowth.class));
public void call() { return true;
GameScene.add( Blob.seed(bolt.collisionPos, 30, Regrowth.class));
afterZap.call();
}
});
break;
//random teleportation //random teleportation
case 2: case 2:
switch(Random.Int(2)){ if(Random.Int(2) == 0) {
case 0: if (user != null && !user.properties().contains(Char.Property.IMMOVABLE)) {
ScrollOfTeleportation.teleportChar(user); ScrollOfTeleportation.teleportChar(user);
afterZap.call(); } else {
break; return cursedEffect(origin, user, targetPos);
case 1: }
cursedFX(user, bolt, new Callback() { } else {
public void call() { Char ch = Actor.findChar( targetPos );
Char ch = Actor.findChar( bolt.collisionPos );
if (ch != null && !ch.properties().contains(Char.Property.IMMOVABLE)) { if (ch != null && !ch.properties().contains(Char.Property.IMMOVABLE)) {
ScrollOfTeleportation.teleportChar(user); ScrollOfTeleportation.teleportChar(ch);
} else {
return cursedEffect(origin, user, targetPos);
} }
afterZap.call();
} }
}); return true;
break;
}
break;
//random gas at location //random gas at location
case 3: case 3:
cursedFX(user, bolt, new Callback() {
public void call() {
switch (Random.Int(3)) {
case 0:
GameScene.add( Blob.seed( bolt.collisionPos, 800, ConfusionGas.class ) );
break;
case 1:
GameScene.add( Blob.seed( bolt.collisionPos, 500, ToxicGas.class ) );
break;
case 2:
GameScene.add( Blob.seed( bolt.collisionPos, 200, ParalyticGas.class ) );
break;
}
Sample.INSTANCE.play( Assets.Sounds.GAS ); Sample.INSTANCE.play( Assets.Sounds.GAS );
afterZap.call(); switch (Random.Int(3)) {
case 0: default:
GameScene.add( Blob.seed( targetPos, 800, ConfusionGas.class ) );
return true;
case 1:
GameScene.add( Blob.seed( targetPos, 500, ToxicGas.class ) );
return true;
case 2:
GameScene.add( Blob.seed( targetPos, 200, ParalyticGas.class ) );
return true;
} }
});
break;
} }
} }
private static void uncommonEffect(final Item origin, final Char user, final Ballistica bolt, final Callback afterZap){ private static boolean uncommonEffect(final Item origin, final Char user, final int targetPos){
switch(Random.Int(4)){ switch(Random.Int(4)){
//Random plant //Random plant
case 0: case 0: default:
cursedFX(user, bolt, new Callback() { int pos = targetPos;
public void call() {
int pos = bolt.collisionPos; if (Dungeon.level.map[pos] != Terrain.ALCHEMY
//place the plant infront of an enemy so they walk into it. && !Dungeon.level.pit[pos]
if (Actor.findChar(pos) != null && bolt.dist > 1) { && Dungeon.level.traps.get(pos) == null
pos = bolt.path.get(bolt.dist - 1); && !Dungeon.isChallenged(Challenges.NO_HERBALISM)) {
Dungeon.level.plant((Plant.Seed) Generator.randomUsingDefaults(Generator.Category.SEED), pos);
} else {
return cursedEffect(origin, user, targetPos);
} }
if (pos == Terrain.EMPTY || return true;
pos == Terrain.EMBERS ||
pos == Terrain.EMPTY_DECO ||
pos == Terrain.GRASS ||
pos == Terrain.HIGH_GRASS ||
pos == Terrain.FURROWED_GRASS) {
Dungeon.level.plant((Plant.Seed) Generator.randomUsingDefaults(Generator.Category.SEED), pos);
}
afterZap.call();
}
});
break;
//Health transfer //Health transfer
case 1: case 1:
final Char target = Actor.findChar( bolt.collisionPos ); final Char target = Actor.findChar( targetPos );
if (target != null) { if (target != null) {
cursedFX(user, bolt, new Callback() {
public void call() {
int damage = Dungeon.depth * 2; int damage = Dungeon.depth * 2;
Char toHeal, toDamage; Char toHeal, toDamage;
switch (Random.Int(2)) { if (Random.Int(2) == 0){
case 0: default:
toHeal = user; toHeal = user;
toDamage = target; toDamage = target;
break; } else {
case 1:
toHeal = target; toHeal = target;
toDamage = user; toDamage = user;
break;
} }
toHeal.HP = Math.min(toHeal.HT, toHeal.HP + damage); toHeal.HP = Math.min(toHeal.HT, toHeal.HP + damage);
toHeal.sprite.emitter().burst(Speck.factory(Speck.HEALING), 3); toHeal.sprite.emitter().burst(Speck.factory(Speck.HEALING), 3);
@ -243,24 +219,15 @@ public class CursedWand {
} else { } else {
Sample.INSTANCE.play(Assets.Sounds.BURNING); Sample.INSTANCE.play(Assets.Sounds.BURNING);
} }
afterZap.call();
}
});
} else { } else {
GLog.i(Messages.get(CursedWand.class, "nothing")); return cursedEffect(origin, user, targetPos);
afterZap.call();
} }
break; return true;
//Bomb explosion //Bomb explosion
case 2: case 2:
cursedFX(user, bolt, new Callback() { new Bomb().explode(targetPos);
public void call() { return true;
new Bomb().explode(bolt.collisionPos);
afterZap.call();
}
});
break;
//shock and recharge //shock and recharge
case 3: case 3:
@ -268,27 +235,19 @@ public class CursedWand {
Buff.prolong(user, Recharging.class, Recharging.DURATION); Buff.prolong(user, Recharging.class, Recharging.DURATION);
ScrollOfRecharging.charge(user); ScrollOfRecharging.charge(user);
SpellSprite.show(user, SpellSprite.CHARGE); SpellSprite.show(user, SpellSprite.CHARGE);
afterZap.call(); return true;
break;
} }
} }
private static void rareEffect(final Item origin, final Char user, final Ballistica bolt, final Callback afterZap){ private static boolean rareEffect(final Item origin, final Char user, final int targetPos){
switch(Random.Int(4)){ switch(Random.Int(4)){
//sheep transformation //sheep transformation
case 0: case 0: default:
if (user != Dungeon.hero){
cursedZap(origin, user, bolt, afterZap);
return;
}
cursedFX(user, bolt, new Callback() { Char ch = Actor.findChar( targetPos );
public void call() { if (ch != null && !(ch instanceof Hero)
Char ch = Actor.findChar( bolt.collisionPos );
if (ch != null && ch != user
&& !ch.properties().contains(Char.Property.BOSS) && !ch.properties().contains(Char.Property.BOSS)
&& !ch.properties().contains(Char.Property.MINIBOSS)){ && !ch.properties().contains(Char.Property.MINIBOSS)){
Sheep sheep = new Sheep(); Sheep sheep = new Sheep();
@ -303,18 +262,18 @@ public class CursedWand {
Sample.INSTANCE.play(Assets.Sounds.PUFF); Sample.INSTANCE.play(Assets.Sounds.PUFF);
Sample.INSTANCE.play(Assets.Sounds.SHEEP); Sample.INSTANCE.play(Assets.Sounds.SHEEP);
} else { } else {
GLog.i(Messages.get(CursedWand.class, "nothing")); return cursedEffect(origin, user, targetPos);
} }
afterZap.call(); return true;
}
});
break;
//curses! //curses!
case 1: case 1:
if (user instanceof Hero) CursingTrap.curse( (Hero) user ); if (user instanceof Hero) {
afterZap.call(); CursingTrap.curse( (Hero) user );
break; } else {
return cursedEffect(origin, user, targetPos);
}
return true;
//inter-level teleportation //inter-level teleportation
case 2: case 2:
@ -340,22 +299,20 @@ public class CursedWand {
ScrollOfTeleportation.teleportChar(user); ScrollOfTeleportation.teleportChar(user);
} }
afterZap.call(); return true;
break;
//summon monsters //summon monsters
case 3: case 3:
new SummoningTrap().set( user.pos ).activate(); new SummoningTrap().set( targetPos ).activate();
afterZap.call(); return true;
break;
} }
} }
private static void veryRareEffect(final Item origin, final Char user, final Ballistica bolt, final Callback afterZap){ private static boolean veryRareEffect(final Item origin, final Char user, final int targetPos){
switch(Random.Int(4)){ switch(Random.Int(4)){
//great forest fire! //great forest fire!
case 0: case 0: default:
for (int i = 0; i < Dungeon.level.length(); i++){ for (int i = 0; i < Dungeon.level.length(); i++){
GameScene.add( Blob.seed(i, 15, Regrowth.class)); GameScene.add( Blob.seed(i, 15, Regrowth.class));
} }
@ -366,15 +323,29 @@ public class CursedWand {
Sample.INSTANCE.play(Assets.Sounds.TELEPORT); Sample.INSTANCE.play(Assets.Sounds.TELEPORT);
GLog.p(Messages.get(CursedWand.class, "grass")); GLog.p(Messages.get(CursedWand.class, "grass"));
GLog.w(Messages.get(CursedWand.class, "fire")); GLog.w(Messages.get(CursedWand.class, "fire"));
afterZap.call(); return true;
break;
//golden mimic //golden mimic
case 1: case 1:
cursedFX(user, bolt, new Callback() {
public void call() { Char ch = Actor.findChar(targetPos);
Mimic mimic = Mimic.spawnAt(bolt.collisionPos, new ArrayList<Item>(), GoldenMimic.class); int spawnCell = targetPos;
if (mimic != null) { if (ch != null){
ArrayList<Integer> candidates = new ArrayList<Integer>();
for (int n : PathFinder.NEIGHBOURS8) {
int cell = targetPos + n;
if (Dungeon.level.passable[cell] && Actor.findChar( cell ) == null) {
candidates.add( cell );
}
}
if (!candidates.isEmpty()){
spawnCell = Random.element(candidates);
} else {
return cursedEffect(origin, user, targetPos);
}
}
Mimic mimic = Mimic.spawnAt(spawnCell, new ArrayList<Item>(), GoldenMimic.class);
mimic.stopHiding(); mimic.stopHiding();
mimic.alignment = Char.Alignment.ENEMY; mimic.alignment = Char.Alignment.ENEMY;
Item reward; Item reward;
@ -388,29 +359,16 @@ public class CursedWand {
mimic.items.clear(); mimic.items.clear();
mimic.items.add(reward); mimic.items.add(reward);
GameScene.add(mimic); GameScene.add(mimic);
} else { return true;
GLog.i(Messages.get(CursedWand.class, "nothing"));
}
afterZap.call();
}
});
break;
//crashes the game, yes, really. //crashes the game, yes, really.
case 2: case 2:
if (user != Dungeon.hero){
cursedZap(origin, user, bolt, afterZap);
return;
}
try { try {
Dungeon.saveAll(); Dungeon.saveAll();
if(Messages.lang() != Languages.ENGLISH){ if(Messages.lang() != Languages.ENGLISH){
//Don't bother doing this joke to none-english speakers, I doubt it would translate. //Don't bother doing this joke to none-english speakers, I doubt it would translate.
GLog.i(Messages.get(CursedWand.class, "nothing")); return cursedEffect(origin, user, targetPos);
afterZap.call();
} else { } else {
GameScene.show( GameScene.show(
new WndOptions("CURSED WAND ERROR", "this application will now self-destruct", "abort", "retry", "fail") { new WndOptions("CURSED WAND ERROR", "this application will now self-destruct", "abort", "retry", "fail") {
@ -426,21 +384,19 @@ public class CursedWand {
} }
} }
); );
return false;
} }
} catch(IOException e){ } catch(IOException e){
ShatteredPixelDungeon.reportException(e); ShatteredPixelDungeon.reportException(e);
//oookay maybe don't kill the game if the save failed. //maybe don't kill the game if the save failed.
GLog.i(Messages.get(CursedWand.class, "nothing")); return cursedEffect(origin, user, targetPos);
afterZap.call();
} }
break;
//random transmogrification //random transmogrification
case 3: case 3:
//skips this effect if there is no item to transmogrify //skips this effect if there is no item to transmogrify
if (origin == null || user != Dungeon.hero || !Dungeon.hero.belongings.contains(origin)){ if (origin == null || user != Dungeon.hero || !Dungeon.hero.belongings.contains(origin)){
cursedZap(origin, user, bolt, afterZap); return cursedEffect(origin, user, targetPos);
return;
} }
origin.detach(Dungeon.hero.belongings.backpack); origin.detach(Dungeon.hero.belongings.backpack);
Item result; Item result;
@ -456,8 +412,7 @@ public class CursedWand {
GLog.w( Messages.get(CursedWand.class, "transmogrify_other") ); GLog.w( Messages.get(CursedWand.class, "transmogrify_other") );
} }
Dungeon.level.drop(result, user.pos).sprite.drop(); Dungeon.level.drop(result, user.pos).sprite.drop();
afterZap.call(); return true;
break;
} }
} }

View File

@ -235,14 +235,8 @@ public abstract class ElementalSprite extends MobSprite {
public static class Chaos extends ElementalSprite { public static class Chaos extends ElementalSprite {
//no bolt, overrides zap instead {
@Override boltType = MagicMissile.RAINBOW;
public void zap( int cell ) {
turnTo( ch.pos , cell );
play( zap );
((Elemental)ch).onZapComplete();
Sample.INSTANCE.play( Assets.Sounds.ZAP );
} }
@Override @Override