diff --git a/assets/plants.png b/assets/plants.png index 96a503a74..1ee5e6057 100644 Binary files a/assets/plants.png and b/assets/plants.png differ diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java index caf25ebab..ad24d38d9 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java @@ -25,9 +25,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Yog; -import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; -import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PoisonParticle; -import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.CloakOfShadows; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door; @@ -202,6 +199,8 @@ public abstract class Char extends Actor { public static boolean hit( Char attacker, Char defender, boolean magic ) { float acuRoll = Random.Float( attacker.attackSkill( defender ) ); float defRoll = Random.Float( defender.defenseSkill( attacker ) ); + if (attacker.buff(Bless.class) != null) acuRoll *= 1.20f; + if (defender.buff(Bless.class) != null) defRoll *= 1.20f; return (magic ? acuRoll * 2 : acuRoll) >= defRoll; } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/Regrowth.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/Regrowth.java index f265108ce..e009d3140 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/Regrowth.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/Regrowth.java @@ -46,7 +46,7 @@ public class Regrowth extends Blob { Level.set( i, cur[i] > 9 ? Terrain.HIGH_GRASS : Terrain.GRASS ); mapUpdated = true; - } else if (c == Terrain.GRASS && cur[i] > 9) { + } else if (c == Terrain.GRASS && cur[i] > 9 && Dungeon.level.plants.get(i) == null ) { Level.set( i, Terrain.HIGH_GRASS ); mapUpdated = true; @@ -54,7 +54,7 @@ public class Regrowth extends Blob { } Char ch = Actor.findChar( i ); - if (ch != null) { + if (ch != null && cur[i] > 1) { Buff.prolong( ch, Roots.class, TICK ); } } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Bless.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Bless.java new file mode 100644 index 000000000..44cd8e6ed --- /dev/null +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Bless.java @@ -0,0 +1,22 @@ +package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; + +/** + * Created by debenhame on 27/04/2015. + */ +public class Bless extends FlavourBuff { + + @Override + public int icon() { + //TODO: add icon + return BuffIndicator.FIRE; + } + + @Override + public String toString() { + return "Blessed"; + } + +} diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 63db3c9fe..b2ef41719 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barkskin; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bleeding; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bless; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning; @@ -1117,12 +1118,11 @@ public class Hero extends Char { defenseSkill++; } else { - //TODO: add blessed buff here - + Buff.prolong(this, Bless.class, 30f); this.exp = 0; GLog.p( "You cannot grow stronger, but your experiences do give you a surge of power!" ); - //TODO: holy SFX + Sample.INSTANCE.play( Assets.SND_LEVELUP ); } if (lvl < 10) { diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java index be82b5514..60d09a4ca 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java @@ -19,7 +19,11 @@ package com.shatteredpixel.shatteredpixeldungeon.items.wands; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.items.Dewdrop; +import com.shatteredpixel.shatteredpixeldungeon.items.Generator; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff; +import com.shatteredpixel.shatteredpixeldungeon.plants.Plant; +import com.shatteredpixel.shatteredpixeldungeon.plants.Starflower; import com.shatteredpixel.shatteredpixeldungeon.plants.Sungrass; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.watabou.noosa.audio.Sample; @@ -36,41 +40,127 @@ import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.utils.Callback; import com.watabou.utils.Random; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +//TODO: finish visuals & polish public class WandOfRegrowth extends Wand { { name = "Wand of Regrowth"; image = ItemSpriteSheet.WAND_REGROWTH; + + collisionProperties = Ballistica.STOP_TERRAIN; } + + private HashSet affectedCells; + private int direction = 0; @Override protected void onZap( Ballistica bolt ) { - - for (int i : bolt.subPath(1, bolt.dist)) { - int c = Dungeon.level.map[i]; - if (c == Terrain.EMPTY || - c == Terrain.EMBERS || - c == Terrain.EMPTY_DECO) { - - Level.set( i, Terrain.GRASS ); - + + affectedCells = new HashSet<>(); + + int maxDist = Math.round(1.2f + chargesPerCast()*.8f); + int dist = Math.min(bolt.dist, maxDist); + + for (int i = 0; i < Level.NEIGHBOURS8.length; i++){ + if (bolt.sourcePos+Level.NEIGHBOURS8[i] == bolt.path.get(1)){ + direction = i; + break; } } - - 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, (level() + 2) * 20, Regrowth.class ) ); - - } else { - - GLog.i( "nothing happened" ); - + + float strength = maxDist; + for (int c : bolt.subPath(1, dist)) { + strength--; //as we start at dist 1, not 0. + if (!Level.losBlocking[c]) { + affectedCells.add(c); + spreadRegrowth(c + Level.NEIGHBOURS8[left(direction)], strength - 1); + spreadRegrowth(c + Level.NEIGHBOURS8[direction], strength - 1); + spreadRegrowth(c + Level.NEIGHBOURS8[right(direction)], strength - 1); + } } + + //ignore tiles which can't have anything grow in them. + for (Iterator i = affectedCells.iterator(); i.hasNext();) { + int c = Dungeon.level.map[i.next()]; + if (!(c == Terrain.EMPTY || + c == Terrain.EMBERS || + c == Terrain.EMPTY_DECO || + c == Terrain.GRASS || + c == Terrain.HIGH_GRASS)) { + i.remove(); + } + } + + float numPlants, numDews, numPods, numStars; + + int chrgUsed = chargesPerCast(); + //numbers greater than n*100% means n garunteed plants, e.g. 210% = 2 plants w/10% chance for 3 plants. + numPlants = 0.2f + chrgUsed*chrgUsed*0.020f; //scales from 22% to 220% + numDews = 0.05f + chrgUsed*chrgUsed*0.016f; //scales from 6.6% to 165% + numPods = 0.02f + chrgUsed*chrgUsed*0.013f; //scales from 3.3% to 135% + numStars = (chrgUsed*chrgUsed*chrgUsed/5f)*0.005f; //scales from 0.1% to 100% + placePlants(numPlants, numDews, numPods, numStars); + + for (int i : affectedCells){ + int c = Dungeon.level.map[i]; + if (c == Terrain.EMPTY || + c == Terrain.EMBERS || + c == Terrain.EMPTY_DECO) { + Level.set( i, Terrain.GRASS ); + } + + GameScene.add( Blob.seed( i, 10, Regrowth.class ) ); + + } + } + + private void spreadRegrowth(int cell, float strength){ + if (strength >= 0 && Level.passable[cell] && !Level.losBlocking[cell]){ + affectedCells.add(cell); + if (strength >= 1.5f) { + spreadRegrowth(cell + Level.NEIGHBOURS8[left(direction)], strength - 1.5f); + spreadRegrowth(cell + Level.NEIGHBOURS8[direction], strength - 1.5f); + spreadRegrowth(cell + Level.NEIGHBOURS8[right(direction)], strength-1.5f); + } + } + } + + private void placePlants(float numPlants, float numDews, float numPods, float numStars){ + Iterator cells = affectedCells.iterator(); + Level floor = Dungeon.level; + + while(cells.hasNext() && Random.Float() <= numPlants){ + floor.plant((Plant.Seed) Generator.random(Generator.Category.SEED), cells.next()); + numPlants --; + } + + while (cells.hasNext() && Random.Float() <= numDews){ + floor.plant(new Dewcatcher.Seed(), cells.next()); + numDews --; + } + + while (cells.hasNext() && Random.Float() <= numPods){ + floor.plant(new Seedpod.Seed(), cells.next()); + numPods --; + } + + while (cells.hasNext() && Random.Float() <= numStars){ + floor.plant(new Starflower.Seed(), cells.next()); + numStars --; + } + + } + + private int left(int direction){ + return direction == 0 ? 7 : direction-1; + } + + private int right(int direction){ + return direction == 7 ? 0 : direction+1; } @Override @@ -90,13 +180,105 @@ public class WandOfRegrowth extends Wand { } protected void fx( Ballistica bolt, Callback callback ) { - MagicMissile.foliage( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); + //TODO: proper effects Sample.INSTANCE.play( Assets.SND_ZAP ); + callback.call(); } - + + @Override + //consumes all available charges, needs at least one. + protected int chargesPerCast() { + return Math.max(1, curCharges); + } + @Override public String desc() { return "\"When life ceases new life always begins to grow... The eternal cycle always remains!\""; } + + + public static class Dewcatcher extends Plant{ + + { + image = 12; + plantName = "Dewcatcher"; + } + + @Override + public void activate(Char ch) { + super.activate( ch ); + + int nDrops = Random.NormalIntRange(2, 8); + + ArrayList candidates = new ArrayList(); + for (int i : Level.NEIGHBOURS8){ + if (Level.passable[pos+i]){ + candidates.add(pos+i); + } + } + + for (int i = 0; i < nDrops && !candidates.isEmpty(); i++){ + Integer c = Random.element(candidates); + Dungeon.level.drop(new Dewdrop(), c).sprite.drop(pos); + candidates.remove(c); + } + + } + + @Override + public String desc() { + return ""; + } + + //seed is never dropped, only care about plant class + public static class Seed extends Plant.Seed { + { + plantClass = Dewcatcher.class; + } + } + } + + public static class Seedpod extends Plant{ + + { + image = 13; + plantName = "Seed Pod"; + } + + @Override + public void activate(Char ch) { + super.activate( ch ); + + int nSeeds = Random.NormalIntRange(1, 5); + + ArrayList candidates = new ArrayList(); + for (int i : Level.NEIGHBOURS8){ + if (Level.passable[pos+i]){ + candidates.add(pos+i); + } + } + + for (int i = 0; i < nSeeds && !candidates.isEmpty(); i++){ + Integer c = Random.element(candidates); + Dungeon.level.drop(Generator.random(Generator.Category.SEED), c).sprite.drop(pos); + candidates.remove(c); + } + + } + + @Override + public String desc() { + return ""; + } + + //seed is never dropped, only care about plant class + public static class Seed extends Plant.Seed { + { + plantClass = Seedpod.class; + } + } + + } + } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/plants/Starflower.java b/src/com/shatteredpixel/shatteredpixeldungeon/plants/Starflower.java new file mode 100644 index 000000000..5b0df4545 --- /dev/null +++ b/src/com/shatteredpixel/shatteredpixeldungeon/plants/Starflower.java @@ -0,0 +1,53 @@ +package com.shatteredpixel.shatteredpixeldungeon.plants; + +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bless; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfExperience; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.watabou.utils.Random; + +public class Starflower extends Plant{ + + private static final String TXT_DESC = "TODO"; + + { + image = 11; + plantName = "Starflower"; + } + + @Override + public void activate(Char ch){ + super.activate(ch); + + if (ch != null) Buff.prolong(ch, Bless.class, 30f); + + if ( Random.Int(1) == 0 ) { + Dungeon.level.drop(new Seed(),pos); + } + } + + @Override + public String desc(){ + return""; + } + + public static class Seed extends Plant.Seed{ + + { + plantName="Starflower"; + + name= "Seed of " + plantName; + image= ItemSpriteSheet.SEED_BLANDFRUIT; + + plantClass = Starflower.class; + alchemyClass = PotionOfExperience.class; + } + + @Override + public String desc() { + return""; + } + } +}