From 02d0f4e01807bb1efd1a7c01a139edf960393465 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 21 Feb 2025 13:38:43 -0500 Subject: [PATCH] v3.0.0: added metamorph fx for T1 cleric talents --- .../assets/messages/actors/actors.properties | 7 ++++++ .../assets/messages/items/items.properties | 1 + .../shatteredpixeldungeon/actors/Char.java | 10 ++++++++ .../actors/hero/Talent.java | 25 ++++++++++++++++--- .../actors/hero/spells/GuidingLight.java | 3 +++ .../actors/mobs/Mob.java | 4 +-- .../items/KindOfWeapon.java | 10 ++++++++ .../items/KindofMisc.java | 11 ++++++++ .../items/armor/Armor.java | 9 +++++++ .../items/artifacts/Artifact.java | 9 +++++++ .../scrolls/exotic/ScrollOfMetamorphosis.java | 5 ++-- .../items/wands/Wand.java | 7 ++++++ 12 files changed, 94 insertions(+), 7 deletions(-) diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 3f23d8476..ead1157c0 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -662,6 +662,7 @@ actors.hero.spells.guidinglight$guidinglightpriestcooldown.desc=The Priest will actors.hero.spells.guidinglight$illuminated.name=Illuminated actors.hero.spells.guidinglight$illuminated.desc=This character is glowing as a result of being struck by guiding light. While the glow isn't strong enough to brighten the surrounding area, the magical effect will make landing blows on them much easier for the Cleric. actors.hero.spells.guidinglight$illuminated.desc_priest=The Priest can additionally consume illuminated with a wand zap, strike from an ally, or effects from some artifacts. Using illuminated in this way will deal bonus damage. +actors.hero.spells.guidinglight$illuminated.desc_generic=Other heroes can still use illuminated to benefit from the searing light talent, but will not gain any accuracy. actors.hero.spells.hallowedground.name=hallowed ground actors.hero.spells.hallowedground.prompt=Choose a location @@ -884,6 +885,8 @@ actors.hero.talent$deadlyfollowuptracker.desc=The Duelist has recently attacked actors.hero.talent$combinedlethalityabilitytracker.executed=executed actors.hero.talent$satiatedspellstracker.name=Shielding Spell actors.hero.talent$satiatedspellstracker.desc=The next spell the Cleric casts will grant them a small amount of shielding. +actors.hero.talent$searinglightcooldown.name=Searing Light +actors.hero.talent$searinglightcooldown.desc=You have recently used this talent, and must wait before using it again.\n\nTurns remaining: %s. #warrior actors.hero.talent.hearty_meal.title=hearty meal @@ -1206,12 +1209,16 @@ actors.hero.talent.counter_ability.desc=_+1:_ If the Duelist uses a weapon abili #cleric actors.hero.talent.satiated_spells.title=Satiated Spells actors.hero.talent.satiated_spells.desc=_+1:_ Eating food causes the Cleric to gain _3 shielding_ the next time they cast a spell.\n\n_+2:_ Eating food causes the Cleric to gain _5 shielding_ the next time they cast a spell. +actors.hero.talent.satiated_spells.meta_desc=_If this talent is gained by a different hero_ it will instead grant shielding immediately, which will start to decay normally after 10 turns. actors.hero.talent.holy_intuition.title=holy intuition actors.hero.talent.holy_intuition.desc=_+1:_ The Cleric can cast _Holy Intuition,_ a spell that reveals whether an item is cursed at the cost of _3 charges._\n\n_+2:_ The Cleric can cast _Holy Intuition,_ a spell that reveals whether an item is cursed at the cost of _2 charges._ +actors.hero.talent.holy_intuition.meta_desc=_If this talent is gained by a different hero_ it will instead let the hero identify the curse status on a cursed item just before equipping it, 15% of the time at +1 or 25% of the time at +2. actors.hero.talent.searing_light.title=searing light actors.hero.talent.searing_light.desc=_+1:_ The Cleric's physical attacks on enemies illuminated by _Guiding Light_ deal _+4 damage._\n\n_+2:_ The Cleric's physical attacks on enemies illuminated by _Guiding Light_ deal _+6 damage._ +actors.hero.talent.searing_light.meta_desc=_If this talent is gained by a different hero_ it will instead grant its bonus damage after a wand or artifact is used on an enemy, with a 20 turn cooldown. actors.hero.talent.shield_of_light.title=shield of light actors.hero.talent.shield_of_light.desc=_+1:_ The Cleric can cast _Shield of Light,_ a spell that is cast instantly and grants them _2-4 armor_ against a target for 4 turns at the cost of 1 charge.\n\n_+2:_ The Cleric can cast _Shield of Light,_ a spell that is cast instantly and grants them _3-6 armor_ against a target for 4 turns at the cost of 1 charge. +actors.hero.talent.shield_of_light.meta_desc=_If this talent is gained by a different hero_ it will instead reduce physical damage taken from your targeted enemy by 1, 33% of the time at +1 or 50% of the time at +2. 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. diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index 4bfa0cab4..103747b4c 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -2195,6 +2195,7 @@ items.dewdrop.name=dewdrop items.dewdrop.already_full=You already have full health. items.dewdrop.desc=A crystal clear dewdrop.\n\nDue to the magic of this place, pure water has minor restorative properties. +items.equipableitem.curse_detected=You sense that the item is cursed just before you equip it! items.equipableitem.unequip_cursed=You can't remove a cursed item! items.equipableitem.ac_equip=EQUIP items.equipableitem.ac_unequip=UNEQUIP diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java index 6ed073107..6f0352bc5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java @@ -75,6 +75,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vulnerable; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness; 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; @@ -144,6 +145,7 @@ import com.shatteredpixel.shatteredpixeldungeon.plants.Swiftthistle; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.MobSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.noosa.audio.Sample; import com.watabou.utils.BArray; @@ -694,6 +696,14 @@ public abstract class Char extends Actor { int min = 1 + Dungeon.hero.pointsInTalent(Talent.SHIELD_OF_LIGHT); damage -= Random.NormalIntRange(min, 2*min); damage = Math.max(damage, 0); + } else if (this == Dungeon.hero + && Dungeon.hero.heroClass != HeroClass.CLERIC + && Dungeon.hero.hasTalent(Talent.SHIELD_OF_LIGHT) + && TargetHealthIndicator.instance.target() == enemy){ + //33/50% + if (Random.Int(6) < 1+Dungeon.hero.pointsInTalent(Talent.SHIELD_OF_LIGHT)){ + damage -= 1; + } } // hero and pris images skip this as they already benefit from hero's armor glyph proc diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java index 1b9919059..4c6f634cd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java @@ -401,13 +401,22 @@ public enum Talent { wepAbilUsed = bundle.getBoolean(WEP_ABIL_USED); } } - public static class CounterAbilityTacker extends FlavourBuff{}; + public static class CounterAbilityTacker extends FlavourBuff{} public static class SatiatedSpellsTracker extends Buff{ @Override public int icon() { return BuffIndicator.SPELL_FOOD; } - }; + } + //used for metamorphed searing light + public static class SearingLightCooldown extends FlavourBuff{ + @Override + public int icon() { + return BuffIndicator.TIME; + } + public void tintIcon(Image icon) { icon.hardlight(0f, 0f, 1f); } + public float iconFadePercent() { return Math.max(0, visualcooldown() / 20); } + } int icon; int maxPoints; @@ -615,7 +624,17 @@ public enum Talent { } } if (hero.hasTalent(SATIATED_SPELLS)){ - Buff.affect( hero, SatiatedSpellsTracker.class ); + if (hero.heroClass == HeroClass.CLERIC) { + Buff.affect(hero, SatiatedSpellsTracker.class); + } else { + //3/5 shielding, delayed up to 10 turns + int amount = 1 + 2*hero.pointsInTalent(SATIATED_SPELLS); + Barrier b = Buff.affect(hero, Barrier.class); + if (b.shielding() <= amount){ + b.setShield(amount); + b.delay(Math.max(10-b.cooldown(), 0)); + } + } } if (hero.hasTalent(ENLIGHTENING_MEAL)){ HolyTome tome = hero.belongings.getItem(HolyTome.class); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java index 98dd5881d..e177b55e6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java @@ -28,6 +28,7 @@ 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.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; @@ -161,6 +162,8 @@ public class GuidingLight extends TargetedClericSpell { if (Dungeon.hero.subClass == HeroSubClass.PRIEST){ desc += "\n\n" + Messages.get(this, "desc_priest"); + } else if (Dungeon.hero.heroClass != HeroClass.CLERIC){ + desc += "\n\n" + Messages.get(this, "desc_generic"); } return desc; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index c3dc4c2d1..7a167bc63 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -675,8 +675,8 @@ public abstract class Mob extends Char { @Override public int defenseSkill( Char enemy ) { - if (buff(GuidingLight.Illuminated.class) != null){ - //if the attacker is the hero, they must be using a weapon they have the str for + if (buff(GuidingLight.Illuminated.class) != null && Dungeon.hero.heroClass == HeroClass.CLERIC){ + //if the attacker is the cleric, they must be using a weapon they have the str for if (enemy instanceof Hero){ Hero h = (Hero) enemy; if (!(h.belongings.attackingWeapon() instanceof Weapon) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindOfWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindOfWeapon.java index 427693043..71f01bcec 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindOfWeapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindOfWeapon.java @@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; 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.messages.Messages; @@ -112,6 +113,15 @@ abstract public class KindOfWeapon extends EquipableItem { } } + // 15/25% chance + if (hero.heroClass != HeroClass.CLERIC && hero.hasTalent(Talent.HOLY_INTUITION) + && cursed && !cursedKnown + && Random.Int(20) < 1 + 2*hero.pointsInTalent(Talent.HOLY_INTUITION)){ + cursedKnown = true; + GLog.p(Messages.get(this, "curse_detected")); + return false; + } + detachAll( hero.belongings.backpack ); if (hero.belongings.weapon == null || hero.belongings.weapon.doUnequip( hero, true )) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindofMisc.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindofMisc.java index 8be302e57..337d0e5b2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindofMisc.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/KindofMisc.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.Artifact; import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring; @@ -31,6 +32,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; +import com.watabou.utils.Random; public abstract class KindofMisc extends EquipableItem { @@ -132,6 +134,15 @@ public abstract class KindofMisc extends EquipableItem { } else { + // 15/25% chance + if (hero.heroClass != HeroClass.CLERIC && hero.hasTalent(Talent.HOLY_INTUITION) + && cursed && !cursedKnown + && Random.Int(20) < 1 + 2*hero.pointsInTalent(Talent.HOLY_INTUITION)){ + cursedKnown = true; + GLog.p(Messages.get(this, "curse_detected")); + return false; + } + if (this instanceof Artifact){ if (hero.belongings.artifact == null) hero.belongings.artifact = (Artifact) this; else hero.belongings.misc = (Artifact) this; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java index 2c0f3bdd7..8f21bbd93 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java @@ -242,6 +242,15 @@ public class Armor extends EquipableItem { detach(hero.belongings.backpack); + // 15/25% chance + if (hero.heroClass != HeroClass.CLERIC && hero.hasTalent(Talent.HOLY_INTUITION) + && cursed && !cursedKnown + && Random.Int(20) < 1 + 2*hero.pointsInTalent(Talent.HOLY_INTUITION)){ + cursedKnown = true; + GLog.p(Messages.get(this, "curse_detected")); + return false; + } + if (hero.belongings.armor == null || hero.belongings.armor.doUnequip( hero, true, false )) { hero.belongings.armor = this; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/Artifact.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/Artifact.java index 53661a2cb..7d058b40e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/Artifact.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/Artifact.java @@ -26,7 +26,9 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicImmune; 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.spells.GuidingLight; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.KindofMisc; @@ -149,6 +151,13 @@ public class Artifact extends KindofMisc { target.buff(GuidingLight.Illuminated.class).detach(); target.damage(Dungeon.hero.lvl, GuidingLight.INSTANCE); } + + if (Dungeon.hero.heroClass != HeroClass.CLERIC + && Dungeon.hero.hasTalent(Talent.SEARING_LIGHT) + && Dungeon.hero.buff(Talent.SearingLightCooldown.class) == null){ + Buff.affect(target, GuidingLight.Illuminated.class); + Buff.affect(Dungeon.hero, Talent.SearingLightCooldown.class, 20f); + } } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfMetamorphosis.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfMetamorphosis.java index efbbe999d..a46570960 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfMetamorphosis.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfMetamorphosis.java @@ -211,8 +211,9 @@ public class ScrollOfMetamorphosis extends ExoticScroll { Set curTalentsAtTier = Dungeon.hero.talents.get(tier-1).keySet(); for (HeroClass cls : HeroClass.values()){ - if (cls == HeroClass.CLERIC && Dungeon.hero.heroClass != HeroClass.CLERIC){ - continue; //TODO CLERIC for now no metamorphing cleric talents + //TODO CLERIC only T1 talents have metamorph effects atm + if (tier != 1 && cls == HeroClass.CLERIC && Dungeon.hero.heroClass != HeroClass.CLERIC){ + continue; } ArrayList> clsTalents = new ArrayList<>(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java index fea268115..eb4378a35 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java @@ -220,6 +220,13 @@ public abstract class Wand extends Item { target.buff(GuidingLight.Illuminated.class).detach(); target.damage(Dungeon.hero.lvl, GuidingLight.INSTANCE); } + + if (Dungeon.hero.heroClass != HeroClass.CLERIC + && Dungeon.hero.hasTalent(Talent.SEARING_LIGHT) + && Dungeon.hero.buff(Talent.SearingLightCooldown.class) == null){ + Buff.affect(target, GuidingLight.Illuminated.class); + Buff.affect(Dungeon.hero, Talent.SearingLightCooldown.class, 20f); + } } @Override