v0.8.1: reworked talisman of foresight

This commit is contained in:
Evan Debenham 2020-06-12 13:50:05 -04:00
parent 0e7ba4e567
commit d22d78255f
5 changed files with 243 additions and 64 deletions

View File

@ -373,14 +373,14 @@ items.artifacts.sandalsofnature.desc_seeds=You have fed the footwear %d seeds.
items.artifacts.talismanofforesight.name=talisman of foresight
items.artifacts.talismanofforesight.ac_scry=SCRY
items.artifacts.talismanofforesight.no_charge=Your talisman isn't fully charged yet.
items.artifacts.talismanofforesight.scry=The Talisman floods your mind with knowledge about the current floor.
items.artifacts.talismanofforesight.desc=A smooth stone with strange engravings on it. You feel like it's watching everything around you, keeping an eye out for anything unusual.
items.artifacts.talismanofforesight.desc_worn=When you hold the talisman you feel like your senses are heightened.
items.artifacts.talismanofforesight.desc_cursed=The cursed talisman is intently staring into you, making it impossible to concentrate.
items.artifacts.talismanofforesight.low_charge=The talisman requires at least 5% charge to scry.
items.artifacts.talismanofforesight.prompt=Choose a location to scan.
items.artifacts.talismanofforesight.levelup=Your Talisman grows stronger!
items.artifacts.talismanofforesight.full_charge=Your Talisman is fully charged!
items.artifacts.talismanofforesight.desc=A smooth stone with strange engravings on it. You feel like it's watching everything around you, keeping an eye out for anything hidden.
items.artifacts.talismanofforesight.desc_worn=When you hold the talisman you feel like your senses are heightened. The talisman is slowly building charge as time passes and when you discover hidden doors or traps.\n\nThe talisman can expend its charge to 'scry' in a cone shape, which reveals all tiles and secrets in the scanned area, and will grant you vision of enemies and items for a short time.
items.artifacts.talismanofforesight.desc_cursed=The cursed talisman is intently staring into you, dulling your senses.
items.artifacts.talismanofforesight$foresight.name=Foresight
items.artifacts.talismanofforesight$foresight.levelup=Your Talisman grows stronger!
items.artifacts.talismanofforesight$foresight.full_charge=Your Talisman is fully charged!
items.artifacts.talismanofforesight$foresight.uneasy=You feel uneasy.
items.artifacts.talismanofforesight$foresight.desc=You feel very nervous, as if there is nearby unseen danger.

View File

@ -37,6 +37,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Ankh;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TalismanOfForesight;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll;
@ -799,6 +800,22 @@ public class Dungeon {
}
}
for (TalismanOfForesight.CharAwareness c : hero.buffs(TalismanOfForesight.CharAwareness.class)){
Char ch = (Char) Actor.findById(c.charID);
if (ch == null) continue;
BArray.or( level.visited, level.heroFOV, ch.pos - 1 - level.width(), 3, level.visited );
BArray.or( level.visited, level.heroFOV, ch.pos - 1, 3, level.visited );
BArray.or( level.visited, level.heroFOV, ch.pos - 1 + level.width(), 3, level.visited );
GameScene.updateFog(ch.pos, 2);
}
for (TalismanOfForesight.HeapAwareness h : hero.buffs(TalismanOfForesight.HeapAwareness.class)){
BArray.or( level.visited, level.heroFOV, h.pos - 1 - level.width(), 3, level.visited );
BArray.or( level.visited, level.heroFOV, h.pos - 1, 3, level.visited );
BArray.or( level.visited, level.heroFOV, h.pos - 1 + level.width(), 3, level.visited );
GameScene.updateFog(h.pos, 2);
}
GameScene.afterObserve();
}

View File

@ -1764,8 +1764,13 @@ public class Hero extends Char {
smthFound = true;
if (talisman != null && !talisman.isCursed())
talisman.charge();
if (talisman != null){
if (oldValue == Terrain.SECRET_TRAP){
talisman.charge(2);
} else if (oldValue == Terrain.SECRET_DOOR){
talisman.charge(10);
}
}
}
}
}

View File

@ -23,12 +23,20 @@ package com.shatteredpixel.shatteredpixeldungeon.items.artifacts;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Awareness;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.effects.CheckedCell;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfMagicMapping;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ConeAOE;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
@ -58,8 +66,7 @@ public class TalismanOfForesight extends Artifact {
@Override
public ArrayList<String> actions( Hero hero ) {
ArrayList<String> actions = super.actions( hero );
if (isEquipped( hero ) && charge == chargeCap && !cursed)
actions.add(AC_SCRY);
if (isEquipped( hero ) && !cursed) actions.add(AC_SCRY);
return actions;
}
@ -68,34 +75,9 @@ public class TalismanOfForesight extends Artifact {
super.execute(hero, action);
if (action.equals(AC_SCRY)){
if (!isEquipped(hero)) GLog.i( Messages.get(Artifact.class, "need_to_equip") );
else if (charge != chargeCap) GLog.i( Messages.get(this, "no_charge") );
else {
hero.sprite.operate(hero.pos);
hero.busy();
Sample.INSTANCE.play(Assets.Sounds.BEACON);
charge = 0;
for (int i = 0; i < Dungeon.level.length(); i++) {
int terr = Dungeon.level.map[i];
if ((Terrain.flags[terr] & Terrain.SECRET) != 0) {
GameScene.updateMap(i);
if (Dungeon.level.heroFOV[i]) {
GameScene.discoverTile(i, terr);
}
}
}
GLog.p( Messages.get(this, "scry") );
updateQuickslot();
Buff.affect(hero, Awareness.class, Awareness.DURATION);
Dungeon.observe();
}
if (!isEquipped(hero)) GLog.i( Messages.get(Artifact.class, "need_to_equip") );
else if (charge < 5) GLog.i( Messages.get(this, "low_charge") );
else GameScene.selectCell(scry);
}
}
@ -107,7 +89,7 @@ public class TalismanOfForesight extends Artifact {
@Override
public void charge(Hero target) {
if (charge < chargeCap){
charge += 4f;
charge += 2f;
if (charge >= chargeCap) {
charge = chargeCap;
partialCharge = 0;
@ -131,7 +113,119 @@ public class TalismanOfForesight extends Artifact {
return desc;
}
private float maxDist(){
return Math.min(5 + 2*level(), (charge-3)/0.88f);
}
private CellSelector.Listener scry = new CellSelector.Listener(){
@Override
public void onSelect(Integer target) {
if (target != null && target != curUser.pos){
//enforces at least 2 tiles of distance
if (Dungeon.level.adjacent(target, curUser.pos)){
target += (target - curUser.pos);
}
float dist = Dungeon.level.trueDistance(curUser.pos, target);
if (dist >= 3 && dist > maxDist()){
Ballistica trajectory = new Ballistica(curUser.pos, target, Ballistica.STOP_TARGET);
int i = 0;
while (i < trajectory.path.size()
&& Dungeon.level.trueDistance(curUser.pos, trajectory.path.get(i)) <= maxDist()){
target = trajectory.path.get(i);
i++;
}
dist = Dungeon.level.trueDistance(curUser.pos, target);
}
//starts at 200 degrees, loses 8% per tile of distance
float angle = Math.round(200*(float)Math.pow(0.92, dist));
ConeAOE cone = new ConeAOE(curUser.pos, target, angle);
int earnedExp = 0;
boolean noticed = false;
for (int cell : cone.cells){
GameScene.effectOverFog(new CheckedCell( cell, curUser.pos ));
if (Dungeon.level.discoverable[cell] && !(Dungeon.level.mapped[cell] || Dungeon.level.visited[cell])){
Dungeon.level.mapped[cell] = true;
earnedExp++;
}
if (Dungeon.level.secret[cell]) {
Dungeon.level.discover(cell);
if (Dungeon.level.heroFOV[cell]) {
int oldValue = Dungeon.level.map[cell];
GameScene.discoverTile(cell, Dungeon.level.map[cell]);
Dungeon.level.discover( cell );
ScrollOfMagicMapping.discover(cell);
noticed = true;
if (oldValue == Terrain.SECRET_TRAP){
earnedExp += 10;
} else if (oldValue == Terrain.SECRET_DOOR){
earnedExp += 100;
}
}
}
Char ch = Actor.findChar(cell);
if (ch != null && ch.alignment != Char.Alignment.NEUTRAL && ch.alignment != curUser.alignment){
Buff.append(curUser, CharAwareness.class, 5 + 2*level()).charID = ch.id();
if (!curUser.fieldOfView[ch.pos]){
earnedExp += 10;
}
}
Heap h = Dungeon.level.heaps.get(cell);
if (h != null){
Buff.append(curUser, HeapAwareness.class, 5 + 2*level()).pos = h.pos;
if (!h.seen){
earnedExp += 10;
}
}
}
exp += earnedExp;
if (exp >= 100 + 50*level() && level() < levelCap) {
exp -= 100 + 50*level();
upgrade();
GLog.p( Messages.get(TalismanOfForesight.class, "levelup") );
}
updateQuickslot();
charge -= 3 + dist*0.88f;
partialCharge -= (dist*0.88f)%1f;
if (partialCharge < 0 && charge > 0){
partialCharge ++;
charge --;
}
updateQuickslot();
Dungeon.observe();
Dungeon.hero.checkVisibleMobs();
GameScene.updateFog();
curUser.sprite.zap(target);
Sample.INSTANCE.play(Assets.Sounds.TELEPORT);
if (noticed) Sample.INSTANCE.play(Assets.Sounds.SECRET);
}
}
@Override
public String prompt() {
return Messages.get(TalismanOfForesight.class, "prompt");
}
};
private static final String WARN = "warn";
@Override
@ -143,10 +237,10 @@ public class TalismanOfForesight extends Artifact {
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
warn = bundle.getInt(WARN);
warn = bundle.getBoolean(WARN);
}
private int warn = 0;
private boolean warn = false;
public class Foresight extends ArtifactBuff{
@ -191,23 +285,21 @@ public class TalismanOfForesight extends Artifact {
}
if (smthFound && !cursed){
if (warn == 0){
if (!warn){
GLog.w( Messages.get(this, "uneasy") );
if (target instanceof Hero){
((Hero)target).interrupt();
}
warn = true;
}
warn = 3;
} else {
if (warn > 0){
warn --;
}
warn = false;
}
//fully charges in 2000 turns at lvl=0, scaling to 667 turns at lvl = 10.
//fully charges in 2000 turns at lvl=0, scaling to 1000 turns at lvl = 10.
LockedFloor lock = target.buff(LockedFloor.class);
if (charge < chargeCap && !cursed && (lock == null || lock.regenOn())) {
partialCharge += 0.05+(level()*0.01);
partialCharge += 0.05f+(level()*0.005f);
if (partialCharge > 1 && charge < chargeCap) {
partialCharge--;
@ -215,22 +307,15 @@ public class TalismanOfForesight extends Artifact {
updateQuickslot();
} else if (charge >= chargeCap) {
partialCharge = 0;
GLog.p( Messages.get(this, "full_charge") );
GLog.p( Messages.get(TalismanOfForesight.class, "full_charge") );
}
}
return true;
}
public void charge(){
charge = Math.min(charge+(2+(level()/3)), chargeCap);
exp++;
if (exp >= 4 && level() < levelCap) {
upgrade();
GLog.p( Messages.get(this, "levelup") );
exp -= 4;
}
updateQuickslot();
public void charge(int boost){
charge = Math.min((charge+boost), chargeCap);
}
@Override
@ -245,10 +330,64 @@ public class TalismanOfForesight extends Artifact {
@Override
public int icon() {
if (warn == 0)
return BuffIndicator.NONE;
else
if (warn)
return BuffIndicator.FORESIGHT;
else
return BuffIndicator.NONE;
}
}
public static class CharAwareness extends FlavourBuff {
public int charID;
private static final String ID = "id";
@Override
public void detach() {
super.detach();
Dungeon.observe();
GameScene.updateFog();
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
charID = bundle.getInt(ID);
}
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(ID, charID);
}
}
public static class HeapAwareness extends FlavourBuff {
public int pos;
private static final String POS = "pos";
@Override
public void detach() {
super.detach();
Dungeon.observe();
GameScene.updateFog();
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
pos = bundle.getInt(POS);
}
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(POS, pos);
}
}
}

View File

@ -54,6 +54,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Stylus;
import com.shatteredpixel.shatteredpixeldungeon.items.Torch;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TalismanOfForesight;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass;
import com.shatteredpixel.shatteredpixeldungeon.items.food.SmallRation;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfStrength;
@ -1082,6 +1083,23 @@ public abstract class Level implements Bundlable {
}
}
for (TalismanOfForesight.CharAwareness a : c.buffs(TalismanOfForesight.CharAwareness.class)){
Char ch = (Char) Actor.findById(a.charID);
if (ch == null) {
a.detach();
continue;
}
int p = ch.pos;
for (int i : PathFinder.NEIGHBOURS9)
fieldOfView[p+i] = true;
}
for (TalismanOfForesight.HeapAwareness h : c.buffs(TalismanOfForesight.HeapAwareness.class)){
int p = h.pos;
for (int i : PathFinder.NEIGHBOURS9)
fieldOfView[p+i] = true;
}
for (Mob ward : mobs){
if (ward instanceof WandOfWarding.Ward){
if (ward.fieldOfView == null || ward.fieldOfView.length != length()){