diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index e6bd3c9eb..eb7d9efaf 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -159,7 +159,7 @@ actors.buffs.fireimbue.name=Imbued with Fire actors.buffs.fireimbue.desc=You are imbued with the power of fire!\n\nAll physical attacks will have a chance to light enemies ablaze. Additionally, you are completely immune to the effects of fire.\n\nTurns of fire imbue remaining: %s. actors.buffs.foresight.name=Foresight -actors.buffs.foresight.desc=Your senses are heightened, allowing you to immediately notice anything out of place.\n\nWhile under the effect of foresight your search radius is increased, and anything that enters your search radius is immediately discovered.\n\nTurns of foresight remaining: %s. +actors.buffs.foresight.desc=You are somehow able to see the layout of surrounding terrain with your mind.\n\nWhile under the effect of foresight all tiles in a wide radius are revealed to you, including any secret traps or doors.\n\nTurns of foresight remaining: %s. actors.buffs.frost.name=Frozen actors.buffs.frost.freezes=%s freezes! diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index c8d35e6c7..79da8aca7 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -988,7 +988,7 @@ items.scrolls.exotic.scrollofenchantment.cancel=cancel items.scrolls.exotic.scrollofenchantment.desc=This scroll will infuse a weapon or armor with powerful magical energy. The reader even has some degree of control over which magic is imbued. items.scrolls.exotic.scrollofforesight.name=scroll of foresight -items.scrolls.exotic.scrollofforesight.desc=When this scroll is read, the detail of nearby terrain will be constantly fed to the reader's mind in crystal clarity. For the duration of this effect, searching will not be necessary, as the reader will automatically detect everything within an enhanced search radius. +items.scrolls.exotic.scrollofforesight.desc=After reading this scroll, the detail of nearby terrain will be constantly fed to the reader's mind in crystal clarity. This effect lasts for a considerable amount of time, and will reveal all hidden doors or traps, making searching unnecessary. items.scrolls.exotic.scrollofmysticalenergy.name=scroll of mystical energy items.scrolls.exotic.scrollofmysticalenergy.desc=The raw magical power bound up in this parchment will, when released, charge a user's equipped artifacts over time. diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Foresight.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Foresight.java index 29b48035f..ad4e51785 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Foresight.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Foresight.java @@ -21,12 +21,16 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; public class Foresight extends FlavourBuff { - public static final float DURATION = 600f; + public static final float DURATION = 250f; + + public static final int DISTANCE = 8; { type = buffType.POSITIVE; @@ -38,6 +42,20 @@ public class Foresight extends FlavourBuff { return BuffIndicator.FORESIGHT; } + @Override + public boolean attachTo(Char target) { + if (super.attachTo(target)){ + //this way we get a nice VFX sweep on initial activation + if (target == Dungeon.hero){ + Dungeon.level.mapped[target.pos] = false; + Dungeon.hero.search(false); + } + return true; + } else { + return false; + } + } + @Override public float iconFadePercent() { return Math.max(0, (DURATION - visualcooldown()) / DURATION); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 38234adac..20066f7a7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -140,6 +140,7 @@ import com.watabou.utils.Bundle; import com.watabou.utils.Callback; import com.watabou.utils.GameMath; import com.watabou.utils.PathFinder; +import com.watabou.utils.Point; import com.watabou.utils.Random; import java.util.ArrayList; @@ -1872,47 +1873,57 @@ public class Hero extends Char { if (hasTalent(Talent.WIDE_SEARCH)) distance++; boolean foresight = buff(Foresight.class) != null; - - if (foresight) distance++; - - int cx = pos % Dungeon.level.width(); - int cy = pos / Dungeon.level.width(); - int ax = cx - distance; - if (ax < 0) { - ax = 0; + boolean foresightScan = foresight && !Dungeon.level.mapped[pos]; + + if (foresightScan){ + Dungeon.level.mapped[pos] = true; } - int bx = cx + distance; - if (bx >= Dungeon.level.width()) { - bx = Dungeon.level.width() - 1; - } - int ay = cy - distance; - if (ay < 0) { - ay = 0; - } - int by = cy + distance; - if (by >= Dungeon.level.height()) { - by = Dungeon.level.height() - 1; + + if (foresight) { + distance = Foresight.DISTANCE; + circular = true; } + Point c = Dungeon.level.cellToPoint(pos); + TalismanOfForesight.Foresight talisman = buff( TalismanOfForesight.Foresight.class ); boolean cursed = talisman != null && talisman.isCursed(); - - for (int y = ay; y <= by; y++) { - for (int x = ax, p = ax + y * Dungeon.level.width(); x <= bx; x++, p++) { - if (circular && Math.abs(x - cx)-1 > ShadowCaster.rounding[distance][distance - Math.abs(y - cy)]){ - continue; + int[] rounding = ShadowCaster.rounding[distance]; + + int left, right; + int curr; + for (int y = Math.max(0, c.y - distance); y <= Math.min(Dungeon.level.height()-1, c.y + distance); y++) { + if (!circular){ + left = c.x - distance; + } else if (rounding[Math.abs(c.y - y)] < Math.abs(c.y - y)) { + left = c.x - rounding[Math.abs(c.y - y)]; + } else { + left = distance; + while (rounding[left] < rounding[Math.abs(c.y - y)]){ + left--; } + left = c.x - left; + } + right = Math.min(Dungeon.level.width()-1, c.x + c.x - left); + left = Math.max(0, left); + for (curr = left + y * Dungeon.level.width(); curr <= right + y * Dungeon.level.width(); curr++){ - if (fieldOfView[p] && p != pos) { - - if (intentional) { - GameScene.effectOverFog(new CheckedCell(p, pos)); + if ((foresight || fieldOfView[curr]) && curr != pos) { + + if ((foresight && (!Dungeon.level.mapped[curr] || foresightScan))){ + GameScene.effectOverFog(new CheckedCell(curr, foresightScan ? pos : curr)); + } else if (intentional) { + GameScene.effectOverFog(new CheckedCell(curr, pos)); + } + + if (foresight){ + Dungeon.level.mapped[curr] = true; } - if (Dungeon.level.secret[p]){ + if (Dungeon.level.secret[curr]){ - Trap trap = Dungeon.level.traps.get( p ); + Trap trap = Dungeon.level.traps.get( curr ); float chance; //searches aided by foresight always succeed, even if trap isn't searchable @@ -1932,7 +1943,7 @@ public class Hero extends Char { chance = 0f; //unintentional trap detection scales from 40% at floor 0 to 30% at floor 25 - } else if (Dungeon.level.map[p] == Terrain.SECRET_TRAP) { + } else if (Dungeon.level.map[curr] == Terrain.SECRET_TRAP) { chance = 0.4f - (Dungeon.depth / 250f); //unintentional door detection scales from 20% at floor 0 to 0% at floor 20 @@ -1942,15 +1953,15 @@ public class Hero extends Char { if (Random.Float() < chance) { - int oldValue = Dungeon.level.map[p]; + int oldValue = Dungeon.level.map[curr]; - GameScene.discoverTile( p, oldValue ); + GameScene.discoverTile( curr, oldValue ); - Dungeon.level.discover( p ); + Dungeon.level.discover( curr ); - ScrollOfMagicMapping.discover( p ); + ScrollOfMagicMapping.discover( curr ); - smthFound = true; + if (fieldOfView[curr]) smthFound = true; if (talisman != null){ if (oldValue == Terrain.SECRET_TRAP){ @@ -1964,7 +1975,6 @@ public class Hero extends Char { } } } - if (intentional) { sprite.showStatus( CharSprite.DEFAULT, Messages.get(this, "search") ); @@ -1986,6 +1996,10 @@ public class Hero extends Char { Sample.INSTANCE.play( Assets.Sounds.SECRET ); interrupt(); } + + if (foresight){ + GameScene.updateFog(pos, Foresight.DISTANCE+1); + } return smthFound; }