Files
shattered-pixel-dungeon-web…/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java
T
2015-06-07 21:55:01 -04:00

419 lines
14 KiB
Java

package com.shatteredpixel.shatteredpixeldungeon.items.wands;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
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.ConfusionGas;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Fire;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ParalyticGas;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Regrowth;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Frost;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.effects.SpellSprite;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Bomb;
import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon;
import com.shatteredpixel.shatteredpixeldungeon.items.KindofMisc;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRecharging;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.LightningTrap;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.SummoningTrap;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.scenes.InterlevelScene;
import com.shatteredpixel.shatteredpixeldungeon.ui.HealthIndicator;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.watabou.noosa.Game;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Callback;
import com.watabou.utils.Random;
import java.io.IOException;
import java.util.ArrayList;
//helper class to contain all the cursed wand zapping logic, so the main wand class doesn't get huge.
public class CursedWand {
private static float COMMON_CHANCE = 0.6f;
private static float UNCOMMON_CHANCE = 0.3f;
private static float RARE_CHANCE = 0.09f;
private static float VERY_RARE_CHANCE = 0.01f;
public static void cursedZap(final Wand wand, final Hero user, final Ballistica bolt){
switch (Random.chances(new float[]{COMMON_CHANCE, UNCOMMON_CHANCE, RARE_CHANCE, VERY_RARE_CHANCE})){
case 0:
default:
commonEffect(wand, user, bolt);
break;
case 1:
uncommonEffect(wand, user, bolt);
break;
case 2:
rareEffect(wand, user, bolt);
break;
case 3:
veryRareEffect(wand, user, bolt);
break;
}
}
private static void commonEffect(final Wand wand, final Hero user, final Ballistica bolt){
switch(Random.Int(4)){
//anti-entropy
case 0:
cursedFX(user, bolt, new Callback() {
public void call() {
Char target = Actor.findChar(bolt.collisionPos);
switch (Random.Int(2)){
case 0:
if (target != null)
Buff.affect(target, Burning.class).reignite(target);
Buff.affect(user, Frost.class, Frost.duration(user) * Random.Float(3f, 5f));
break;
case 1:
Buff.affect(user, Burning.class).reignite(user);
if (target != null)
Buff.affect(target, Frost.class, Frost.duration(target) * Random.Float(3f, 5f));
break;
}
wand.wandUsed();
}
});
break;
//spawns some regrowth
case 1:
cursedFX(user, bolt, new Callback() {
public void call() {
int c = Dungeon.level.map[bolt.collisionPos];
if (c == Terrain.EMPTY ||
c == Terrain.EMBERS ||
c == Terrain.EMPTY_DECO ||
c == Terrain.GRASS ||
c == Terrain.HIGH_GRASS) {
GameScene.add( Blob.seed(bolt.collisionPos, 30, Regrowth.class));
}
wand.wandUsed();
}
});
break;
//random teleportation
case 2:
switch(Random.Int(2)){
case 0:
ScrollOfTeleportation.teleportHero(user);
wand.wandUsed();
break;
case 1:
cursedFX(user, bolt, new Callback() {
public void call() {
Char ch = Actor.findChar( bolt.collisionPos );
if (ch != null) {
int count = 10;
int pos;
do {
pos = Dungeon.level.randomRespawnCell();
if (count-- <= 0) {
break;
}
} while (pos == -1);
if (pos == -1) {
GLog.w(ScrollOfTeleportation.TXT_NO_TELEPORT);
} else {
ch.pos = pos;
ch.sprite.place(ch.pos);
ch.sprite.visible = Dungeon.visible[pos];
}
}
wand.wandUsed();
}
});
break;
}
break;
//random gas at location
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;
}
wand.wandUsed();
}
});
break;
}
}
private static void uncommonEffect(final Wand wand, final Hero user, final Ballistica bolt){
switch(Random.Int(4)){
//Random plant
case 0:
cursedFX(user, bolt, new Callback() {
public void call() {
int pos = bolt.collisionPos;
//place the plant infront of an enemy so they walk into it.
if (Actor.findChar(pos) != null && bolt.dist > 1) {
pos = bolt.path.get(bolt.dist - 1);
}
Dungeon.level.plant((Plant.Seed) Generator.random(Generator.Category.SEED), pos);
wand.wandUsed();
}
});
break;
//Health transfer
case 1:
final Char target = Actor.findChar( bolt.collisionPos );
if (target != null) {
cursedFX(user, bolt, new Callback() {
public void call() {
int damage = user.lvl * 2;
switch (Random.Int(2)) {
case 0:
user.HP = Math.min(user.HT, user.HP + damage);
user.sprite.emitter().burst(Speck.factory(Speck.HEALING), 3);
target.damage(damage, wand);
target.sprite.emitter().start(ShadowParticle.UP, 0.05f, 10);
break;
case 1:
user.damage( damage, this );
user.sprite.emitter().start(ShadowParticle.UP, 0.05f, 10);
target.HP = Math.min(target.HT, target.HP + damage);
target.sprite.emitter().burst(Speck.factory(Speck.HEALING), 3);
Sample.INSTANCE.play(Assets.SND_CURSED);
if (!user.isAlive()) {
Dungeon.fail(Utils.format(ResultDescriptions.ITEM, wand.name()));
GLog.n("You were killed by your own " + wand.name());
}
break;
}
wand.wandUsed();
}
});
} else {
GLog.i("nothing happens");
wand.wandUsed();
}
break;
//Bomb explosion
case 2:
cursedFX(user, bolt, new Callback() {
public void call() {
new Bomb().explode(bolt.collisionPos);
wand.wandUsed();
}
});
break;
//shock and recharge
case 3:
LightningTrap.trigger(user.pos, user);
Buff.prolong(user, ScrollOfRecharging.Recharging.class, 20f);
ScrollOfRecharging.charge(user);
SpellSprite.show(user, SpellSprite.CHARGE);
wand.wandUsed();
break;
}
}
private static void rareEffect(final Wand wand, final Hero user, final Ballistica bolt){
switch(Random.Int(4)){
//sheep transformation
case 0:
cursedFX(user, bolt, new Callback() {
public void call() {
Char ch = Actor.findChar( bolt.collisionPos );
if (ch != null && ch != user){
WandOfFlock.Sheep sheep = new WandOfFlock.Sheep();
sheep.lifespan = 10;
sheep.pos = ch.pos;
ch.sprite.killAndErase();
Actor.remove(ch);
Actor.freeCell(ch.pos);
Dungeon.level.mobs.remove(ch);
HealthIndicator.instance.target(null);
GameScene.add(sheep);
CellEmitter.get(sheep.pos).burst(Speck.factory(Speck.WOOL), 4);
} else {
GLog.i("nothing happens");
}
wand.wandUsed();
}
});
break;
//curses!
case 1:
KindOfWeapon weapon = user.belongings.weapon;
Armor armor = user.belongings.armor;
KindofMisc misc1 = user.belongings.misc1;
KindofMisc misc2 = user.belongings.misc2;
if (weapon != null) weapon.cursed = weapon.cursedKnown = true;
if (armor != null) armor.cursed = armor.cursedKnown = true;
if (misc1 != null) misc1.cursed = misc1.cursedKnown = true;
if (misc2 != null) misc2.cursed = misc2.cursedKnown = true;
EquipableItem.equipCursed(user);
GLog.n("Your worn equipment becomes cursed!");
wand.wandUsed();
break;
//inter-level teleportation
case 2:
if (Dungeon.depth > 1 && Dungeon.depth % 5 != 0) {
Buff buff = Dungeon.hero.buff(TimekeepersHourglass.timeFreeze.class);
if (buff != null) buff.detach();
for (Mob mob : Dungeon.level.mobs.toArray( new Mob[0] ))
if (mob instanceof DriedRose.GhostHero) mob.destroy();
InterlevelScene.mode = InterlevelScene.Mode.RETURN;
InterlevelScene.returnDepth = Random.Int(Dungeon.depth-1)+1;
InterlevelScene.returnPos = -1;
Game.switchScene(InterlevelScene.class);
} else {
ScrollOfTeleportation.teleportHero(user);
wand.wandUsed();
}
break;
//summon monsters
case 3:
SummoningTrap.trigger( user.pos, user );
wand.wandUsed();
break;
}
}
private static void veryRareEffect(final Wand wand, final Hero user, final Ballistica bolt){
switch(Random.Int(4)){
//great forest fire!
case 0:
for (int i = 0; i < Level.LENGTH; i++){
int c = Dungeon.level.map[i];
if (c == Terrain.EMPTY ||
c == Terrain.EMBERS ||
c == Terrain.EMPTY_DECO ||
c == Terrain.GRASS ||
c == Terrain.HIGH_GRASS) {
GameScene.add( Blob.seed(i, 15, Regrowth.class));
}
}
do {
GameScene.add(Blob.seed(Dungeon.level.randomDestination(), 10, Fire.class));
} while (Random.Int(5) != 0);
new Flare(8, 32).color(0xFFFF66, true).show(user.sprite, 2f);
Sample.INSTANCE.play(Assets.SND_TELEPORT);
GLog.p("grass explodes around you!");
GLog.w("you smell burning...");
wand.wandUsed();
break;
//superpowered mimic
case 1:
cursedFX(user, bolt, new Callback() {
public void call() {
Mimic mimic = Mimic.spawnAt(bolt.collisionPos, new ArrayList<Item>());
mimic.adjustStats(Dungeon.depth + 10);
mimic.HP = mimic.HT;
Item reward;
do {
reward = Generator.random(Random.oneOf(Generator.Category.WEAPON, Generator.Category.ARMOR,
Generator.Category.RING, Generator.Category.WAND));
} while (reward.level < 2 && !(reward instanceof MissileWeapon));
Sample.INSTANCE.play(Assets.SND_MIMIC, 1, 1, 0.5f);
mimic.items.clear();
mimic.items.add(reward);
wand.wandUsed();
}
});
break;
//crashes the game, yes, really.
case 2:
try {
Dungeon.saveAll();
GameScene.show(
new WndOptions("CURSED WAND ERROR", "this application will now self-destruct", "abort", "retry", "fail") {
@Override
public void hide() {
throw new RuntimeException("critical wand exception");
}
}
);
} catch(IOException e){
//oookay maybe don't kill the game if the save failed.
GLog.i("nothing happens");
wand.wandUsed();
}
break;
//random transmogrification
case 3:
wand.wandUsed();
wand.detach(user.belongings.backpack);
Item result;
do {
result = Generator.random(Random.oneOf(Generator.Category.WEAPON, Generator.Category.ARMOR,
Generator.Category.RING, Generator.Category.ARTIFACT));
} while (result.level < 0 && !(result instanceof MissileWeapon));
if (result.isUpgradable()) result.upgrade();
result.cursed = result.cursedKnown = true;
GLog.w("your wand transmogrifies into a different item!");
Dungeon.level.drop(result, user.pos).sprite.drop();
wand.wandUsed();
break;
}
}
private static void cursedFX(final Hero user, final Ballistica bolt, final Callback callback){
MagicMissile.rainbow(user.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback);
Sample.INSTANCE.play( Assets.SND_ZAP );
}
}