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.name=talisman of foresight
items.artifacts.talismanofforesight.ac_scry=SCRY items.artifacts.talismanofforesight.ac_scry=SCRY
items.artifacts.talismanofforesight.no_charge=Your talisman isn't fully charged yet. items.artifacts.talismanofforesight.low_charge=The talisman requires at least 5% charge to scry.
items.artifacts.talismanofforesight.scry=The Talisman floods your mind with knowledge about the current floor. items.artifacts.talismanofforesight.prompt=Choose a location to scan.
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.levelup=Your Talisman grows stronger!
items.artifacts.talismanofforesight.desc_worn=When you hold the talisman you feel like your senses are heightened. items.artifacts.talismanofforesight.full_charge=Your Talisman is fully charged!
items.artifacts.talismanofforesight.desc_cursed=The cursed talisman is intently staring into you, making it impossible to concentrate. 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.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.uneasy=You feel uneasy.
items.artifacts.talismanofforesight$foresight.desc=You feel very nervous, as if there is nearby unseen danger. 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.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; 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.potions.Potion;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring; import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll; 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(); GameScene.afterObserve();
} }

View File

@ -1764,8 +1764,13 @@ public class Hero extends Char {
smthFound = true; smthFound = true;
if (talisman != null && !talisman.isCursed()) if (talisman != null){
talisman.charge(); 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.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; 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.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; 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.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ConeAOE;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector;
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.ui.BuffIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
@ -58,8 +66,7 @@ public class TalismanOfForesight extends Artifact {
@Override @Override
public ArrayList<String> actions( Hero hero ) { public ArrayList<String> actions( Hero hero ) {
ArrayList<String> actions = super.actions( hero ); ArrayList<String> actions = super.actions( hero );
if (isEquipped( hero ) && charge == chargeCap && !cursed) if (isEquipped( hero ) && !cursed) actions.add(AC_SCRY);
actions.add(AC_SCRY);
return actions; return actions;
} }
@ -68,34 +75,9 @@ public class TalismanOfForesight extends Artifact {
super.execute(hero, action); super.execute(hero, action);
if (action.equals(AC_SCRY)){ if (action.equals(AC_SCRY)){
if (!isEquipped(hero)) GLog.i( Messages.get(Artifact.class, "need_to_equip") );
if (!isEquipped(hero)) GLog.i( Messages.get(Artifact.class, "need_to_equip") ); else if (charge < 5) GLog.i( Messages.get(this, "low_charge") );
else if (charge != chargeCap) GLog.i( Messages.get(this, "no_charge") ); else GameScene.selectCell(scry);
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();
}
} }
} }
@ -107,7 +89,7 @@ public class TalismanOfForesight extends Artifact {
@Override @Override
public void charge(Hero target) { public void charge(Hero target) {
if (charge < chargeCap){ if (charge < chargeCap){
charge += 4f; charge += 2f;
if (charge >= chargeCap) { if (charge >= chargeCap) {
charge = chargeCap; charge = chargeCap;
partialCharge = 0; partialCharge = 0;
@ -131,7 +113,119 @@ public class TalismanOfForesight extends Artifact {
return desc; 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"; private static final String WARN = "warn";
@Override @Override
@ -143,10 +237,10 @@ public class TalismanOfForesight extends Artifact {
@Override @Override
public void restoreFromBundle(Bundle bundle) { public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(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{ public class Foresight extends ArtifactBuff{
@ -191,23 +285,21 @@ public class TalismanOfForesight extends Artifact {
} }
if (smthFound && !cursed){ if (smthFound && !cursed){
if (warn == 0){ if (!warn){
GLog.w( Messages.get(this, "uneasy") ); GLog.w( Messages.get(this, "uneasy") );
if (target instanceof Hero){ if (target instanceof Hero){
((Hero)target).interrupt(); ((Hero)target).interrupt();
} }
warn = true;
} }
warn = 3;
} else { } else {
if (warn > 0){ warn = false;
warn --;
}
} }
//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); LockedFloor lock = target.buff(LockedFloor.class);
if (charge < chargeCap && !cursed && (lock == null || lock.regenOn())) { 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) { if (partialCharge > 1 && charge < chargeCap) {
partialCharge--; partialCharge--;
@ -215,22 +307,15 @@ public class TalismanOfForesight extends Artifact {
updateQuickslot(); updateQuickslot();
} else if (charge >= chargeCap) { } else if (charge >= chargeCap) {
partialCharge = 0; partialCharge = 0;
GLog.p( Messages.get(this, "full_charge") ); GLog.p( Messages.get(TalismanOfForesight.class, "full_charge") );
} }
} }
return true; return true;
} }
public void charge(){ public void charge(int boost){
charge = Math.min(charge+(2+(level()/3)), chargeCap); charge = Math.min((charge+boost), chargeCap);
exp++;
if (exp >= 4 && level() < levelCap) {
upgrade();
GLog.p( Messages.get(this, "levelup") );
exp -= 4;
}
updateQuickslot();
} }
@Override @Override
@ -245,10 +330,64 @@ public class TalismanOfForesight extends Artifact {
@Override @Override
public int icon() { public int icon() {
if (warn == 0) if (warn)
return BuffIndicator.NONE;
else
return BuffIndicator.FORESIGHT; 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.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Stylus; import com.shatteredpixel.shatteredpixeldungeon.items.Stylus;
import com.shatteredpixel.shatteredpixeldungeon.items.Torch; 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.artifacts.TimekeepersHourglass;
import com.shatteredpixel.shatteredpixeldungeon.items.food.SmallRation; import com.shatteredpixel.shatteredpixeldungeon.items.food.SmallRation;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfStrength; 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){ for (Mob ward : mobs){
if (ward instanceof WandOfWarding.Ward){ if (ward instanceof WandOfWarding.Ward){
if (ward.fieldOfView == null || ward.fieldOfView.length != length()){ if (ward.fieldOfView == null || ward.fieldOfView.length != length()){