v3.0.0: implemented life link's spell sharing effect

also fixed mnemonic prayer extending buffs from trinity and PoM
This commit is contained in:
Evan Debenham
2025-02-17 15:55:22 -05:00
parent a9c179f452
commit 344b313b59
12 changed files with 210 additions and 79 deletions

View File

@@ -642,7 +642,7 @@ actors.hero.spells.divinesense.name=divine sense
actors.hero.spells.divinesense.short_desc=Gain temporary mind vision in a wide range.
actors.hero.spells.divinesense.desc=The Cleric focuses their senses on their surroundings, gaining mind vision with a %d tile range for 30 turns.
actors.hero.spells.divinesense$divinesensetracker.name=divine sense
actors.hero.spells.divinesense$divinesensetracker.desc=The Cleric is temporarily able to see other nearby creatures with their mind!\n\nTurns remaining: %s.
actors.hero.spells.divinesense$divinesensetracker.desc=This character is temporarily able to see other nearby creatures with their mind!\n\nTurns remaining: %s.
actors.hero.spells.divineintervention.name=divine intervention
actors.hero.spells.divineintervention.short_desc=Massive shield boost to Cleric and allies.
@@ -738,7 +738,7 @@ actors.hero.spells.shieldoflight.name=shield of light
actors.hero.spells.shieldoflight.short_desc=Grants temporary armor against a target.
actors.hero.spells.shieldoflight.desc=The Cleric creates a thin barrier of light between themselves and an enemy, increasing their armor's block power against that enemy by %1$d-%2$d for 4 turns.\n\nThis spell takes no time to cast, but cannot be used against multiple targets simultaneously.
actors.hero.spells.shieldoflight$shieldoflighttracker.name=shield of light
actors.hero.spells.shieldoflight$shieldoflighttracker.desc=A thin shield of light is standing between the Cleric and an enemy. It's not strong enough to outright block attacks, but will soften them.\n\nTurns Remaining: %s
actors.hero.spells.shieldoflight$shieldoflighttracker.desc=A thin shield of light is standing between this character and an enemy. It's not strong enough to outright block attacks, but will soften them.\n\nTurns Remaining: %s
actors.hero.spells.spiritform.name=spirit form
actors.hero.spells.spiritform.short_desc=Assigns Trinity to a ring or artifact.

View File

@@ -458,8 +458,8 @@ public abstract class Char extends Actor {
}
if (Dungeon.hero.alignment == enemy.alignment
&& Dungeon.level.distance(enemy.pos, Dungeon.hero.pos) <= 2
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null){
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null
&& (Dungeon.level.distance(enemy.pos, Dungeon.hero.pos) <= 2 || enemy.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null)){
dmg *= 0.925f - 0.075f*Dungeon.hero.pointsInTalent(Talent.AURA_OF_PROTECTION);
}
@@ -699,8 +699,8 @@ public abstract class Char extends Actor {
// hero and pris images skip this as they already benefit from hero's armor glyph proc
if (!(this instanceof Hero || this instanceof PrismaticImage)) {
if (Dungeon.hero.alignment == alignment && Dungeon.hero.belongings.armor() != null
&& Dungeon.level.distance(pos, Dungeon.hero.pos) <= 2
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null) {
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null
&& (Dungeon.level.distance(pos, Dungeon.hero.pos) <= 2 || buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null)) {
damage = Dungeon.hero.belongings.armor().proc( enemy, this, damage );
}
}
@@ -713,8 +713,8 @@ public abstract class Char extends Actor {
public int glyphLevel(Class<? extends Armor.Glyph> cls){
if (Dungeon.hero != null && Dungeon.level != null
&& this != Dungeon.hero && Dungeon.hero.alignment == alignment
&& Dungeon.level.distance(pos, Dungeon.hero.pos) <= 2
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null) {
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null
&& (Dungeon.level.distance(pos, Dungeon.hero.pos) <= 2 || buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null)) {
return Dungeon.hero.glyphLevel(cls);
} else {
return -1;
@@ -795,8 +795,8 @@ public abstract class Char extends Actor {
//if dmg is from a character we already reduced it in defenseProc
if (!(src instanceof Char)) {
if (Dungeon.hero.alignment == alignment
&& Dungeon.level.distance(pos, Dungeon.hero.pos) <= 2
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null) {
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null
&& (Dungeon.level.distance(pos, Dungeon.hero.pos) <= 2 || buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null)) {
damage *= 0.925f - 0.075f*Dungeon.hero.pointsInTalent(Talent.AURA_OF_PROTECTION);
}
}

View File

@@ -30,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bless;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
@@ -72,15 +73,35 @@ public class BlessSpell extends TargetedClericSpell {
Sample.INSTANCE.play(Assets.Sounds.TELEPORT);
new Flare(6, 32).color(0xFFFF00, true).show(ch.sprite, 2f);
affectChar(hero, ch);
if (ch == hero){
hero.busy();
hero.sprite.operate(ch.pos);
hero.spend( 1f );
} else {
hero.sprite.zap(ch.pos);
hero.spendAndNext( 1f );
}
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
if (ch == hero){
affectChar(hero, ally); //if cast on hero, duplicate to ally
} else if (ally == ch) {
affectChar(hero, hero); //if cast on ally, duplicate to hero
}
}
onSpellCast(tome, hero);
}
private void affectChar(Hero hero, Char ch){
new Flare(6, 32).color(0xFFFF00, true).show(ch.sprite, 2f);
if (ch == hero){
Buff.prolong(ch, Bless.class, 2f + 4*hero.pointsInTalent(Talent.BLESS));
Buff.affect(ch, Barrier.class).setShield(5 + 5*hero.pointsInTalent(Talent.BLESS));
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(5 + 5*hero.pointsInTalent(Talent.BLESS)), FloatingText.SHIELDING );
hero.busy();
hero.sprite.operate(ch.pos);
hero.spend( 1f );
} else {
Buff.prolong(ch, Bless.class, 5f + 5*hero.pointsInTalent(Talent.BLESS));
int totalHeal = 5 + 5*hero.pointsInTalent(Talent.BLESS);
@@ -99,12 +120,7 @@ public class BlessSpell extends TargetedClericSpell {
ch.HP = ch.HP + totalHeal;
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(totalHeal), FloatingText.HEALING );
}
hero.sprite.zap(ch.pos);
hero.spendAndNext( 1f );
}
onSpellCast(tome, hero);
}
public String desc(){

View File

@@ -30,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LostInventory;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
@@ -78,6 +79,13 @@ public class Cleanse extends ClericSpell {
}
}
Char ally = PowerOfMany.getPoweredAlly();
//hero is always affected, to just check for life linked ally
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null
&& !affected.contains(ally)){
affected.add(ally);
}
for (Char ch : affected) {
for (Buff b : ch.buffs()) {
if (b.type == Buff.buffType.NEGATIVE

View File

@@ -22,6 +22,7 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility;
@@ -29,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.AscendedForm;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon;
@@ -74,7 +76,12 @@ public abstract class ClericSpell {
public void onSpellCast(HolyTome tome, Hero hero){
Invisibility.dispel();
if (hero.hasTalent(Talent.SATIATED_SPELLS) && hero.buff(Talent.SatiatedSpellsTracker.class) != null){
Buff.affect(hero, Barrier.class).setShield(1 + 2*hero.pointsInTalent(Talent.SATIATED_SPELLS));
int amount = 1 + 2*hero.pointsInTalent(Talent.SATIATED_SPELLS);
Buff.affect(hero, Barrier.class).setShield(amount);
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
Buff.affect(ally, Barrier.class).setShield(amount);
}
hero.buff(Talent.SatiatedSpellsTracker.class).detach();
}
tome.spendCharge(chargeUse(hero));

View File

@@ -23,10 +23,13 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
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.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.effects.SpellSprite;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
@@ -55,15 +58,22 @@ public class DivineSense extends ClericSpell {
@Override
public void onCast(HolyTome tome, Hero hero) {
Buff.affect(hero, DivineSenseTracker.class, 30f);
Buff.prolong(hero, DivineSenseTracker.class, 30f);
Dungeon.observe();
Sample.INSTANCE.play(Assets.Sounds.READ);
hero.spend( 1f );
hero.busy();
SpellSprite.show(hero, SpellSprite.VISION);
hero.sprite.operate(hero.pos);
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
Buff.prolong(ally, DivineSenseTracker.class, 30f);
SpellSprite.show(ally, SpellSprite.VISION);
}
onSpellCast(tome, hero);
}

View File

@@ -35,6 +35,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Regeneration;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText;
@@ -54,6 +55,8 @@ import com.watabou.utils.BArray;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
import java.util.ArrayList;
public class HallowedGround extends TargetedClericSpell {
public static final HallowedGround INSTANCE = new HallowedGround();
@@ -90,6 +93,8 @@ public class HallowedGround extends TargetedClericSpell {
return;
}
ArrayList<Char> affected = new ArrayList<>();
PathFinder.buildDistanceMap(target, BArray.not(Dungeon.level.solid, null), hero.pointsInTalent(Talent.HALLOWED_GROUND));
for (int i = 0; i < Dungeon.level.length(); i++){
if (PathFinder.distance[i] != Integer.MAX_VALUE){
@@ -104,27 +109,24 @@ public class HallowedGround extends TargetedClericSpell {
Char ch = Actor.findChar(i);
if (ch != null){
if (ch.alignment == Char.Alignment.ALLY){
if (ch == Dungeon.hero || ch.HP == ch.HT){
Buff.affect(ch, Barrier.class).incShield(10);
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "10", FloatingText.SHIELDING );
} else {
int barrier = 10 - (ch.HT - ch.HP);
barrier = Math.max(barrier, 0);
ch.HP += 10 - barrier;
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(10-barrier), FloatingText.HEALING );
if (barrier > 0){
Buff.affect(ch, Barrier.class).incShield(barrier);
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(barrier), FloatingText.SHIELDING );
}
}
} else if (!ch.flying) {
Buff.affect(ch, Roots.class, 1f);
}
affected.add(ch);
}
}
}
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
if (affected.contains(hero) && !affected.contains(ally)){
affected.add(ally);
} else if (!affected.contains(hero) && affected.contains(ally)){
affected.add(hero);
}
}
for (Char ch : affected){
affectChar(ch);
}
//5 casts per hero level before furrowing
Buff.affect(hero, HallowedFurrowTracker.class).countUp(1);
@@ -136,6 +138,27 @@ public class HallowedGround extends TargetedClericSpell {
}
private void affectChar( Char ch ){
if (ch.alignment == Char.Alignment.ALLY){
if (ch == Dungeon.hero || ch.HP == ch.HT){
Buff.affect(ch, Barrier.class).incShield(10);
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "10", FloatingText.SHIELDING );
} else {
int barrier = 10 - (ch.HT - ch.HP);
barrier = Math.max(barrier, 0);
ch.HP += 10 - barrier;
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(10-barrier), FloatingText.HEALING );
if (barrier > 0){
Buff.affect(ch, Barrier.class).incShield(barrier);
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(barrier), FloatingText.SHIELDING );
}
}
} else if (!ch.flying) {
Buff.affect(ch, Roots.class, 1f);
}
}
public String desc(){
int area = 1 + 2*Dungeon.hero.pointsInTalent(Talent.HALLOWED_GROUND);
return Messages.get(this, "desc", area) + "\n\n" + Messages.get(this, "charge_cost", (int)chargeUse(Dungeon.hero));
@@ -150,6 +173,8 @@ public class HallowedGround extends TargetedClericSpell {
Fire fire = (Fire)Dungeon.level.blobs.get( Fire.class );
ArrayList<Char> affected = new ArrayList<>();
// on avg, hallowed ground produces 9/17/25 tiles of grass, 100/67/50% of total tiles
int chance = 10 + 10*Dungeon.hero.pointsInTalent(Talent.HALLOWED_GROUND);
@@ -184,17 +209,7 @@ public class HallowedGround extends TargetedClericSpell {
Char ch = Actor.findChar(cell);
if (ch != null){
if (ch.alignment == Char.Alignment.ALLY){
if (ch == Dungeon.hero || ch.HP == ch.HT){
Buff.affect(ch, Barrier.class).incShield(1);
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "1", FloatingText.SHIELDING );
} else {
ch.HP++;
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "1", FloatingText.HEALING );
}
} else if (!ch.flying && ch.buff(Roots.class) == null){
Buff.prolong(ch, Cripple.class, 1f);
}
affected.add(ch);
}
off[cell] = cur[cell] - 1;
@@ -204,6 +219,34 @@ public class HallowedGround extends TargetedClericSpell {
}
}
}
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
if (affected.contains(Dungeon.hero) && !affected.contains(ally)){
affected.add(ally);
} else if (!affected.contains(Dungeon.hero) && affected.contains(ally)){
affected.add(Dungeon.hero);
}
}
for (Char ch :affected){
affectChar(ch);
}
}
private void affectChar( Char ch ){
if (ch.alignment == Char.Alignment.ALLY){
if (ch == Dungeon.hero || ch.HP == ch.HT){
Buff.affect(ch, Barrier.class).incShield(1);
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "1", FloatingText.SHIELDING );
} else {
ch.HP++;
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "1", FloatingText.HEALING );
}
} else if (!ch.flying && ch.buff(Roots.class) == null){
Buff.prolong(ch, Cripple.class, 1f);
}
}
@Override

View File

@@ -29,6 +29,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@@ -80,6 +81,30 @@ public class LayOnHands extends TargetedClericSpell {
Sample.INSTANCE.play(Assets.Sounds.TELEPORT);
affectChar(hero, ch);
if (ch == hero){
hero.sprite.operate(ch.pos);
hero.next();
} else {
hero.sprite.zap(ch.pos);
hero.next();
}
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
if (ch == hero){
affectChar(hero, ally); //if cast on hero, duplicate to ally
} else if (ally == ch) {
affectChar(hero, hero); //if cast on ally, duplicate to hero
}
}
onSpellCast(tome, hero);
}
private void affectChar(Hero hero, Char ch){
Barrier barrier = Buff.affect(ch, Barrier.class);
int totalHeal = 5 + 5*hero.pointsInTalent(Talent.LAY_ON_HANDS);
int totalBarrier = 0;
@@ -89,8 +114,6 @@ public class LayOnHands extends TargetedClericSpell {
totalBarrier = Math.max(0, totalBarrier);
Buff.affect(ch, Barrier.class).incShield(totalBarrier);
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(totalBarrier), FloatingText.SHIELDING );
hero.sprite.operate(ch.pos);
hero.next();
} else {
if (ch.HT - ch.HP < totalHeal){
totalBarrier = totalHeal - (ch.HT - ch.HP);
@@ -100,7 +123,7 @@ public class LayOnHands extends TargetedClericSpell {
ch.HP = ch.HT;
ch.sprite.showStatusWithIcon(CharSprite.POSITIVE, Integer.toString(totalHeal - totalBarrier), FloatingText.HEALING);
}
if (totalBarrier >= 0) {
if (totalBarrier > 0) {
barrier.incShield(totalBarrier);
ch.sprite.showStatusWithIcon(CharSprite.POSITIVE, Integer.toString(totalBarrier), FloatingText.SHIELDING);
}
@@ -108,12 +131,6 @@ public class LayOnHands extends TargetedClericSpell {
ch.HP = ch.HP + totalHeal;
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(totalHeal), FloatingText.HEALING );
}
hero.sprite.zap(ch.pos);
hero.next();
}
onSpellCast(tome, hero);
}
}

View File

@@ -38,6 +38,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FireImbue;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.GreaterHaste;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Healing;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LifeLink;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Ooze;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ShieldBuff;
@@ -46,6 +47,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.WellFed;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.AscendedForm;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
@@ -97,7 +99,32 @@ public class MnemonicPrayer extends TargetedClericSpell {
QuickSlotButton.target(ch);
float extension = 2 + hero.pointsInTalent(Talent.MNEMONIC_PRAYER);
affectChar(ch, extension);
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
if (ch == hero){
affectChar(ally, extension); //if cast on hero, duplicate to ally
} else if (ch == ally){
affectChar(hero, extension); //if cast on ally, duplicate to hero
}
}
if (ch == hero){
hero.busy();
hero.sprite.operate(ch.pos);
hero.spend( 1f );
BuffIndicator.refreshHero();
} else {
hero.sprite.zap(ch.pos);
hero.spendAndNext( 1f );
}
onSpellCast(tome, hero);
}
private void affectChar( Char ch, float extension ){
if (ch.alignment == Char.Alignment.ALLY){
Sample.INSTANCE.play(Assets.Sounds.CHARGEUP);
@@ -108,8 +135,10 @@ public class MnemonicPrayer extends TargetedClericSpell {
continue;
}
//no it does not boost ascended form lmao
if (b instanceof AscendedForm.AscendBuff){
//does not boost buffs from armor abilities or T4 spells
if (b instanceof AscendedForm.AscendBuff
|| b instanceof BodyForm.BodyFormBuff || b instanceof SpiritForm.SpiritFormBuff
|| b instanceof PowerOfMany.PowerBuff || b instanceof BeamingRay.BeamingRayBoost || b instanceof LifeLink || b instanceof LifeLinkSpell.LifeLinkSpellBuff){
continue;
}
@@ -164,19 +193,6 @@ public class MnemonicPrayer extends TargetedClericSpell {
}
}
if (ch == hero){
hero.busy();
hero.sprite.operate(ch.pos);
hero.spend( 1f );
BuffIndicator.refreshHero();
} else {
hero.sprite.zap(ch.pos);
hero.spendAndNext( 1f );
}
onSpellCast(tome, hero);
}
public String desc(){

View File

@@ -29,6 +29,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
@@ -84,6 +85,12 @@ public class ShieldOfLight extends TargetedClericSpell {
hero.sprite.operate(hero.pos);
hero.sprite.emitter().start(Speck.factory(Speck.LIGHT), 0.15f, 6);
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null){
Buff.prolong( ally, ShieldOfLightTracker.class, 3f).object = ch.id();
ally.sprite.emitter().start(Speck.factory(Speck.LIGHT), 0.15f, 6);
}
onSpellCast(tome, hero);
}

View File

@@ -36,6 +36,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.AuraOfProtection;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.BodyForm;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWard;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.LifeLinkSpell;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal;
import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem;
@@ -464,8 +465,8 @@ public class Armor extends EquipableItem {
}
//so that this effect procs for allies using this armor via aura of protection
if (defender.alignment == Dungeon.hero.alignment
&& Dungeon.level.distance(defender.pos, Dungeon.hero.pos) <= 2
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null
&& (Dungeon.level.distance(defender.pos, Dungeon.hero.pos) <= 2 || defender.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null)
&& Dungeon.hero.buff(HolyWard.HolyArmBuff.class) != null) {
int blocking = Dungeon.hero.subClass == HeroSubClass.PALADIN ? 3 : 1;
damage -= Math.round(blocking * Glyph.genericProcChanceMultiplier(defender));
@@ -756,8 +757,8 @@ public class Armor extends EquipableItem {
float multi = RingOfArcana.enchantPowerMultiplier(defender);
if (Dungeon.hero.alignment == defender.alignment
&& Dungeon.level.distance(defender.pos, Dungeon.hero.pos) <= 2
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null){
&& Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null
&& (Dungeon.level.distance(defender.pos, Dungeon.hero.pos) <= 2 || defender.buff(LifeLinkSpell.LifeLinkSpellBuff.class) != null)){
multi += 0.25f + 0.25f*Dungeon.hero.pointsInTalent(Talent.AURA_OF_PROTECTION);
}

View File

@@ -1377,13 +1377,19 @@ public abstract class Level implements Bundlable {
}
mindVisRange = Math.max(mindVisRange, EyeOfNewt.mindVisionRange());
//power of many's life link spell allows allies to get divine sense
Char ally = PowerOfMany.getPoweredAlly();
if (ally != null && ally.buff(DivineSense.DivineSenseTracker.class) == null){
ally = null;
}
if (mindVisRange >= 1) {
for (Mob mob : mobs) {
if (mob instanceof Mimic && mob.alignment == Char.Alignment.NEUTRAL&& ((Mimic) mob).stealthy()){
if (mob instanceof Mimic && mob.alignment == Char.Alignment.NEUTRAL && ((Mimic) mob).stealthy()){
continue;
}
int p = mob.pos;
if (!fieldOfView[p] && distance(c.pos, p) <= mindVisRange) {
if (!fieldOfView[p] && (distance(c.pos, p) <= mindVisRange || (ally != null && distance(ally.pos, p) <= mindVisRange))) {
for (int i : PathFinder.NEIGHBOURS9) {
heroMindFov[mob.pos + i] = true;
}