v0.8.1: reworked wand of regrowth!

This commit is contained in:
Evan Debenham 2020-06-18 14:00:02 -04:00
parent c4ffb9b82a
commit f5cba1a9ba
20 changed files with 414 additions and 167 deletions

View File

@ -1206,11 +1206,13 @@ items.wands.wandofprismaticlight.stats_desc=This wand shoots rays of light which
items.wands.wandofregrowth.name=wand of regrowth items.wands.wandofregrowth.name=wand of regrowth
items.wands.wandofregrowth.staff_name=staff of regrowth items.wands.wandofregrowth.staff_name=staff of regrowth
items.wands.wandofregrowth.desc=This wand is made from a thin shaft of expertly carved wood. Somehow it is still alive and vibrant, bright green like a young tree's core. items.wands.wandofregrowth.desc=This wand is made from a thin shaft of expertly carved wood. Somehow it is still alive and vibrant, bright green like a young tree's core.
items.wands.wandofregrowth.stats_desc=When used, this wand will consume all its charges to blast magical regrowth energy outward in a cone. This magic will cause grass, roots, and rare plants to spring to life. "When life ceases new life always begins to grow... The eternal cycle always remains!" items.wands.wandofregrowth.stats_desc=When used, this wand will blast magical regrowth energy outward in a cone, causing grass, roots, and rare plants to spring to life. As this wand is upgraded it will consume more charges, the effect becomes significantly more powerful the more charges are consumed. Its next zap will consume _%1$d charges_. "When life ceases new life always begins to grow... The eternal cycle always remains!"
items.wands.wandofregrowth$dewcatcher.name=Dewcatcher items.wands.wandofregrowth$dewcatcher.name=Dewcatcher
items.wands.wandofregrowth$dewcatcher.desc=Dewcatchers camouflage as grass to avoid attention, but their bulges of collected dew give them away. items.wands.wandofregrowth$dewcatcher.desc=Dewcatchers are wonderous plants that fill themselves with magical dew. They attempt to camouflage as grass to avoid attention, but their bulges of collected dew give them away.
items.wands.wandofregrowth$seedpod.name=Seed Pod items.wands.wandofregrowth$seedpod.name=Seed Pod
items.wands.wandofregrowth$seedpod.desc=Seed Pods look pretty, but the seeds they carry are actually stolen from other plants they kill with their roots. items.wands.wandofregrowth$seedpod.desc=Seed Pods are magical plants that produce seeds from other plan types, rather than any seeds of their own. They somehow manage to spread despite having no seed of their own.
items.wands.wandofregrowth$lotus.name=Golden Lotus
items.wands.wandofregrowth$lotus.desc=The golden lotus is a mystical plant that can only be conjured by a powerful wand of regrowth. Its aura enhances all plants and plant effects, but it burns through its energy and dies after a short time.\n\nThis lotus was produced by a _+%1$d_ wand of regrowth. All plants in its effect will _instantly trigger_ if they are planted on a character. Plants will also have a _%2$d%% chance_ to drop their seed, and tipped darts gain _%3$d%% extra durability_.
items.wands.wandoftransfusion.name=wand of transfusion items.wands.wandoftransfusion.name=wand of transfusion
items.wands.wandoftransfusion.staff_name=staff of transfusion items.wands.wandoftransfusion.staff_name=staff of transfusion

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -267,5 +267,6 @@ public class Assets {
public static final String DM100 = "sprites/dm100.png"; public static final String DM100 = "sprites/dm100.png";
public static final String PYLON = "sprites/pylon.png"; public static final String PYLON = "sprites/pylon.png";
public static final String DM200 = "sprites/dm200.png"; public static final String DM200 = "sprites/dm200.png";
public static final String LOTUS = "sprites/lotus.png";
} }
} }

View File

@ -25,8 +25,10 @@ import com.shatteredpixel.shatteredpixeldungeon.Assets;
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.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Regrowth; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.NPC;
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
import com.shatteredpixel.shatteredpixeldungeon.items.Dewdrop; import com.shatteredpixel.shatteredpixeldungeon.items.Dewdrop;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator; import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
@ -35,10 +37,12 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ConeAOE;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant; import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
import com.shatteredpixel.shatteredpixeldungeon.plants.Starflower;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.sprites.LotusSprite;
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;
@ -47,7 +51,6 @@ import com.watabou.utils.PathFinder;
import com.watabou.utils.Random; import com.watabou.utils.Random;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
public class WandOfRegrowth extends Wand { public class WandOfRegrowth extends Wand {
@ -57,139 +60,137 @@ public class WandOfRegrowth extends Wand {
collisionProperties = Ballistica.STOP_TERRAIN; collisionProperties = Ballistica.STOP_TERRAIN;
} }
//the actual affected cells
private HashSet<Integer> affectedCells;
//the cells to trace growth particles to, for visual effects.
private HashSet<Integer> visualCells;
private int direction = 0;
private int totChrgUsed = 0; private int totChrgUsed = 0;
ConeAOE cone;
int target;
@Override
public boolean tryToZap(Hero owner, int target) {
if (super.tryToZap(owner, target)){
this.target = target;
return true;
} else {
return false;
}
}
@Override @Override
protected void onZap( Ballistica bolt ) { protected void onZap( Ballistica bolt ) {
//ignore tiles which can't have anything grow in them. ArrayList<Integer> cells = new ArrayList<>(cone.cells);
for (Iterator<Integer> 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 ||
c == Terrain.FURROWED_GRASS)) {
i.remove();
}
}
float numPlants, numDews, numPods, numStars;
int overLimit = totChrgUsed - chargeLimit(Dungeon.hero.lvl); int overLimit = totChrgUsed - chargeLimit(Dungeon.hero.lvl);
float furrowedChance = overLimit > 0 ? (overLimit / (10f + Dungeon.hero.lvl)) : 0;
int chrgUsed = chargesPerCast(); int chrgUsed = chargesPerCast();
//numbers greater than n*100% means n guaranteed plants, e.g. 210% = 2 plants w/10% chance for 3 plants. int grassToPlace = Math.round((3.5f+buffedLvl()/2f)*chrgUsed);
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%
if (overLimit > 0){
numPlants -= overLimit*0.02f;
numDews -= overLimit*0.02f;
numPods -= overLimit*0.02f;
numStars -= overLimit*0.02f;
}
placePlants(numPlants, numDews, numPods, numStars);
for (int i : affectedCells){ //ignore cells which can't have anything grow in them.
int c = Dungeon.level.map[i]; for (Iterator<Integer> i = cells.iterator(); i.hasNext();) {
if (c == Terrain.EMPTY || int cell = i.next();
c == Terrain.EMBERS || int terr = Dungeon.level.map[cell];
c == Terrain.EMPTY_DECO) { if (!(terr == Terrain.EMPTY ||
Level.set( i, Terrain.GRASS ); terr == Terrain.EMBERS ||
} terr == Terrain.EMPTY_DECO ||
terr == Terrain.GRASS ||
Char ch = Actor.findChar(i); terr == Terrain.HIGH_GRASS ||
if (ch != null){ terr == Terrain.FURROWED_GRASS)) {
processSoulMark(ch, chargesPerCast()); i.remove();
}
if (Random.Int(50) < overLimit) {
if (Dungeon.level.map[i] == Terrain.GRASS) {
Level.set( i, Terrain.FURROWED_GRASS );
GameScene.updateMap( i );
}
GameScene.add(Blob.seed(i, 9, Regrowth.class));
} else { } else {
GameScene.add(Blob.seed(i, 10, Regrowth.class)); Level.set( cell, Terrain.GRASS );
GameScene.updateMap( cell );
Char ch = Actor.findChar(cell);
if (ch != null){
processSoulMark(ch, chargesPerCast());
Buff.prolong( ch, Roots.class, 4f * chrgUsed );
}
} }
} }
totChrgUsed += chrgUsed; Random.shuffle(cells);
if (chargesPerCast() >= 3){
Lotus l = new Lotus();
l.setLevel(buffedLvl());
if (cells.contains(target)){
cells.remove((Integer)target);
l.pos = target;
GameScene.add(l);
} else {
for (int i = bolt.path.size()-1; i >= 0; i--){
if (cells.contains(bolt.path.get(i))){
cells.remove((Integer)bolt.path.get(i));
l.pos = bolt.path.get(i);
GameScene.add(l);
break;
}
}
}
}
//places grass along center of cone
for (int cell : bolt.path){
if (grassToPlace > 0 && cells.contains(cell)){
if (Random.Float() > furrowedChance) {
Level.set(cell, Terrain.HIGH_GRASS);
} else {
Level.set(cell, Terrain.FURROWED_GRASS);
}
GameScene.updateMap( cell );
grassToPlace--;
//moves cell to the back
cells.remove((Integer)cell);
cells.add(cell);
}
}
if (!cells.isEmpty() && Random.Float() > furrowedChance &&
(chrgUsed == 3 || (chrgUsed == 2 && Random.Int(2) == 0))){
int cell = cells.remove(0);
Dungeon.level.plant( Random.Int(2) == 0 ? new Seedpod.Seed() : new Dewcatcher.Seed(), cell);
}
if (!cells.isEmpty() && Random.Float() > furrowedChance && chrgUsed == 3){
int cell = cells.remove(0);
Dungeon.level.plant((Plant.Seed) Generator.randomUsingDefaults(Generator.Category.SEED), cell);
}
if (!cells.isEmpty() && Random.Float() > furrowedChance &&
(chrgUsed >= 2 || (chrgUsed == 1 && Random.Int(2) == 0))){
int cell = cells.remove(0);
Dungeon.level.plant((Plant.Seed) Generator.randomUsingDefaults(Generator.Category.SEED), cell);
}
for (int cell : cells){
if (grassToPlace <= 0 || bolt.path.contains(cell)) break;
if (Random.Float() > furrowedChance) {
Level.set(cell, Terrain.HIGH_GRASS);
} else {
Level.set(cell, Terrain.FURROWED_GRASS);
}
GameScene.updateMap( cell );
grassToPlace--;
}
if (furrowedChance < 1f) {
totChrgUsed += chrgUsed;
}
} }
private int chargeLimit( int heroLevel ){ private int chargeLimit( int heroLvl ){
if (level() >= 12){ if (level() >= 10){
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} else { } else {
//4 charges per hero level at +0, with another 2-4 each upgrade from +1 to +9. //8 charges at base, plus:
//then +7 at +10, +16 at +11, and infinite at +12. //2/3.33/5/7/10/14/20/30/50/110/infinite charges per hero level, based on wand level
return Math.round(((4 + 2*level())*heroLevel) * (11f/12f + 1f/(12f-level()))); float lvl = buffedLvl();
return Math.round(8 + heroLvl * (2+lvl) * (1f + (lvl/(10 - lvl))));
} }
} }
private void spreadRegrowth(int cell, float strength){
if (strength >= 0 && Dungeon.level.passable[cell]){
affectedCells.add(cell);
if (strength >= 1.5f) {
spreadRegrowth(cell + PathFinder.CIRCLE8[left(direction)], strength - 1.5f);
spreadRegrowth(cell + PathFinder.CIRCLE8[direction], strength - 1.5f);
spreadRegrowth(cell + PathFinder.CIRCLE8[right(direction)], strength-1.5f);
} else {
visualCells.add(cell);
}
} else if (!Dungeon.level.passable[cell])
visualCells.add(cell);
}
private void placePlants(float numPlants, float numDews, float numPods, float numStars){
Iterator<Integer> cells = affectedCells.iterator();
Level floor = Dungeon.level;
while(cells.hasNext() && Random.Float() <= numPlants){
Plant.Seed seed = (Plant.Seed) Generator.randomUsingDefaults(Generator.Category.SEED);
floor.plant(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 @Override
public void onHit(MagesStaff staff, Char attacker, Char defender, int damage) { public void onHit(MagesStaff staff, Char attacker, Char defender, int damage) {
new Blooming().proc(staff, attacker, defender, damage); new Blooming().proc(staff, attacker, defender, damage);
@ -197,62 +198,43 @@ public class WandOfRegrowth extends Wand {
protected void fx( Ballistica bolt, Callback callback ) { protected void fx( Ballistica bolt, Callback callback ) {
affectedCells = new HashSet<>(); // 4/6/8 distance
visualCells = new HashSet<>(); int maxDist = 2 + 2*chargesPerCast();
int maxDist = Math.round(1.2f + chargesPerCast()*.8f);
int dist = Math.min(bolt.dist, maxDist); int dist = Math.min(bolt.dist, maxDist);
for (int i = 0; i < PathFinder.CIRCLE8.length; i++){ cone = new ConeAOE( bolt.sourcePos, bolt.path.get(dist),
if (bolt.sourcePos+PathFinder.CIRCLE8[i] == bolt.path.get(1)){ maxDist,
direction = i; 20 + 10*chargesPerCast(),
break; collisionProperties | Ballistica.STOP_TARGET);
}
}
float strength = maxDist; //cast to cells at the tip, rather than all cells, better performance.
for (int c : bolt.subPath(1, dist)) { for (Ballistica ray : cone.rays){
strength--; //as we start at dist 1, not 0.
if (Dungeon.level.passable[c]) {
affectedCells.add(c);
spreadRegrowth(c + PathFinder.CIRCLE8[left(direction)], strength - 1);
spreadRegrowth(c + PathFinder.CIRCLE8[direction], strength - 1);
spreadRegrowth(c + PathFinder.CIRCLE8[right(direction)], strength - 1);
} else {
visualCells.add(c);
}
}
//going to call this one manually
visualCells.remove(bolt.path.get(dist));
for (int cell : visualCells){
//this way we only get the cells at the tip, much better performance.
((MagicMissile)curUser.sprite.parent.recycle( MagicMissile.class )).reset( ((MagicMissile)curUser.sprite.parent.recycle( MagicMissile.class )).reset(
MagicMissile.FOLIAGE_CONE, MagicMissile.FOLIAGE_CONE,
curUser.sprite, curUser.sprite,
cell, ray.path.get(ray.dist),
null null
); );
} }
//final zap at half distance, for timing of the actual wand effect
MagicMissile.boltFromChar( curUser.sprite.parent, MagicMissile.boltFromChar( curUser.sprite.parent,
MagicMissile.FOLIAGE_CONE, MagicMissile.FOLIAGE_CONE,
curUser.sprite, curUser.sprite,
bolt.path.get(dist/2), bolt.path.get(dist/2),
callback ); callback );
Sample.INSTANCE.play( Assets.Sounds.ZAP ); Sample.INSTANCE.play( Assets.Sounds.ZAP );
} }
@Override @Override
protected int initialCharges() { protected int chargesPerCast() {
return 1; //consumes 30% of current charges, rounded up, with a minimum of one.
return Math.max(1, (int)Math.ceil(curCharges*0.3f));
} }
@Override @Override
//consumes all available charges, needs at least one. public String statsDesc() {
protected int chargesPerCast() { return Messages.get(this, "stats_desc", chargesPerCast());
return Math.max(1, curCharges);
} }
@Override @Override
@ -354,4 +336,89 @@ public class WandOfRegrowth extends Wand {
} }
public static class Lotus extends NPC {
{
alignment = Alignment.ALLY;
properties.add(Property.IMMOVABLE);
spriteClass = LotusSprite.class;
viewDistance = 1;
}
private int wandLvl = 0;
private void setLevel( int lvl ){
wandLvl = lvl;
HP = HT = lvl*4;
}
public boolean inRange(int pos){
return Dungeon.level.trueDistance(this.pos, pos) <= wandLvl;
}
public float seedPreservation(){
return 0.25f + 0.05f*wandLvl;
}
@Override
public boolean canInteract(Char c) {
return false;
}
@Override
protected boolean act() {
super.act();
throwItem();
if (--HP <= 0){
destroy();
sprite.die();
}
spend(TICK);
return true;
}
@Override
public void damage( int dmg, Object src ) {
}
@Override
public void add( Buff buff ) {
}
@Override
public void destroy() {
super.destroy();
Dungeon.observe();
GameScene.updateFog(pos, viewDistance+1);
}
@Override
public boolean isInvulnerable(Class effect) {
return true;
}
@Override
public String description() {
return Messages.get(this, "desc", wandLvl, (int)(seedPreservation()*100), (int)(seedPreservation()*100) );
}
private static final String WAND_LVL = "wand_lvl";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(WAND_LVL, wandLvl);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
wandLvl = bundle.getInt(WAND_LVL);
}
}
} }

View File

@ -22,12 +22,14 @@
package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts; package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.PinCushion; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.PinCushion;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator; import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.plants.Blindweed; import com.shatteredpixel.shatteredpixeldungeon.plants.Blindweed;
import com.shatteredpixel.shatteredpixeldungeon.plants.Dreamfoil; import com.shatteredpixel.shatteredpixeldungeon.plants.Dreamfoil;
@ -102,9 +104,10 @@ public abstract class TippedDart extends Dart {
} }
//exact same damage as regular darts, despite being higher tier. //exact same damage as regular darts, despite being higher tier.
@Override @Override
protected void rangedHit(Char enemy, int cell) { protected void rangedHit(Char enemy, int cell) {
targetPos = cell;
super.rangedHit( enemy, cell); super.rangedHit( enemy, cell);
//need to spawn a dart //need to spawn a dart
@ -121,7 +124,9 @@ public abstract class TippedDart extends Dart {
Dungeon.level.drop( d, enemy.pos ).sprite.drop(); Dungeon.level.drop( d, enemy.pos ).sprite.drop();
} }
} }
private static int targetPos = -1;
@Override @Override
protected float durabilityPerUse() { protected float durabilityPerUse() {
float use = super.durabilityPerUse(); float use = super.durabilityPerUse();
@ -129,6 +134,30 @@ public abstract class TippedDart extends Dart {
if (Dungeon.hero.subClass == HeroSubClass.WARDEN){ if (Dungeon.hero.subClass == HeroSubClass.WARDEN){
use /= 2f; use /= 2f;
} }
//checks both destination and source position
float lotusPreserve = 0f;
if (targetPos != -1){
for (Char ch : Actor.chars()){
if (ch instanceof WandOfRegrowth.Lotus){
WandOfRegrowth.Lotus l = (WandOfRegrowth.Lotus) ch;
if (l.inRange(targetPos)){
lotusPreserve = Math.max(lotusPreserve, l.seedPreservation());
}
}
}
targetPos = -1;
}
int p = curUser == null ? Dungeon.hero.pos : curUser.pos;
for (Char ch : Actor.chars()){
if (ch instanceof WandOfRegrowth.Lotus){
WandOfRegrowth.Lotus l = (WandOfRegrowth.Lotus) ch;
if (l.inRange(p)){
lotusPreserve = Math.max(lotusPreserve, l.seedPreservation());
}
}
}
use *= (1f - lotusPreserve);
return use; return use;
} }

View File

@ -61,6 +61,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfStrength;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfEnchantment; import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfEnchantment;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfIntuition; import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfIntuition;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfWarding; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfWarding;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door;
@ -791,6 +792,15 @@ public abstract class Level implements Bundlable {
plants.put( pos, plant ); plants.put( pos, plant );
GameScene.plantSeed( pos ); GameScene.plantSeed( pos );
for (Char ch : Actor.chars()){
if (ch instanceof WandOfRegrowth.Lotus
&& ((WandOfRegrowth.Lotus) ch).inRange(pos)
&& Actor.findChar(pos) != null){
plant.trigger();
return null;
}
}
return plant; return plant;
} }
@ -1100,19 +1110,19 @@ public abstract class Level implements Bundlable {
fieldOfView[p+i] = true; fieldOfView[p+i] = true;
} }
for (Mob ward : mobs){ for (Mob m : mobs){
if (ward instanceof WandOfWarding.Ward){ if (m instanceof WandOfWarding.Ward || m instanceof WandOfRegrowth.Lotus){
if (ward.fieldOfView == null || ward.fieldOfView.length != length()){ if (m.fieldOfView == null || m.fieldOfView.length != length()){
ward.fieldOfView = new boolean[length()]; m.fieldOfView = new boolean[length()];
Dungeon.level.updateFieldOfView( ward, ward.fieldOfView ); Dungeon.level.updateFieldOfView( m, m.fieldOfView );
} }
for (Mob m : mobs){ for (Mob m1 : mobs){
if (ward.fieldOfView[m.pos] && !fieldOfView[m.pos] && if (m.fieldOfView[m1.pos] && !fieldOfView[m1.pos] &&
!Dungeon.hero.mindVisionEnemies.contains(m)){ !Dungeon.hero.mindVisionEnemies.contains(m1)){
Dungeon.hero.mindVisionEnemies.add(m); Dungeon.hero.mindVisionEnemies.add(m1);
} }
} }
BArray.or(fieldOfView, ward.fieldOfView, fieldOfView); BArray.or(fieldOfView, m.fieldOfView, fieldOfView);
} }
} }
} }

View File

@ -39,6 +39,7 @@ public class Blindweed extends Plant {
{ {
image = 11; image = 11;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -37,6 +37,7 @@ public class Dreamfoil extends Plant {
{ {
image = 7; image = 7;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -40,6 +40,7 @@ public class Earthroot extends Plant {
{ {
image = 8; image = 8;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -41,6 +41,7 @@ public class Fadeleaf extends Plant {
{ {
image = 10; image = 10;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -38,6 +38,7 @@ public class Firebloom extends Plant {
{ {
image = 1; image = 1;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -37,6 +37,7 @@ public class Icecap extends Plant {
{ {
image = 4; image = 4;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@ -40,6 +41,7 @@ import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Bundlable; import com.watabou.utils.Bundlable;
import com.watabou.utils.Bundle; import com.watabou.utils.Bundle;
import com.watabou.utils.PathFinder; import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
import com.watabou.utils.Reflection; import com.watabou.utils.Reflection;
import java.util.ArrayList; import java.util.ArrayList;
@ -51,6 +53,8 @@ public abstract class Plant implements Bundlable {
public int image; public int image;
public int pos; public int pos;
protected Class<? extends Plant.Seed> seedClass;
public void trigger(){ public void trigger(){
Char ch = Actor.findChar(pos); Char ch = Actor.findChar(pos);
@ -71,6 +75,22 @@ public abstract class Plant implements Bundlable {
if (Dungeon.level.heroFOV[pos]) { if (Dungeon.level.heroFOV[pos]) {
CellEmitter.get( pos ).burst( LeafParticle.GENERAL, 6 ); CellEmitter.get( pos ).burst( LeafParticle.GENERAL, 6 );
} }
float seedChance = 0f;
for (Char c : Actor.chars()){
if (c instanceof WandOfRegrowth.Lotus){
WandOfRegrowth.Lotus l = (WandOfRegrowth.Lotus) c;
if (l.inRange(pos)){
seedChance = Math.max(seedChance, l.seedPreservation());
}
}
}
if (Random.Float() < seedChance){
if (seedClass != null && seedClass != Rotberry.Seed.class) {
Dungeon.level.drop(Reflection.newInstance(seedClass), pos).sprite.drop();
}
}
} }

View File

@ -35,6 +35,7 @@ public class Rotberry extends Plant {
{ {
image = 0; image = 0;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -36,6 +36,7 @@ public class Sorrowmoss extends Plant {
{ {
image = 6; image = 6;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -35,6 +35,7 @@ public class Starflower extends Plant {
{ {
image = 9; image = 9;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -33,6 +33,7 @@ public class Stormvine extends Plant {
{ {
image = 5; image = 5;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -41,6 +41,7 @@ public class Sungrass extends Plant {
{ {
image = 3; image = 3;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -42,6 +42,7 @@ public class Swiftthistle extends Plant {
{ {
image = 2; image = 2;
seedClass = Seed.class;
} }
@Override @Override

View File

@ -0,0 +1,106 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2020 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.sprites;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth;
import com.watabou.noosa.MovieClip;
import com.watabou.noosa.TextureFilm;
import com.watabou.noosa.particles.Emitter;
import java.util.ArrayList;
//TODO implement on WIP sprite
public class LotusSprite extends MobSprite {
private ArrayList<Emitter> grassVfx;
public LotusSprite(){
super();
perspectiveRaise = 0.2f;
texture( Assets.Sprites.LOTUS );
TextureFilm frames = new TextureFilm( texture, 17, 14 );
idle = new MovieClip.Animation( 1, true );
idle.frames( frames, 0 );
run = new MovieClip.Animation( 1, true );
run.frames( frames, 0 );
attack = new MovieClip.Animation( 1, false );
attack.frames( frames, 0 );
die = new MovieClip.Animation( 1, false );
die.frames( frames, 0 );
play( idle );
}
@Override
public void link( Char ch ) {
super.link( ch );
renderShadow = false;
if (grassVfx == null && ch instanceof WandOfRegrowth.Lotus){
WandOfRegrowth.Lotus l = (WandOfRegrowth.Lotus) ch;
grassVfx = new ArrayList<>();
for (int i = 0; i < Dungeon.level.length(); i++){
if (!Dungeon.level.solid[i] && l.inRange(i)) {
Emitter e = CellEmitter.get(i);
e.pour(LeafParticle.LEVEL_SPECIFIC, 0.5f);
grassVfx.add(e);
}
}
}
}
@Override
public void turnTo(int from, int to) {
//do nothing
}
@Override
public void update() {
visible = true;
super.update();
}
@Override
public void die() {
super.die();
if (grassVfx != null){
for (Emitter e : grassVfx){
e.on = false;
}
grassVfx = null;
}
}
}