v3.0.0: added metamorph fx for T2 and T3 cleric talents

This commit is contained in:
Evan Debenham
2025-02-21 15:13:51 -05:00
parent 02d0f4e018
commit 9e0f2a5077
9 changed files with 137 additions and 20 deletions

View File

@@ -1222,19 +1222,27 @@ actors.hero.talent.shield_of_light.meta_desc=_If this talent is gained by a diff
actors.hero.talent.enlightening_meal.title=Enlightening Meal
actors.hero.talent.enlightening_meal.desc=_+1:_ Eating food takes the Cleric 1 turn and grants them _1 charge_ on their holy tome.\n\n_+2:_ Eating food takes the Cleric 1 turn and grants them _1.5 charges_ on their holy tome.
actors.hero.talent.enlightening_meal.meta_desc=_If this talent is gained by a different hero_ it will instead grant 2 turns of wand and artifact recharging at +1, or 3 turns at +2.
actors.hero.talent.recall_inscription.title=Recall Inscription
actors.hero.talent.recall_inscription.refunded=Your item was refunded!
actors.hero.talent.recall_inscription.desc=_+1:_ The Cleric can cast _Recall Inscription,_ a spell that lets them repeat the effect of the last runestone or scroll they used within _10 turns._\n\n_+2:_ The Cleric can cast _Recall Inscription,_ a spell that lets them repeat the effect of the last runestone or scroll they used within _300 turns._\n\nRecall Inscription cannot be used with scrolls of upgrade. This spell's charge cost varies based on which item was used recently: 2 for a runestone, 3 for a scroll, 4 for an exotic scroll. This charge cost is also doubled when used with a scroll of transmutation, or alchemy items that must be crafted using transmutation or upgrade.
actors.hero.talent.recall_inscription.meta_desc=_If this talent is gained by a different hero_ it will instead refund any scroll or runestone 10% of the time at +1 or 15% of the time at +2. Scrolls of Upgrade are exempt from this effect.
actors.hero.talent.sunray.title=Sunray
actors.hero.talent.sunray.desc=_+1:_ The Cleric can cast _Sunray,_ a spell that deals _4-8 damage_ and blinds the target for _4 turns,_ at the cost of 1 charge.\n\n_+2:_ The Cleric can cast _Sunray,_ a spell that deals _6-12 damage_ and blinds the target for _6 turns,_ at the cost of 1 charge.\n\nSunray can only blind each target once, but if the target is already blinded by Sunray then it paralyses instead. Sunray always deals maximum damage to demonic and undead foes.
actors.hero.talent.sunray.meta_desc=_If this talent is gained by a different hero_ it will instead cause wands and artifacts to blind enemies for 4 turns, 15% of the time at +1 or 25% of the time at +2.
actors.hero.talent.divine_sense.title=Divine Sense
actors.hero.talent.divine_sense.desc=_+1:_ The Cleric can cast _Divine Sense,_ a spell that grants them _8 tiles_ of Mind Vision for 30 turns, at the cost of 2 charges.\n\n_+2:_ The Cleric can cast _Divine Sense,_ a spell that grants them _12 tiles_ of Mind Vision for 30 turns, at the cost of 2 charges.
actors.hero.talent.divine_sense.meta_desc=_If this talent is gained by a different hero_ it will instead grant them mind vision for a brief moment after using a wand or artifact with a range of 3 tiles at +1 or 5 tiles at +2.
actors.hero.talent.bless.title=Bless
actors.hero.talent.bless.desc=_+1:_ The Cleric can cast _Bless,_ a spell that grants _6 turns of bless and 10 shielding_ when cast on themselves or _10 turns of bless and 10 healing_ when cast on another character, at the cost of 1 charge.\n\n_+2:_ The Cleric can cast _Bless,_ a spell that grants _10 turns of bless and 15 shielding_ when cast on themselves or _15 turns of bless and 15 healing_ when cast on another character, at the cost of 1 charge.\n\nExcess healing from this spell is converted into shielding.
actors.hero.talent.bless.meta_desc=_If this talent is gained by a different hero_ it will instead boost accuracy and evasion for the hero and all allies by 3% at +1 or 5% at +2.
actors.hero.talent.cleanse.title=Cleanse
actors.hero.talent.cleanse.desc=_+1:_ The Cleric can cast _Cleanse,_ a spell which is cast instantly, _removes negative status effects_ from the Cleric and any nearby allies, and grants them _10 shielding,_ at the cost of 2 charges.\n\n_+2:_ The Cleric can cast _Cleanse,_ a spell which is cast instantly, _grants 3 turns of negative status immunity_ to the Cleric and any nearby allies, and grants them _20 shielding,_ at the cost of 2 charges.\n\n_+3:_ The Cleric can cast _Cleanse,_ a spell which is cast instantly, _grants 5 turns of negative status immunity_ to the Cleric and any nearby allies, and grants them _30 shielding,_ at the cost of 2 charges.
actors.hero.talent.cleanse.meta_desc=_If this talent is gained by a different hero_ it will instead cleanse negative status effects on the hero after using a wand or artifact, 10/20/30% of the time at +1/+2/+3.
actors.hero.talent.light_reading.title=Light Reading
actors.hero.talent.light_reading.desc=_+1:_ The Cleric can use their holy tome when it is not equipped, but it recharges at _25% speed_ when unequipped.\n\n_+2:_ The Cleric can use their holy tome when it is not equipped, but it recharges at _50% speed_ when unequipped.\n\n_+3:_ The Cleric can use their holy tome when it is not equipped, but it recharges at _75% speed_ when unequipped.
actors.hero.talent.light_reading.meta_desc=_If this talent is gained by a different hero_ it will instead increase the recharging speed of all wands by 7/13/20% at +1/+2/+3.
actors.hero.talent.holy_lance.title=Holy Lance
actors.hero.talent.holy_lance.desc=_+1:_ The Priest can cast _Holy Lance,_ a devastating spell that deals _30-55 damage_ at the cost of 4 charges.\n\n_+2:_ The Priest can cast _Holy Lance,_ a devastating spell that deals _45-83 damage_ at the cost of 4 charges.\n\n_+3:_ The Priest can cast _Holy Lance,_ a devastating spell that deals _60-110 damage_ at the cost of 4 charges.\n\nHoly Lance always deals maximum damage to demonic and undead foes. Holy Lance has a 50 turn cooldown before it can be cast again.

View File

@@ -637,6 +637,12 @@ public abstract class Char extends Actor {
acuRoll *= buff.evasionAndAccuracyFactor();
}
acuRoll *= AscensionChallenge.statModifier(attacker);
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.BLESS)
&& attacker.alignment == Alignment.ALLY){
// + 3%/5%
acuRoll *= 1.01f + 0.02f*Dungeon.hero.pointsInTalent(Talent.BLESS);
}
float defRoll = Random.Float( defStat );
if (defender.buff(Bless.class) != null) defRoll *= 1.25f;
@@ -646,6 +652,12 @@ public abstract class Char extends Actor {
defRoll *= buff.evasionAndAccuracyFactor();
}
defRoll *= AscensionChallenge.statModifier(defender);
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.BLESS)
&& defender.alignment == Alignment.ALLY){
// + 3%/5%
defRoll *= 1.01f + 0.02f*Dungeon.hero.pointsInTalent(Talent.BLESS);
}
return (acuRoll * accMulti) >= defRoll;
}

View File

@@ -43,9 +43,11 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ScrollEmpower;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.WandEmpower;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.Ratmogrify;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.DivineSense;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.RecallInscription;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText;
import com.shatteredpixel.shatteredpixeldungeon.effects.SpellSprite;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
@@ -61,6 +63,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRecharging;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.Runestone;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfIntuition;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.SpiritBow;
@@ -74,12 +77,14 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.Image;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Bundle;
import com.watabou.utils.GameMath;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
import com.watabou.utils.Reflection;
import java.util.ArrayList;
import java.util.Collections;
@@ -637,10 +642,21 @@ public enum Talent {
}
}
if (hero.hasTalent(ENLIGHTENING_MEAL)){
HolyTome tome = hero.belongings.getItem(HolyTome.class);
if (tome != null) {
tome.directCharge( 0.5f * (1+hero.pointsInTalent(ENLIGHTENING_MEAL)));
ScrollOfRecharging.charge(hero);
if (hero.heroClass == HeroClass.CLERIC) {
HolyTome tome = hero.belongings.getItem(HolyTome.class);
if (tome != null) {
tome.directCharge( 0.5f * (1+hero.pointsInTalent(ENLIGHTENING_MEAL)));
ScrollOfRecharging.charge(hero);
}
} else {
//2/3 turns of recharging
ArtifactRecharge buff = Buff.affect( hero, ArtifactRecharge.class);
if (buff.left() < 1 + (hero.pointsInTalent(ENLIGHTENING_MEAL))){
Buff.affect( hero, ArtifactRecharge.class).set(1 + (hero.pointsInTalent(ENLIGHTENING_MEAL))).ignoreHornOfPlenty = foodSource instanceof HornOfPlenty;
}
Buff.prolong( hero, Recharging.class, 1 + (hero.pointsInTalent(ENLIGHTENING_MEAL)) );
ScrollOfRecharging.charge( hero );
SpellSprite.show(hero, SpellSprite.CHARGE);
}
}
}
@@ -745,19 +761,35 @@ public enum Talent {
Buff.affect(hero, Invisibility.class, factor * (1 + 2*hero.pointsInTalent(INSCRIBED_STEALTH)));
Sample.INSTANCE.play( Assets.Sounds.MELD );
}
if (hero.heroClass == HeroClass.CLERIC
&& hero.hasTalent(RECALL_INSCRIPTION)
&& Scroll.class.isAssignableFrom(cls)
&& cls != ScrollOfUpgrade.class){
Buff.prolong(hero, RecallInscription.UsedItemTracker.class, hero.pointsInTalent(RECALL_INSCRIPTION) == 2 ? 300 : 10).item = cls;
if (hero.hasTalent(RECALL_INSCRIPTION) && Scroll.class.isAssignableFrom(cls) && cls != ScrollOfUpgrade.class){
if (hero.heroClass == HeroClass.CLERIC){
Buff.prolong(hero, RecallInscription.UsedItemTracker.class, hero.pointsInTalent(RECALL_INSCRIPTION) == 2 ? 300 : 10).item = cls;
} else {
// 10/15%
if (Random.Int(20) < 1 + hero.pointsInTalent(RECALL_INSCRIPTION)){
Reflection.newInstance(cls).collect();
GLog.p("refunded!");
}
}
}
}
public static void onRunestoneUsed( Hero hero, int pos, Class<?extends Item> cls ){
if (hero.heroClass == HeroClass.CLERIC
&& hero.hasTalent(RECALL_INSCRIPTION)
&& Runestone.class.isAssignableFrom(cls)){
Buff.prolong(hero, RecallInscription.UsedItemTracker.class, hero.pointsInTalent(RECALL_INSCRIPTION) == 2 ? 300 : 10).item = cls;
if (hero.hasTalent(RECALL_INSCRIPTION) && Runestone.class.isAssignableFrom(cls)){
if (hero.heroClass == HeroClass.CLERIC){
Buff.prolong(hero, RecallInscription.UsedItemTracker.class, hero.pointsInTalent(RECALL_INSCRIPTION) == 2 ? 300 : 10).item = cls;
} else {
//don't trigger on 1st intuition use
if (cls.equals(StoneOfIntuition.class) && hero.buff(StoneOfIntuition.IntuitionUseTracker.class) != null){
return;
}
// 10/15%
if (Random.Int(20) < 1 + hero.pointsInTalent(RECALL_INSCRIPTION)){
Reflection.newInstance(cls).collect();
GLog.p("refunded!");
}
}
}
}
@@ -765,6 +797,25 @@ public enum Talent {
if (hero.hasTalent(ENHANCED_RINGS)){
Buff.prolong(hero, EnhancedRings.class, 3f*hero.pointsInTalent(ENHANCED_RINGS));
}
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.DIVINE_SENSE)){
Buff.prolong(Dungeon.hero, DivineSense.DivineSenseTracker.class, Dungeon.hero.cooldown()+1);
}
// 10/20/30%
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.CLEANSE)
&& Random.Int(10) < Dungeon.hero.pointsInTalent(Talent.CLEANSE)){
boolean removed = false;
for (Buff b : Dungeon.hero.buffs()) {
if (b.type == Buff.buffType.NEGATIVE) {
b.detach();
removed = true;
}
}
if (removed) new Flare( 6, 32 ).color(0xFF4CD2, true).show( Dungeon.hero.sprite, 2f );
}
}
public static void onItemEquipped( Hero hero, Item item ){

View File

@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.artifacts;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicImmune;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
@@ -158,6 +159,14 @@ public class Artifact extends KindofMisc {
Buff.affect(target, GuidingLight.Illuminated.class);
Buff.affect(Dungeon.hero, Talent.SearingLightCooldown.class, 20f);
}
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.SUNRAY)){
// 15/25% chance
if (Random.Int(20) < 1 + 2*Dungeon.hero.pointsInTalent(Talent.SUNRAY)){
Buff.prolong(target, Blindness.class, 4f);
}
}
}
@Override

View File

@@ -62,7 +62,13 @@ public class RingOfEnergy extends Ring {
}
public static float wandChargeMultiplier( Char target ){
return (float)Math.pow(1.175, getBuffedBonus(target, Energy.class));
float bonus = (float)Math.pow(1.175, getBuffedBonus(target, Energy.class));
if (target instanceof Hero && ((Hero) target).heroClass != HeroClass.CLERIC && ((Hero) target).hasTalent(Talent.LIGHT_READING)){
bonus *= 1f + (0.2f * ((Hero) target).pointsInTalent(Talent.LIGHT_READING)/3f);
}
return bonus;
}
public static float artifactChargeMultiplier( Char target ){

View File

@@ -211,10 +211,6 @@ public class ScrollOfMetamorphosis extends ExoticScroll {
Set<Talent> curTalentsAtTier = Dungeon.hero.talents.get(tier-1).keySet();
for (HeroClass cls : HeroClass.values()){
//TODO CLERIC only T1 talents have metamorph effects atm
if (tier != 1 && cls == HeroClass.CLERIC && Dungeon.hero.heroClass != HeroClass.CLERIC){
continue;
}
ArrayList<LinkedHashMap<Talent, Integer>> clsTalents = new ArrayList<>();
Talent.initClassTalents(cls, clsTalents);

View File

@@ -128,13 +128,13 @@ public class StoneOfIntuition extends InventoryStone {
}
if (!anonymous) {
Catalog.countUse(StoneOfIntuition.class);
Talent.onRunestoneUsed(curUser, curUser.pos, StoneOfIntuition.class);
if (curUser.buff(IntuitionUseTracker.class) == null) {
Buff.affect(curUser, IntuitionUseTracker.class);
} else {
curItem.detach(curUser.belongings.backpack);
curUser.buff(IntuitionUseTracker.class).detach();
}
Talent.onRunestoneUsed(curUser, curUser.pos, StoneOfIntuition.class);
}
curGuess = null;
hide();

View File

@@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Degrade;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility;
@@ -40,7 +41,9 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WildMagic;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.DivineSense;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.GuidingLight;
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText;
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
@@ -227,6 +230,14 @@ public abstract class Wand extends Item {
Buff.affect(target, GuidingLight.Illuminated.class);
Buff.affect(Dungeon.hero, Talent.SearingLightCooldown.class, 20f);
}
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.SUNRAY)){
// 15/25% chance
if (Random.Int(20) < 1 + 2*Dungeon.hero.pointsInTalent(Talent.SUNRAY)){
Buff.prolong(target, Blindness.class, 4f);
}
}
}
@Override
@@ -502,6 +513,25 @@ public abstract class Wand extends Item {
Buff.prolong(Dungeon.hero, Talent.LingeringMagicTracker.class, 5f);
}
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.DIVINE_SENSE)){
Buff.prolong(Dungeon.hero, DivineSense.DivineSenseTracker.class, Dungeon.hero.cooldown()+1);
}
// 10/20/30%
if (Dungeon.hero.heroClass != HeroClass.CLERIC
&& Dungeon.hero.hasTalent(Talent.CLEANSE)
&& Random.Int(10) < Dungeon.hero.pointsInTalent(Talent.CLEANSE)){
boolean removed = false;
for (Buff b : Dungeon.hero.buffs()) {
if (b.type == Buff.buffType.NEGATIVE) {
b.detach();
removed = true;
}
}
if (removed) new Flare( 6, 32 ).color(0xFF4CD2, true).show( Dungeon.hero.sprite, 2f );
}
Invisibility.dispel();
updateQuickslot();

View File

@@ -46,6 +46,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Regeneration;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.RevealedArea;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Shadows;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany;
@@ -1380,7 +1381,11 @@ public abstract class Level implements Bundlable {
mindVisRange = 1+((Hero) c).pointsInTalent(Talent.HEIGHTENED_SENSES);
}
if (c.buff(DivineSense.DivineSenseTracker.class) != null){
mindVisRange = 4+4*((Hero) c).pointsInTalent(Talent.DIVINE_SENSE);
if (((Hero) c).heroClass == HeroClass.CLERIC){
mindVisRange = 4+4*((Hero) c).pointsInTalent(Talent.DIVINE_SENSE);
} else {
mindVisRange = 1+2*((Hero) c).pointsInTalent(Talent.DIVINE_SENSE);
}
}
mindVisRange = Math.max(mindVisRange, EyeOfNewt.mindVisionRange());